mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-03 22:28:46 +00:00
Compile wasm64; Add lb_run_remove_unused_function_pass
This commit is contained in:
@@ -1,23 +1,12 @@
|
|||||||
package runtime
|
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_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" {
|
when ODIN_OS == "freestanding" {
|
||||||
|
Default_Temp_Allocator :: struct {
|
||||||
|
}
|
||||||
|
|
||||||
default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backup_allocator := context.allocator) {
|
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
|
return nil, nil
|
||||||
}
|
}
|
||||||
} else {
|
} 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) {
|
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.data = make_aligned([]byte, size, 2*align_of(rawptr), backup_allocator)
|
||||||
s.curr_offset = 0
|
s.curr_offset = 0
|
||||||
|
|||||||
@@ -2,6 +2,11 @@ package runtime
|
|||||||
|
|
||||||
import "core:intrinsics"
|
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 {
|
bswap_16 :: proc "contextless" (x: u16) -> u16 {
|
||||||
return x>>8 | x<<8
|
return x>>8 | x<<8
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -895,7 +895,11 @@ void init_build_context(TargetMetrics *cross_target) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else if (is_arch_wasm()) {
|
} 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 {
|
} else {
|
||||||
gb_printf_err("Compiler Error: Unsupported architecture\n");;
|
gb_printf_err("Compiler Error: Unsupported architecture\n");;
|
||||||
gb_exit(1);
|
gb_exit(1);
|
||||||
|
|||||||
@@ -899,6 +899,10 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
|||||||
mutex_unlock(&ctx->info->foreign_mutex);
|
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) {
|
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);
|
string_map_set(fp, key, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (e->Variable.link_name.len > 0) {
|
||||||
|
e->flags |= EntityFlag_CustomLinkName;
|
||||||
|
}
|
||||||
|
|
||||||
if (init_expr == nullptr) {
|
if (init_expr == nullptr) {
|
||||||
if (type_expr == nullptr) {
|
if (type_expr == nullptr) {
|
||||||
|
|||||||
+2
-1
@@ -74,9 +74,10 @@ enum EntityFlag : u64 {
|
|||||||
|
|
||||||
EntityFlag_Test = 1ull<<30,
|
EntityFlag_Test = 1ull<<30,
|
||||||
EntityFlag_Init = 1ull<<31,
|
EntityFlag_Init = 1ull<<31,
|
||||||
|
|
||||||
|
EntityFlag_CustomLinkName = 1ull<<40,
|
||||||
|
|
||||||
EntityFlag_Overridden = 1ull<<63,
|
EntityFlag_Overridden = 1ull<<63,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum EntityState : u32 {
|
enum EntityState : u32 {
|
||||||
|
|||||||
+11
-5
@@ -1064,14 +1064,10 @@ struct lbLLVMModulePassWorkerData {
|
|||||||
};
|
};
|
||||||
|
|
||||||
WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) {
|
WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) {
|
||||||
GB_ASSERT(MULTITHREAD_OBJECT_GENERATION);
|
|
||||||
|
|
||||||
auto wd = cast(lbLLVMModulePassWorkerData *)data;
|
auto wd = cast(lbLLVMModulePassWorkerData *)data;
|
||||||
|
|
||||||
LLVMPassManagerRef module_pass_manager = LLVMCreatePassManager();
|
LLVMPassManagerRef module_pass_manager = LLVMCreatePassManager();
|
||||||
lb_populate_module_pass_manager(wd->target_machine, module_pass_manager, build_context.optimization_level);
|
lb_populate_module_pass_manager(wd->target_machine, module_pass_manager, build_context.optimization_level);
|
||||||
LLVMRunPassManager(module_pass_manager, wd->m->mod);
|
LLVMRunPassManager(module_pass_manager, wd->m->mod);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1661,6 +1657,8 @@ void lb_generate_code(lbGenerator *gen) {
|
|||||||
|
|
||||||
for_array(i, gen->modules.entries) {
|
for_array(i, gen->modules.entries) {
|
||||||
lbModule *m = gen->modules.entries[i].value;
|
lbModule *m = gen->modules.entries[i].value;
|
||||||
|
|
||||||
|
lb_run_remove_unused_function_pass(m->mod);
|
||||||
|
|
||||||
auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
|
auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
|
||||||
wd->m = m;
|
wd->m = m;
|
||||||
@@ -1738,8 +1736,16 @@ void lb_generate_code(lbGenerator *gen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TIME_SECTION("LLVM Object Generation");
|
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) {
|
for_array(j, gen->modules.entries) {
|
||||||
lbModule *m = gen->modules.entries[j].value;
|
lbModule *m = gen->modules.entries[j].value;
|
||||||
if (lb_is_module_empty(m)) {
|
if (lb_is_module_empty(m)) {
|
||||||
|
|||||||
@@ -585,3 +585,24 @@ enum : LLVMAttributeIndex {
|
|||||||
LLVMAttributeIndex_FunctionIndex = ~0u,
|
LLVMAttributeIndex_FunctionIndex = ~0u,
|
||||||
LLVMAttributeIndex_FirstArgIndex = 1,
|
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"
|
||||||
|
};
|
||||||
@@ -355,3 +355,52 @@ void lb_run_function_pass_manager(LLVMPassManagerRef fpm, lbProcedure *p) {
|
|||||||
// are not removed
|
// are not removed
|
||||||
lb_run_remove_dead_instruction_pass(p);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
// 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) {
|
if (entity->pkg != nullptr && entity->pkg->kind == Package_Runtime && p->body != nullptr) {
|
||||||
GB_ASSERT(entity->kind == Entity_Procedure);
|
GB_ASSERT(entity->kind == Entity_Procedure);
|
||||||
if (entity->Procedure.link_name != "") {
|
String link_name = entity->Procedure.link_name;
|
||||||
LLVMSetLinkage(p->value, LLVMExternalLinkage);
|
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 (p->is_foreign) {
|
||||||
if (is_arch_wasm()) {
|
if (is_arch_wasm()) {
|
||||||
char const *import_name = alloc_cstring(permanent_allocator(), p->name);
|
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);
|
LLVMAddTargetDependentFunctionAttr(p->value, "wasm-import-module", module_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// NOTE(bill): offset==0 is the return value
|
// NOTE(bill): offset==0 is the return value
|
||||||
isize offset = 1;
|
isize offset = 1;
|
||||||
|
|||||||
+6
-13
@@ -135,19 +135,12 @@ i32 linker_stage(lbGenerator *gen) {
|
|||||||
|
|
||||||
if (is_arch_wasm()) {
|
if (is_arch_wasm()) {
|
||||||
timings_start_section(timings, str_lit("wasm-ld"));
|
timings_start_section(timings, str_lit("wasm-ld"));
|
||||||
|
|
||||||
if (build_context.metrics.arch == TargetArch_wasm32) {
|
GB_ASSERT(build_context.metrics.arch == TargetArch_wasm64);
|
||||||
result = system_exec_command_line_app("wasm-ld",
|
result = system_exec_command_line_app("wasm-ld",
|
||||||
"\"%.*s\\bin\\wasm-ld\" \"%.*s.wasm.o\" -o \"%.*s.wasm\" %.*s %.*s",
|
"\"%.*s\\bin\\wasm-ld\" \"%.*s.wasm.o\" -o \"%.*s.wasm\" %.*s %.*s",
|
||||||
LIT(build_context.ODIN_ROOT),
|
LIT(build_context.ODIN_ROOT),
|
||||||
LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags));
|
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));
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user