authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-05-27 15:11:53+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-05-31 18:04:32+02:00
log969f9211622b3f2d296a6f51449605d65b66bb31
tree0921d62ea4fd4fe0d2c97eded2064d965c5688c3
parentffa89d3b8370377b56be594650c0ea73f225c926
signaturelock-open Commit is signed but in an unrecognized format.

wasm: `ptr_elem_val` use pointer type for local

When storing the address after calculating the element's address, ensure it's stored in a local with the correct type. Previously it would incorrectly use the element's type, which could be a float for example and therefore generate invalid WebAssembly code. This change also introduces a more robust `store` function.

1 files changed, 19 insertions(+), 13 deletions(-)

src/arch/wasm/CodeGen.zig+19-13
......@@ -2318,6 +2318,7 @@ fn airStore(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void
23182318
23192319fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void {
23202320 assert(!(lhs != .stack and rhs == .stack));
2321 const abi_size = ty.abiSize(func.target);
23212322 switch (ty.zigTypeTag()) {
23222323 .ErrorUnion => {
23232324 const pl_ty = ty.errorUnionPayload();
......@@ -2325,7 +2326,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
23252326 return func.store(lhs, rhs, Type.anyerror, 0);
23262327 }
23272328
2328 const len = @intCast(u32, ty.abiSize(func.target));
2329 const len = @intCast(u32, abi_size);
23292330 return func.memcpy(lhs, rhs, .{ .imm32 = len });
23302331 },
23312332 .Optional => {
......@@ -2341,16 +2342,16 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
23412342 return func.store(lhs, rhs, Type.anyerror, 0);
23422343 }
23432344
2344 const len = @intCast(u32, ty.abiSize(func.target));
2345 const len = @intCast(u32, abi_size);
23452346 return func.memcpy(lhs, rhs, .{ .imm32 = len });
23462347 },
23472348 .Struct, .Array, .Union => if (isByRef(ty, func.target)) {
2348 const len = @intCast(u32, ty.abiSize(func.target));
2349 const len = @intCast(u32, abi_size);
23492350 return func.memcpy(lhs, rhs, .{ .imm32 = len });
23502351 },
23512352 .Vector => switch (determineSimdStoreStrategy(ty, func.target)) {
23522353 .unrolled => {
2353 const len = @intCast(u32, ty.abiSize(func.target));
2354 const len = @intCast(u32, abi_size);
23542355 return func.memcpy(lhs, rhs, .{ .imm32 = len });
23552356 },
23562357 .direct => {
......@@ -2382,7 +2383,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
23822383 return;
23832384 }
23842385 },
2385 .Int => if (ty.intInfo(func.target).bits > 64) {
2386 .Int, .Float => if (abi_size > 8 and abi_size <= 16) {
23862387 try func.emitWValue(lhs);
23872388 const lsb = try func.load(rhs, Type.u64, 0);
23882389 try func.store(.{ .stack = {} }, lsb, Type.u64, 0 + lhs.offset());
......@@ -2391,8 +2392,15 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
23912392 const msb = try func.load(rhs, Type.u64, 8);
23922393 try func.store(.{ .stack = {} }, msb, Type.u64, 8 + lhs.offset());
23932394 return;
2395 } else if (abi_size > 16) {
2396 try func.memcpy(lhs, rhs, .{ .imm32 = @intCast(u32, ty.abiSize(func.target)) });
2397 },
2398 else => if (abi_size > 8) {
2399 return func.fail("TODO: `store` for type `{}` with abisize `{d}`", .{
2400 ty.fmt(func.bin_file.base.options.module.?),
2401 abi_size,
2402 });
23942403 },
2395 else => {},
23962404 }
23972405 try func.emitWValue(lhs);
23982406 // In this case we're actually interested in storing the stack position
......@@ -2400,11 +2408,9 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
24002408 try func.lowerToStack(rhs);
24012409
24022410 const valtype = typeToValtype(ty, func.target);
2403 const abi_size = @intCast(u8, ty.abiSize(func.target));
2404
24052411 const opcode = buildOpcode(.{
24062412 .valtype1 = valtype,
2407 .width = abi_size * 8,
2413 .width = @intCast(u8, abi_size * 8),
24082414 .op = .store,
24092415 });
24102416
......@@ -3960,7 +3966,7 @@ fn airUnwrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: boo
39603966 const result = result: {
39613967 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
39623968 if (op_is_ptr) {
3963 break :result WValue{ .imm32 = 0 };
3969 break :result func.reuseOperand(ty_op.operand, operand);
39643970 }
39653971 break :result WValue{ .none = {} };
39663972 }
......@@ -4453,7 +4459,7 @@ fn airPtrElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
44534459 try func.addTag(.i32_add);
44544460
44554461 const elem_result = val: {
4456 var result = try func.allocLocal(elem_ty);
4462 var result = try func.allocLocal(Type.usize);
44574463 try func.addLabel(.local_set, result.local.value);
44584464 if (isByRef(elem_ty, func.target)) {
44594465 break :val result;
......@@ -5155,8 +5161,8 @@ fn cmpOptionals(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op:
51555161fn cmpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {
51565162 assert(operand_ty.abiSize(func.target) >= 16);
51575163 assert(!(lhs != .stack and rhs == .stack));
5158 if (operand_ty.intInfo(func.target).bits > 128) {
5159 return func.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.intInfo(func.target).bits});
5164 if (operand_ty.bitSize(func.target) > 128) {
5165 return func.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.bitSize(func.target)});
51605166 }
51615167
51625168 var lhs_high_bit = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64);