mirror of
https://github.com/odin-lang/Odin.git
synced 2026-01-04 12:07:45 +00:00
Compile wasm64; Add lb_run_remove_unused_function_pass
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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"
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
19
src/main.cpp
19
src/main.cpp
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user