Commit 09d6938df9
Changed files (5)
lib
std
src
arch
link
lib/std/wasm.zig
@@ -189,7 +189,9 @@ pub const Opcode = enum(u8) {
i64_extend16_s = 0xC3,
i64_extend32_s = 0xC4,
- prefixed = 0xFC,
+ misc_prefix = 0xFC,
+ simd_prefix = 0xFD,
+ atomics_prefix = 0xFE,
_,
};
@@ -217,7 +219,7 @@ test "Wasm - opcodes" {
/// Opcodes that require a prefix `0xFC`
/// Each opcode represents a varuint32, meaning
/// they are encoded as leb128 in binary.
-pub const PrefixedOpcode = enum(u32) {
+pub const MiscOpcode = enum(u32) {
i32_trunc_sat_f32_s = 0x00,
i32_trunc_sat_f32_u = 0x01,
i32_trunc_sat_f64_s = 0x02,
@@ -239,6 +241,12 @@ pub const PrefixedOpcode = enum(u32) {
_,
};
+/// Returns the integer value of an `MiscOpcode`. Used by the Zig compiler
+/// to write instructions to the wasm binary file
+pub fn miscOpcode(op: MiscOpcode) u32 {
+ return @enumToInt(op);
+}
+
/// Simd opcodes that require a prefix `0xFD`.
/// Each opcode represents a varuint32, meaning
/// they are encoded as leb128 in binary.
@@ -510,6 +518,86 @@ pub fn simdOpcode(op: SimdOpcode) u32 {
return @enumToInt(op);
}
+/// Simd opcodes that require a prefix `0xFE`.
+/// Each opcode represents a varuint32, meaning
+/// they are encoded as leb128 in binary.
+pub const AtomicsOpcode = enum(u32) {
+ memory_atomic_notify = 0x00,
+ memory_atomic_wait32 = 0x01,
+ memory_atomic_wait64 = 0x02,
+ atomic_fence = 0x03,
+ i32_atomic_load = 0x10,
+ i64_atomic_load = 0x11,
+ i32_atomic_load8_u = 0x12,
+ i32_atomic_load16_u = 0x13,
+ i64_atomic_load8_u = 0x14,
+ i64_atomic_load16_u = 0x15,
+ i64_atomic_load32_u = 0x16,
+ i32_atomic_store = 0x17,
+ i64_atomic_store = 0x18,
+ i32_atomic_store8 = 0x19,
+ i32_atomic_store16 = 0x1A,
+ i64_atomic_store8 = 0x1B,
+ i64_atomic_store16 = 0x1C,
+ i64_atomic_store32 = 0x1D,
+ i32_atomic_rmw_add = 0x1E,
+ i64_atomic_rmw_add = 0x1F,
+ i32_atomic_rmw8_add_u = 0x20,
+ i32_atomic_rmw16_add_u = 0x21,
+ i64_atomic_rmw8_add_u = 0x22,
+ i64_atomic_rmw16_add_u = 0x23,
+ i64_atomic_rmw32_add_u = 0x24,
+ i32_atomic_rmw_sub = 0x25,
+ i64_atomic_rmw_sub = 0x26,
+ i32_atomic_rmw8_sub_u = 0x27A,
+ i32_atomic_rmw16_sub_u = 0x28A,
+ i64_atomic_rmw8_sub_u = 0x29A,
+ i64_atomic_rmw16_sub_u = 0x2A,
+ i64_atomic_rmw32_sub_u = 0x2B,
+ i32_atomic_rmw_and = 0x2C,
+ i64_atomic_rmw_and = 0x2D,
+ i32_atomic_rmw8_and_u = 0x2E,
+ i32_atomic_rmw16_and_u = 0x2F,
+ i64_atomic_rmw8_and_u = 0x30,
+ i64_atomic_rmw16_and_u = 0x31,
+ i64_atomic_rmw32_and_u = 0x32,
+ i32_atomic_rmw_or = 0x33,
+ i64_atomic_rmw_or = 0x34,
+ i32_atomic_rmw8_or_u = 0x35,
+ i32_atomic_rmw16_or_u = 0x36,
+ i64_atomic_rmw8_or_u = 0x37,
+ i64_atomic_rmw16_or_u = 0x38,
+ i64_atomic_rmw32_or_u = 0x39,
+ i32_atomic_rmw_xor = 0x3A,
+ i64_atomic_rmw_xor = 0x3B,
+ i32_atomic_rmw8_xor_u = 0x3C,
+ i32_atomic_rmw16_xor_u = 0x3D,
+ i64_atomic_rmw8_xor_u = 0x3E,
+ i64_atomic_rmw16_xor_u = 0x3F,
+ i64_atomic_rmw32_xor_u = 0x40,
+ i32_atomic_rmw_xchg = 0x41,
+ i64_atomic_rmw_xchg = 0x42,
+ i32_atomic_rmw8_xchg_u = 0x43,
+ i32_atomic_rmw16_xchg_u = 0x44,
+ i64_atomic_rmw8_xchg_u = 0x45,
+ i64_atomic_rmw16_xchg_u = 0x46,
+ i64_atomic_rmw32_xchg_u = 0x47,
+
+ i32_atomic_rmw_cmpxchg = 0x48,
+ i64_atomic_rmw_cmpxchg = 0x49,
+ i32_atomic_rmw8_cmpxchg_u = 0x4A,
+ i32_atomic_rmw16_cmpxchg_u = 0x4B,
+ i64_atomic_rmw8_cmpxchg_u = 0x4C,
+ i64_atomic_rmw16_cmpxchg_u = 0x4D,
+ i64_atomic_rmw32_cmpxchg_u = 0x4E,
+};
+
+/// Returns the integer value of an `AtomicsOpcode`. Used by the Zig compiler
+/// to write instructions to the wasm binary file
+pub fn atomicsOpcode(op: AtomicsOpcode) u32 {
+ return @enumToInt(op);
+}
+
/// Enum representing all Wasm value types as per spec:
/// https://webassembly.github.io/spec/core/binary/types.html
pub const Valtype = enum(u8) {
src/arch/wasm/CodeGen.zig
@@ -895,10 +895,10 @@ fn addTag(func: *CodeGen, tag: Mir.Inst.Tag) error{OutOfMemory}!void {
try func.addInst(.{ .tag = tag, .data = .{ .tag = {} } });
}
-fn addExtended(func: *CodeGen, opcode: wasm.PrefixedOpcode) error{OutOfMemory}!void {
+fn addExtended(func: *CodeGen, opcode: wasm.MiscOpcode) error{OutOfMemory}!void {
const extra_index = @intCast(u32, func.mir_extra.items.len);
try func.mir_extra.append(func.gpa, @enumToInt(opcode));
- try func.addInst(.{ .tag = .extended, .data = .{ .payload = extra_index } });
+ try func.addInst(.{ .tag = .misc_prefix, .data = .{ .payload = extra_index } });
}
fn addLabel(func: *CodeGen, tag: Mir.Inst.Tag, label: u32) error{OutOfMemory}!void {
@@ -925,7 +925,7 @@ fn addImm128(func: *CodeGen, index: u32) error{OutOfMemory}!void {
try func.mir_extra.ensureUnusedCapacity(func.gpa, 5);
func.mir_extra.appendAssumeCapacity(std.wasm.simdOpcode(.v128_const));
func.mir_extra.appendSliceAssumeCapacity(@alignCast(4, mem.bytesAsSlice(u32, &simd_values)));
- try func.addInst(.{ .tag = .simd, .data = .{ .payload = extra_index } });
+ try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
}
fn addFloat64(func: *CodeGen, float: f64) error{OutOfMemory}!void {
@@ -2310,7 +2310,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
offset + lhs.offset(),
ty.abiAlignment(func.target),
});
- return func.addInst(.{ .tag = .simd, .data = .{ .payload = extra_index } });
+ return func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
},
},
.Pointer => {
@@ -2420,7 +2420,7 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu
offset + operand.offset(),
ty.abiAlignment(func.target),
});
- try func.addInst(.{ .tag = .simd, .data = .{ .payload = extra_index } });
+ try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
return WValue{ .stack = {} };
}
@@ -4477,7 +4477,7 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
operand.offset(),
elem_ty.abiAlignment(func.target),
});
- try func.addInst(.{ .tag = .simd, .data = .{ .payload = extra_index } });
+ try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
try func.addLabel(.local_set, result.local.value);
return func.finishAir(inst, result, &.{ty_op.operand});
},
@@ -4493,7 +4493,7 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
try func.emitWValue(operand);
const extra_index = @intCast(u32, func.mir_extra.items.len);
try func.mir_extra.append(func.gpa, opcode);
- try func.addInst(.{ .tag = .simd, .data = .{ .payload = extra_index } });
+ try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
try func.addLabel(.local_set, result.local.value);
return func.finishAir(inst, result, &.{ty_op.operand});
},
src/arch/wasm/Emit.zig
@@ -239,8 +239,9 @@ pub fn emitMir(emit: *Emit) InnerError!void {
.i64_clz => try emit.emitTag(tag),
.i64_ctz => try emit.emitTag(tag),
- .extended => try emit.emitExtended(inst),
- .simd => try emit.emitSimd(inst),
+ .misc_prefix => try emit.emitExtended(inst),
+ .simd_prefix => try emit.emitSimd(inst),
+ .atomics_prefix => try emit.emitAtomic(inst),
}
}
}
@@ -433,9 +434,9 @@ fn emitExtended(emit: *Emit, inst: Mir.Inst.Index) !void {
const extra_index = emit.mir.instructions.items(.data)[inst].payload;
const opcode = emit.mir.extra[extra_index];
const writer = emit.code.writer();
- try emit.code.append(0xFC);
+ try emit.code.append(std.wasm.opcode(.misc_prefix));
try leb128.writeULEB128(writer, opcode);
- switch (@intToEnum(std.wasm.PrefixedOpcode, opcode)) {
+ switch (@intToEnum(std.wasm.MiscOpcode, opcode)) {
// bulk-memory opcodes
.data_drop => {
const segment = emit.mir.extra[extra_index + 1];
@@ -472,7 +473,7 @@ fn emitSimd(emit: *Emit, inst: Mir.Inst.Index) !void {
const extra_index = emit.mir.instructions.items(.data)[inst].payload;
const opcode = emit.mir.extra[extra_index];
const writer = emit.code.writer();
- try emit.code.append(0xFD);
+ try emit.code.append(std.wasm.opcode(.simd_prefix));
try leb128.writeULEB128(writer, opcode);
switch (@intToEnum(std.wasm.SimdOpcode, opcode)) {
.v128_store,
@@ -496,10 +497,15 @@ fn emitSimd(emit: *Emit, inst: Mir.Inst.Index) !void {
.f32x4_splat,
.f64x2_splat,
=> {}, // opcode already written
- else => |tag| return emit.fail("TODO: Implement simd instruction: {s}\n", .{@tagName(tag)}),
+ else => |tag| return emit.fail("TODO: Implement simd instruction: {s}", .{@tagName(tag)}),
}
}
+fn emitAtomic(emit: *Emit, inst: Mir.Inst.Index) !void {
+ _ = inst;
+ return emit.fail("TODO: Implement atomics instructions", .{});
+}
+
fn emitMemFill(emit: *Emit) !void {
try emit.code.append(0xFC);
try emit.code.append(0x0B);
src/arch/wasm/Mir.zig
@@ -87,6 +87,13 @@ pub const Inst = struct {
///
/// Uses `label`
call_indirect = 0x11,
+ /// Contains a symbol to a function pointer
+ /// uses `label`
+ ///
+ /// Note: This uses `0x16` as value which is reserved by the WebAssembly
+ /// specification but unused, meaning we must update this if the specification were to
+ /// use this value.
+ function_index = 0x16,
/// Pops three values from the stack and pushes
/// the first or second value dependent on the third value.
/// Uses `tag`
@@ -510,24 +517,24 @@ pub const Inst = struct {
i64_extend16_s = 0xC3,
/// Uses `tag`
i64_extend32_s = 0xC4,
- /// The instruction consists of an extension opcode.
+ /// The instruction consists of a prefixed opcode.
/// The prefixed opcode can be found at payload's index.
///
/// The `data` field depends on the extension instruction and
/// may contain additional data.
- extended = 0xFC,
+ misc_prefix = 0xFC,
/// The instruction consists of a simd opcode.
/// The actual simd-opcode is found at payload's index.
///
/// The `data` field depends on the simd instruction and
/// may contain additional data.
- simd = 0xFD,
- /// Contains a symbol to a function pointer
- /// uses `label`
+ simd_prefix = 0xFD,
+ /// The instruction consists of an atomics opcode.
+ /// The actual atomics-opcode is found at payload's index.
///
- /// Note: This uses `0xFE` as value as it is unused and not reserved
- /// by the wasm specification, making it safe to use.
- function_index = 0xFE,
+ /// The `data` field depends on the atomics instruction and
+ /// may contain additional data.
+ atomics_prefix = 0xFE,
/// Contains a symbol to a memory address
/// Uses `label`
///
src/link/Wasm.zig
@@ -2128,8 +2128,8 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
}
// perform the bulk-memory operation to initialize the data segment
- try writer.writeByte(std.wasm.opcode(.prefixed));
- try leb.writeULEB128(writer, @enumToInt(std.wasm.PrefixedOpcode.memory_init));
+ try writer.writeByte(std.wasm.opcode(.misc_prefix));
+ try leb.writeULEB128(writer, std.wasm.miscOpcode(.memory_init));
// segment immediate
try leb.writeULEB128(writer, @intCast(u32, data_index));
// memory index immediate (always 0)