authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-05-15 21:53:24+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-05-19 20:20:26+02:00
log061d99285d5a73a71a97ed7bbb45f0a7f65acf2d
tree844a8219a345ef94eab7b8e6df04eccd0e40c2e0
parent6c06944b5958e2b624004e986deee8e52c765e6e
signaturelock-open Commit is signed but in an unrecognized format.

wasm: correctly use elem type when lowering

Previously when lowering a value of `elem_ptr` we would multiply the abisize of the parent type by the index, rather than the element type. This would result in an invalid pointer way beyond the correct pointer. We now also pass the current offset to each recursive call to ensure we do not miss inner offsets.

2 files changed, 21 insertions(+), 43 deletions(-)

src/arch/wasm/CodeGen.zig+21-42
......@@ -2885,26 +2885,25 @@ fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue {
28852885 return WValue{ .stack = {} };
28862886}
28872887
2888fn lowerParentPtr(func: *CodeGen, ptr_val: Value, ptr_child_ty: Type) InnerError!WValue {
2888fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue {
28892889 switch (ptr_val.tag()) {
28902890 .decl_ref_mut => {
28912891 const decl_index = ptr_val.castTag(.decl_ref_mut).?.data.decl_index;
2892 return func.lowerParentPtrDecl(ptr_val, decl_index);
2892 return func.lowerParentPtrDecl(ptr_val, decl_index, offset);
28932893 },
28942894 .decl_ref => {
28952895 const decl_index = ptr_val.castTag(.decl_ref).?.data;
2896 return func.lowerParentPtrDecl(ptr_val, decl_index);
2896 return func.lowerParentPtrDecl(ptr_val, decl_index, offset);
28972897 },
28982898 .variable => {
28992899 const decl_index = ptr_val.castTag(.variable).?.data.owner_decl;
2900 return func.lowerParentPtrDecl(ptr_val, decl_index);
2900 return func.lowerParentPtrDecl(ptr_val, decl_index, offset);
29012901 },
29022902 .field_ptr => {
29032903 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
29042904 const parent_ty = field_ptr.container_ty;
2905 const parent_ptr = try func.lowerParentPtr(field_ptr.container_ptr, parent_ty);
29062905
2907 const offset = switch (parent_ty.zigTypeTag()) {
2906 const field_offset = switch (parent_ty.zigTypeTag()) {
29082907 .Struct => switch (parent_ty.containerLayout()) {
29092908 .Packed => parent_ty.packedStructFieldByteOffset(field_ptr.field_index, func.target),
29102909 else => parent_ty.structFieldOffset(field_ptr.field_index, func.target),
......@@ -2917,8 +2916,8 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, ptr_child_ty: Type) InnerError
29172916 if (layout.payload_align > layout.tag_align) break :blk 0;
29182917
29192918 // tag is stored first so calculate offset from where payload starts
2920 const offset = @intCast(u32, std.mem.alignForwardGeneric(u64, layout.tag_size, layout.tag_align));
2921 break :blk offset;
2919 const field_offset = @intCast(u32, std.mem.alignForwardGeneric(u64, layout.tag_size, layout.tag_align));
2920 break :blk field_offset;
29222921 },
29232922 },
29242923 .Pointer => switch (parent_ty.ptrSize()) {
......@@ -2931,43 +2930,23 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, ptr_child_ty: Type) InnerError
29312930 },
29322931 else => unreachable,
29332932 };
2934
2935 return switch (parent_ptr) {
2936 .memory => |ptr| WValue{
2937 .memory_offset = .{
2938 .pointer = ptr,
2939 .offset = @intCast(u32, offset),
2940 },
2941 },
2942 .memory_offset => |mem_off| WValue{
2943 .memory_offset = .{
2944 .pointer = mem_off.pointer,
2945 .offset = @intCast(u32, offset) + mem_off.offset,
2946 },
2947 },
2948 else => unreachable,
2949 };
2933 return func.lowerParentPtr(field_ptr.container_ptr, offset + @intCast(u32, field_offset));
29502934 },
29512935 .elem_ptr => {
29522936 const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
29532937 const index = elem_ptr.index;
2954 const offset = index * ptr_child_ty.abiSize(func.target);
2955 const array_ptr = try func.lowerParentPtr(elem_ptr.array_ptr, elem_ptr.elem_ty);
2956
2957 return WValue{ .memory_offset = .{
2958 .pointer = array_ptr.memory,
2959 .offset = @intCast(u32, offset),
2960 } };
2938 const elem_offset = index * elem_ptr.elem_ty.abiSize(func.target);
2939 return func.lowerParentPtr(elem_ptr.array_ptr, offset + @intCast(u32, elem_offset));
29612940 },
29622941 .opt_payload_ptr => {
29632942 const payload_ptr = ptr_val.castTag(.opt_payload_ptr).?.data;
2964 return func.lowerParentPtr(payload_ptr.container_ptr, payload_ptr.container_ty);
2943 return func.lowerParentPtr(payload_ptr.container_ptr, offset);
29652944 },
29662945 else => |tag| return func.fail("TODO: Implement lowerParentPtr for tag: {}", .{tag}),
29672946 }
29682947}
29692948
2970fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: Module.Decl.Index) InnerError!WValue {
2949fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: Module.Decl.Index, offset: u32) InnerError!WValue {
29712950 const module = func.bin_file.base.options.module.?;
29722951 const decl = module.declPtr(decl_index);
29732952 module.markDeclAlive(decl);
......@@ -2976,10 +2955,10 @@ fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: Module.Decl.In
29762955 .data = decl.ty,
29772956 };
29782957 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
2979 return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index);
2958 return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index, offset);
29802959}
29812960
2982fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Index) InnerError!WValue {
2961fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Index, offset: u32) InnerError!WValue {
29832962 if (tv.ty.isSlice()) {
29842963 return WValue{ .memory = try func.bin_file.lowerUnnamedConst(tv, decl_index) };
29852964 }
......@@ -2998,7 +2977,9 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Ind
29982977 if (decl.ty.zigTypeTag() == .Fn) {
29992978 try func.bin_file.addTableFunction(target_sym_index);
30002979 return WValue{ .function_index = target_sym_index };
3001 } else return WValue{ .memory = target_sym_index };
2980 } else if (offset == 0) {
2981 return WValue{ .memory = target_sym_index };
2982 } else return WValue{ .memory_offset = .{ .pointer = target_sym_index, .offset = offset } };
30022983}
30032984
30042985/// Converts a signed integer to its 2's complement form and returns
......@@ -3025,11 +3006,11 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
30253006 if (val.isUndefDeep()) return func.emitUndefined(ty);
30263007 if (val.castTag(.decl_ref)) |decl_ref| {
30273008 const decl_index = decl_ref.data;
3028 return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl_index);
3009 return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl_index, 0);
30293010 }
30303011 if (val.castTag(.decl_ref_mut)) |decl_ref_mut| {
30313012 const decl_index = decl_ref_mut.data.decl_index;
3032 return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl_index);
3013 return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl_index, 0);
30333014 }
30343015 const target = func.target;
30353016 switch (ty.zigTypeTag()) {
......@@ -3063,9 +3044,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
30633044 else => unreachable,
30643045 },
30653046 .Pointer => switch (val.tag()) {
3066 .field_ptr, .elem_ptr, .opt_payload_ptr => {
3067 return func.lowerParentPtr(val, ty.childType());
3068 },
3047 .field_ptr, .elem_ptr, .opt_payload_ptr => return func.lowerParentPtr(val, 0),
30693048 .int_u64, .one => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt(target)) },
30703049 .zero, .null_value => return WValue{ .imm32 = 0 },
30713050 else => return func.fail("Wasm TODO: lowerConstant for other const pointer tag {}", .{val.tag()}),
......@@ -5281,7 +5260,7 @@ fn airMemcpy(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
52815260 const src_ty = func.air.typeOf(bin_op.rhs);
52825261 const len = switch (dst_ty.ptrSize()) {
52835262 .Slice => try func.sliceLen(dst),
5284 .One => @as(WValue, .{ .imm64 = dst_ty.childType().arrayLen() }),
5263 .One => @as(WValue, .{ .imm32 = @intCast(u32, dst_ty.childType().arrayLen()) }),
52855264 .C, .Many => unreachable,
52865265 };
52875266 const dst_ptr = try func.sliceOrArrayPtr(dst, dst_ty);
test/behavior/slice.zig-1
......@@ -185,7 +185,6 @@ test "slicing zero length array" {
185185}
186186
187187test "slicing pointer by length" {
188 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
189188 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
190189
191190 const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };