diff options
author | Ernesto Lanchares <elancha98@proton.me> | 2025-03-23 18:20:38 +0000 |
---|---|---|
committer | Lorenzo Torres <torres@sideros.org> | 2025-03-23 19:32:10 +0100 |
commit | 874134f3ff726d969fd901fee18c1aceb415c03b (patch) | |
tree | 5cd25aba47d6dc91737a2794622fe8dc21a8b9f6 /src | |
parent | b7854d7325dfe35ca41e56dcccfb8fb7b7d0aa22 (diff) |
PROPOSAL: IR
This is a proposal of a custom IR to run wasm.
At the moment only `ir.zig` has some parts related
to this IR. The idea of the IR is to be a subset
of the one defined in wasm. There are some gaps
(mostly in wasm instructions that have opcode
0xFC) but in wasm they don't use all of the
opcodes for some reason so maybe we could try to
utilize them and be a superset of wasm.
Diffstat (limited to 'src')
-rw-r--r-- | src/main.zig | 7 | ||||
-rw-r--r-- | src/mods/Parser.zig | 2 | ||||
-rw-r--r-- | src/mods/ir.zig | 279 | ||||
-rw-r--r-- | src/mods/mods.zig | 5 |
4 files changed, 288 insertions, 5 deletions
diff --git a/src/main.zig b/src/main.zig index 97aa5bf..e8ff1d1 100644 --- a/src/main.zig +++ b/src/main.zig @@ -5,9 +5,8 @@ const window = @import("rendering/window.zig"); const config = @import("config"); const Renderer = @import("rendering/renderer_vulkan.zig"); const math = @import("math.zig"); -const Parser = @import("mods/Parser.zig"); -const vm = @import("mods/vm.zig"); -const wasm = @import("mods/wasm.zig"); +const mods = @import("mods"); + const components = @import("ecs/components.zig"); const entities = @import("ecs/entities.zig"); @@ -30,7 +29,7 @@ pub fn main() !void { // const file = try std.fs.cwd().openFile("assets/core.wasm", .{}); // const all = try file.readToEndAlloc(allocator, 1_000_000); // 1 MB - // var parser = Parser{ + // var parser = mods.Parser{ // .bytes = all, // .byte_idx = 0, // .allocator = allocator, diff --git a/src/mods/Parser.zig b/src/mods/Parser.zig index 29f18d8..d9f7ccf 100644 --- a/src/mods/Parser.zig +++ b/src/mods/Parser.zig @@ -144,7 +144,7 @@ fn parseReftype(self: *Parser) !std.wasm.RefType { // NOTE: Parsing of Valtype can be improved but it makes it less close to spec so... // TODO: Do we really need Valtype? -const Valtype = union(enum) { +pub const Valtype = union(enum) { val: std.wasm.Valtype, ref: std.wasm.RefType, }; diff --git a/src/mods/ir.zig b/src/mods/ir.zig new file mode 100644 index 0000000..ecb8d31 --- /dev/null +++ b/src/mods/ir.zig @@ -0,0 +1,279 @@ +const std = @import("std"); +const Parser = @import("Parser.zig"); + +const Allocator = std.mem.Allocator; + +const DIndex = packed struct { + first: u32, + second: u32, +}; +comptime { + // TODO: is this too big? we could do with 32 bits and a bit more indirection + std.debug.assert(@sizeOf(Index) == 8); +} +/// packed union has no tag +const Index = packed union { + u32: u32, + i32: i32, + u64: u64, + i64: i64, + f32: f32, + f64: f64, + di: DIndex, +}; + + +opcodes: []Opcode, +/// Indices means something different depending on the Opcode. +/// Read the docs of each opcode to know what the index means. +indices: []Index, + +select_valtypes: []Parser.Valtype, + +/// Opcodes +pub const Opcode = enum(u8) { + // CONTROL INSTRUCTIONS + // The rest of instructions should be implemented in terms of these ones + @"unreachable" = 0x00, + nop = 0x01, + /// Index: `u64`. Meaning: the next instruction pointer + br = 0x0C, + /// Index: `u64`. Meaning: the next instruction pointer + br_if = 0x0D, + /// TODO: this instruction (could be also implemented in terms of br and br_if) + br_table = 0x0E, + @"return" = 0x0F, + /// Index: `u64`. Meaning: The function index to call + call = 0x10, + /// TODO: index (is it enough with using a double index here? if we consider it enough then the other indices should use u32) + call_indirect = 0x11, + + // REFERENCE INSTRUCTIONS + // This should be resolved at parse time and therefore not part of IR + + // PARAMETRIC INSTRUCTIONS + // Select with no valtypes should be resolved at parse time + drop = 0x1A, + /// Index: `DIndex`. Meaning: + /// `first` is the index into `select_valtypes` array and + /// `second` is the number of valtypes + select = 0x1C, + + // VARIABLE INSTRUCTIONS + /// Index: `u32`. Meaing: index into local variables + localget = 0x20, + /// Index: `u32`. Meaing: index into local variables + localset = 0x21, + /// Index: `u32`. Meaing: index into local variables + localtee = 0x22, + /// Index: `u32`. Meaing: index into global variables + globalget = 0x23, + /// Index: `u32`. Meaing: index into global variables + globalset = 0x24, + + // TABLE INSTRUCTIONS + /// Index: `u32`. Meaning: index into table index + tableget = 0x25, + /// Index: `u32`. Meaning: index into table index + tableset = 0x26, + /// TODO: table operation. Value in wasm: 0xFC. Note wher is 0x27? + tableop = 0xF0, + + // MEMORY INSTRUCTIONS + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + i32load = 0x28, + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + i64load = 0x29, + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + f32load = 0x2A, + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + f64load = 0x2B, + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + i32load8_s = 0x2C, + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + i32load8_u = 0x2D, + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + i32load16_s = 0x2E, + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + i32load16_u = 0x2F, + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + i64load8_s = 0x30, + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + i64load8_u = 0x31, + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + i64load16_s = 0x32, + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + i64load16_u = 0x33, + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + i64load32_s = 0x34, + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + i64load32_u = 0x35, + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + i32store = 0x36, + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + i64store = 0x37, + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + f32store = 0x38, + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + f64store = 0x39, + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + i32store8 = 0x3A, + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + i32store16 = 0x3B, + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + i64store8 = 0x3C, + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + i64store16 = 0x3D, + /// Index: `DIndex`. Meaning: `firts` is alignment, `second` is offset + i64store32 = 0x3E, + memorysize = 0x3F, + memorygrow = 0x40, + /// TODO: memory operation. Value in wasm: 0xFC + memoryop = 0xF1, + + // NUMERIC INSTRUCTION + /// Index: `i32`. Meaning: constant + i32const = 0x41, + /// Index: `i64`. Meaning: constant + i64const = 0x42, + /// Index: `f32`. Meaning: constant + f32const = 0x43, + /// Index: `f64`. Meaning: constant + f64const = 0x44, + i32eqz = 0x45, + i32eq = 0x46, + i32ne = 0x47, + i32lt_s = 0x48, + i32lt_u = 0x49, + i32gt_s = 0x4A, + i32gt_u = 0x4B, + i32le_s = 0x4C, + i32le_u = 0x4D, + i32ge_s = 0x4E, + i32ge_u = 0x4F, + i64eqz = 0x50, + i64eq = 0x51, + i64ne = 0x52, + i64lt_s = 0x53, + i64lt_u = 0x54, + i64gt_s = 0x55, + i64gt_u = 0x56, + i64le_s = 0x57, + i64le_u = 0x58, + i64ge_s = 0x59, + i64ge_u = 0x5A, + f32eq = 0x5B, + f32ne = 0x5C, + f32lt = 0x5D, + f32gt = 0x5E, + f32le = 0x5F, + f32ge = 0x60, + f64eq = 0x61, + f64ne = 0x62, + f64lt = 0x63, + f64gt = 0x64, + f64le = 0x65, + f64ge = 0x66, + i32clz = 0x67, + i32ctz = 0x68, + i32popcnt = 0x69, + i32add = 0x6A, + i32sub = 0x6B, + i32mul = 0x6C, + i32div_s = 0x6D, + i32div_u = 0x6E, + i32rem_s = 0x6F, + i32rem_u = 0x70, + i32and = 0x71, + i32or = 0x72, + i32xor = 0x73, + i32shl = 0x74, + i32shr_s = 0x75, + i32shr_u = 0x76, + i32rotl = 0x77, + i32rotr = 0x78, + i64clz = 0x79, + i64ctz = 0x7A, + i64popcnt = 0x7B, + i64add = 0x7C, + i64sub = 0x7D, + i64mul = 0x7E, + i64div_s = 0x7F, + i64div_u = 0x80, + i64rem_s = 0x81, + i64rem_u = 0x82, + i64and = 0x83, + i64or = 0x84, + i64xor = 0x85, + i64shl = 0x86, + i64shr_s = 0x87, + i64shr_u = 0x88, + i64rotl = 0x89, + i64rotr = 0x8A, + f32abs = 0x8B, + f32neg = 0x8C, + f32ceil = 0x8D, + f32floor = 0x8E, + f32trunc = 0x8F, + f32nearest = 0x90, + f32sqrt = 0x91, + f32add = 0x92, + f32sub = 0x93, + f32mul = 0x94, + f32div = 0x95, + f32min = 0x96, + f32max = 0x97, + f32copysign = 0x98, + f64abs = 0x99, + f64neg = 0x9A, + f64ceil = 0x9B, + f64floor = 0x9C, + f64trunc = 0x9D, + f64nearest = 0x9E, + f64sqrt = 0x9F, + f64add = 0xA0, + f64sub = 0xA1, + f64mul = 0xA2, + f64div = 0xA3, + f64min = 0xA4, + f64max = 0xA5, + f64copysign = 0xA6, + i32wrap_i64 = 0xA7, + i32trunc_f32_s = 0xA8, + i32trunc_f32_u = 0xA9, + i32trunc_f64_s = 0xAA, + i32trunc_f64_u = 0xAB, + i64extend_i32_s = 0xAC, + i64extend_i32_u = 0xAD, + i64trunc_f32_s = 0xAE, + i64trunc_f32_u = 0xAF, + i64trunc_f64_s = 0xB0, + i64trunc_f64_u = 0xB1, + f32convert_i32_s = 0xB2, + f32convert_i32_u = 0xB3, + f32convert_i64_s = 0xB4, + f32convert_i64_u = 0xB5, + f32demote_f64 = 0xB6, + f64convert_i32_s = 0xB7, + f64convert_i32_u = 0xB8, + f64convert_i64_s = 0xB9, + f64convert_i64_u = 0xBA, + f64promote_f32 = 0xBB, + i32reinterpret_f32 = 0xBC, + i64reinterpret_f64 = 0xBD, + f32reinterpret_i32 = 0xBE, + f64reinterpret_i64 = 0xBF, + i32extend8_s = 0xC0, + i32extend16_s = 0xC1, + i64extend8_s = 0xC2, + i64extend16_s = 0xC3, + i64extend32_s = 0xC4, + /// TODO: saturation truncation instructions. Value in wasm: 0xFC + sattrunc = 0xF2, + + // VECTOR INSTRUCTIONS + /// TODO: vector instructions. Value in wasm: 0xFC. Note: there are opcodes available lol + vecinst = 0xF3, + +}; + diff --git a/src/mods/mods.zig b/src/mods/mods.zig new file mode 100644 index 0000000..9d845e1 --- /dev/null +++ b/src/mods/mods.zig @@ -0,0 +1,5 @@ +pub const Parser = @import("Parser.zig"); +pub const VM = @import("vm.zig"); +// TODO: is this really needed? +pub const Wasm = @import("wasm.zig"); +pub const IR = @import("ir.zig"); |