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.
This commit is contained in:
Luuk de Gram 2023-05-15 21:53:24 +02:00
parent 6c06944b59
commit 061d99285d
No known key found for this signature in database
GPG Key ID: A8CFE58E4DC7D664
2 changed files with 21 additions and 43 deletions

View File

@ -2885,26 +2885,25 @@ fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue {
return WValue{ .stack = {} };
}
fn lowerParentPtr(func: *CodeGen, ptr_val: Value, ptr_child_ty: Type) InnerError!WValue {
fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue {
switch (ptr_val.tag()) {
.decl_ref_mut => {
const decl_index = ptr_val.castTag(.decl_ref_mut).?.data.decl_index;
return func.lowerParentPtrDecl(ptr_val, decl_index);
return func.lowerParentPtrDecl(ptr_val, decl_index, offset);
},
.decl_ref => {
const decl_index = ptr_val.castTag(.decl_ref).?.data;
return func.lowerParentPtrDecl(ptr_val, decl_index);
return func.lowerParentPtrDecl(ptr_val, decl_index, offset);
},
.variable => {
const decl_index = ptr_val.castTag(.variable).?.data.owner_decl;
return func.lowerParentPtrDecl(ptr_val, decl_index);
return func.lowerParentPtrDecl(ptr_val, decl_index, offset);
},
.field_ptr => {
const field_ptr = ptr_val.castTag(.field_ptr).?.data;
const parent_ty = field_ptr.container_ty;
const parent_ptr = try func.lowerParentPtr(field_ptr.container_ptr, parent_ty);
const offset = switch (parent_ty.zigTypeTag()) {
const field_offset = switch (parent_ty.zigTypeTag()) {
.Struct => switch (parent_ty.containerLayout()) {
.Packed => parent_ty.packedStructFieldByteOffset(field_ptr.field_index, func.target),
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
if (layout.payload_align > layout.tag_align) break :blk 0;
// tag is stored first so calculate offset from where payload starts
const offset = @intCast(u32, std.mem.alignForwardGeneric(u64, layout.tag_size, layout.tag_align));
break :blk offset;
const field_offset = @intCast(u32, std.mem.alignForwardGeneric(u64, layout.tag_size, layout.tag_align));
break :blk field_offset;
},
},
.Pointer => switch (parent_ty.ptrSize()) {
@ -2931,43 +2930,23 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, ptr_child_ty: Type) InnerError
},
else => unreachable,
};
return switch (parent_ptr) {
.memory => |ptr| WValue{
.memory_offset = .{
.pointer = ptr,
.offset = @intCast(u32, offset),
},
},
.memory_offset => |mem_off| WValue{
.memory_offset = .{
.pointer = mem_off.pointer,
.offset = @intCast(u32, offset) + mem_off.offset,
},
},
else => unreachable,
};
return func.lowerParentPtr(field_ptr.container_ptr, offset + @intCast(u32, field_offset));
},
.elem_ptr => {
const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
const index = elem_ptr.index;
const offset = index * ptr_child_ty.abiSize(func.target);
const array_ptr = try func.lowerParentPtr(elem_ptr.array_ptr, elem_ptr.elem_ty);
return WValue{ .memory_offset = .{
.pointer = array_ptr.memory,
.offset = @intCast(u32, offset),
} };
const elem_offset = index * elem_ptr.elem_ty.abiSize(func.target);
return func.lowerParentPtr(elem_ptr.array_ptr, offset + @intCast(u32, elem_offset));
},
.opt_payload_ptr => {
const payload_ptr = ptr_val.castTag(.opt_payload_ptr).?.data;
return func.lowerParentPtr(payload_ptr.container_ptr, payload_ptr.container_ty);
return func.lowerParentPtr(payload_ptr.container_ptr, offset);
},
else => |tag| return func.fail("TODO: Implement lowerParentPtr for tag: {}", .{tag}),
}
}
fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: Module.Decl.Index) InnerError!WValue {
fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: Module.Decl.Index, offset: u32) InnerError!WValue {
const module = func.bin_file.base.options.module.?;
const decl = module.declPtr(decl_index);
module.markDeclAlive(decl);
@ -2976,10 +2955,10 @@ fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: Module.Decl.In
.data = decl.ty,
};
const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index);
return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index, offset);
}
fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Index) InnerError!WValue {
fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Index, offset: u32) InnerError!WValue {
if (tv.ty.isSlice()) {
return WValue{ .memory = try func.bin_file.lowerUnnamedConst(tv, decl_index) };
}
@ -2998,7 +2977,9 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Ind
if (decl.ty.zigTypeTag() == .Fn) {
try func.bin_file.addTableFunction(target_sym_index);
return WValue{ .function_index = target_sym_index };
} else return WValue{ .memory = target_sym_index };
} else if (offset == 0) {
return WValue{ .memory = target_sym_index };
} else return WValue{ .memory_offset = .{ .pointer = target_sym_index, .offset = offset } };
}
/// 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 {
if (val.isUndefDeep()) return func.emitUndefined(ty);
if (val.castTag(.decl_ref)) |decl_ref| {
const decl_index = decl_ref.data;
return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl_index);
return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl_index, 0);
}
if (val.castTag(.decl_ref_mut)) |decl_ref_mut| {
const decl_index = decl_ref_mut.data.decl_index;
return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl_index);
return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl_index, 0);
}
const target = func.target;
switch (ty.zigTypeTag()) {
@ -3063,9 +3044,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
else => unreachable,
},
.Pointer => switch (val.tag()) {
.field_ptr, .elem_ptr, .opt_payload_ptr => {
return func.lowerParentPtr(val, ty.childType());
},
.field_ptr, .elem_ptr, .opt_payload_ptr => return func.lowerParentPtr(val, 0),
.int_u64, .one => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt(target)) },
.zero, .null_value => return WValue{ .imm32 = 0 },
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 {
const src_ty = func.air.typeOf(bin_op.rhs);
const len = switch (dst_ty.ptrSize()) {
.Slice => try func.sliceLen(dst),
.One => @as(WValue, .{ .imm64 = dst_ty.childType().arrayLen() }),
.One => @as(WValue, .{ .imm32 = @intCast(u32, dst_ty.childType().arrayLen()) }),
.C, .Many => unreachable,
};
const dst_ptr = try func.sliceOrArrayPtr(dst, dst_ty);

View File

@ -185,7 +185,6 @@ test "slicing zero length array" {
}
test "slicing pointer by length" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };