| ... | @@ -395,11 +395,11 @@ pub const Object = struct { | ... | @@ -395,11 +395,11 @@ pub const Object = struct { |
| 395 | return slice.ptr; | 395 | return slice.ptr; |
| 396 | } | 396 | } |
| 397 | | 397 | |
| 398 | fn genErrorNameTable(self: *Object, comp: *Compilation) !void { | 398 | fn genErrorNameTable(self: *Object) !void { |
| 399 | // If self.error_name_table is null, there was no instruction that actually referenced the error table. | 399 | // If self.error_name_table is null, there was no instruction that actually referenced the error table. |
| 400 | const error_name_table_ptr_global = self.error_name_table orelse return; | 400 | const error_name_table_ptr_global = self.error_name_table orelse return; |
| 401 | | 401 | |
| 402 | const mod = comp.bin_file.options.module.?; | 402 | const mod = self.module; |
| 403 | const target = mod.getTarget(); | 403 | const target = mod.getTarget(); |
| 404 | | 404 | |
| 405 | const llvm_ptr_ty = self.context.intType(8).pointerType(0); // TODO: Address space | 405 | const llvm_ptr_ty = self.context.intType(8).pointerType(0); // TODO: Address space |
| ... | @@ -413,8 +413,8 @@ pub const Object = struct { | ... | @@ -413,8 +413,8 @@ pub const Object = struct { |
| 413 | const slice_alignment = slice_ty.abiAlignment(target); | 413 | const slice_alignment = slice_ty.abiAlignment(target); |
| 414 | | 414 | |
| 415 | const error_name_list = mod.error_name_list.items; | 415 | const error_name_list = mod.error_name_list.items; |
| 416 | const llvm_errors = try comp.gpa.alloc(*const llvm.Value, error_name_list.len); | 416 | const llvm_errors = try mod.gpa.alloc(*const llvm.Value, error_name_list.len); |
| 417 | defer comp.gpa.free(llvm_errors); | 417 | defer mod.gpa.free(llvm_errors); |
| 418 | | 418 | |
| 419 | llvm_errors[0] = llvm_slice_ty.getUndef(); | 419 | llvm_errors[0] = llvm_slice_ty.getUndef(); |
| 420 | for (llvm_errors[1..]) |*llvm_error, i| { | 420 | for (llvm_errors[1..]) |*llvm_error, i| { |
| ... | @@ -447,10 +447,10 @@ pub const Object = struct { | ... | @@ -447,10 +447,10 @@ pub const Object = struct { |
| 447 | error_name_table_ptr_global.setInitializer(error_name_table_ptr); | 447 | error_name_table_ptr_global.setInitializer(error_name_table_ptr); |
| 448 | } | 448 | } |
| 449 | | 449 | |
| 450 | fn genCmpLtErrorsLenFunction(object: *Object, comp: *Compilation) !void { | 450 | fn genCmpLtErrorsLenFunction(object: *Object) !void { |
| 451 | // If there is no such function in the module, it means the source code does not need it. | 451 | // If there is no such function in the module, it means the source code does not need it. |
| 452 | const llvm_fn = object.llvm_module.getNamedFunction(lt_errors_fn_name) orelse return; | 452 | const llvm_fn = object.llvm_module.getNamedFunction(lt_errors_fn_name) orelse return; |
| 453 | const mod = comp.bin_file.options.module.?; | 453 | const mod = object.module; |
| 454 | const errors_len = mod.global_error_set.count(); | 454 | const errors_len = mod.global_error_set.count(); |
| 455 | | 455 | |
| 456 | // Delete previous implementation. We replace it with every flush() because the | 456 | // Delete previous implementation. We replace it with every flush() because the |
| ... | @@ -476,10 +476,10 @@ pub const Object = struct { | ... | @@ -476,10 +476,10 @@ pub const Object = struct { |
| 476 | _ = builder.buildRet(is_lt); | 476 | _ = builder.buildRet(is_lt); |
| 477 | } | 477 | } |
| 478 | | 478 | |
| 479 | fn genModuleLevelAssembly(object: *Object, comp: *Compilation) !void { | 479 | fn genModuleLevelAssembly(object: *Object) !void { |
| 480 | const mod = comp.bin_file.options.module.?; | 480 | const mod = object.module; |
| 481 | if (mod.global_assembly.count() == 0) return; | 481 | if (mod.global_assembly.count() == 0) return; |
| 482 | var buffer = std.ArrayList(u8).init(comp.gpa); | 482 | var buffer = std.ArrayList(u8).init(mod.gpa); |
| 483 | defer buffer.deinit(); | 483 | defer buffer.deinit(); |
| 484 | var it = mod.global_assembly.iterator(); | 484 | var it = mod.global_assembly.iterator(); |
| 485 | while (it.next()) |kv| { | 485 | while (it.next()) |kv| { |
| ... | @@ -489,15 +489,53 @@ pub const Object = struct { | ... | @@ -489,15 +489,53 @@ pub const Object = struct { |
| 489 | object.llvm_module.setModuleInlineAsm2(buffer.items.ptr, buffer.items.len - 1); | 489 | object.llvm_module.setModuleInlineAsm2(buffer.items.ptr, buffer.items.len - 1); |
| 490 | } | 490 | } |
| 491 | | 491 | |
| | 492 | fn resolveExportExternCollisions(object: *Object) !void { |
| | 493 | const mod = object.module; |
| | 494 | |
| | 495 | const export_keys = mod.decl_exports.keys(); |
| | 496 | for (mod.decl_exports.values()) |export_list, i| { |
| | 497 | const decl_index = export_keys[i]; |
| | 498 | const llvm_global = object.decl_map.get(decl_index) orelse continue; |
| | 499 | for (export_list) |exp| { |
| | 500 | // Detect if the LLVM global has already been created as an extern. In such |
| | 501 | // case, we need to replace all uses of it with this exported global. |
| | 502 | // TODO update std.builtin.ExportOptions to have the name be a |
| | 503 | // null-terminated slice. |
| | 504 | const exp_name_z = try mod.gpa.dupeZ(u8, exp.options.name); |
| | 505 | defer mod.gpa.free(exp_name_z); |
| | 506 | |
| | 507 | const other_global = object.getLlvmGlobal(exp_name_z.ptr) orelse continue; |
| | 508 | if (other_global == llvm_global) continue; |
| | 509 | |
| | 510 | // replaceAllUsesWith requires the type to be unchanged. So we bitcast |
| | 511 | // the new global to the old type and use that as the thing to replace |
| | 512 | // old uses. |
| | 513 | const new_global_ptr = llvm_global.constBitCast(other_global.typeOf()); |
| | 514 | other_global.replaceAllUsesWith(new_global_ptr); |
| | 515 | llvm_global.takeName(other_global); |
| | 516 | other_global.deleteGlobal(); |
| | 517 | // Problem: now we need to replace in the decl_map that |
| | 518 | // the extern decl index points to this new global. However we don't |
| | 519 | // know the decl index. |
| | 520 | // Even if we did, a future incremental update to the extern would then |
| | 521 | // treat the LLVM global as an extern rather than an export, so it would |
| | 522 | // need a way to check that. |
| | 523 | // This is a TODO that needs to be solved when making |
| | 524 | // the LLVM backend support incremental compilation. |
| | 525 | } |
| | 526 | } |
| | 527 | } |
| | 528 | |
| 492 | pub fn flushModule(self: *Object, comp: *Compilation, prog_node: *std.Progress.Node) !void { | 529 | pub fn flushModule(self: *Object, comp: *Compilation, prog_node: *std.Progress.Node) !void { |
| 493 | var sub_prog_node = prog_node.start("LLVM Emit Object", 0); | 530 | var sub_prog_node = prog_node.start("LLVM Emit Object", 0); |
| 494 | sub_prog_node.activate(); | 531 | sub_prog_node.activate(); |
| 495 | sub_prog_node.context.refresh(); | 532 | sub_prog_node.context.refresh(); |
| 496 | defer sub_prog_node.end(); | 533 | defer sub_prog_node.end(); |
| 497 | | 534 | |
| 498 | try self.genErrorNameTable(comp); | 535 | try self.resolveExportExternCollisions(); |
| 499 | try self.genCmpLtErrorsLenFunction(comp); | 536 | try self.genErrorNameTable(); |
| 500 | try self.genModuleLevelAssembly(comp); | 537 | try self.genCmpLtErrorsLenFunction(); |
| | 538 | try self.genModuleLevelAssembly(); |
| 501 | | 539 | |
| 502 | if (self.di_builder) |dib| { | 540 | if (self.di_builder) |dib| { |
| 503 | // When lowering debug info for pointers, we emitted the element types as | 541 | // When lowering debug info for pointers, we emitted the element types as |
| ... | @@ -761,6 +799,14 @@ pub const Object = struct { | ... | @@ -761,6 +799,14 @@ pub const Object = struct { |
| 761 | try self.updateDeclExports(module, decl_index, decl_exports); | 799 | try self.updateDeclExports(module, decl_index, decl_exports); |
| 762 | } | 800 | } |
| 763 | | 801 | |
| | 802 | /// TODO replace this with a call to `Module::getNamedValue`. This will require adding |
| | 803 | /// a new wrapper in zig_llvm.h/zig_llvm.cpp. |
| | 804 | fn getLlvmGlobal(o: Object, name: [*:0]const u8) ?*const llvm.Value { |
| | 805 | if (o.llvm_module.getNamedFunction(name)) |x| return x; |
| | 806 | if (o.llvm_module.getNamedGlobal(name)) |x| return x; |
| | 807 | return null; |
| | 808 | } |
| | 809 | |
| 764 | pub fn updateDeclExports( | 810 | pub fn updateDeclExports( |
| 765 | self: *Object, | 811 | self: *Object, |
| 766 | module: *Module, | 812 | module: *Module, |
| ... | @@ -827,6 +873,7 @@ pub const Object = struct { | ... | @@ -827,6 +873,7 @@ pub const Object = struct { |
| 827 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); | 873 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| 828 | } | 874 | } |
| 829 | } | 875 | } |
| | 876 | |
| 830 | // If a Decl is exported more than one time (which is rare), | 877 | // If a Decl is exported more than one time (which is rare), |
| 831 | // we add aliases for all but the first export. | 878 | // we add aliases for all but the first export. |
| 832 | // TODO LLVM C API does not support deleting aliases. We need to | 879 | // TODO LLVM C API does not support deleting aliases. We need to |