lib/choir/src/passes/pass/base.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 const subject = @import("root.zig");
  3 
  4 const DependentDialects = subject.DependentDialects;
  5 const PassContext = subject.PassContext;
  6 const PassMutationScope = subject.PassMutationScope;
  7 const PassRerunPolicy = subject.PassRerunPolicy;
  8 const PassResult = subject.PassResult;
  9 const PassStateConcurrency = subject.PassStateConcurrency;
 10 
 11 pub const Pass = struct {
 12     work_contract: ?subject.work.Contract = null,
 13 
 14     name: []const u8,
 15 
 16     description: []const u8,
 17 
 18     run_fn: ?*const fn (*PassContext) PassResult = null,
 19 
 20     state: ?*anyopaque = null,
 21 
 22     run_with_state_fn: ?*const fn (?*anyopaque, *PassContext) PassResult = null,
 23 
 24     state_concurrency: PassStateConcurrency = .exclusive,
 25 
 26     rerun_policy: PassRerunPolicy = .always,
 27 
 28     state_clone_fn: ?*const fn (?*anyopaque, std.mem.Allocator) anyerror!?*anyopaque = null,
 29 
 30     state_deinit_fn: ?*const fn (?*anyopaque, std.mem.Allocator) void = null,
 31 
 32     mutation_scope: PassMutationScope = .whole_module,
 33 
 34     dependent_dialects: DependentDialects = &.{},
 35 
 36     textual_options: ?[]const u8 = null,
 37 
 38     owns_textual_options: bool = false,
 39 
 40     pub fn run(self: Pass, ctx: *PassContext) PassResult {
 41         if (self.run_with_state_fn) |run_with_state| {
 42             return run_with_state(self.state, ctx);
 43         }
 44         if (self.run_fn) |run_pass| {
 45             return run_pass(ctx);
 46         }
 47         return .failure;
 48     }
 49 
 50     pub fn readOnly(self: Pass) bool {
 51         return self.mutation_scope == .read_only;
 52     }
 53 
 54     pub fn isolatedMutation(self: Pass) bool {
 55         return self.mutation_scope == .isolated;
 56     }
 57 
 58     pub fn wholeModuleMutation(self: Pass) bool {
 59         return self.mutation_scope == .whole_module;
 60     }
 61 
 62     pub fn parallelStateSafe(self: Pass) bool {
 63         if (self.state == null) return true;
 64         if (self.state_concurrency == .shared) return true;
 65         return self.state_clone_fn != null;
 66     }
 67 
 68     pub fn validRerunContract(self: Pass) bool {
 69         return switch (self.rerun_policy) {
 70             .always => true,
 71             .skip_if_unchanged => self.state == null and
 72                 self.run_with_state_fn == null and
 73                 self.run_fn != null,
 74         };
 75     }
 76 
 77     pub fn sameRerunIdentity(self: Pass, previous: Pass) bool {
 78         if (self.rerun_policy != .skip_if_unchanged) return false;
 79         if (previous.rerun_policy != .skip_if_unchanged) return false;
 80         if (!self.validRerunContract() or !previous.validRerunContract()) return false;
 81         if (self.run_fn != previous.run_fn) return false;
 82         return std.mem.eql(
 83             u8,
 84             self.textual_options orelse "",
 85             previous.textual_options orelse "",
 86         );
 87     }
 88 
 89     pub fn cloneForParallelTarget(self: Pass, allocator: std.mem.Allocator) anyerror!Pass {
 90         var cloned = self;
 91         cloned.owns_textual_options = false;
 92         if (self.state) |_| {
 93             if (self.state_clone_fn) |clone_fn| {
 94                 cloned.state = try clone_fn(self.state, allocator);
 95                 return cloned;
 96             }
 97             if (self.state_concurrency == .shared) {
 98                 cloned.state_deinit_fn = null;
 99                 return cloned;
100             }
101             return error.PassStateNotParallel;
102         }
103         cloned.state_deinit_fn = null;
104         return cloned;
105     }
106 
107     pub fn deinit(self: *Pass, allocator: std.mem.Allocator) void {
108         if (self.state_deinit_fn) |deinit_fn| deinit_fn(self.state, allocator);
109         if (self.owns_textual_options) {
110             if (self.textual_options) |text| allocator.free(text);
111         }
112         self.* = undefined;
113     }
114 };