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 {...@@ -2885,26 +2885,25 @@ fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue {
2885 return WValue{ .stack = {} };2885 return WValue{ .stack = {} };
2886}2886}
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 {
2889 switch (ptr_val.tag()) {2889 switch (ptr_val.tag()) {
2890 .decl_ref_mut => {2890 .decl_ref_mut => {
2891 const decl_index = ptr_val.castTag(.decl_ref_mut).?.data.decl_index;2891 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);
2893 },2893 },
2894 .decl_ref => {2894 .decl_ref => {
2895 const decl_index = ptr_val.castTag(.decl_ref).?.data;2895 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);
2897 },2897 },
2898 .variable => {2898 .variable => {
2899 const decl_index = ptr_val.castTag(.variable).?.data.owner_decl;2899 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);
2901 },2901 },
2902 .field_ptr => {2902 .field_ptr => {
2903 const field_ptr = ptr_val.castTag(.field_ptr).?.data;2903 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
2904 const parent_ty = field_ptr.container_ty;2904 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()) {
2908 .Struct => switch (parent_ty.containerLayout()) {2907 .Struct => switch (parent_ty.containerLayout()) {
2909 .Packed => parent_ty.packedStructFieldByteOffset(field_ptr.field_index, func.target),2908 .Packed => parent_ty.packedStructFieldByteOffset(field_ptr.field_index, func.target),
2910 else => parent_ty.structFieldOffset(field_ptr.field_index, func.target),2909 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...@@ -2917,8 +2916,8 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, ptr_child_ty: Type) InnerError
2917 if (layout.payload_align > layout.tag_align) break :blk 0;2916 if (layout.payload_align > layout.tag_align) break :blk 0;
29182917
2919 // tag is stored first so calculate offset from where payload starts2918 // 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));2919 const field_offset = @intCast(u32, std.mem.alignForwardGeneric(u64, layout.tag_size, layout.tag_align));
2921 break :blk offset;2920 break :blk field_offset;
2922 },2921 },
2923 },2922 },
2924 .Pointer => switch (parent_ty.ptrSize()) {2923 .Pointer => switch (parent_ty.ptrSize()) {
...@@ -2931,43 +2930,23 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, ptr_child_ty: Type) InnerError...@@ -2931,43 +2930,23 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, ptr_child_ty: Type) InnerError
2931 },2930 },
2932 else => unreachable,2931 else => unreachable,
2933 };2932 };
29342933 return func.lowerParentPtr(field_ptr.container_ptr, offset + @intCast(u32, field_offset));
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 };
2950 },2934 },
2951 .elem_ptr => {2935 .elem_ptr => {
2952 const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;2936 const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
2953 const index = elem_ptr.index;2937 const index = elem_ptr.index;
2954 const offset = index * ptr_child_ty.abiSize(func.target);2938 const elem_offset = index * elem_ptr.elem_ty.abiSize(func.target);
2955 const array_ptr = try func.lowerParentPtr(elem_ptr.array_ptr, elem_ptr.elem_ty);2939 return func.lowerParentPtr(elem_ptr.array_ptr, offset + @intCast(u32, elem_offset));
2956
2957 return WValue{ .memory_offset = .{
2958 .pointer = array_ptr.memory,
2959 .offset = @intCast(u32, offset),
2960 } };
2961 },2940 },
2962 .opt_payload_ptr => {2941 .opt_payload_ptr => {
2963 const payload_ptr = ptr_val.castTag(.opt_payload_ptr).?.data;2942 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);
2965 },2944 },
2966 else => |tag| return func.fail("TODO: Implement lowerParentPtr for tag: {}", .{tag}),2945 else => |tag| return func.fail("TODO: Implement lowerParentPtr for tag: {}", .{tag}),
2967 }2946 }
2968}2947}
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 {
2971 const module = func.bin_file.base.options.module.?;2950 const module = func.bin_file.base.options.module.?;
2972 const decl = module.declPtr(decl_index);2951 const decl = module.declPtr(decl_index);
2973 module.markDeclAlive(decl);2952 module.markDeclAlive(decl);
...@@ -2976,10 +2955,10 @@ fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: Module.Decl.In...@@ -2976,10 +2955,10 @@ fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: Module.Decl.In
2976 .data = decl.ty,2955 .data = decl.ty,
2977 };2956 };
2978 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);2957 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);
2980}2959}
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 {
2983 if (tv.ty.isSlice()) {2962 if (tv.ty.isSlice()) {
2984 return WValue{ .memory = try func.bin_file.lowerUnnamedConst(tv, decl_index) };2963 return WValue{ .memory = try func.bin_file.lowerUnnamedConst(tv, decl_index) };
2985 }2964 }
...@@ -2998,7 +2977,9 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Ind...@@ -2998,7 +2977,9 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Ind
2998 if (decl.ty.zigTypeTag() == .Fn) {2977 if (decl.ty.zigTypeTag() == .Fn) {
2999 try func.bin_file.addTableFunction(target_sym_index);2978 try func.bin_file.addTableFunction(target_sym_index);
3000 return WValue{ .function_index = target_sym_index };2979 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 } };
3002}2983}
30032984
3004/// Converts a signed integer to its 2's complement form and returns2985/// 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 {...@@ -3025,11 +3006,11 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
3025 if (val.isUndefDeep()) return func.emitUndefined(ty);3006 if (val.isUndefDeep()) return func.emitUndefined(ty);
3026 if (val.castTag(.decl_ref)) |decl_ref| {3007 if (val.castTag(.decl_ref)) |decl_ref| {
3027 const decl_index = decl_ref.data;3008 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);
3029 }3010 }
3030 if (val.castTag(.decl_ref_mut)) |decl_ref_mut| {3011 if (val.castTag(.decl_ref_mut)) |decl_ref_mut| {
3031 const decl_index = decl_ref_mut.data.decl_index;3012 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);
3033 }3014 }
3034 const target = func.target;3015 const target = func.target;
3035 switch (ty.zigTypeTag()) {3016 switch (ty.zigTypeTag()) {
...@@ -3063,9 +3044,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {...@@ -3063,9 +3044,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
3063 else => unreachable,3044 else => unreachable,
3064 },3045 },
3065 .Pointer => switch (val.tag()) {3046 .Pointer => switch (val.tag()) {
3066 .field_ptr, .elem_ptr, .opt_payload_ptr => {3047 .field_ptr, .elem_ptr, .opt_payload_ptr => return func.lowerParentPtr(val, 0),
3067 return func.lowerParentPtr(val, ty.childType());
3068 },
3069 .int_u64, .one => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt(target)) },3048 .int_u64, .one => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt(target)) },
3070 .zero, .null_value => return WValue{ .imm32 = 0 },3049 .zero, .null_value => return WValue{ .imm32 = 0 },
3071 else => return func.fail("Wasm TODO: lowerConstant for other const pointer tag {}", .{val.tag()}),3050 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 {...@@ -5281,7 +5260,7 @@ fn airMemcpy(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5281 const src_ty = func.air.typeOf(bin_op.rhs);5260 const src_ty = func.air.typeOf(bin_op.rhs);
5282 const len = switch (dst_ty.ptrSize()) {5261 const len = switch (dst_ty.ptrSize()) {
5283 .Slice => try func.sliceLen(dst),5262 .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()) }),
5285 .C, .Many => unreachable,5264 .C, .Many => unreachable,
5286 };5265 };
5287 const dst_ptr = try func.sliceOrArrayPtr(dst, dst_ty);5266 const dst_ptr = try func.sliceOrArrayPtr(dst, dst_ty);
test/behavior/slice.zig-1
...@@ -185,7 +185,6 @@ test "slicing zero length array" {...@@ -185,7 +185,6 @@ test "slicing zero length array" {
185}185}
186186
187test "slicing pointer by length" {187test "slicing pointer by length" {
188 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
189 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;188 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
190189
191 const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };190 const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };