lib/choir/src/backends/wasm/emission/function/instruction/writer.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const wasm = @import("../../../root.zig");
3 const ir = @import("../../../../../core/root.zig");
4 const dialects = @import("../../../../../dialects/root.zig");
5 const emission = @import("../../root.zig");
6 const instruction = @import("root.zig");
7
8 const ArithDialect = dialects.ArithDialect;
9 const FuncDialect = dialects.FuncDialect;
10 const MemrefDialect = dialects.MemrefDialect;
11
12 pub fn Writer(comptime Out: type) type {
13 return struct {
14 out: Out,
15 plan: *const emission.Plan,
16 function_ordinal: usize,
17
18 const Self = @This();
19
20 pub fn writeOperation(self: *Self, operation: *ir.Operation) emission.Error!void {
21 const name = operation.name.name;
22 if (std.mem.eql(u8, name, ArithDialect.ConstantOp.operation_name)) {
23 return instruction.arithmetic.lowering.writeConstant(Out, self, operation);
24 }
25 if (std.mem.eql(u8, name, ArithDialect.AddOp.operation_name)) {
26 return instruction.arithmetic.lowering.writeBinary(Out, self, operation, .add);
27 }
28 if (std.mem.eql(u8, name, ArithDialect.SubOp.operation_name)) {
29 return instruction.arithmetic.lowering.writeBinary(Out, self, operation, .sub);
30 }
31 if (std.mem.eql(u8, name, ArithDialect.MulOp.operation_name)) {
32 return instruction.arithmetic.lowering.writeBinary(Out, self, operation, .mul);
33 }
34 if (std.mem.eql(u8, name, ArithDialect.DivOp.operation_name)) {
35 return instruction.arithmetic.lowering.writeBinary(Out, self, operation, .div);
36 }
37 if (std.mem.eql(u8, name, ArithDialect.RemOp.operation_name)) {
38 return instruction.arithmetic.lowering.writeBinary(Out, self, operation, .rem);
39 }
40 if (std.mem.eql(u8, name, ArithDialect.AndOp.operation_name)) {
41 return instruction.arithmetic.lowering.writeBinary(Out, self, operation, .band);
42 }
43 if (std.mem.eql(u8, name, ArithDialect.OrOp.operation_name)) {
44 return instruction.arithmetic.lowering.writeBinary(Out, self, operation, .bor);
45 }
46 if (std.mem.eql(u8, name, ArithDialect.XorOp.operation_name)) {
47 return instruction.arithmetic.lowering.writeBinary(Out, self, operation, .bxor);
48 }
49 if (std.mem.eql(u8, name, ArithDialect.ShlOp.operation_name)) {
50 return instruction.arithmetic.lowering.writeBinary(Out, self, operation, .shl);
51 }
52 if (std.mem.eql(u8, name, ArithDialect.ShrOp.operation_name)) {
53 return instruction.arithmetic.lowering.writeBinary(Out, self, operation, .shr);
54 }
55 if (std.mem.eql(u8, name, ArithDialect.UshrOp.operation_name)) {
56 return instruction.arithmetic.lowering.writeBinary(Out, self, operation, .ushr);
57 }
58 if (std.mem.eql(u8, name, ArithDialect.CmpOp.operation_name)) {
59 return instruction.arithmetic.lowering.writeCmp(Out, self, operation);
60 }
61 if (std.mem.eql(u8, name, ArithDialect.SelectOp.operation_name)) {
62 return instruction.arithmetic.lowering.writeSelect(Out, self, operation);
63 }
64 if (std.mem.eql(u8, name, ArithDialect.NegOp.operation_name)) {
65 return instruction.arithmetic.lowering.writeNeg(Out, self, operation);
66 }
67 if (std.mem.eql(u8, name, ArithDialect.AbsOp.operation_name)) {
68 return instruction.arithmetic.lowering.writeAbs(Out, self, operation);
69 }
70 if (std.mem.eql(u8, name, ArithDialect.SqrtOp.operation_name)) {
71 return instruction.arithmetic.lowering.writeSqrt(Out, self, operation);
72 }
73 if (std.mem.eql(u8, name, ArithDialect.BitcastOp.operation_name)) {
74 return instruction.cast.write(Out, self, operation, true);
75 }
76 if (std.mem.eql(u8, name, ArithDialect.CastOp.operation_name)) {
77 return instruction.cast.write(Out, self, operation, false);
78 }
79 if (std.mem.eql(u8, name, FuncDialect.CallOp.operation_name)) {
80 return instruction.call.write(Out, self, operation);
81 }
82 if (std.mem.eql(u8, name, MemrefDialect.LoadOp.operation_name)) {
83 return instruction.memory.writeLoad(Out, self, operation);
84 }
85 if (std.mem.eql(u8, name, MemrefDialect.StoreOp.operation_name)) {
86 return instruction.memory.writeStore(Out, self, operation);
87 }
88 inline for (.{ ArithDialect.AddoOp, ArithDialect.SuboOp, ArithDialect.MuloOp }) |Op| {
89 if (std.mem.eql(u8, name, Op.operation_name)) return error.UnsupportedOperation;
90 }
91 return error.CodeGenFailed;
92 }
93
94 pub fn writeValue(self: *Self, value: *ir.Value) emission.Error!void {
95 try self.writeLocalGet(try self.localFor(value));
96 }
97
98 pub fn writeLocalGet(self: *Self, local: u32) emission.Error!void {
99 try self.out.writeByte(0x20);
100 try wasm.binary.writeUleb(self.out, local);
101 }
102
103 pub fn writeLocalSet(self: *Self, local: u32) emission.Error!void {
104 try self.out.writeByte(0x21);
105 try wasm.binary.writeUleb(self.out, local);
106 }
107
108 pub fn localFor(self: *const Self, value: *ir.Value) emission.Error!u32 {
109 return self.plan.localFor(self.function_ordinal, value) orelse
110 error.CodeGenFailed;
111 }
112 };
113 }