lib/choir/src/backends/artifact/serialization/linkage.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const artifact = @import("../root.zig");
3 const format = @import("root.zig").format;
4
5 const Signature = artifact.Signature;
6
7 pub fn write(writer: *format.Writer, value: artifact.Linkage) format.WriteError!void {
8 try writer.writeCount(value.required_symbols.items.len);
9 for (value.required_symbols.items) |symbol| try writeSymbol(writer, symbol);
10 try writer.writeCount(value.provided_symbols.items.len);
11 for (value.provided_symbols.items) |symbol| try writeSymbol(writer, symbol);
12 try writer.writeCount(value.relocations.items.len);
13 for (value.relocations.items) |relocation| {
14 try writer.writeInt(u64, relocation.offset);
15 try writer.writeString(relocation.symbol);
16 try writer.writeTag(relocation.kind);
17 try writer.writeInt(i64, relocation.addend);
18 try writer.writeOptionalU16(relocation.width_bits);
19 }
20 }
21
22 pub fn readInto(reader: *format.Reader, value: *artifact.Linkage) (format.Error || std.mem.Allocator.Error)!void {
23 const required_count = try reader.readCount();
24 for (0..required_count) |_| try value.addRequired(try readSymbol(reader));
25 const provided_count = try reader.readCount();
26 for (0..provided_count) |_| try value.addProvided(try readSymbol(reader));
27 const relocation_count = try reader.readCount();
28 for (0..relocation_count) |_| {
29 try value.addRelocation(.{
30 .offset = try reader.readInt(u64),
31 .symbol = try reader.readString(),
32 .kind = try reader.readTag(artifact.RelocationKind),
33 .addend = try reader.readInt(i64),
34 .width_bits = try reader.readOptionalU16(),
35 });
36 }
37 }
38
39 fn writeSymbol(writer: *format.Writer, symbol: artifact.Symbol) format.WriteError!void {
40 try writer.writeString(symbol.name);
41 try writer.writeTag(symbol.kind);
42 try writer.writeTag(symbol.binding);
43 try writer.writeBool(symbol.signature != null);
44 if (symbol.signature) |*signature| try writeSignature(writer, signature);
45 }
46
47 fn readSymbol(reader: *format.Reader) format.Error!artifact.Symbol {
48 const name = try reader.readString();
49 const kind = try reader.readTag(artifact.SymbolKind);
50 const binding = try reader.readTag(artifact.SymbolBinding);
51 const signature: ?Signature = if (try reader.readBool()) try readSignature(reader) else null;
52 return .{ .name = name, .kind = kind, .binding = binding, .signature = signature };
53 }
54
55 fn writeSignature(writer: *format.Writer, signature: *const Signature) format.WriteError!void {
56 std.debug.assert(signature.isValid());
57 try writer.writeInt(u8, signature.parameter_count);
58 try writer.writeInt(u8, signature.result_count);
59 for (signature.parameters()) |value_type| try writeValueType(writer, value_type);
60 for (signature.results()) |value_type| try writeValueType(writer, value_type);
61 }
62
63 fn readSignature(reader: *format.Reader) format.Error!Signature {
64 const parameter_count = try reader.readInt(u8);
65 const result_count = try reader.readInt(u8);
66 if (parameter_count > Signature.max_parameters) return error.LimitExceeded;
67 if (result_count > Signature.max_results) return error.LimitExceeded;
68 var parameters: [Signature.max_parameters]artifact.ValueType = undefined;
69 for (parameters[0..parameter_count]) |*value_type| value_type.* = try readValueType(reader);
70 var results: [Signature.max_results]artifact.ValueType = undefined;
71 for (results[0..result_count]) |*value_type| value_type.* = try readValueType(reader);
72 const signature = Signature.init(
73 parameters[0..parameter_count],
74 results[0..result_count],
75 ) catch |err| switch (err) {
76 error.TooManyParameters, error.TooManyResults => unreachable,
77 error.InvalidValueType => return error.InvalidValue,
78 };
79 std.debug.assert(signature.parameter_count == parameter_count);
80 std.debug.assert(signature.result_count == result_count);
81 return signature;
82 }
83
84 fn writeValueType(writer: *format.Writer, value_type: artifact.ValueType) format.WriteError!void {
85 try writer.writeTag(std.meta.activeTag(value_type));
86 switch (value_type) {
87 .scalar => |scalar| try writer.writeTag(scalar),
88 .memref => {},
89 .vector => |vector| {
90 try writer.writeTag(vector.element);
91 try writer.writeInt(u8, vector.lanes);
92 },
93 }
94 }
95
96 fn readValueType(reader: *format.Reader) format.Error!artifact.ValueType {
97 return switch (try reader.readTag(artifact.ValueKind)) {
98 .scalar => .{ .scalar = try reader.readTag(artifact.ScalarType) },
99 .memref => .memref,
100 .vector => .{ .vector = .{
101 .element = try reader.readTag(artifact.ScalarType),
102 .lanes = try reader.readInt(u8),
103 } },
104 };
105 }