From 4d01385e147ae36ad96a1c28d2b6fdec69ce69c9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 7 Jul 2020 03:48:20 +0000 Subject: [PATCH] fix liveness analysis and not correctly propagating link errors We still flush the ELF file even when there are compile errors. --- src-self-hosted/Module.zig | 12 +++++++----- src-self-hosted/link.zig | 23 ++++++++++++----------- src-self-hosted/liveness.zig | 35 ++++++++++++++++++++--------------- src-self-hosted/main.zig | 5 ++++- 4 files changed, 43 insertions(+), 32 deletions(-) diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 776e63018b..6cd64e9235 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -867,15 +867,16 @@ pub fn update(self: *Module) !void { try self.deleteDecl(decl); } + // This is needed before reading the error flags. + try self.bin_file.flush(); + self.link_error_flags = self.bin_file.error_flags; + std.log.debug(.module, "link_error_flags: {}\n", .{self.link_error_flags}); // If there are any errors, we anticipate the source files being loaded // to report error messages. Otherwise we unload all source files to save memory. - if (self.totalErrorCount() == 0) { - if (!self.keep_source_files_loaded) { - self.root_scope.unload(self.gpa); - } - try self.bin_file.flush(); + if (self.totalErrorCount() == 0 and !self.keep_source_files_loaded) { + self.root_scope.unload(self.gpa); } } @@ -975,6 +976,7 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void { // lifetime annotations in the ZIR. var decl_arena = decl.typed_value.most_recent.arena.?.promote(self.gpa); defer decl.typed_value.most_recent.arena.?.* = decl_arena.state; + std.log.debug(.module, "analyze liveness of {}\n", .{decl.name}); try liveness.analyze(self.gpa, &decl_arena.allocator, payload.func.analysis.success); } diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig index a0894fb1a1..c297c3a1ce 100644 --- a/src-self-hosted/link.zig +++ b/src-self-hosted/link.zig @@ -369,7 +369,7 @@ pub const ElfFile = struct { const file_size = self.options.program_code_size_hint; const p_align = 0x1000; const off = self.findFreeSpace(file_size, p_align); - //std.log.debug(.link, "found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); + std.log.debug(.link, "found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); try self.program_headers.append(self.allocator, .{ .p_type = elf.PT_LOAD, .p_offset = off, @@ -390,7 +390,7 @@ pub const ElfFile = struct { // page align. const p_align = 0x1000; const off = self.findFreeSpace(file_size, p_align); - //std.log.debug(.link, "found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); + std.log.debug(.link, "found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at. // we'll need to re-use that function anyway, in case the GOT grows and overlaps something // else in virtual memory. @@ -412,7 +412,7 @@ pub const ElfFile = struct { assert(self.shstrtab.items.len == 0); try self.shstrtab.append(self.allocator, 0); // need a 0 at position 0 const off = self.findFreeSpace(self.shstrtab.items.len, 1); - //std.log.debug(.link, "found shstrtab free space 0x{x} to 0x{x}\n", .{ off, off + self.shstrtab.items.len }); + std.log.debug(.link, "found shstrtab free space 0x{x} to 0x{x}\n", .{ off, off + self.shstrtab.items.len }); try self.sections.append(self.allocator, .{ .sh_name = try self.makeString(".shstrtab"), .sh_type = elf.SHT_STRTAB, @@ -470,7 +470,7 @@ pub const ElfFile = struct { const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym); const file_size = self.options.symbol_count_hint * each_size; const off = self.findFreeSpace(file_size, min_align); - //std.log.debug(.link, "found symtab free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); + std.log.debug(.link, "found symtab free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); try self.sections.append(self.allocator, .{ .sh_name = try self.makeString(".symtab"), @@ -586,7 +586,7 @@ pub const ElfFile = struct { shstrtab_sect.sh_offset = self.findFreeSpace(needed_size, 1); } shstrtab_sect.sh_size = needed_size; - //std.log.debug(.link, "shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size }); + std.log.debug(.link, "shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size }); try self.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset); if (!self.shdr_table_dirty) { @@ -632,7 +632,7 @@ pub const ElfFile = struct { for (buf) |*shdr, i| { shdr.* = self.sections.items[i]; - //std.log.debug(.link, "writing section {}\n", .{shdr.*}); + std.log.debug(.link, "writing section {}\n", .{shdr.*}); if (foreign_endian) { bswapAllFields(elf.Elf64_Shdr, shdr); } @@ -643,6 +643,7 @@ pub const ElfFile = struct { self.shdr_table_dirty = false; } if (self.entry_addr == null and self.options.output_mode == .Exe) { + std.log.debug(.link, "no_entry_point_found = true\n", .{}); self.error_flags.no_entry_point_found = true; } else { self.error_flags.no_entry_point_found = false; @@ -956,10 +957,10 @@ pub const ElfFile = struct { try self.offset_table_free_list.ensureCapacity(self.allocator, self.local_symbols.items.len); if (self.local_symbol_free_list.popOrNull()) |i| { - //std.log.debug(.link, "reusing symbol index {} for {}\n", .{i, decl.name}); + std.log.debug(.link, "reusing symbol index {} for {}\n", .{i, decl.name}); decl.link.local_sym_index = i; } else { - //std.log.debug(.link, "allocating symbol index {} for {}\n", .{self.local_symbols.items.len, decl.name}); + std.log.debug(.link, "allocating symbol index {} for {}\n", .{self.local_symbols.items.len, decl.name}); decl.link.local_sym_index = @intCast(u32, self.local_symbols.items.len); _ = self.local_symbols.addOneAssumeCapacity(); } @@ -1027,11 +1028,11 @@ pub const ElfFile = struct { !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment); if (need_realloc) { const vaddr = try self.growTextBlock(&decl.link, code.len, required_alignment); - //std.log.debug(.link, "growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr }); + std.log.debug(.link, "growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr }); if (vaddr != local_sym.st_value) { local_sym.st_value = vaddr; - //std.log.debug(.link, " (writing new offset table entry)\n", .{}); + std.log.debug(.link, " (writing new offset table entry)\n", .{}); self.offset_table.items[decl.link.offset_table_index] = vaddr; try self.writeOffsetTableEntry(decl.link.offset_table_index); } @@ -1049,7 +1050,7 @@ pub const ElfFile = struct { const decl_name = mem.spanZ(decl.name); const name_str_index = try self.makeString(decl_name); const vaddr = try self.allocateTextBlock(&decl.link, code.len, required_alignment); - //std.log.debug(.link, "allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr }); + std.log.debug(.link, "allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr }); errdefer self.freeTextBlock(&decl.link); local_sym.* = .{ diff --git a/src-self-hosted/liveness.zig b/src-self-hosted/liveness.zig index 2e0aad49c3..28eb2145c7 100644 --- a/src-self-hosted/liveness.zig +++ b/src-self-hosted/liveness.zig @@ -25,24 +25,27 @@ fn analyzeWithTable(arena: *std.mem.Allocator, table: *std.AutoHashMap(*ir.Inst, while (i != 0) { i -= 1; const base = body.instructions[i]; - - // Obtain the corresponding instruction type based on the tag type. - inline for (std.meta.declarations(ir.Inst)) |decl| { - switch (decl.data) { - .Type => |T| { - if (@hasDecl(T, "base_tag")) { - if (T.base_tag == base.tag) { - return analyzeInst(arena, table, T, @fieldParentPtr(T, "base", base)); - } - } - }, - else => continue, - } - } - unreachable; + try analyzeInstGeneric(arena, table, base); } } +fn analyzeInstGeneric(arena: *std.mem.Allocator, table: *std.AutoHashMap(*ir.Inst, void), base: *ir.Inst) error{OutOfMemory}!void { + // Obtain the corresponding instruction type based on the tag type. + inline for (std.meta.declarations(ir.Inst)) |decl| { + switch (decl.data) { + .Type => |T| { + if (@hasDecl(T, "base_tag")) { + if (T.base_tag == base.tag) { + return analyzeInst(arena, table, T, @fieldParentPtr(T, "base", base)); + } + } + }, + else => {}, + } + } + unreachable; +} + fn analyzeInst(arena: *std.mem.Allocator, table: *std.AutoHashMap(*ir.Inst, void), comptime T: type, inst: *T) error{OutOfMemory}!void { inst.base.deaths = 0; @@ -131,4 +134,6 @@ fn analyzeInst(arena: *std.mem.Allocator, table: *std.AutoHashMap(*ir.Inst, void arg_index += 1; } } + + std.log.debug(.liveness, "analyze {}: 0b{b}\n", .{inst.base.tag, inst.base.deaths}); } diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig index 82edcc4eff..7a47fc5f78 100644 --- a/src-self-hosted/main.zig +++ b/src-self-hosted/main.zig @@ -50,7 +50,10 @@ pub fn log( const scope_prefix = "(" ++ switch (scope) { // Uncomment to hide logs //.compiler, - .link => return, + .module, + .liveness, + .link, + => return, else => @tagName(scope), } ++ "): ";