diff options
Diffstat (limited to 'src/stage1/codegen.cpp')
| -rw-r--r-- | src/stage1/codegen.cpp | 39 |
1 files changed, 33 insertions, 6 deletions
diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index 38c537ae12..b9c068d7f7 100644 --- a/src/stage1/codegen.cpp +++ b/src/stage1/codegen.cpp @@ -380,9 +380,36 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { LLVMTypeRef fn_llvm_type = fn->raw_type_ref; LLVMValueRef llvm_fn = nullptr; if (fn->body_node == nullptr) { + assert(fn->proto_node->type == NodeTypeFnProto); + AstNodeFnProto *fn_proto = &fn->proto_node->data.fn_proto; + const unsigned fn_addrspace = ZigLLVMDataLayoutGetProgramAddressSpace(g->target_data_ref); + + // The compiler tries to deduplicate extern definitions by looking up + // their name, this was introduced to allow the declaration of the same + // extern function with differing prototypes. + // When Wasm is targeted this check becomes a problem as the user may + // declare two (or more) extern functions sharing the same name but + // imported from different modules! + // To overcome this problem we generate a mangled identifier out of the + // import and the function name, this name is only visible within the + // compiler as we're telling LLVM (using 'wasm-import-name' and + // 'wasm-import-name') what the real function name is and where to find + // it. + const bool use_mangled_name = target_is_wasm(g->zig_target) && + fn_proto->is_extern && fn_proto->lib_name != nullptr; + // Pick a weird name to avoid collisions... + // This whole function should be burned to the ground. + Buf *mangled_symbol_buf = use_mangled_name ? + buf_sprintf("%s|%s", unmangled_name, buf_ptr(fn_proto->lib_name)) : + nullptr; + symbol_name = use_mangled_name ? + buf_ptr(mangled_symbol_buf) : unmangled_name; + LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, symbol_name); + if (existing_llvm_fn) { + if (mangled_symbol_buf) buf_destroy(mangled_symbol_buf); return LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, fn_addrspace)); } else { Buf *buf_symbol_name = buf_create_from_str(symbol_name); @@ -392,12 +419,9 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { if (entry == nullptr) { llvm_fn = LLVMAddFunction(g->module, symbol_name, fn_llvm_type); - if (target_is_wasm(g->zig_target)) { - assert(fn->proto_node->type == NodeTypeFnProto); - AstNodeFnProto *fn_proto = &fn->proto_node->data.fn_proto; - if (fn_proto-> is_extern && fn_proto->lib_name != nullptr ) { - addLLVMFnAttrStr(llvm_fn, "wasm-import-module", buf_ptr(fn_proto->lib_name)); - } + if (use_mangled_name) { + addLLVMFnAttrStr(llvm_fn, "wasm-import-name", unmangled_name); + addLLVMFnAttrStr(llvm_fn, "wasm-import-module", buf_ptr(fn_proto->lib_name)); } } else { assert(entry->value->id == TldIdFn); @@ -407,8 +431,11 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { tld_fn->fn_entry->llvm_value = LLVMAddFunction(g->module, symbol_name, tld_fn->fn_entry->raw_type_ref); llvm_fn = LLVMConstBitCast(tld_fn->fn_entry->llvm_value, LLVMPointerType(fn_llvm_type, fn_addrspace)); + if (mangled_symbol_buf) buf_destroy(mangled_symbol_buf); return llvm_fn; } + + if (mangled_symbol_buf) buf_destroy(mangled_symbol_buf); } } else { if (llvm_fn == nullptr) { |
