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...@@ -2318,6 +2318,7 @@ fn airStore(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void
23182318
2319fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void {2319fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void {
2320 assert(!(lhs != .stack and rhs == .stack));2320 assert(!(lhs != .stack and rhs == .stack));
2321 const abi_size = ty.abiSize(func.target);
2321 switch (ty.zigTypeTag()) {2322 switch (ty.zigTypeTag()) {
2322 .ErrorUnion => {2323 .ErrorUnion => {
2323 const pl_ty = ty.errorUnionPayload();2324 const pl_ty = ty.errorUnionPayload();
...@@ -2325,7 +2326,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE...@@ -2325,7 +2326,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
2325 return func.store(lhs, rhs, Type.anyerror, 0);2326 return func.store(lhs, rhs, Type.anyerror, 0);
2326 }2327 }
23272328
2328 const len = @intCast(u32, ty.abiSize(func.target));2329 const len = @intCast(u32, abi_size);
2329 return func.memcpy(lhs, rhs, .{ .imm32 = len });2330 return func.memcpy(lhs, rhs, .{ .imm32 = len });
2330 },2331 },
2331 .Optional => {2332 .Optional => {
...@@ -2341,16 +2342,16 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE...@@ -2341,16 +2342,16 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
2341 return func.store(lhs, rhs, Type.anyerror, 0);2342 return func.store(lhs, rhs, Type.anyerror, 0);
2342 }2343 }
23432344
2344 const len = @intCast(u32, ty.abiSize(func.target));2345 const len = @intCast(u32, abi_size);
2345 return func.memcpy(lhs, rhs, .{ .imm32 = len });2346 return func.memcpy(lhs, rhs, .{ .imm32 = len });
2346 },2347 },
2347 .Struct, .Array, .Union => if (isByRef(ty, func.target)) {2348 .Struct, .Array, .Union => if (isByRef(ty, func.target)) {
2348 const len = @intCast(u32, ty.abiSize(func.target));2349 const len = @intCast(u32, abi_size);
2349 return func.memcpy(lhs, rhs, .{ .imm32 = len });2350 return func.memcpy(lhs, rhs, .{ .imm32 = len });
2350 },2351 },
2351 .Vector => switch (determineSimdStoreStrategy(ty, func.target)) {2352 .Vector => switch (determineSimdStoreStrategy(ty, func.target)) {
2352 .unrolled => {2353 .unrolled => {
2353 const len = @intCast(u32, ty.abiSize(func.target));2354 const len = @intCast(u32, abi_size);
2354 return func.memcpy(lhs, rhs, .{ .imm32 = len });2355 return func.memcpy(lhs, rhs, .{ .imm32 = len });
2355 },2356 },
2356 .direct => {2357 .direct => {
...@@ -2382,7 +2383,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE...@@ -2382,7 +2383,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
2382 return;2383 return;
2383 }2384 }
2384 },2385 },
2385 .Int => if (ty.intInfo(func.target).bits > 64) {2386 .Int, .Float => if (abi_size > 8 and abi_size <= 16) {
2386 try func.emitWValue(lhs);2387 try func.emitWValue(lhs);
2387 const lsb = try func.load(rhs, Type.u64, 0);2388 const lsb = try func.load(rhs, Type.u64, 0);
2388 try func.store(.{ .stack = {} }, lsb, Type.u64, 0 + lhs.offset());2389 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...@@ -2391,8 +2392,15 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
2391 const msb = try func.load(rhs, Type.u64, 8);2392 const msb = try func.load(rhs, Type.u64, 8);
2392 try func.store(.{ .stack = {} }, msb, Type.u64, 8 + lhs.offset());2393 try func.store(.{ .stack = {} }, msb, Type.u64, 8 + lhs.offset());
2393 return;2394 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 });
2394 },2403 },
2395 else => {},
2396 }2404 }
2397 try func.emitWValue(lhs);2405 try func.emitWValue(lhs);
2398 // In this case we're actually interested in storing the stack position2406 // 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...@@ -2400,11 +2408,9 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
2400 try func.lowerToStack(rhs);2408 try func.lowerToStack(rhs);
24012409
2402 const valtype = typeToValtype(ty, func.target);2410 const valtype = typeToValtype(ty, func.target);
2403 const abi_size = @intCast(u8, ty.abiSize(func.target));
2404
2405 const opcode = buildOpcode(.{2411 const opcode = buildOpcode(.{
2406 .valtype1 = valtype,2412 .valtype1 = valtype,
2407 .width = abi_size * 8,2413 .width = @intCast(u8, abi_size * 8),
2408 .op = .store,2414 .op = .store,
2409 });2415 });
24102416
...@@ -3960,7 +3966,7 @@ fn airUnwrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: boo...@@ -3960,7 +3966,7 @@ fn airUnwrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: boo
3960 const result = result: {3966 const result = result: {
3961 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {3967 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
3962 if (op_is_ptr) {3968 if (op_is_ptr) {
3963 break :result WValue{ .imm32 = 0 };3969 break :result func.reuseOperand(ty_op.operand, operand);
3964 }3970 }
3965 break :result WValue{ .none = {} };3971 break :result WValue{ .none = {} };
3966 }3972 }
...@@ -4453,7 +4459,7 @@ fn airPtrElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4453,7 +4459,7 @@ fn airPtrElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4453 try func.addTag(.i32_add);4459 try func.addTag(.i32_add);
44544460
4455 const elem_result = val: {4461 const elem_result = val: {
4456 var result = try func.allocLocal(elem_ty);4462 var result = try func.allocLocal(Type.usize);
4457 try func.addLabel(.local_set, result.local.value);4463 try func.addLabel(.local_set, result.local.value);
4458 if (isByRef(elem_ty, func.target)) {4464 if (isByRef(elem_ty, func.target)) {
4459 break :val result;4465 break :val result;
...@@ -5155,8 +5161,8 @@ fn cmpOptionals(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op:...@@ -5155,8 +5161,8 @@ fn cmpOptionals(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op:
5155fn cmpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {5161fn cmpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {
5156 assert(operand_ty.abiSize(func.target) >= 16);5162 assert(operand_ty.abiSize(func.target) >= 16);
5157 assert(!(lhs != .stack and rhs == .stack));5163 assert(!(lhs != .stack and rhs == .stack));
5158 if (operand_ty.intInfo(func.target).bits > 128) {5164 if (operand_ty.bitSize(func.target) > 128) {
5159 return func.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.intInfo(func.target).bits});5165 return func.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.bitSize(func.target)});
5160 }5166 }
51615167
5162 var lhs_high_bit = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64);5168 var lhs_high_bit = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64);