Merge pull request #14494 from Techatrix/wasm-optional-slice

wasm: correctly handle optional slices
This commit is contained in:
Luuk de Gram 2023-01-31 23:11:58 +01:00 committed by GitHub
commit 6f13a725a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 12 additions and 9 deletions

View File

@ -1706,9 +1706,11 @@ fn isByRef(ty: Type, target: std.Target) bool {
return true;
},
.Optional => {
if (ty.optionalReprIsPayload()) return false;
if (ty.isPtrLikeOptional()) return false;
var buf: Type.Payload.ElemType = undefined;
return ty.optionalChild(&buf).hasRuntimeBitsIgnoreComptime();
const pl_type = ty.optionalChild(&buf);
if (pl_type.zigTypeTag() == .ErrorSet) return false;
return pl_type.hasRuntimeBitsIgnoreComptime();
},
.Pointer => {
// Slices act like struct and will be passed by reference
@ -3869,14 +3871,20 @@ fn airIsNull(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind:
/// NOTE: Leaves the result on the stack
fn isNull(func: *CodeGen, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) InnerError!WValue {
try func.emitWValue(operand);
var buf: Type.Payload.ElemType = undefined;
const payload_ty = optional_ty.optionalChild(&buf);
if (!optional_ty.optionalReprIsPayload()) {
var buf: Type.Payload.ElemType = undefined;
const payload_ty = optional_ty.optionalChild(&buf);
// When payload is zero-bits, we can treat operand as a value, rather than
// a pointer to the stack value
if (payload_ty.hasRuntimeBitsIgnoreComptime()) {
try func.addMemArg(.i32_load8_u, .{ .offset = operand.offset(), .alignment = 1 });
}
} else if (payload_ty.isSlice()) {
switch (func.arch()) {
.wasm32 => try func.addMemArg(.i32_load, .{ .offset = operand.offset(), .alignment = 4 }),
.wasm64 => try func.addMemArg(.i64_load, .{ .offset = operand.offset(), .alignment = 8 }),
else => unreachable,
}
}
// Compare the null value with '0'

View File

@ -1179,7 +1179,6 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
test "implicitly cast from [N]T to ?[]const T" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
try expect(mem.eql(u8, castToOptionalSlice().?, "hi"));
@ -1264,7 +1263,6 @@ test "cast from array reference to fn: runtime fn ptr" {
test "*const [N]null u8 to ?[]const u8" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
const S = struct {
@ -1413,7 +1411,6 @@ test "cast i8 fn call peers to i32 result" {
test "cast compatible optional types" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
var a: ?[:0]const u8 = null;

View File

@ -439,7 +439,6 @@ test "Optional slice size is optimized" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
try expect(@sizeOf(?[]u8) == @sizeOf([]u8));
@ -479,7 +478,6 @@ test "cast slice to const slice nested in error union and optional" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
const S = struct {
fn inner() !?[]u8 {