Commit 52fb044669
Changed files (3)
src
arch
src/arch/wasm/CodeGen.zig
@@ -551,7 +551,7 @@ mir_extra: std.ArrayListUnmanaged(u32) = .{},
initial_stack_value: WValue = .none,
/// Arguments of this function declaration
/// This will be set after `resolveCallingConventionValues`
-args: []WValue = undefined,
+args: []WValue = &.{},
/// This will only be `.none` if the function returns void, or returns an immediate.
/// When it returns a pointer to the stack, the `.local` tag will be active and must be populated
/// before this function returns its execution to the caller.
@@ -1117,6 +1117,13 @@ fn moveStack(self: *Self, offset: u32, local: u32) !void {
try self.addLabel(.global_set, 0);
}
+/// From given zig bitsize, returns the wasm bitsize
+fn toWasmIntBits(bits: u16) ?u16 {
+ return for ([_]u16{ 32, 64 }) |wasm_bits| {
+ if (bits <= wasm_bits) return wasm_bits;
+ } else null;
+}
+
fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
const air_tags = self.air.instructions.items(.tag);
return switch (air_tags[inst]) {
@@ -1563,6 +1570,7 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
}
fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
+ if (val.isUndefDeep()) return self.emitUndefined(ty);
switch (ty.zigTypeTag()) {
.Int => {
const int_info = ty.intInfo(self.target);
@@ -1668,6 +1676,22 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
}
}
+fn emitUndefined(self: *Self, ty: Type) InnerError!void {
+ switch (ty.zigTypeTag()) {
+ .Int => switch (ty.intInfo(self.target).bits) {
+ 0...32 => try self.addImm32(@bitCast(i32, @as(u32, 0xaaaaaaaa))),
+ 33...64 => try self.addImm64(0xaaaaaaaaaaaaaaaa),
+ else => |bits| return self.fail("Wasm TODO: emitUndefined for integer bitsize: {d}", .{bits}),
+ },
+ .Float => switch (ty.floatBits(self.target)) {
+ 0...32 => try self.addInst(.{ .tag = .f32_const, .data = .{ .float32 = @bitCast(f32, @as(u32, 0xaaaaaaaa)) } }),
+ 33...64 => try self.addFloat64(@bitCast(f64, @as(u64, 0xaaaaaaaaaaaaaaaa))),
+ else => |bits| return self.fail("Wasm TODO: emitUndefined for float bitsize: {d}", .{bits}),
+ },
+ else => return self.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty}),
+ }
+}
+
/// Returns a `Value` as a signed 32 bit value.
/// It's illegal to provide a value with a type that cannot be represented
/// as an integer value.
@@ -2233,19 +2257,21 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
const operand = self.resolveInst(ty_op.operand);
const pointer_width = self.target.cpu.arch.ptrBitWidth() / 8;
- // Get pointer to slice
- try self.emitWValue(operand);
- // length of slice is stored after the pointer of the slice
- const extra_index = try self.addExtra(Mir.MemArg{
- .offset = pointer_width,
- .alignment = pointer_width,
- });
- try self.addInst(.{ .tag = .i32_load, .data = .{ .payload = extra_index } });
+ return try self.load(operand, Type.usize, pointer_width);
- const result = try self.allocLocal(Type.initTag(.i32)); // pointer is always i32
- // store slice length in local
- try self.addLabel(.local_set, result.local);
- return result;
+ // // Get pointer to slice
+ // try self.emitWValue(operand);
+ // // length of slice is stored after the pointer of the slice
+ // const extra_index = try self.addExtra(Mir.MemArg{
+ // .offset = pointer_width,
+ // .alignment = pointer_width,
+ // });
+ // try self.addInst(.{ .tag = .i32_load, .data = .{ .payload = extra_index } });
+
+ // const result = try self.allocLocal(Type.initTag(.i32)); // pointer is always i32
+ // // store slice length in local
+ // try self.addLabel(.local_set, result.local);
+ // return result;
}
fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
@@ -2272,3 +2298,70 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
try self.addLabel(.local_set, result.local);
return result;
}
+
+fn airSlicePtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
+ if (self.liveness.isUnused(inst)) return WValue.none;
+ const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+ const operand = self.resolveInst(ty_op.operand);
+ return try self.load(operand, Type.usize, 0);
+}
+
+fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
+ if (self.liveness.isUnused(inst)) return WValue.none;
+ const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+ const operand = self.resolveInst(ty_op.operand);
+ const op_ty = self.air.typeOf(ty_op.operand);
+ const int_info = self.air.getRefType(ty_op.ty).intInfo(self.target);
+ const wanted_bits = int_info.bits;
+ const result = try self.allocLocal(self.air.getRefType(ty_op.ty));
+ const op_bits = op_ty.intInfo(self.target).bits;
+
+ const wasm_bits = toWasmIntBits(wanted_bits) orelse
+ return self.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{wanted_bits});
+
+ // Use wasm's instruction to wrap from 64bit to 32bit integer when possible
+ if (op_bits == 64 and wanted_bits == 32) {
+ try self.emitWValue(operand);
+ try self.addTag(.i32_wrap_i64);
+ try self.addLabel(.local_set, result.local);
+ return result;
+ }
+
+ // Any other truncation must be done manually
+ if (int_info.signedness == .unsigned) {
+ const mask = (@as(u65, 1) << @intCast(u7, wanted_bits)) - 1;
+ try self.emitWValue(operand);
+ switch (wasm_bits) {
+ 32 => {
+ try self.addImm32(@bitCast(i32, @intCast(u32, mask)));
+ try self.addTag(.i32_and);
+ },
+ 64 => {
+ try self.addImm64(@intCast(u64, mask));
+ try self.addTag(.i64_and);
+ },
+ else => unreachable,
+ }
+ } else {
+ const shift_bits = wasm_bits - wanted_bits;
+ try self.emitWValue(operand);
+ switch (wasm_bits) {
+ 32 => {
+ try self.addImm32(@bitCast(i16, shift_bits));
+ try self.addTag(.i32_shl);
+ try self.addImm32(@bitCast(i16, shift_bits));
+ try self.addTag(.i32_shr_s);
+ },
+ 64 => {
+ try self.addImm64(shift_bits);
+ try self.addTag(.i64_shl);
+ try self.addImm64(shift_bits);
+ try self.addTag(.i64_shr_s);
+ },
+ else => unreachable,
+ }
+ }
+
+ try self.addLabel(.local_set, result.local);
+ return result;
+}
src/arch/wasm/Emit.zig
@@ -147,6 +147,11 @@ pub fn emitMir(emit: *Emit) InnerError!void {
.i64_div_s => try emit.emitTag(tag),
.i64_div_u => try emit.emitTag(tag),
.i64_and => try emit.emitTag(tag),
+ .i64_or => try emit.emitTag(tag),
+ .i64_xor => try emit.emitTag(tag),
+ .i64_shl => try emit.emitTag(tag),
+ .i64_shr_s => try emit.emitTag(tag),
+ .i64_shr_u => try emit.emitTag(tag),
.i32_wrap_i64 => try emit.emitTag(tag),
.i64_extend_i32_s => try emit.emitTag(tag),
.i64_extend_i32_u => try emit.emitTag(tag),
src/arch/wasm/Mir.zig
@@ -348,6 +348,16 @@ pub const Inst = struct {
/// Uses `tag`
i64_and = 0x83,
/// Uses `tag`
+ i64_or = 0x84,
+ /// Uses `tag`
+ i64_xor = 0x85,
+ /// Uses `tag`
+ i64_shl = 0x86,
+ /// Uses `tag`
+ i64_shr_s = 0x87,
+ /// Uses `tag`
+ i64_shr_u = 0x88,
+ /// Uses `tag`
i32_wrap_i64 = 0xA7,
/// Uses `tag`
i64_extend_i32_s = 0xAC,