aboutsummaryrefslogtreecommitdiff
path: root/src-self-hosted/codegen/wasm.zig
diff options
context:
space:
mode:
authorIsaac Freund <ifreund@ifreund.xyz>2020-08-07 00:53:55 +0200
committerIsaac Freund <ifreund@ifreund.xyz>2020-08-18 00:32:58 +0200
commit3370b5f1097d0610048e29b322b4cbf81ff0a431 (patch)
tree5e21fa0c927c13619d9e7a128eccaf8b3f5bba80 /src-self-hosted/codegen/wasm.zig
parent96a27557e2ef53b8d1d3132f02c83b716c966277 (diff)
downloadzig-3370b5f1097d0610048e29b322b4cbf81ff0a431.tar.gz
zig-3370b5f1097d0610048e29b322b4cbf81ff0a431.zip
stage2/wasm: implement basic container generation
Thus far, we only generate the type, function, export, and code sections. These are sufficient to generate and export simple functions. Codegen is currently hardcoded to `i32.const 42`, the main goal of this commit is to create infrastructure for the container format which will work with incremental compilation.
Diffstat (limited to 'src-self-hosted/codegen/wasm.zig')
-rw-r--r--src-self-hosted/codegen/wasm.zig70
1 files changed, 70 insertions, 0 deletions
diff --git a/src-self-hosted/codegen/wasm.zig b/src-self-hosted/codegen/wasm.zig
new file mode 100644
index 0000000000..78d8d22ded
--- /dev/null
+++ b/src-self-hosted/codegen/wasm.zig
@@ -0,0 +1,70 @@
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+const ArrayList = std.ArrayList;
+const assert = std.debug.assert;
+const leb = std.debug.leb;
+
+const Decl = @import("../Module.zig").Decl;
+const Type = @import("../type.zig").Type;
+
+fn genValtype(ty: Type) u8 {
+ return switch (ty.tag()) {
+ .u32, .i32 => 0x7F,
+ .u64, .i64 => 0x7E,
+ .f32 => 0x7D,
+ .f64 => 0x7C,
+ else => @panic("TODO: Implement more types for wasm."),
+ };
+}
+
+pub fn genFunctype(buf: *ArrayList(u8), decl: *Decl) !void {
+ const ty = decl.typed_value.most_recent.typed_value.ty;
+ const writer = buf.writer();
+
+ // functype magic
+ try writer.writeByte(0x60);
+
+ // param types
+ try leb.writeULEB128(writer, @intCast(u32, ty.fnParamLen()));
+ if (ty.fnParamLen() != 0) {
+ const params = try buf.allocator.alloc(Type, ty.fnParamLen());
+ defer buf.allocator.free(params);
+ ty.fnParamTypes(params);
+ for (params) |param_type| try writer.writeByte(genValtype(param_type));
+ }
+
+ // return type
+ const return_type = ty.fnReturnType();
+ switch (return_type.tag()) {
+ .void, .noreturn => try leb.writeULEB128(writer, @as(u32, 0)),
+ else => {
+ try leb.writeULEB128(writer, @as(u32, 1));
+ try writer.writeByte(genValtype(return_type));
+ },
+ }
+}
+
+pub fn genCode(buf: *ArrayList(u8), decl: *Decl) !void {
+ assert(buf.items.len == 0);
+ const writer = buf.writer();
+
+ // Reserve space to write the size after generating the code
+ try writer.writeAll(&([1]u8{undefined} ** 5));
+
+ // Write the size of the locals vec
+ // TODO: implement locals
+ try leb.writeULEB128(writer, @as(u32, 0));
+
+ // Write instructions
+
+ // TODO: actually implement codegen
+ try writer.writeByte(0x41); // i32.const
+ try leb.writeILEB128(writer, @as(i32, 42));
+
+ // Write 'end' opcode
+ try writer.writeByte(0x0B);
+
+ // Fill in the size of the generated code to the reserved space at the
+ // beginning of the buffer.
+ leb.writeUnsignedFixed(5, buf.items[0..5], @intCast(u32, buf.items.len - 5));
+}