| ... | @@ -155,6 +155,15 @@ pub const Object = struct { | ... | @@ -155,6 +155,15 @@ pub const Object = struct { |
| 155 | llvm_module: *const llvm.Module, | 155 | llvm_module: *const llvm.Module, |
| 156 | context: *const llvm.Context, | 156 | context: *const llvm.Context, |
| 157 | target_machine: *const llvm.TargetMachine, | 157 | target_machine: *const llvm.TargetMachine, |
| | 158 | /// Ideally we would use `llvm_module.getNamedFunction` to go from *Decl to LLVM function, |
| | 159 | /// but that has some downsides: |
| | 160 | /// * we have to compute the fully qualified name every time we want to do the lookup |
| | 161 | /// * for externally linked functions, the name is not fully qualified, but when |
| | 162 | /// a Decl goes from exported to not exported and vice-versa, we would use the wrong |
| | 163 | /// version of the name and incorrectly get function not found in the llvm module. |
| | 164 | /// * it works for functions not all globals. |
| | 165 | /// Therefore, this table keeps track of the mapping. |
| | 166 | decl_map: std.AutoHashMapUnmanaged(*const Module.Decl, *const llvm.Value), |
| 158 | | 167 | |
| 159 | pub fn create(gpa: *Allocator, options: link.Options) !*Object { | 168 | pub fn create(gpa: *Allocator, options: link.Options) !*Object { |
| 160 | const obj = try gpa.create(Object); | 169 | const obj = try gpa.create(Object); |
| ... | @@ -241,18 +250,20 @@ pub const Object = struct { | ... | @@ -241,18 +250,20 @@ pub const Object = struct { |
| 241 | .llvm_module = llvm_module, | 250 | .llvm_module = llvm_module, |
| 242 | .context = context, | 251 | .context = context, |
| 243 | .target_machine = target_machine, | 252 | .target_machine = target_machine, |
| | 253 | .decl_map = .{}, |
| 244 | }; | 254 | }; |
| 245 | } | 255 | } |
| 246 | | 256 | |
| 247 | pub fn deinit(self: *Object) void { | 257 | pub fn deinit(self: *Object, gpa: *Allocator) void { |
| 248 | self.target_machine.dispose(); | 258 | self.target_machine.dispose(); |
| 249 | self.llvm_module.dispose(); | 259 | self.llvm_module.dispose(); |
| 250 | self.context.dispose(); | 260 | self.context.dispose(); |
| | 261 | self.decl_map.deinit(gpa); |
| 251 | self.* = undefined; | 262 | self.* = undefined; |
| 252 | } | 263 | } |
| 253 | | 264 | |
| 254 | pub fn destroy(self: *Object, gpa: *Allocator) void { | 265 | pub fn destroy(self: *Object, gpa: *Allocator) void { |
| 255 | self.deinit(); | 266 | self.deinit(gpa); |
| 256 | gpa.destroy(self); | 267 | gpa.destroy(self); |
| 257 | } | 268 | } |
| 258 | | 269 | |
| ... | @@ -450,41 +461,62 @@ pub const Object = struct { | ... | @@ -450,41 +461,62 @@ pub const Object = struct { |
| 450 | ) !void { | 461 | ) !void { |
| 451 | // If the module does not already have the function, we ignore this function call | 462 | // If the module does not already have the function, we ignore this function call |
| 452 | // because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`. | 463 | // because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`. |
| 453 | const llvm_fn = self.llvm_module.getNamedFunction(decl.name) orelse return; | 464 | const llvm_fn = self.decl_map.get(decl) orelse return; |
| 454 | const is_extern = decl.val.tag() == .extern_fn; | 465 | const is_extern = decl.val.tag() == .extern_fn; |
| 455 | if (is_extern or exports.len != 0) { | 466 | if (is_extern) { |
| | 467 | llvm_fn.setValueName(decl.name); |
| | 468 | llvm_fn.setUnnamedAddr(.False); |
| 456 | llvm_fn.setLinkage(.External); | 469 | llvm_fn.setLinkage(.External); |
| | 470 | } else if (exports.len != 0) { |
| | 471 | const exp_name = exports[0].options.name; |
| | 472 | llvm_fn.setValueName2(exp_name.ptr, exp_name.len); |
| 457 | llvm_fn.setUnnamedAddr(.False); | 473 | llvm_fn.setUnnamedAddr(.False); |
| | 474 | switch (exports[0].options.linkage) { |
| | 475 | .Internal => unreachable, |
| | 476 | .Strong => llvm_fn.setLinkage(.External), |
| | 477 | .Weak => llvm_fn.setLinkage(.WeakODR), |
| | 478 | .LinkOnce => llvm_fn.setLinkage(.LinkOnceODR), |
| | 479 | } |
| | 480 | // If a Decl is exported more than one time (which is rare), |
| | 481 | // we add aliases for all but the first export. |
| | 482 | // TODO LLVM C API does not support deleting aliases. We need to |
| | 483 | // patch it to support this or figure out how to wrap the C++ API ourselves. |
| | 484 | // Until then we iterate over existing aliases and make them point |
| | 485 | // to the correct decl, or otherwise add a new alias. Old aliases are leaked. |
| | 486 | for (exports[1..]) |exp| { |
| | 487 | const exp_name_z = try module.gpa.dupeZ(u8, exp.options.name); |
| | 488 | defer module.gpa.free(exp_name_z); |
| | 489 | |
| | 490 | if (self.llvm_module.getNamedGlobalAlias(exp_name_z.ptr, exp_name_z.len)) |alias| { |
| | 491 | alias.setAliasee(llvm_fn); |
| | 492 | } else { |
| | 493 | const alias = self.llvm_module.addAlias(llvm_fn.typeOf(), llvm_fn, exp_name_z); |
| | 494 | switch (exp.options.linkage) { |
| | 495 | .Internal => alias.setLinkage(.Internal), |
| | 496 | .Strong => alias.setLinkage(.External), |
| | 497 | .Weak => { |
| | 498 | if (is_extern) { |
| | 499 | alias.setLinkage(.ExternalWeak); |
| | 500 | } else { |
| | 501 | alias.setLinkage(.WeakODR); |
| | 502 | } |
| | 503 | }, |
| | 504 | .LinkOnce => alias.setLinkage(.LinkOnceODR), |
| | 505 | } |
| | 506 | } |
| | 507 | } |
| 458 | } else { | 508 | } else { |
| | 509 | const fqn = try decl.getFullyQualifiedName(module.gpa); |
| | 510 | defer module.gpa.free(fqn); |
| | 511 | llvm_fn.setValueName2(fqn.ptr, fqn.len); |
| 459 | llvm_fn.setLinkage(.Internal); | 512 | llvm_fn.setLinkage(.Internal); |
| 460 | llvm_fn.setUnnamedAddr(.True); | 513 | llvm_fn.setUnnamedAddr(.True); |
| 461 | } | 514 | } |
| 462 | // TODO LLVM C API does not support deleting aliases. We need to | 515 | } |
| 463 | // patch it to support this or figure out how to wrap the C++ API ourselves. | 516 | |
| 464 | // Until then we iterate over existing aliases and make them point | 517 | pub fn freeDecl(self: *Object, decl: *Module.Decl) void { |
| 465 | // to the correct decl, or otherwise add a new alias. Old aliases are leaked. | 518 | const llvm_value = self.decl_map.get(decl) orelse return; |
| 466 | for (exports) |exp| { | 519 | llvm_value.deleteGlobal(); |
| 467 | const exp_name_z = try module.gpa.dupeZ(u8, exp.options.name); | | |
| 468 | defer module.gpa.free(exp_name_z); | | |
| 469 | | | |
| 470 | if (self.llvm_module.getNamedGlobalAlias(exp_name_z.ptr, exp_name_z.len)) |alias| { | | |
| 471 | alias.setAliasee(llvm_fn); | | |
| 472 | } else { | | |
| 473 | const alias = self.llvm_module.addAlias(llvm_fn.typeOf(), llvm_fn, exp_name_z); | | |
| 474 | switch (exp.options.linkage) { | | |
| 475 | .Internal => alias.setLinkage(.Internal), | | |
| 476 | .Strong => alias.setLinkage(.External), | | |
| 477 | .Weak => { | | |
| 478 | if (is_extern) { | | |
| 479 | alias.setLinkage(.ExternalWeak); | | |
| 480 | } else { | | |
| 481 | alias.setLinkage(.WeakODR); | | |
| 482 | } | | |
| 483 | }, | | |
| 484 | .LinkOnce => alias.setLinkage(.LinkOnceODR), | | |
| 485 | } | | |
| 486 | } | | |
| 487 | } | | |
| 488 | } | 520 | } |
| 489 | }; | 521 | }; |
| 490 | | 522 | |
| ... | @@ -493,9 +525,8 @@ pub const DeclGen = struct { | ... | @@ -493,9 +525,8 @@ pub const DeclGen = struct { |
| 493 | object: *Object, | 525 | object: *Object, |
| 494 | module: *Module, | 526 | module: *Module, |
| 495 | decl: *Module.Decl, | 527 | decl: *Module.Decl, |
| 496 | err_msg: ?*Module.ErrorMsg, | | |
| 497 | | | |
| 498 | gpa: *Allocator, | 528 | gpa: *Allocator, |
| | 529 | err_msg: ?*Module.ErrorMsg, |
| 499 | | 530 | |
| 500 | fn todo(self: *DeclGen, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } { | 531 | fn todo(self: *DeclGen, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } { |
| 501 | @setCold(true); | 532 | @setCold(true); |
| ... | @@ -540,7 +571,8 @@ pub const DeclGen = struct { | ... | @@ -540,7 +571,8 @@ pub const DeclGen = struct { |
| 540 | /// Note that this can be called before the function's semantic analysis has | 571 | /// Note that this can be called before the function's semantic analysis has |
| 541 | /// completed, so if any attributes rely on that, they must be done in updateFunc, not here. | 572 | /// completed, so if any attributes rely on that, they must be done in updateFunc, not here. |
| 542 | fn resolveLlvmFunction(self: *DeclGen, decl: *Module.Decl) !*const llvm.Value { | 573 | fn resolveLlvmFunction(self: *DeclGen, decl: *Module.Decl) !*const llvm.Value { |
| 543 | if (self.llvmModule().getNamedFunction(decl.name)) |llvm_fn| return llvm_fn; | 574 | const gop = try self.object.decl_map.getOrPut(self.gpa, decl); |
| | 575 | if (gop.found_existing) return gop.value_ptr.*; |
| 544 | | 576 | |
| 545 | assert(decl.has_tv); | 577 | assert(decl.has_tv); |
| 546 | const zig_fn_type = decl.ty; | 578 | const zig_fn_type = decl.ty; |
| ... | @@ -570,7 +602,12 @@ pub const DeclGen = struct { | ... | @@ -570,7 +602,12 @@ pub const DeclGen = struct { |
| 570 | .False, | 602 | .False, |
| 571 | ); | 603 | ); |
| 572 | const llvm_addrspace = self.llvmAddressSpace(decl.@"addrspace"); | 604 | const llvm_addrspace = self.llvmAddressSpace(decl.@"addrspace"); |
| 573 | const llvm_fn = self.llvmModule().addFunctionInAddressSpace(decl.name, fn_type, llvm_addrspace); | 605 | |
| | 606 | const fqn = try decl.getFullyQualifiedName(self.gpa); |
| | 607 | defer self.gpa.free(fqn); |
| | 608 | |
| | 609 | const llvm_fn = self.llvmModule().addFunctionInAddressSpace(fqn, fn_type, llvm_addrspace); |
| | 610 | gop.value_ptr.* = llvm_fn; |
| 574 | | 611 | |
| 575 | const is_extern = decl.val.tag() == .extern_fn; | 612 | const is_extern = decl.val.tag() == .extern_fn; |
| 576 | if (!is_extern) { | 613 | if (!is_extern) { |