From f90ba235d04165e654af0787e1e381159cbc5202 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 2 Nov 2023 18:23:50 -0700 Subject: [PATCH] zig reduce proof of concept --- src/reduce.zig | 83 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 14 deletions(-) diff --git a/src/reduce.zig b/src/reduce.zig index e50817503a..f238125528 100644 --- a/src/reduce.zig +++ b/src/reduce.zig @@ -3,20 +3,38 @@ const Allocator = std.mem.Allocator; const assert = std.debug.assert; const usage = - \\zig reduce [source_file] [transformation] + \\zig reduce [source_file] [interestingness] \\ ; +const Interestingness = enum { interesting, boring, unknown }; + // Roadmap: -// - add the main loop that checks for interestingness -// - add transformations // - add thread pool // - add support for `@import` detection and other files +// - more fancy transformations // - reduce flags sent to the compiler +// - @import inlining +// - deleting unused functions and other globals +// - removing statements or blocks of code +// - replacing operands of `and` and `or` with `true` and `false` +// - replacing if conditions with `true` and `false` +// - integrate the build system? pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { const file_path = args[2]; - const transformation_index = try std.fmt.parseInt(u32, args[3], 0); + const interestingness_argv_template = args[3..]; + + var interestingness_argv: std.ArrayListUnmanaged([]const u8) = .{}; + try interestingness_argv.ensureUnusedCapacity(arena, interestingness_argv_template.len + 1); + interestingness_argv.appendSliceAssumeCapacity(interestingness_argv_template); + interestingness_argv.appendAssumeCapacity(file_path); + + var rendered = std.ArrayList(u8).init(gpa); + defer rendered.deinit(); + + var prev_rendered = std.ArrayList(u8).init(gpa); + defer prev_rendered.deinit(); const source_code = try std.fs.cwd().readFileAllocOptions( arena, @@ -33,19 +51,56 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { if (tree.errors.len != 0) { @panic("syntax errors occurred"); } - var rendered = std.ArrayList(u8).init(gpa); - defer rendered.deinit(); - rendered.clearRetainingCapacity(); - var gut_functions: std.AutoHashMapUnmanaged(u32, void) = .{}; - try gut_functions.put(arena, transformation_index, {}); + var next_gut_fn_index: u32 = 0; + var fixups: std.zig.Ast.Fixups = .{}; - try tree.renderToArrayList(&rendered, .{ - .gut_functions = gut_functions, - }); + while (true) { + try fixups.gut_functions.put(arena, next_gut_fn_index, {}); - const stdout = std.io.getStdOut(); - try stdout.writeAll(rendered.items); + rendered.clearRetainingCapacity(); + try tree.renderToArrayList(&rendered, fixups); + if (std.mem.eql(u8, rendered.items, prev_rendered.items)) { + std.debug.print("no remaining transformations\n", .{}); + break; + } + prev_rendered.clearRetainingCapacity(); + try prev_rendered.appendSlice(rendered.items); + + try std.fs.cwd().writeFile(file_path, rendered.items); + + const result = try std.process.Child.run(.{ + .allocator = arena, + .argv = interestingness_argv.items, + }); + if (result.stderr.len != 0) + std.debug.print("{s}", .{result.stderr}); + const interestingness: Interestingness = switch (result.term) { + .Exited => |code| switch (code) { + 0 => .interesting, + 1 => .unknown, + else => .boring, + }, + else => b: { + std.debug.print("interestingness check aborted unexpectedly\n", .{}); + break :b .boring; + }, + }; + std.debug.print("{s}\n", .{@tagName(interestingness)}); + switch (interestingness) { + .interesting => { + next_gut_fn_index += 1; + }, + .unknown, .boring => { + // revert the change and try the next transformation + assert(fixups.gut_functions.remove(next_gut_fn_index)); + next_gut_fn_index += 1; + + rendered.clearRetainingCapacity(); + try tree.renderToArrayList(&rendered, fixups); + }, + } + } return std.process.cleanExit(); }