| ... | ... | @@ -395,11 +395,11 @@ pub const Object = struct { |
| 395 | 395 | return slice.ptr; |
| 396 | 396 | } |
| 397 | 397 | |
| 398 | | fn genErrorNameTable(self: *Object, comp: *Compilation) !void { |
| 398 | fn genErrorNameTable(self: *Object) !void { |
| 399 | 399 | // If self.error_name_table is null, there was no instruction that actually referenced the error table. |
| 400 | 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 | 403 | const target = mod.getTarget(); |
| 404 | 404 | |
| 405 | 405 | const llvm_ptr_ty = self.context.intType(8).pointerType(0); // TODO: Address space |
| ... | ... | @@ -413,8 +413,8 @@ pub const Object = struct { |
| 413 | 413 | const slice_alignment = slice_ty.abiAlignment(target); |
| 414 | 414 | |
| 415 | 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); |
| 417 | | defer comp.gpa.free(llvm_errors); |
| 416 | const llvm_errors = try mod.gpa.alloc(*const llvm.Value, error_name_list.len); |
| 417 | defer mod.gpa.free(llvm_errors); |
| 418 | 418 | |
| 419 | 419 | llvm_errors[0] = llvm_slice_ty.getUndef(); |
| 420 | 420 | for (llvm_errors[1..]) |*llvm_error, i| { |
| ... | ... | @@ -447,10 +447,10 @@ pub const Object = struct { |
| 447 | 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 | 451 | // If there is no such function in the module, it means the source code does not need it. |
| 452 | 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 | 454 | const errors_len = mod.global_error_set.count(); |
| 455 | 455 | |
| 456 | 456 | // Delete previous implementation. We replace it with every flush() because the |
| ... | ... | @@ -476,10 +476,10 @@ pub const Object = struct { |
| 476 | 476 | _ = builder.buildRet(is_lt); |
| 477 | 477 | } |
| 478 | 478 | |
| 479 | | fn genModuleLevelAssembly(object: *Object, comp: *Compilation) !void { |
| 480 | | const mod = comp.bin_file.options.module.?; |
| 479 | fn genModuleLevelAssembly(object: *Object) !void { |
| 480 | const mod = object.module; |
| 481 | 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 | 483 | defer buffer.deinit(); |
| 484 | 484 | var it = mod.global_assembly.iterator(); |
| 485 | 485 | while (it.next()) |kv| { |
| ... | ... | @@ -489,15 +489,53 @@ pub const Object = struct { |
| 489 | 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 | 529 | pub fn flushModule(self: *Object, comp: *Compilation, prog_node: *std.Progress.Node) !void { |
| 493 | 530 | var sub_prog_node = prog_node.start("LLVM Emit Object", 0); |
| 494 | 531 | sub_prog_node.activate(); |
| 495 | 532 | sub_prog_node.context.refresh(); |
| 496 | 533 | defer sub_prog_node.end(); |
| 497 | 534 | |
| 498 | | try self.genErrorNameTable(comp); |
| 499 | | try self.genCmpLtErrorsLenFunction(comp); |
| 500 | | try self.genModuleLevelAssembly(comp); |
| 535 | try self.resolveExportExternCollisions(); |
| 536 | try self.genErrorNameTable(); |
| 537 | try self.genCmpLtErrorsLenFunction(); |
| 538 | try self.genModuleLevelAssembly(); |
| 501 | 539 | |
| 502 | 540 | if (self.di_builder) |dib| { |
| 503 | 541 | // When lowering debug info for pointers, we emitted the element types as |
| ... | ... | @@ -761,6 +799,14 @@ pub const Object = struct { |
| 761 | 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 | 810 | pub fn updateDeclExports( |
| 765 | 811 | self: *Object, |
| 766 | 812 | module: *Module, |
| ... | ... | @@ -827,6 +873,7 @@ pub const Object = struct { |
| 827 | 873 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| 828 | 874 | } |
| 829 | 875 | } |
| 876 | |
| 830 | 877 | // If a Decl is exported more than one time (which is rare), |
| 831 | 878 | // we add aliases for all but the first export. |
| 832 | 879 | // TODO LLVM C API does not support deleting aliases. We need to |