Compile wasm64; Add lb_run_remove_unused_function_pass

This commit is contained in:
gingerBill
2021-10-31 00:11:38 +01:00
parent 5bc8a491a7
commit 8ef6f9dd7b
10 changed files with 128 additions and 37 deletions

View File

@@ -1,23 +1,12 @@
package runtime
@(private)
byte_slice :: #force_inline proc "contextless" (data: rawptr, len: int) -> []byte {
return transmute([]u8)Raw_Slice{data=data, len=max(len, 0)}
}
DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE: int : #config(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, 1<<22)
Default_Temp_Allocator :: struct {
data: []byte,
curr_offset: int,
prev_allocation: rawptr,
backup_allocator: Allocator,
leaked_allocations: [dynamic][]byte,
}
when ODIN_OS == "freestanding" {
Default_Temp_Allocator :: struct {
}
default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backup_allocator := context.allocator) {
}
@@ -30,6 +19,14 @@ when ODIN_OS == "freestanding" {
return nil, nil
}
} else {
Default_Temp_Allocator :: struct {
data: []byte,
curr_offset: int,
prev_allocation: rawptr,
backup_allocator: Allocator,
leaked_allocations: [dynamic][]byte,
}
default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backup_allocator := context.allocator) {
s.data = make_aligned([]byte, size, 2*align_of(rawptr), backup_allocator)
s.curr_offset = 0

View File

@@ -2,6 +2,11 @@ package runtime
import "core:intrinsics"
@(private)
byte_slice :: #force_inline proc "contextless" (data: rawptr, len: int) -> []byte #no_bounds_check {
return ([^]byte)(data)[:max(len, 0)]
}
bswap_16 :: proc "contextless" (x: u16) -> u16 {
return x>>8 | x<<8
}

View File

