authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-07 03:48:20+00:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-07 03:48:20+00:00
log4d01385e147ae36ad96a1c28d2b6fdec69ce69c9
treed7cb1e0603857a77cb99dd5f02c79c8bd1b9c54a
parent12737c9a3071a49f8c05348fadd0b602b6952542

fix liveness analysis and not correctly propagating link errors

We still flush the ELF file even when there are compile errors.

4 files changed, 40 insertions(+), 29 deletions(-)

src-self-hosted/Module.zig+7-5
...@@ -867,15 +867,16 @@ pub fn update(self: *Module) !void {...@@ -867,15 +867,16 @@ pub fn update(self: *Module) !void {
867 try self.deleteDecl(decl);867 try self.deleteDecl(decl);
868 }868 }
869869
870 // This is needed before reading the error flags.
871 try self.bin_file.flush();
872
870 self.link_error_flags = self.bin_file.error_flags;873 self.link_error_flags = self.bin_file.error_flags;
874 std.log.debug(.module, "link_error_flags: {}\n", .{self.link_error_flags});
871875
872 // If there are any errors, we anticipate the source files being loaded876 // If there are any errors, we anticipate the source files being loaded
873 // to report error messages. Otherwise we unload all source files to save memory.877 // to report error messages. Otherwise we unload all source files to save memory.
874 if (self.totalErrorCount() == 0) {878 if (self.totalErrorCount() == 0 and !self.keep_source_files_loaded) {
875 if (!self.keep_source_files_loaded) {879 self.root_scope.unload(self.gpa);
876 self.root_scope.unload(self.gpa);
877 }
878 try self.bin_file.flush();
879 }880 }
880}881}
881882
...@@ -975,6 +976,7 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {...@@ -975,6 +976,7 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
975 // lifetime annotations in the ZIR.976 // lifetime annotations in the ZIR.
976 var decl_arena = decl.typed_value.most_recent.arena.?.promote(self.gpa);977 var decl_arena = decl.typed_value.most_recent.arena.?.promote(self.gpa);
977 defer decl.typed_value.most_recent.arena.?.* = decl_arena.state;978 defer decl.typed_value.most_recent.arena.?.* = decl_arena.state;
979 std.log.debug(.module, "analyze liveness of {}\n", .{decl.name});
978 try liveness.analyze(self.gpa, &decl_arena.allocator, payload.func.analysis.success);980 try liveness.analyze(self.gpa, &decl_arena.allocator, payload.func.analysis.success);
979 }981 }
980982
src-self-hosted/link.zig+12-11
...@@ -369,7 +369,7 @@ pub const ElfFile = struct {...@@ -369,7 +369,7 @@ pub const ElfFile = struct {
369 const file_size = self.options.program_code_size_hint;369 const file_size = self.options.program_code_size_hint;
370 const p_align = 0x1000;370 const p_align = 0x1000;
371 const off = self.findFreeSpace(file_size, p_align);371 const off = self.findFreeSpace(file_size, p_align);
372 //std.log.debug(.link, "found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });372 std.log.debug(.link, "found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
373 try self.program_headers.append(self.allocator, .{373 try self.program_headers.append(self.allocator, .{
374 .p_type = elf.PT_LOAD,374 .p_type = elf.PT_LOAD,
375 .p_offset = off,375 .p_offset = off,
...@@ -390,7 +390,7 @@ pub const ElfFile = struct {...@@ -390,7 +390,7 @@ pub const ElfFile = struct {
390 // page align.390 // page align.
391 const p_align = 0x1000;391 const p_align = 0x1000;
392 const off = self.findFreeSpace(file_size, p_align);392 const off = self.findFreeSpace(file_size, p_align);
393 //std.log.debug(.link, "found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });393 std.log.debug(.link, "found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
394 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.394 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
395 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something395 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
396 // else in virtual memory.396 // else in virtual memory.
...@@ -412,7 +412,7 @@ pub const ElfFile = struct {...@@ -412,7 +412,7 @@ pub const ElfFile = struct {
412 assert(self.shstrtab.items.len == 0);412 assert(self.shstrtab.items.len == 0);
413 try self.shstrtab.append(self.allocator, 0); // need a 0 at position 0413 try self.shstrtab.append(self.allocator, 0); // need a 0 at position 0
414 const off = self.findFreeSpace(self.shstrtab.items.len, 1);414 const off = self.findFreeSpace(self.shstrtab.items.len, 1);
415 //std.log.debug(.link, "found shstrtab free space 0x{x} to 0x{x}\n", .{ off, off + self.shstrtab.items.len });415 std.log.debug(.link, "found shstrtab free space 0x{x} to 0x{x}\n", .{ off, off + self.shstrtab.items.len });
416 try self.sections.append(self.allocator, .{416 try self.sections.append(self.allocator, .{
417 .sh_name = try self.makeString(".shstrtab"),417 .sh_name = try self.makeString(".shstrtab"),
418 .sh_type = elf.SHT_STRTAB,418 .sh_type = elf.SHT_STRTAB,
...@@ -470,7 +470,7 @@ pub const ElfFile = struct {...@@ -470,7 +470,7 @@ pub const ElfFile = struct {
470 const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);470 const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);
471 const file_size = self.options.symbol_count_hint * each_size;471 const file_size = self.options.symbol_count_hint * each_size;
472 const off = self.findFreeSpace(file_size, min_align);472 const off = self.findFreeSpace(file_size, min_align);
473 //std.log.debug(.link, "found symtab free space 0x{x} to 0x{x}\n", .{ off, off + file_size });473 std.log.debug(.link, "found symtab free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
474474
475 try self.sections.append(self.allocator, .{475 try self.sections.append(self.allocator, .{
476 .sh_name = try self.makeString(".symtab"),476 .sh_name = try self.makeString(".symtab"),
...@@ -586,7 +586,7 @@ pub const ElfFile = struct {...@@ -586,7 +586,7 @@ pub const ElfFile = struct {
586 shstrtab_sect.sh_offset = self.findFreeSpace(needed_size, 1);586 shstrtab_sect.sh_offset = self.findFreeSpace(needed_size, 1);
587 }587 }
588 shstrtab_sect.sh_size = needed_size;588 shstrtab_sect.sh_size = needed_size;
589 //std.log.debug(.link, "shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size });589 std.log.debug(.link, "shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size });
590590
591 try self.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset);591 try self.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset);
592 if (!self.shdr_table_dirty) {592 if (!self.shdr_table_dirty) {
...@@ -632,7 +632,7 @@ pub const ElfFile = struct {...@@ -632,7 +632,7 @@ pub const ElfFile = struct {
632632
633 for (buf) |*shdr, i| {633 for (buf) |*shdr, i| {
634 shdr.* = self.sections.items[i];634 shdr.* = self.sections.items[i];
635 //std.log.debug(.link, "writing section {}\n", .{shdr.*});635 std.log.debug(.link, "writing section {}\n", .{shdr.*});
636 if (foreign_endian) {636 if (foreign_endian) {
637 bswapAllFields(elf.Elf64_Shdr, shdr);637 bswapAllFields(elf.Elf64_Shdr, shdr);
638 }638 }
...@@ -643,6 +643,7 @@ pub const ElfFile = struct {...@@ -643,6 +643,7 @@ pub const ElfFile = struct {
643 self.shdr_table_dirty = false;643 self.shdr_table_dirty = false;
644 }644 }
645 if (self.entry_addr == null and self.options.output_mode == .Exe) {645 if (self.entry_addr == null and self.options.output_mode == .Exe) {
646 std.log.debug(.link, "no_entry_point_found = true\n", .{});
646 self.error_flags.no_entry_point_found = true;647 self.error_flags.no_entry_point_found = true;
647 } else {648 } else {
648 self.error_flags.no_entry_point_found = false;649 self.error_flags.no_entry_point_found = false;
...@@ -956,10 +957,10 @@ pub const ElfFile = struct {...@@ -956,10 +957,10 @@ pub const ElfFile = struct {
956 try self.offset_table_free_list.ensureCapacity(self.allocator, self.local_symbols.items.len);957 try self.offset_table_free_list.ensureCapacity(self.allocator, self.local_symbols.items.len);
957958
958 if (self.local_symbol_free_list.popOrNull()) |i| {959 if (self.local_symbol_free_list.popOrNull()) |i| {
959 //std.log.debug(.link, "reusing symbol index {} for {}\n", .{i, decl.name});960 std.log.debug(.link, "reusing symbol index {} for {}\n", .{i, decl.name});
960 decl.link.local_sym_index = i;961 decl.link.local_sym_index = i;
961 } else {962 } else {
962 //std.log.debug(.link, "allocating symbol index {} for {}\n", .{self.local_symbols.items.len, decl.name});963 std.log.debug(.link, "allocating symbol index {} for {}\n", .{self.local_symbols.items.len, decl.name});
963 decl.link.local_sym_index = @intCast(u32, self.local_symbols.items.len);964 decl.link.local_sym_index = @intCast(u32, self.local_symbols.items.len);
964 _ = self.local_symbols.addOneAssumeCapacity();965 _ = self.local_symbols.addOneAssumeCapacity();
965 }966 }
...@@ -1027,11 +1028,11 @@ pub const ElfFile = struct {...@@ -1027,11 +1028,11 @@ pub const ElfFile = struct {
1027 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);1028 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);
1028 if (need_realloc) {1029 if (need_realloc) {
1029 const vaddr = try self.growTextBlock(&decl.link, code.len, required_alignment);1030 const vaddr = try self.growTextBlock(&decl.link, code.len, required_alignment);
1030 //std.log.debug(.link, "growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr });1031 std.log.debug(.link, "growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr });
1031 if (vaddr != local_sym.st_value) {1032 if (vaddr != local_sym.st_value) {
1032 local_sym.st_value = vaddr;1033 local_sym.st_value = vaddr;
10331034
1034 //std.log.debug(.link, " (writing new offset table entry)\n", .{});1035 std.log.debug(.link, " (writing new offset table entry)\n", .{});
1035 self.offset_table.items[decl.link.offset_table_index] = vaddr;1036 self.offset_table.items[decl.link.offset_table_index] = vaddr;
1036 try self.writeOffsetTableEntry(decl.link.offset_table_index);1037 try self.writeOffsetTableEntry(decl.link.offset_table_index);
1037 }1038 }
...@@ -1049,7 +1050,7 @@ pub const ElfFile = struct {...@@ -1049,7 +1050,7 @@ pub const ElfFile = struct {
1049 const decl_name = mem.spanZ(decl.name);1050 const decl_name = mem.spanZ(decl.name);
1050 const name_str_index = try self.makeString(decl_name);1051 const name_str_index = try self.makeString(decl_name);
1051 const vaddr = try self.allocateTextBlock(&decl.link, code.len, required_alignment);1052 const vaddr = try self.allocateTextBlock(&decl.link, code.len, required_alignment);
1052 //std.log.debug(.link, "allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr });1053 std.log.debug(.link, "allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr });
1053 errdefer self.freeTextBlock(&decl.link);1054 errdefer self.freeTextBlock(&decl.link);
10541055
1055 local_sym.* = .{1056 local_sym.* = .{
src-self-hosted/liveness.zig+17-12
...@@ -25,22 +25,25 @@ fn analyzeWithTable(arena: *std.mem.Allocator, table: *std.AutoHashMap(*ir.Inst,...@@ -25,22 +25,25 @@ fn analyzeWithTable(arena: *std.mem.Allocator, table: *std.AutoHashMap(*ir.Inst,
25 while (i != 0) {25 while (i != 0) {
26 i -= 1;26 i -= 1;
27 const base = body.instructions[i];27 const base = body.instructions[i];
28 try analyzeInstGeneric(arena, table, base);
29 }
30}
2831
29 // Obtain the corresponding instruction type based on the tag type.32fn analyzeInstGeneric(arena: *std.mem.Allocator, table: *std.AutoHashMap(*ir.Inst, void), base: *ir.Inst) error{OutOfMemory}!void {
30 inline for (std.meta.declarations(ir.Inst)) |decl| {33 // Obtain the corresponding instruction type based on the tag type.
31 switch (decl.data) {34 inline for (std.meta.declarations(ir.Inst)) |decl| {
32 .Type => |T| {35 switch (decl.data) {
33 if (@hasDecl(T, "base_tag")) {36 .Type => |T| {
34 if (T.base_tag == base.tag) {37 if (@hasDecl(T, "base_tag")) {
35 return analyzeInst(arena, table, T, @fieldParentPtr(T, "base", base));38 if (T.base_tag == base.tag) {
36 }39 return analyzeInst(arena, table, T, @fieldParentPtr(T, "base", base));
37 }40 }
38 },41 }
39 else => continue,42 },
40 }43 else => {},
41 }44 }
42 unreachable;
43 }45 }
46 unreachable;
44}47}
4548
46fn analyzeInst(arena: *std.mem.Allocator, table: *std.AutoHashMap(*ir.Inst, void), comptime T: type, inst: *T) error{OutOfMemory}!void {49fn analyzeInst(arena: *std.mem.Allocator, table: *std.AutoHashMap(*ir.Inst, void), comptime T: type, inst: *T) error{OutOfMemory}!void {
...@@ -131,4 +134,6 @@ fn analyzeInst(arena: *std.mem.Allocator, table: *std.AutoHashMap(*ir.Inst, void...@@ -131,4 +134,6 @@ fn analyzeInst(arena: *std.mem.Allocator, table: *std.AutoHashMap(*ir.Inst, void
131 arg_index += 1;134 arg_index += 1;
132 }135 }
133 }136 }
137
138 std.log.debug(.liveness, "analyze {}: 0b{b}\n", .{inst.base.tag, inst.base.deaths});
134}139}
src-self-hosted/main.zig+4-1
...@@ -50,7 +50,10 @@ pub fn log(...@@ -50,7 +50,10 @@ pub fn log(
50 const scope_prefix = "(" ++ switch (scope) {50 const scope_prefix = "(" ++ switch (scope) {
51 // Uncomment to hide logs51 // Uncomment to hide logs
52 //.compiler,52 //.compiler,
53 .link => return,53 .module,
54 .liveness,
55 .link,
56 => return,
5457
55 else => @tagName(scope),58 else => @tagName(scope),
56 } ++ "): ";59 } ++ "): ";