authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-01-31 23:11:58+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-01-31 23:11:58+01:00
log6f13a725a3249c7f0a0f5258ac00003cd132bf15
treeb3d9b4b8592bf40572180e1d6a21a4093809607f
parentef8f694d777029caaa48c50c28ff805c058ccccb
parent47ff57ed7ddbf4c4a0f93208fc96851c9033b8b7
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

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

wasm: correctly handle optional slices

3 files changed, 12 insertions(+), 9 deletions(-)

src/arch/wasm/CodeGen.zig+12-4
...@@ -1706,9 +1706,11 @@ fn isByRef(ty: Type, target: std.Target) bool {...@@ -1706,9 +1706,11 @@ fn isByRef(ty: Type, target: std.Target) bool {
1706 return true;1706 return true;
1707 },1707 },
1708 .Optional => {1708 .Optional => {
1709 if (ty.optionalReprIsPayload()) return false;1709 if (ty.isPtrLikeOptional()) return false;
1710 var buf: Type.Payload.ElemType = undefined;1710 var buf: Type.Payload.ElemType = undefined;
1711 return ty.optionalChild(&buf).hasRuntimeBitsIgnoreComptime();1711 const pl_type = ty.optionalChild(&buf);
1712 if (pl_type.zigTypeTag() == .ErrorSet) return false;
1713 return pl_type.hasRuntimeBitsIgnoreComptime();
1712 },1714 },
1713 .Pointer => {1715 .Pointer => {
1714 // Slices act like struct and will be passed by reference1716 // 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:...@@ -3869,14 +3871,20 @@ fn airIsNull(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind:
3869/// NOTE: Leaves the result on the stack3871/// NOTE: Leaves the result on the stack
3870fn isNull(func: *CodeGen, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) InnerError!WValue {3872fn isNull(func: *CodeGen, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) InnerError!WValue {
3871 try func.emitWValue(operand);3873 try func.emitWValue(operand);
3874 var buf: Type.Payload.ElemType = undefined;
3875 const payload_ty = optional_ty.optionalChild(&buf);
3872 if (!optional_ty.optionalReprIsPayload()) {3876 if (!optional_ty.optionalReprIsPayload()) {
3873 var buf: Type.Payload.ElemType = undefined;
3874 const payload_ty = optional_ty.optionalChild(&buf);
3875 // When payload is zero-bits, we can treat operand as a value, rather than3877 // When payload is zero-bits, we can treat operand as a value, rather than
3876 // a pointer to the stack value3878 // a pointer to the stack value
3877 if (payload_ty.hasRuntimeBitsIgnoreComptime()) {3879 if (payload_ty.hasRuntimeBitsIgnoreComptime()) {
3878 try func.addMemArg(.i32_load8_u, .{ .offset = operand.offset(), .alignment = 1 });3880 try func.addMemArg(.i32_load8_u, .{ .offset = operand.offset(), .alignment = 1 });
3879 }3881 }
3882 } else if (payload_ty.isSlice()) {
3883 switch (func.arch()) {
3884 .wasm32 => try func.addMemArg(.i32_load, .{ .offset = operand.offset(), .alignment = 4 }),
3885 .wasm64 => try func.addMemArg(.i64_load, .{ .offset = operand.offset(), .alignment = 8 }),
3886 else => unreachable,
3887 }
3880 }3888 }
38813889
3882 // Compare the null value with '0'3890 // Compare the null value with '0'
test/behavior/cast.zig-3
...@@ -1179,7 +1179,6 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {...@@ -1179,7 +1179,6 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
1179test "implicitly cast from [N]T to ?[]const T" {1179test "implicitly cast from [N]T to ?[]const T" {
1180 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1180 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1181 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1181 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1182 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1183 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1182 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11841183
1185 try expect(mem.eql(u8, castToOptionalSlice().?, "hi"));1184 try expect(mem.eql(u8, castToOptionalSlice().?, "hi"));
...@@ -1264,7 +1263,6 @@ test "cast from array reference to fn: runtime fn ptr" {...@@ -1264,7 +1263,6 @@ test "cast from array reference to fn: runtime fn ptr" {
1264test "*const [N]null u8 to ?[]const u8" {1263test "*const [N]null u8 to ?[]const u8" {
1265 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1264 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1266 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1265 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1267 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1268 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1266 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12691267
1270 const S = struct {1268 const S = struct {
...@@ -1413,7 +1411,6 @@ test "cast i8 fn call peers to i32 result" {...@@ -1413,7 +1411,6 @@ test "cast i8 fn call peers to i32 result" {
1413test "cast compatible optional types" {1411test "cast compatible optional types" {
1414 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1412 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1415 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1413 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1416 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1417 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1414 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14181415
1419 var a: ?[:0]const u8 = null;1416 var a: ?[:0]const u8 = null;
test/behavior/optional.zig-2
...@@ -439,7 +439,6 @@ test "Optional slice size is optimized" {...@@ -439,7 +439,6 @@ test "Optional slice size is optimized" {
439 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;439 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
440 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;440 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
441 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;441 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
442 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
443 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO442 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
444443
445 try expect(@sizeOf(?[]u8) == @sizeOf([]u8));444 try expect(@sizeOf(?[]u8) == @sizeOf([]u8));
...@@ -479,7 +478,6 @@ test "cast slice to const slice nested in error union and optional" {...@@ -479,7 +478,6 @@ test "cast slice to const slice nested in error union and optional" {
479 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;478 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
480 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;479 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
481 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;480 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
482 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
483481
484 const S = struct {482 const S = struct {
485 fn inner() !?[]u8 {483 fn inner() !?[]u8 {