@@ -895,7 +895,11 @@ void init_build_context(TargetMetrics *cross_target) {
}
} else if (is_arch_wasm()) {
bc->link_flags = str_lit("--no-entry --export-table --export-all --allow-undefined ");
if (bc->metrics.arch == TargetArch_wasm32) {
bc->link_flags = str_lit("--no-entry --export-table --export-all --allow-undefined ");
} else {
bc->link_flags = str_lit("--no-entry --export-table --export-all --allow-undefined -mwasm64 ");
}
} else {
gb_printf_err("Compiler Error: Unsupported architecture\n");;
gb_exit(1);

View File

@@ -899,6 +899,10 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
mutex_unlock(&ctx->info->foreign_mutex);
}
}
if (e->Procedure.link_name.len > 0 ) {
e->flags |= EntityFlag_CustomLinkName;
}
}
void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr, Ast *init_expr) {
@@ -990,6 +994,10 @@ void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr,
string_map_set(fp, key, e);
}
}
if (e->Variable.link_name.len > 0) {
e->flags |= EntityFlag_CustomLinkName;
}
if (init_expr == nullptr) {
if (type_expr == nullptr) {

View File

@@ -74,9 +74,10 @@ enum EntityFlag : u64 {
EntityFlag_Test = 1ull<<30,
EntityFlag_Init = 1ull<<31,
EntityFlag_CustomLinkName = 1ull<<40,
EntityFlag_Overridden = 1ull<<63,
};
enum EntityState : u32 {

View File

@@ -1064,14 +1064,10 @@ struct lbLLVMModulePassWorkerData {
};
WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) {
GB_ASSERT(MULTITHREAD_OBJECT_GENERATION);
auto wd = cast(lbLLVMModulePassWorkerData *)data;
LLVMPassManagerRef module_pass_manager = LLVMCreatePassManager();
lb_populate_module_pass_manager(wd->target_machine, module_pass_manager, build_context.optimization_level);
LLVMRunPassManager(module_pass_manager, wd->m->mod);
return 0;
}
@@ -1661,6 +1657,8 @@ void lb_generate_code(lbGenerator *gen) {
for_array(i, gen->modules.entries) {
lbModule *m = gen->modules.entries[i].value;
lb_run_remove_unused_function_pass(m->mod);
auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
wd->m = m;
@@ -1738,8 +1736,16 @@ void lb_generate_code(lbGenerator *gen) {
}
TIME_SECTION("LLVM Object Generation");
isize non_empty_module_count = 0;
for_array(j, gen->modules.entries) {
lbModule *m = gen->modules.entries[j].value;
if (!lb_is_module_empty(m)) {
non_empty_module_count += 1;
}
}
if (do_threading) {
if (do_threading && non_empty_module_count > 1) {
for_array(j, gen->modules.entries) {
lbModule *m = gen->modules.entries[j].value;
if (lb_is_module_empty(m)) {

View File

@@ -585,3 +585,24 @@ enum : LLVMAttributeIndex {
LLVMAttributeIndex_FunctionIndex = ~0u,
LLVMAttributeIndex_FirstArgIndex = 1,
};
char const *llvm_linkage_strings[] = {
"external linkage",
"available externally linkage",
"link once any linkage",
"link once odr linkage",
"link once odr auto hide linkage",
"weak any linkage",
"weak odr linkage",
"appending linkage",
"internal linkage",
"private linkage",
"dllimport linkage",
"dllexport linkage",
"external weak linkage",
"ghost linkage",
"common linkage",
"linker private linkage",
"linker private weak linkage"
};

View File

@@ -355,3 +355,52 @@ void lb_run_function_pass_manager(LLVMPassManagerRef fpm, lbProcedure *p) {
// are not removed
lb_run_remove_dead_instruction_pass(p);
}
void lb_run_remove_unused_function_pass(LLVMModuleRef mod) {
isize removal_count = 0;
isize pass_count = 0;
isize const max_pass_count = 10;
// Custom remove dead function pass
for (; pass_count < max_pass_count; pass_count++) {
bool was_dead_function = false;
for (LLVMValueRef func = LLVMGetFirstFunction(mod);
func != nullptr;
/**/
) {
LLVMValueRef curr_func = func;
func = LLVMGetNextFunction(func);
LLVMUseRef first_use = LLVMGetFirstUse(curr_func);
if (first_use != nullptr) {
continue;
}
String name = {};
name.text = cast(u8 *)LLVMGetValueName2(curr_func, cast(size_t *)&name.len);
if (LLVMIsDeclaration(curr_func)) {
// Ignore for the time being
continue;
}
LLVMLinkage linkage = LLVMGetLinkage(curr_func);
switch (linkage) {
case LLVMExternalLinkage:
case LLVMDLLImportLinkage:
case LLVMDLLExportLinkage:
default:
continue;
case LLVMInternalLinkage:
break;
}
LLVMDeleteFunction(curr_func);
was_dead_function = true;
removal_count += 1;
}
if (!was_dead_function) {
break;
}
}
}

View File

@@ -195,13 +195,19 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
// then it is very likely it is required by LLVM and thus cannot have internal linkage
if (entity->pkg != nullptr && entity->pkg->kind == Package_Runtime && p->body != nullptr) {
GB_ASSERT(entity->kind == Entity_Procedure);
if (entity->Procedure.link_name != "") {
LLVMSetLinkage(p->value, LLVMExternalLinkage);
String link_name = entity->Procedure.link_name;
if (entity->flags & EntityFlag_CustomLinkName &&
link_name != "") {
if (string_starts_with(link_name, str_lit("__"))) {
LLVMSetLinkage(p->value, LLVMExternalLinkage);
} else {
LLVMSetLinkage(p->value, LLVMInternalLinkage);
}
}
}
}
}
if (p->is_foreign) {
if (is_arch_wasm()) {
char const *import_name = alloc_cstring(permanent_allocator(), p->name);
@@ -217,6 +223,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
LLVMAddTargetDependentFunctionAttr(p->value, "wasm-import-module", module_name);
}
}
// NOTE(bill): offset==0 is the return value
isize offset = 1;

View File

@@ -135,19 +135,12 @@ i32 linker_stage(lbGenerator *gen) {
if (is_arch_wasm()) {
timings_start_section(timings, str_lit("wasm-ld"));
if (build_context.metrics.arch == TargetArch_wasm32) {
result = system_exec_command_line_app("wasm-ld",
"\"%.*s\\bin\\wasm-ld\" \"%.*s.wasm.o\" -o \"%.*s.wasm\" %.*s %.*s",
LIT(build_context.ODIN_ROOT),
LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags));
} else {
GB_ASSERT(build_context.metrics.arch == TargetArch_wasm64);
result = system_exec_command_line_app("wasm-ld",
"\"%.*s\\bin\\wasm-ld\" \"%.*s.wasm.o\" -o \"%.*s.wasm\" %.*s %.*s",
LIT(build_context.ODIN_ROOT),
LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags));
}
GB_ASSERT(build_context.metrics.arch == TargetArch_wasm64);
result = system_exec_command_line_app("wasm-ld",
"\"%.*s\\bin\\wasm-ld\" \"%.*s.wasm.o\" -o \"%.*s.wasm\" %.*s %.*s",
LIT(build_context.ODIN_ROOT),
LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags));
return result;
}