mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 16:54:52 +00:00
wasm: Implement memCpy and get if behavior tests passing
This commit is contained in:
parent
b9a0401e23
commit
28cfc49c3e
@ -973,6 +973,41 @@ fn genTypedValue(self: *Self, ty: Type, val: Value) InnerError!Result {
|
||||
},
|
||||
else => return self.fail("TODO: Implement zig decl gen for pointer type value: '{s}'", .{@tagName(val.tag())}),
|
||||
},
|
||||
.ErrorUnion => {
|
||||
const error_ty = ty.errorUnionSet();
|
||||
const payload_ty = ty.errorUnionPayload();
|
||||
const is_pl = val.errorUnionIsPayload();
|
||||
|
||||
const err_val = if (!is_pl) val else Value.initTag(.zero);
|
||||
switch (try self.genTypedValue(error_ty, err_val)) {
|
||||
.externally_managed => |data| try self.code.appendSlice(data),
|
||||
.appended => {},
|
||||
}
|
||||
|
||||
if (payload_ty.hasCodeGenBits()) {
|
||||
const pl_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef);
|
||||
switch (try self.genTypedValue(payload_ty, pl_val)) {
|
||||
.externally_managed => |data| try self.code.appendSlice(data),
|
||||
.appended => {},
|
||||
}
|
||||
}
|
||||
|
||||
return Result.appended;
|
||||
},
|
||||
.ErrorSet => {
|
||||
switch (val.tag()) {
|
||||
.@"error" => {
|
||||
const name = val.castTag(.@"error").?.data.name;
|
||||
const value = self.global_error_set.get(name).?;
|
||||
try self.code.writer().writeIntLittle(u32, value);
|
||||
},
|
||||
else => {
|
||||
const abi_size = @intCast(usize, ty.abiSize(self.target));
|
||||
try self.code.appendNTimes(0, abi_size);
|
||||
},
|
||||
}
|
||||
return Result.appended;
|
||||
},
|
||||
else => |tag| return self.fail("TODO: Implement zig type codegen for type: '{s}'", .{tag}),
|
||||
}
|
||||
}
|
||||
@ -1149,6 +1184,26 @@ fn toWasmIntBits(bits: u16) ?u16 {
|
||||
} else null;
|
||||
}
|
||||
|
||||
/// Performs a copy of bytes for a given type. Copying all bytes
|
||||
/// from rhs to lhs.
|
||||
/// Asserts `lhs` and `rhs` have their active tag set to `local`
|
||||
///
|
||||
/// TODO: Perform feature detection and when bulk_memory is available,
|
||||
/// use wasm's mem.copy instruction.
|
||||
fn memCopy(self: *Self, ty: Type, lhs: WValue, rhs: WValue) !void {
|
||||
const abi_size = ty.abiSize(self.target);
|
||||
var offset: u32 = 0;
|
||||
while (offset < abi_size) : (offset += 1) {
|
||||
// get lhs' address to store the result
|
||||
try self.addLabel(.local_get, lhs.local);
|
||||
// load byte from rhs' adress
|
||||
try self.addLabel(.local_get, rhs.local);
|
||||
try self.addMemArg(.i32_load8_u, .{ .offset = offset, .alignment = 1 });
|
||||
// store the result in lhs (we already have its address on the stack)
|
||||
try self.addMemArg(.i32_store8, .{ .offset = offset, .alignment = 1 });
|
||||
}
|
||||
}
|
||||
|
||||
fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
|
||||
const air_tags = self.air.instructions.items(.tag);
|
||||
return switch (air_tags[inst]) {
|
||||
@ -1482,20 +1537,12 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
|
||||
}
|
||||
},
|
||||
.Struct => {
|
||||
// we are copying a struct with its fields.
|
||||
// Replace this with a wasm memcpy instruction once we support that feature.
|
||||
const fields_len = ty.structFieldCount();
|
||||
var index: usize = 0;
|
||||
while (index < fields_len) : (index += 1) {
|
||||
const field_ty = ty.structFieldType(index);
|
||||
if (!field_ty.hasCodeGenBits()) continue;
|
||||
const field_offset = std.math.cast(u32, ty.structFieldOffset(index, self.target)) catch {
|
||||
return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty});
|
||||
};
|
||||
const field_local = try self.load(rhs, field_ty, field_offset);
|
||||
try self.store(lhs, field_local, field_ty, field_offset);
|
||||
if (rhs == .constant) {
|
||||
try self.emitWValue(rhs);
|
||||
try self.addLabel(.local_set, lhs.local);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
return try self.memCopy(ty, lhs, rhs);
|
||||
},
|
||||
.Pointer => {
|
||||
if (ty.isSlice() and rhs == .constant) {
|
||||
@ -2086,19 +2133,20 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u32) InnerEr
|
||||
field_ty,
|
||||
});
|
||||
};
|
||||
// field points to another struct, so retrieve that struct first
|
||||
switch (struct_ptr) {
|
||||
.local => return structFieldPtr(struct_ptr, offset),
|
||||
.local_with_offset => |with_offset| {
|
||||
const result = try self.load(struct_ptr, field_ty, with_offset.offset);
|
||||
return structFieldPtr(result, offset);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
return structFieldPtr(struct_ptr, offset);
|
||||
}
|
||||
|
||||
fn structFieldPtr(struct_ptr: WValue, offset: u32) InnerError!WValue {
|
||||
return WValue{ .local_with_offset = .{ .local = struct_ptr.local, .offset = offset } };
|
||||
var final_offset = offset;
|
||||
const local = switch (struct_ptr) {
|
||||
.local => |local| local,
|
||||
.local_with_offset => |with_offset| blk: {
|
||||
final_offset += with_offset.offset;
|
||||
break :blk with_offset.local;
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
return WValue{ .local_with_offset = .{ .local = local, .offset = final_offset } };
|
||||
}
|
||||
|
||||
fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
|
||||
@ -2114,7 +2162,19 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
|
||||
const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, self.target)) catch {
|
||||
return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty});
|
||||
};
|
||||
return try self.load(operand, field_ty, offset);
|
||||
|
||||
// TODO: Replace this check with some 'isByRef' function to de-duplicate logic
|
||||
if (field_ty.zigTypeTag() == .Struct) {
|
||||
return WValue{ .local_with_offset = .{
|
||||
.local = operand.local,
|
||||
.offset = offset,
|
||||
} };
|
||||
}
|
||||
|
||||
switch (operand) {
|
||||
.local_with_offset => |with_offset| return try self.load(operand, field_ty, offset + with_offset.offset),
|
||||
else => return try self.load(operand, field_ty, offset),
|
||||
}
|
||||
}
|
||||
|
||||
fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
|
||||
|
||||
@ -29,6 +29,7 @@ test {
|
||||
_ = @import("behavior/fn_in_struct_in_comptime.zig");
|
||||
_ = @import("behavior/hasdecl.zig");
|
||||
_ = @import("behavior/hasfield.zig");
|
||||
_ = @import("behavior/if.zig");
|
||||
_ = @import("behavior/import.zig");
|
||||
_ = @import("behavior/incomplete_struct_param_tld.zig");
|
||||
_ = @import("behavior/inttoptr.zig");
|
||||
@ -61,7 +62,6 @@ test {
|
||||
_ = @import("behavior/fn_in_struct_in_comptime.zig");
|
||||
_ = @import("behavior/for.zig");
|
||||
_ = @import("behavior/generics.zig");
|
||||
_ = @import("behavior/if.zig");
|
||||
_ = @import("behavior/int128.zig");
|
||||
_ = @import("behavior/member_func.zig");
|
||||
_ = @import("behavior/null.zig");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user