lib/choir/src/backends/wasm/emission/symbols.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const std = @import("std");
 2 const ir = @import("../../../core/root.zig");
 3 const dialects = @import("../../../dialects/root.zig");
 4 const emission = @import("root.zig");
 5 
 6 const BuiltinDialect = dialects.BuiltinDialect;
 7 const FuncDialect = dialects.FuncDialect;
 8 
 9 pub const Role = enum {
10     required,
11     provided,
12 };
13 
14 pub const Symbol = struct {
15     name: []const u8,
16     role: Role,
17     function_ordinal: usize,
18 };
19 
20 pub const Iterator = struct {
21     operations: ir.Block.OperationIterator,
22     options: emission.Options,
23     function_ordinal: usize = 0,
24 
25     pub fn init(module: *ir.Operation, options: emission.Options) emission.Error!Iterator {
26         if (!std.mem.eql(u8, module.name.name, BuiltinDialect.ModuleOp.operation_name)) {
27             return error.CodeGenFailed;
28         }
29         const module_op = BuiltinDialect.ModuleOp{ .op = module };
30         return .{
31             .operations = module_op.getBodyBlock().getOperations(),
32             .options = options,
33         };
34     }
35 
36     pub fn next(self: *Iterator) emission.Error!?Symbol {
37         while (self.operations.next()) |operation| {
38             const function_ordinal = self.function_ordinal;
39             self.function_ordinal = std.math.add(
40                 usize,
41                 self.function_ordinal,
42                 1,
43             ) catch return error.CapacityOverflow;
44             if (!std.mem.eql(u8, operation.name.name, FuncDialect.FuncOp.operation_name)) {
45                 return error.CodeGenFailed;
46             }
47             const function = FuncDialect.FuncOp{ .op = operation };
48             const name = function.getName() orelse return error.CodeGenFailed;
49             if (function.isDeclaration()) {
50                 return .{
51                     .name = name,
52                     .role = .required,
53                     .function_ordinal = function_ordinal,
54                 };
55             }
56             if (shouldExport(operation, name, self.options.entry)) {
57                 return .{
58                     .name = name,
59                     .role = .provided,
60                     .function_ordinal = function_ordinal,
61                 };
62             }
63         }
64         return null;
65     }
66 };
67 
68 fn shouldExport(
69     operation: *ir.Operation,
70     name: []const u8,
71     entry: ?[]const u8,
72 ) bool {
73     if (entry) |requested| return std.mem.eql(u8, requested, name);
74     return ir.SymbolTable.getSymbolVisibility(operation) == .public;
75 }
76 
77 test {
78     std.testing.refAllDecls(@This());
79 }