| ... | ... | @@ -380,9 +380,36 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { |
| 380 | 380 | LLVMTypeRef fn_llvm_type = fn->raw_type_ref; |
| 381 | 381 | LLVMValueRef llvm_fn = nullptr; |
| 382 | 382 | if (fn->body_node == nullptr) { |
| 383 | assert(fn->proto_node->type == NodeTypeFnProto); |
| 384 | AstNodeFnProto *fn_proto = &fn->proto_node->data.fn_proto; |
| 385 | |
| 383 | 386 | const unsigned fn_addrspace = ZigLLVMDataLayoutGetProgramAddressSpace(g->target_data_ref); |
| 387 | |
| 388 | // The compiler tries to deduplicate extern definitions by looking up |
| 389 | // their name, this was introduced to allow the declaration of the same |
| 390 | // extern function with differing prototypes. |
| 391 | // When Wasm is targeted this check becomes a problem as the user may |
| 392 | // declare two (or more) extern functions sharing the same name but |
| 393 | // imported from different modules! |
| 394 | // To overcome this problem we generate a mangled identifier out of the |
| 395 | // import and the function name, this name is only visible within the |
| 396 | // compiler as we're telling LLVM (using 'wasm-import-name' and |
| 397 | // 'wasm-import-name') what the real function name is and where to find |
| 398 | // it. |
| 399 | const bool use_mangled_name = target_is_wasm(g->zig_target) && |
| 400 | fn_proto->is_extern && fn_proto->lib_name != nullptr; |
| 401 | // Pick a weird name to avoid collisions... |
| 402 | // This whole function should be burned to the ground. |
| 403 | Buf *mangled_symbol_buf = use_mangled_name ? |
| 404 | buf_sprintf("%s|%s", unmangled_name, buf_ptr(fn_proto->lib_name)) : |
| 405 | nullptr; |
| 406 | symbol_name = use_mangled_name ? |
| 407 | buf_ptr(mangled_symbol_buf) : unmangled_name; |
| 408 | |
| 384 | 409 | LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, symbol_name); |
| 410 | |
| 385 | 411 | if (existing_llvm_fn) { |
| 412 | if (mangled_symbol_buf) buf_destroy(mangled_symbol_buf); |
| 386 | 413 | return LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, fn_addrspace)); |
| 387 | 414 | } else { |
| 388 | 415 | Buf *buf_symbol_name = buf_create_from_str(symbol_name); |
| ... | ... | @@ -392,12 +419,9 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { |
| 392 | 419 | if (entry == nullptr) { |
| 393 | 420 | llvm_fn = LLVMAddFunction(g->module, symbol_name, fn_llvm_type); |
| 394 | 421 | |
| 395 | | if (target_is_wasm(g->zig_target)) { |
| 396 | | assert(fn->proto_node->type == NodeTypeFnProto); |
| 397 | | AstNodeFnProto *fn_proto = &fn->proto_node->data.fn_proto; |
| 398 | | if (fn_proto-> is_extern && fn_proto->lib_name != nullptr ) { |
| 399 | | addLLVMFnAttrStr(llvm_fn, "wasm-import-module", buf_ptr(fn_proto->lib_name)); |
| 400 | | } |
| 422 | if (use_mangled_name) { |
| 423 | addLLVMFnAttrStr(llvm_fn, "wasm-import-name", unmangled_name); |
| 424 | addLLVMFnAttrStr(llvm_fn, "wasm-import-module", buf_ptr(fn_proto->lib_name)); |
| 401 | 425 | } |
| 402 | 426 | } else { |
| 403 | 427 | assert(entry->value->id == TldIdFn); |
| ... | ... | @@ -407,8 +431,11 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { |
| 407 | 431 | tld_fn->fn_entry->llvm_value = LLVMAddFunction(g->module, symbol_name, |
| 408 | 432 | tld_fn->fn_entry->raw_type_ref); |
| 409 | 433 | llvm_fn = LLVMConstBitCast(tld_fn->fn_entry->llvm_value, LLVMPointerType(fn_llvm_type, fn_addrspace)); |
| 434 | if (mangled_symbol_buf) buf_destroy(mangled_symbol_buf); |
| 410 | 435 | return llvm_fn; |
| 411 | 436 | } |
| 437 | |
| 438 | if (mangled_symbol_buf) buf_destroy(mangled_symbol_buf); |
| 412 | 439 | } |
| 413 | 440 | } else { |
| 414 | 441 | if (llvm_fn == nullptr) { |