lib/accy/src/kernel/dsl/program/root.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 const kernel = @import("../../root.zig");
  3 const kernel_compile = @import("../../compile/root.zig");
  4 const executable = @import("../../../executable/root.zig");
  5 const execute = @import("execute.zig");
  6 const parameter = @import("../../program/root.zig").parameter;
  7 
  8 pub fn Program(comptime definition: anytype) type {
  9     return Source(definition);
 10 }
 11 
 12 pub fn Family(comptime definition: anytype) type {
 13     return struct {
 14         pub const name = definition.name;
 15         pub const parameters = definition.parameters;
 16         pub const Layout: type = parameter.Standard(parameters);
 17         pub const Instance: type = definition.Instance;
 18         pub const Limits: type = kernel.Limits;
 19 
 20         pub fn arg(comptime name_value: anytype) usize {
 21             return Layout.index(name_value);
 22         }
 23 
 24         pub fn schema() []const kernel.Param {
 25             return parameter.schema(parameters);
 26         }
 27 
 28         pub fn build(allocator: std.mem.Allocator, limits: Limits, instance: Instance) !kernel.Graph {
 29             return execute.buildInstanceSource(definition, instance, allocator, limits);
 30         }
 31 
 32         pub fn buildNamed(allocator: std.mem.Allocator, limits: Limits, graph_name: []const u8, instance: Instance) !kernel.Graph {
 33             return execute.buildNamedInstanceSource(definition, graph_name, instance, allocator, limits);
 34         }
 35 
 36         pub fn interpret(allocator: std.mem.Allocator, limits: Limits, instance: Instance, initial: anytype) !execute.result(@TypeOf(initial)) {
 37             return execute.interpretInstanceSource(definition, instance, allocator, limits, initial);
 38         }
 39 
 40         pub fn launch(allocator: std.mem.Allocator, limits: Limits, instance: Instance) !kernel.Launch {
 41             var graph = try build(allocator, limits, instance);
 42             defer graph.deinit();
 43             return graph.launch();
 44         }
 45 
 46         pub fn scheduleSnapshot(allocator: std.mem.Allocator, limits: Limits, instance: Instance) !kernel.ScheduleSnapshot {
 47             var graph = try build(allocator, limits, instance);
 48             defer graph.deinit();
 49             return graph.scheduleSnapshot(allocator);
 50         }
 51 
 52         pub fn createPlan(allocator: std.mem.Allocator, limits: Limits, instance: Instance, options: kernel.PlanOptions) !kernel.Plan {
 53             var graph = try build(allocator, limits, instance);
 54             defer graph.deinit();
 55             return graph.createPlan(allocator, options);
 56         }
 57 
 58         pub fn createCheckedPlan(allocator: std.mem.Allocator, limits: Limits, instance: Instance, options: kernel.PlanOptions) !kernel.Plan {
 59             var graph = try build(allocator, limits, instance);
 60             defer graph.deinit();
 61             return graph.createCheckedPlan(allocator, options);
 62         }
 63 
 64         pub fn compileFragment(
 65             allocator: std.mem.Allocator,
 66             limits: Limits,
 67             instance: Instance,
 68             handle: kernel.BackendHandle,
 69             options: executable.FragmentCompilerOptions,
 70         ) !*executable.CompiledFragment {
 71             var graph = try build(allocator, limits, instance);
 72             defer graph.deinit();
 73             return kernel_compile.compileFragment(allocator, handle, &graph, options);
 74         }
 75 
 76         pub fn createKernelArtifact(
 77             allocator: std.mem.Allocator,
 78             limits: Limits,
 79             instance: Instance,
 80             handle: kernel.BackendHandle,
 81             options: executable.KernelCompilerOptions,
 82         ) !kernel.KernelArtifact {
 83             var graph = try build(allocator, limits, instance);
 84             defer graph.deinit();
 85             return kernel_compile.createArtifact(allocator, handle, &graph, options);
 86         }
 87 
 88         pub fn createKernelCallArtifact(
 89             allocator: std.mem.Allocator,
 90             limits: Limits,
 91             instance: Instance,
 92             handle: kernel.BackendHandle,
 93             options: kernel.KernelCallArtifactOptions,
 94         ) !kernel.OwnedKernelCallArtifact {
 95             var graph = try build(allocator, limits, instance);
 96             defer graph.deinit();
 97             return kernel.createKernelCallArtifact(allocator, handle, &graph, options);
 98         }
 99 
100         pub fn runCpu(allocator: std.mem.Allocator, limits: Limits, instance: Instance, args: []const kernel.Argument) !void {
101             var graph = try build(allocator, limits, instance);
102             defer graph.deinit();
103             try graph.runCpu(allocator, args);
104         }
105 
106         pub fn runCpuWithDiagnostic(
107             allocator: std.mem.Allocator,
108             limits: Limits,
109             instance: Instance,
110             args: []const kernel.Argument,
111             diagnostic: *kernel.ExecutionDiagnostic,
112         ) !void {
113             var graph = try build(allocator, limits, instance);
114             defer graph.deinit();
115             try graph.runCpuWithDiagnostic(allocator, args, diagnostic);
116         }
117 
118         pub fn verify(allocator: std.mem.Allocator, limits: Limits, instance: Instance) !void {
119             var graph = try build(allocator, limits, instance);
120             defer graph.deinit();
121             try graph.verify();
122         }
123     };
124 }
125 
126 fn Source(comptime definition: anytype) type {
127     return struct {
128         pub const name = definition.name;
129         pub const parameters = definition.parameters;
130         pub const Layout: type = parameter.Standard(parameters);
131         pub const Limits: type = kernel.Limits;
132         const Methods: type = Surface(@This());
133 
134         pub fn arg(comptime name_value: anytype) usize {
135             return Layout.index(name_value);
136         }
137 
138         pub fn schema() []const kernel.Param {
139             return parameter.schema(parameters);
140         }
141 
142         pub fn build(allocator: std.mem.Allocator, limits: Limits) !kernel.Graph {
143             return execute.buildSource(definition, allocator, limits);
144         }
145 
146         pub fn interpret(allocator: std.mem.Allocator, limits: Limits, initial: anytype) !execute.result(@TypeOf(initial)) {
147             return execute.interpretSource(definition, allocator, limits, initial);
148         }
149 
150         pub const analyze = Methods.analyze;
151         pub const transform = Methods.transform;
152         pub const launch = Methods.launch;
153         pub const scheduleSnapshot = Methods.scheduleSnapshot;
154         pub const createPlan = Methods.createPlan;
155         pub const createCheckedPlan = Methods.createCheckedPlan;
156         pub const compileFragment = Methods.compileFragment;
157         pub const createKernelArtifact = Methods.createKernelArtifact;
158         pub const createKernelCallArtifact = Methods.createKernelCallArtifact;
159         pub const runCpu = Methods.runCpu;
160         pub const runCpuWithDiagnostic = Methods.runCpuWithDiagnostic;
161         pub const verify = Methods.verify;
162     };
163 }
164 
165 fn Derived(comptime SourceProgram: type, comptime transform_spec: anytype) type {
166     return struct {
167         pub const name = SourceProgram.name;
168         pub const parameters = SourceProgram.parameters;
169         pub const Layout: type = SourceProgram.Layout;
170         pub const Source: type = SourceProgram;
171         pub const spec = transform_spec;
172         pub const Limits: type = kernel.Limits;
173         const Methods: type = Surface(@This());
174 
175         pub fn arg(comptime name_value: anytype) usize {
176             return Layout.index(name_value);
177         }
178 
179         pub fn schema() []const kernel.Param {
180             return SourceProgram.schema();
181         }
182 
183         pub fn build(allocator: std.mem.Allocator, limits: Limits) !kernel.Graph {
184             return execute.buildDerived(SourceProgram, transform_spec, allocator, limits);
185         }
186 
187         pub fn interpret(allocator: std.mem.Allocator, limits: Limits, initial: anytype) !execute.stackedResult(@TypeOf(transform_spec), @TypeOf(initial)) {
188             return execute.interpretDerived(SourceProgram, transform_spec, allocator, limits, initial);
189         }
190 
191         pub const analyze = Methods.analyze;
192         pub const transform = Methods.transform;
193         pub const launch = Methods.launch;
194         pub const scheduleSnapshot = Methods.scheduleSnapshot;
195         pub const createPlan = Methods.createPlan;
196         pub const createCheckedPlan = Methods.createCheckedPlan;
197         pub const compileFragment = Methods.compileFragment;
198         pub const createKernelArtifact = Methods.createKernelArtifact;
199         pub const createKernelCallArtifact = Methods.createKernelCallArtifact;
200         pub const runCpu = Methods.runCpu;
201         pub const runCpuWithDiagnostic = Methods.runCpuWithDiagnostic;
202         pub const verify = Methods.verify;
203     };
204 }
205 
206 fn Analysis(comptime ProgramType: type, comptime analysis_impl: anytype) type {
207     return struct {
208         pub const Program: type = ProgramType;
209         pub const name = ProgramType.name;
210         pub const parameters = ProgramType.parameters;
211         pub const Layout: type = ProgramType.Layout;
212         pub const Limits: type = kernel.Limits;
213 
214         pub fn arg(comptime name_value: anytype) usize {
215             return Layout.index(name_value);
216         }
217 
218         pub fn schema() []const kernel.Param {
219             return ProgramType.schema();
220         }
221 
222         pub fn interpret(allocator: std.mem.Allocator, limits: Limits) !execute.result(@TypeOf(analysis_impl)) {
223             return ProgramType.interpret(allocator, limits, analysis_impl);
224         }
225 
226         pub fn transform(comptime make_transform: anytype) type {
227             return AnalysisTransform(ProgramType, analysis_impl, make_transform);
228         }
229     };
230 }
231 
232 fn AnalysisTransform(comptime ProgramType: type, comptime analysis_impl: anytype, comptime make_transform: anytype) type {
233     return struct {
234         pub const name = ProgramType.name;
235         pub const parameters = ProgramType.parameters;
236         pub const Layout: type = ProgramType.Layout;
237         pub const Source: type = ProgramType;
238         pub const Limits: type = kernel.Limits;
239         const Methods: type = Surface(@This());
240         const AnalysisResult: type = execute.AnalysisResult(analysis_impl);
241         const TransformSpec: type = execute.TransformSpec(analysis_impl, make_transform);
242 
243         pub fn arg(comptime name_value: anytype) usize {
244             return Layout.index(name_value);
245         }
246 
247         pub fn schema() []const kernel.Param {
248             return ProgramType.schema();
249         }
250 
251         pub fn build(allocator: std.mem.Allocator, limits: Limits) !kernel.Graph {
252             return execute.buildAnalysisTransform(ProgramType, analysis_impl, make_transform, allocator, limits);
253         }
254 
255         pub fn interpret(allocator: std.mem.Allocator, limits: Limits, initial: anytype) !execute.stackedResult(TransformSpec, @TypeOf(initial)) {
256             return execute.interpretAnalysisTransform(ProgramType, analysis_impl, make_transform, allocator, limits, initial);
257         }
258 
259         pub const analyze = Methods.analyze;
260         pub const transform = Methods.transform;
261         pub const launch = Methods.launch;
262         pub const scheduleSnapshot = Methods.scheduleSnapshot;
263         pub const createPlan = Methods.createPlan;
264         pub const createCheckedPlan = Methods.createCheckedPlan;
265         pub const compileFragment = Methods.compileFragment;
266         pub const createKernelArtifact = Methods.createKernelArtifact;
267         pub const createKernelCallArtifact = Methods.createKernelCallArtifact;
268         pub const runCpu = Methods.runCpu;
269         pub const runCpuWithDiagnostic = Methods.runCpuWithDiagnostic;
270         pub const verify = Methods.verify;
271     };
272 }
273 
274 fn Surface(comptime ProgramType: type) type {
275     return struct {
276         pub fn transform(comptime impl: anytype) type {
277             const next_spec = kernel.interpret.asSpec(impl);
278             if (comptime @hasDecl(ProgramType, "spec")) {
279                 return Derived(ProgramType.Source, kernel.interpret.stack(.{ ProgramType.spec, next_spec }));
280             }
281             return Derived(ProgramType, next_spec);
282         }
283 
284         pub fn analyze(comptime analysis_impl: anytype) type {
285             return Analysis(ProgramType, analysis_impl);
286         }
287 
288         pub fn launch(allocator: std.mem.Allocator, limits: kernel.Limits) !kernel.Launch {
289             return execute.launch(ProgramType, allocator, limits);
290         }
291 
292         pub fn scheduleSnapshot(allocator: std.mem.Allocator, limits: kernel.Limits) !kernel.ScheduleSnapshot {
293             return execute.scheduleSnapshot(ProgramType, allocator, limits);
294         }
295 
296         pub fn createPlan(allocator: std.mem.Allocator, limits: kernel.Limits, options: kernel.PlanOptions) !kernel.Plan {
297             return execute.createPlan(ProgramType, allocator, limits, options);
298         }
299 
300         pub fn createCheckedPlan(allocator: std.mem.Allocator, limits: kernel.Limits, options: kernel.PlanOptions) !kernel.Plan {
301             return execute.createCheckedPlan(ProgramType, allocator, limits, options);
302         }
303 
304         pub fn compileFragment(
305             allocator: std.mem.Allocator,
306             limits: kernel.Limits,
307             handle: kernel.BackendHandle,
308             options: executable.FragmentCompilerOptions,
309         ) !*executable.CompiledFragment {
310             return execute.compileFragment(ProgramType, allocator, limits, handle, options);
311         }
312 
313         pub fn createKernelArtifact(
314             allocator: std.mem.Allocator,
315             limits: kernel.Limits,
316             handle: kernel.BackendHandle,
317             options: executable.KernelCompilerOptions,
318         ) !kernel.KernelArtifact {
319             return execute.createKernelArtifact(ProgramType, allocator, limits, handle, options);
320         }
321 
322         pub fn createKernelCallArtifact(
323             allocator: std.mem.Allocator,
324             limits: kernel.Limits,
325             handle: kernel.BackendHandle,
326             options: kernel.KernelCallArtifactOptions,
327         ) !kernel.OwnedKernelCallArtifact {
328             return execute.createKernelCallArtifact(ProgramType, allocator, limits, handle, options);
329         }
330 
331         pub fn runCpu(allocator: std.mem.Allocator, limits: kernel.Limits, args: []const kernel.Argument) !void {
332             try execute.runCpu(ProgramType, allocator, limits, args);
333         }
334 
335         pub fn runCpuWithDiagnostic(
336             allocator: std.mem.Allocator,
337             limits: kernel.Limits,
338             args: []const kernel.Argument,
339             diagnostic: *kernel.ExecutionDiagnostic,
340         ) !void {
341             try execute.runCpuWithDiagnostic(ProgramType, allocator, limits, args, diagnostic);
342         }
343 
344         pub fn verify(allocator: std.mem.Allocator, limits: kernel.Limits) !void {
345             try execute.verify(ProgramType, allocator, limits);
346         }
347     };
348 }