Commit 30a555eed4

Andrew Kelley <andrew@ziglang.org>
2019-10-11 23:08:08
merge dumps tool: merging ast nodes
-fgenerate-docs is replaced ith -femit-docs -fno-emit-bin is added to prevent outputting binary
1 parent 8aa2022
lib/std/json/write_stream.zig
@@ -152,10 +152,17 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type {
         ) !void {
             assert(self.state[self.state_index] == State.Value);
             switch (@typeInfo(@typeOf(value))) {
-                .Int => |info| if (info.bits < 53 or (value < 4503599627370496 and value > -4503599627370496)) {
-                    try self.stream.print("{}", value);
-                    self.popState();
-                    return;
+                .Int => |info| {
+                    if (info.bits < 53) {
+                        try self.stream.print("{}", value);
+                        self.popState();
+                        return;
+                    }
+                    if (value < 4503599627370496 and (!info.is_signed or value > -4503599627370496)) {
+                        try self.stream.print("{}", value);
+                        self.popState();
+                        return;
+                    }
                 },
                 .Float => if (@floatCast(f64, value) == value) {
                     try self.stream.print("{}", value);
lib/std/hash.zig
@@ -3,6 +3,8 @@ pub const Adler32 = adler.Adler32;
 
 const auto_hash = @import("hash/auto_hash.zig");
 pub const autoHash = auto_hash.autoHash;
+pub const autoHashStrat = auto_hash.hash;
+pub const Strategy = auto_hash.HashStrategy;
 
 // pub for polynomials + generic crc32 construction
 pub const crc = @import("hash/crc.zig");
lib/std/hash_map.zig
@@ -550,3 +550,13 @@ pub fn getAutoEqlFn(comptime K: type) (fn (K, K) bool) {
         }
     }.eql;
 }
+
+pub fn getAutoHashStratFn(comptime K: type, comptime strategy: std.hash.Strategy) (fn (K) u32) {
+    return struct {
+        fn hash(key: K) u32 {
+            var hasher = Wyhash.init(0);
+            std.hash.autoHashStrat(&hasher, key, strategy);
+            return @truncate(u32, hasher.final());
+        }
+    }.hash;
+}
src/all_types.hpp
@@ -2091,6 +2091,7 @@ struct CodeGen {
     bool function_sections;
     bool enable_dump_analysis;
     bool enable_doc_generation;
+    bool disable_bin_generation;
 
     Buf *mmacosx_version_min;
     Buf *mios_version_min;
src/codegen.cpp
@@ -7586,6 +7586,8 @@ static void zig_llvm_emit_output(CodeGen *g) {
     char *err_msg = nullptr;
     switch (g->emit_file_type) {
         case EmitFileTypeBinary:
+            if (g->disable_bin_generation)
+                return;
             if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
                         ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug, is_small,
                         g->enable_time_report))
@@ -10158,6 +10160,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
     cache_bool(ch, g->function_sections);
     cache_bool(ch, g->enable_dump_analysis);
     cache_bool(ch, g->enable_doc_generation);
+    cache_bool(ch, g->disable_bin_generation);
     cache_buf_opt(ch, g->mmacosx_version_min);
     cache_buf_opt(ch, g->mios_version_min);
     cache_usize(ch, g->version_major);
@@ -10396,7 +10399,8 @@ void codegen_build_and_link(CodeGen *g) {
         // If there is more than one object, we have to link them (with -r).
         // Finally, if we didn't make an object from zig source, and we don't have caching enabled,
         // then we have an object from C source that we must copy to the output dir which we do with a -r link.
-        if (g->emit_file_type == EmitFileTypeBinary && (g->out_type != OutTypeObj || g->link_objects.length > 1 ||
+        if (!g->disable_bin_generation && g->emit_file_type == EmitFileTypeBinary &&
+                (g->out_type != OutTypeObj || g->link_objects.length > 1 ||
                     (!need_llvm_module(g) && !g->enable_cache)))
         {
             codegen_link(g);
src/dump_analysis.cpp
@@ -1309,15 +1309,6 @@ void zig_print_analysis_dump(CodeGen *g, FILE *f, const char *one_indent, const
     }
     jw_end_array(jw);
 
-    jw_object_field(jw, "files");
-    jw_begin_array(jw);
-    for (uint32_t i = 0; i < ctx.file_list.length; i += 1) {
-        Buf *file = ctx.file_list.at(i);
-        jw_array_elem(jw);
-        anal_dump_file(&ctx, file);
-    }
-    jw_end_array(jw);
-
     jw_object_field(jw, "errors");
     jw_begin_array(jw);
     for (uint32_t i = 0; i < ctx.err_list.length; i += 1) {
@@ -1336,5 +1327,14 @@ void zig_print_analysis_dump(CodeGen *g, FILE *f, const char *one_indent, const
     }
     jw_end_array(jw);
 
+    jw_object_field(jw, "files");
+    jw_begin_array(jw);
+    for (uint32_t i = 0; i < ctx.file_list.length; i += 1) {
+        Buf *file = ctx.file_list.at(i);
+        jw_array_elem(jw);
+        anal_dump_file(&ctx, file);
+    }
+    jw_end_array(jw);
+
     jw_end_object(jw);
 }
src/main.cpp
@@ -65,7 +65,8 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
         "  -ftime-report                print timing diagnostics\n"
         "  -fstack-report               print stack size diagnostics\n"
         "  -fdump-analysis              write analysis.json file with type information\n"
-        "  -fgenerate-docs              create a docs/ dir with html documentation\n"
+        "  -femit-docs                  create a docs/ dir with html documentation\n"
+        "  -fno-emit-bin                skip emitting machine code\n"
         "  --libc [file]                Provide a file which specifies libc paths\n"
         "  --name [name]                override output name\n"
         "  --output-dir [dir]           override output directory (defaults to cwd)\n"
@@ -483,6 +484,7 @@ int main(int argc, char **argv) {
     bool stack_report = false;
     bool enable_dump_analysis = false;
     bool enable_doc_generation = false;
+    bool disable_bin_generation = false;
     const char *cache_dir = nullptr;
     CliPkg *cur_pkg = allocate<CliPkg>(1);
     BuildMode build_mode = BuildModeDebug;
@@ -668,8 +670,10 @@ int main(int argc, char **argv) {
                 stack_report = true;
             } else if (strcmp(arg, "-fdump-analysis") == 0) {
                 enable_dump_analysis = true;
-            } else if (strcmp(arg, "-fgenerate-docs") == 0) {
+            } else if (strcmp(arg, "-femit-docs") == 0) {
                 enable_doc_generation = true;
+            } else if (strcmp(arg, "-fno-emit-bin") == 0) {
+                disable_bin_generation = true;
             } else if (strcmp(arg, "--enable-valgrind") == 0) {
                 valgrind_support = ValgrindSupportEnabled;
             } else if (strcmp(arg, "--disable-valgrind") == 0) {
@@ -1148,6 +1152,7 @@ int main(int argc, char **argv) {
             g->enable_stack_report = stack_report;
             g->enable_dump_analysis = enable_dump_analysis;
             g->enable_doc_generation = enable_doc_generation;
+            g->disable_bin_generation = disable_bin_generation;
             codegen_set_out_name(g, buf_out_name);
             codegen_set_lib_version(g, ver_major, ver_minor, ver_patch);
             g->want_single_threaded = want_single_threaded;
@@ -1290,6 +1295,11 @@ int main(int argc, char **argv) {
                     zig_print_stack_report(g, stdout);
                 }
 
+                if (g->disable_bin_generation) {
+                    fprintf(stderr, "Semantic analysis complete. No binary produced due to -fno-emit-bin.\n");
+                    return 0;
+                }
+
                 Buf *test_exe_path_unresolved = &g->output_file_path;
                 Buf *test_exe_path = buf_alloc();
                 *test_exe_path = os_path_resolve(&test_exe_path_unresolved, 1);
tools/merge_anal_dumps.zig
@@ -24,19 +24,49 @@ pub fn main() anyerror!void {
     try dump.render(&stdout.outStream().stream);
 }
 
+/// AST source node
+const Node = struct {
+    file: usize,
+    line: usize,
+    col: usize,
+    fields: []usize,
+
+    fn hash(n: Node) u32 {
+        var hasher = std.hash.Wyhash.init(0);
+        std.hash.autoHash(&hasher, n.file);
+        std.hash.autoHash(&hasher, n.line);
+        std.hash.autoHash(&hasher, n.col);
+        return @truncate(u32, hasher.final());
+    }
+
+    fn eql(a: Node, b: Node) bool {
+        return a.file == b.file and
+            a.line == b.line and
+            a.col == b.col;
+    }
+};
+
 const Dump = struct {
     zig_id: ?[]const u8 = null,
     zig_version: ?[]const u8 = null,
     root_name: ?[]const u8 = null,
     targets: std.ArrayList([]const u8),
-    files_list: std.ArrayList([]const u8),
-    files_map: std.StringHashMap(usize),
+
+    const FileMap = std.StringHashMap(usize);
+    file_list: std.ArrayList([]const u8),
+    file_map: FileMap,
+
+    const NodeMap = std.HashMap(Node, usize, Node.hash, Node.eql);
+    node_list: std.ArrayList(Node),
+    node_map: NodeMap,
 
     fn init(allocator: *mem.Allocator) Dump {
         return Dump{
             .targets = std.ArrayList([]const u8).init(allocator),
-            .files_list = std.ArrayList([]const u8).init(allocator),
-            .files_map = std.StringHashMap(usize).init(allocator),
+            .file_list = std.ArrayList([]const u8).init(allocator),
+            .file_map = FileMap.init(allocator),
+            .node_list = std.ArrayList(Node).init(allocator),
+            .node_map = NodeMap.init(allocator),
         };
     }
 
@@ -56,17 +86,45 @@ const Dump = struct {
         const other_files = root.Object.get("files").?.value.Array.toSliceConst();
         var other_file_to_mine = std.AutoHashMap(usize, usize).init(self.a());
         for (other_files) |other_file, i| {
-            const gop = try self.files_map.getOrPut(other_file.String);
-            if (gop.found_existing) {
-                try other_file_to_mine.putNoClobber(i, gop.kv.value);
-            } else {
-                gop.kv.value = self.files_list.len;
-                try self.files_list.append(other_file.String);
+            const gop = try self.file_map.getOrPut(other_file.String);
+            if (!gop.found_existing) {
+                gop.kv.value = self.file_list.len;
+                try self.file_list.append(other_file.String);
             }
+            try other_file_to_mine.putNoClobber(i, gop.kv.value);
         }
 
+        // Merge ast nodes
         const other_ast_nodes = root.Object.get("astNodes").?.value.Array.toSliceConst();
         var other_ast_node_to_mine = std.AutoHashMap(usize, usize).init(self.a());
+        for (other_ast_nodes) |other_ast_node_json, i| {
+            const other_file_id = jsonObjInt(other_ast_node_json, "file");
+            const other_node = Node{
+                .line = jsonObjInt(other_ast_node_json, "line"),
+                .col = jsonObjInt(other_ast_node_json, "col"),
+                .file = other_file_to_mine.getValue(other_file_id).?,
+                .fields = ([*]usize)(undefined)[0..0],
+            };
+            const gop = try self.node_map.getOrPut(other_node);
+            if (!gop.found_existing) {
+                gop.kv.value = self.node_list.len;
+                try self.node_list.append(other_node);
+            }
+            try other_ast_node_to_mine.putNoClobber(i, gop.kv.value);
+        }
+        // convert fields lists
+        for (other_ast_nodes) |other_ast_node_json, i| {
+            const my_node_index = other_ast_node_to_mine.get(i).?.value;
+            const my_node = &self.node_list.toSlice()[my_node_index];
+            if (other_ast_node_json.Object.get("fields")) |fields_json_kv| {
+                const other_fields = fields_json_kv.value.Array.toSliceConst();
+                my_node.fields = try self.a().alloc(usize, other_fields.len);
+                for (other_fields) |other_field_index, field_i| {
+                    const other_index = @intCast(usize, other_field_index.Integer);
+                    my_node.fields[field_i] = other_ast_node_to_mine.get(other_index).?.value;
+                }
+            }
+        }
     }
 
     fn render(self: *Dump, stream: var) !void {
@@ -81,9 +139,39 @@ const Dump = struct {
         }
         try jw.endArray();
 
+        try jw.objectField("astNodes");
+        try jw.beginArray();
+        for (self.node_list.toSliceConst()) |node| {
+            try jw.arrayElem();
+            try jw.beginObject();
+
+            try jw.objectField("file");
+            try jw.emitNumber(node.file);
+
+            try jw.objectField("line");
+            try jw.emitNumber(node.line);
+
+            try jw.objectField("col");
+            try jw.emitNumber(node.col);
+
+            if (node.fields.len != 0) {
+                try jw.objectField("fields");
+                try jw.beginArray();
+
+                for (node.fields) |field_node_index| {
+                    try jw.arrayElem();
+                    try jw.emitNumber(field_node_index);
+                }
+                try jw.endArray();
+            }
+
+            try jw.endObject();
+        }
+        try jw.endArray();
+
         try jw.objectField("files");
         try jw.beginArray();
-        for (self.files_list.toSliceConst()) |file| {
+        for (self.file_list.toSliceConst()) |file| {
             try jw.arrayElem();
             try jw.emitString(file);
         }
@@ -105,3 +193,8 @@ const Dump = struct {
         }
     }
 };
+
+fn jsonObjInt(json_val: json.Value, field: []const u8) usize {
+    const uncasted = json_val.Object.get(field).?.value.Integer;
+    return @intCast(usize, uncasted);
+}