| ... | ... | @@ -155,6 +155,15 @@ pub const Object = struct { |
| 155 | 155 | llvm_module: *const llvm.Module, |
| 156 | 156 | context: *const llvm.Context, |
| 157 | 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 | 168 | pub fn create(gpa: *Allocator, options: link.Options) !*Object { |
| 160 | 169 | const obj = try gpa.create(Object); |
| ... | ... | @@ -241,18 +250,20 @@ pub const Object = struct { |
| 241 | 250 | .llvm_module = llvm_module, |
| 242 | 251 | .context = context, |
| 243 | 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 | 258 | self.target_machine.dispose(); |
| 249 | 259 | self.llvm_module.dispose(); |
| 250 | 260 | self.context.dispose(); |
| 261 | self.decl_map.deinit(gpa); |
| 251 | 262 | self.* = undefined; |
| 252 | 263 | } |
| 253 | 264 | |
| 254 | 265 | pub fn destroy(self: *Object, gpa: *Allocator) void { |
| 255 | | self.deinit(); |
| 266 | self.deinit(gpa); |
| 256 | 267 | gpa.destroy(self); |
| 257 | 268 | } |
| 258 | 269 | |
| ... | ... | @@ -450,41 +461,62 @@ pub const Object = struct { |
| 450 | 461 | ) !void { |
| 451 | 462 | // If the module does not already have the function, we ignore this function call |
| 452 | 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 | 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 | 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 | 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 | 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 | 512 | llvm_fn.setLinkage(.Internal); |
| 460 | 513 | llvm_fn.setUnnamedAddr(.True); |
| 461 | 514 | } |
| 462 | | // TODO LLVM C API does not support deleting aliases. We need to |
| 463 | | // patch it to support this or figure out how to wrap the C++ API ourselves. |
| 464 | | // Until then we iterate over existing aliases and make them point |
| 465 | | // to the correct decl, or otherwise add a new alias. Old aliases are leaked. |
| 466 | | for (exports) |exp| { |
| 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 | | } |
| 515 | } |
| 516 | |
| 517 | pub fn freeDecl(self: *Object, decl: *Module.Decl) void { |
| 518 | const llvm_value = self.decl_map.get(decl) orelse return; |
| 519 | llvm_value.deleteGlobal(); |
| 488 | 520 | } |
| 489 | 521 | }; |
| 490 | 522 | |
| ... | ... | @@ -493,9 +525,8 @@ pub const DeclGen = struct { |
| 493 | 525 | object: *Object, |
| 494 | 526 | module: *Module, |
| 495 | 527 | decl: *Module.Decl, |
| 496 | | err_msg: ?*Module.ErrorMsg, |
| 497 | | |
| 498 | 528 | gpa: *Allocator, |
| 529 | err_msg: ?*Module.ErrorMsg, |
| 499 | 530 | |
| 500 | 531 | fn todo(self: *DeclGen, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } { |
| 501 | 532 | @setCold(true); |
| ... | ... | @@ -540,7 +571,8 @@ pub const DeclGen = struct { |
| 540 | 571 | /// Note that this can be called before the function's semantic analysis has |
| 541 | 572 | /// completed, so if any attributes rely on that, they must be done in updateFunc, not here. |
| 542 | 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 | 577 | assert(decl.has_tv); |
| 546 | 578 | const zig_fn_type = decl.ty; |
| ... | ... | @@ -570,7 +602,12 @@ pub const DeclGen = struct { |
| 570 | 602 | .False, |
| 571 | 603 | ); |
| 572 | 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 | 612 | const is_extern = decl.val.tag() == .extern_fn; |
| 576 | 613 | if (!is_extern) { |