authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-07-26 16:46:58+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-08-11 11:08:00+02:00
logcde16f61eb41f2beda85e838331a30869e420c68
tree8fcc59582608f43a55e362bcd5bb9167d8bf4226
parent699bc6171dcc18d681de754ca2eeb63645aea889
signaturelock-open Commit is signed but in an unrecognized format.

wasm: `wrapOperand` - leave value on the stack

This also does it for `wrapBinOp` which internally uses the already refactored `binOp` and `wrapOperand` heavily simplifying this function and not duplicate the logic from `binOp`

1 files changed, 33 insertions(+), 52 deletions(-)

src/arch/wasm/CodeGen.zig+33-52
...@@ -2179,40 +2179,22 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {...@@ -2179,40 +2179,22 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
2179 return self.fail("TODO: Implement wrapping arithmetic for vectors", .{});2179 return self.fail("TODO: Implement wrapping arithmetic for vectors", .{});
2180 }2180 }
21812181
2182 return self.wrapBinOp(lhs, rhs, ty, op);2182 return (try self.wrapBinOp(lhs, rhs, ty, op)).toLocal(self, ty);
2183}2183}
21842184
2185/// Performs a wrapping binary operation.
2186/// Asserts rhs is not a stack value when lhs also isn't.
2187/// NOTE: Leaves the result on the stack when its Type is <= 64 bits
2185fn wrapBinOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {2188fn wrapBinOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
2186 const bit_size = ty.intInfo(self.target).bits;2189 const bin_local = try self.binOp(lhs, rhs, ty, op);
2187 var wasm_bits = toWasmBits(bit_size) orelse {
2188 return self.fail("TODO: Implement wrapping arithmetic for integers with bitsize: {d}\n", .{bit_size});
2189 };
2190
2191 if (wasm_bits == 128) {
2192 const bin_op = try self.binOpBigInt(lhs, rhs, ty, op);
2193 return self.wrapOperand(bin_op, ty);
2194 }
2195
2196 const opcode: wasm.Opcode = buildOpcode(.{
2197 .op = op,
2198 .valtype1 = typeToValtype(ty, self.target),
2199 .signedness = if (ty.isSignedInt()) .signed else .unsigned,
2200 });
2201
2202 try self.emitWValue(lhs);
2203 try self.emitWValue(rhs);
2204 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
2205 const bin_local = try self.allocLocal(ty);
2206 try self.addLabel(.local_set, bin_local.local);
2207
2208 return self.wrapOperand(bin_local, ty);2190 return self.wrapOperand(bin_local, ty);
2209}2191}
22102192
2211/// Wraps an operand based on a given type's bitsize.2193/// Wraps an operand based on a given type's bitsize.
2212/// Asserts `Type` is <= 128 bits.2194/// Asserts `Type` is <= 128 bits.
2195/// NOTE: When the Type is <= 64 bits, leaves the value on top of the stack.
2213fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue {2196fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue {
2214 assert(ty.abiSize(self.target) <= 16);2197 assert(ty.abiSize(self.target) <= 16);
2215 const result_local = try self.allocLocal(ty);
2216 const bitsize = ty.intInfo(self.target).bits;2198 const bitsize = ty.intInfo(self.target).bits;
2217 const wasm_bits = toWasmBits(bitsize) orelse {2199 const wasm_bits = toWasmBits(bitsize) orelse {
2218 return self.fail("TODO: Implement wrapOperand for bitsize '{d}'", .{bitsize});2200 return self.fail("TODO: Implement wrapOperand for bitsize '{d}'", .{bitsize});
...@@ -2246,8 +2228,7 @@ fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue {...@@ -2246,8 +2228,7 @@ fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue {
2246 try self.addTag(.i64_and);2228 try self.addTag(.i64_and);
2247 } else unreachable;2229 } else unreachable;
22482230
2249 try self.addLabel(.local_set, result_local.local);2231 return WValue{ .stack = {} };
2250 return result_local;
2251}2232}
22522233
2253fn lowerParentPtr(self: *Self, ptr_val: Value, ptr_child_ty: Type) InnerError!WValue {2234fn lowerParentPtr(self: *Self, ptr_val: Value, ptr_child_ty: Type) InnerError!WValue {
...@@ -3471,11 +3452,11 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3471,11 +3452,11 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3471 return self.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{int_info.bits});3452 return self.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{int_info.bits});
3472 }3453 }
34733454
3474 const result = try self.intcast(operand, op_ty, wanted_ty);3455 var result = try self.intcast(operand, op_ty, wanted_ty);
3475 const wanted_bits = wanted_ty.intInfo(self.target).bits;3456 const wanted_bits = wanted_ty.intInfo(self.target).bits;
3476 const wasm_bits = toWasmBits(wanted_bits).?;3457 const wasm_bits = toWasmBits(wanted_bits).?;
3477 if (wasm_bits != wanted_bits) {3458 if (wasm_bits != wanted_bits) {
3478 return self.wrapOperand(result, wanted_ty);3459 result = try self.wrapOperand(result, wanted_ty);
3479 }3460 }
3480 return result.toLocal(self, wanted_ty);3461 return result.toLocal(self, wanted_ty);
3481}3462}
...@@ -3749,11 +3730,8 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3749,11 +3730,8 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3749 .signedness = if (dest_ty.isSignedInt()) .signed else .unsigned,3730 .signedness = if (dest_ty.isSignedInt()) .signed else .unsigned,
3750 });3731 });
3751 try self.addTag(Mir.Inst.Tag.fromOpcode(op));3732 try self.addTag(Mir.Inst.Tag.fromOpcode(op));
37523733 const wrapped = try self.wrapOperand(.{ .stack = {} }, dest_ty);
3753 const result = try self.allocLocal(dest_ty);3734 return wrapped.toLocal(self, dest_ty);
3754 try self.addLabel(.local_set, result.local);
3755
3756 return self.wrapOperand(result, dest_ty);
3757}3735}
37583736
3759fn airIntToFloat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3737fn airIntToFloat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -4339,7 +4317,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W...@@ -4339,7 +4317,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W
43394317
4340 const bin_op = try (try self.binOp(lhs, rhs, lhs_ty, op)).toLocal(self, lhs_ty);4318 const bin_op = try (try self.binOp(lhs, rhs, lhs_ty, op)).toLocal(self, lhs_ty);
4341 const result = if (wasm_bits != int_info.bits) blk: {4319 const result = if (wasm_bits != int_info.bits) blk: {
4342 break :blk try self.wrapOperand(bin_op, lhs_ty);4320 break :blk try (try self.wrapOperand(bin_op, lhs_ty)).toLocal(self, lhs_ty);
4343 } else bin_op;4321 } else bin_op;
43444322
4345 const cmp_op: std.math.CompareOperator = if (op == .sub) .gt else .lt;4323 const cmp_op: std.math.CompareOperator = if (op == .sub) .gt else .lt;
...@@ -4438,13 +4416,15 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4438,13 +4416,15 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
44384416
4439 const shl = try (try self.binOp(lhs, rhs, lhs_ty, .shl)).toLocal(self, lhs_ty);4417 const shl = try (try self.binOp(lhs, rhs, lhs_ty, .shl)).toLocal(self, lhs_ty);
4440 const result = if (wasm_bits != int_info.bits) blk: {4418 const result = if (wasm_bits != int_info.bits) blk: {
4441 break :blk try self.wrapOperand(shl, lhs_ty);4419 break :blk try (try self.wrapOperand(shl, lhs_ty)).toLocal(self, lhs_ty);
4442 } else shl;4420 } else shl;
44434421
4444 const overflow_bit = if (wasm_bits != int_info.bits and is_signed) blk: {4422 const overflow_bit = if (wasm_bits != int_info.bits and is_signed) blk: {
4445 const abs = try self.signAbsValue(shl, lhs_ty);4423 const abs = try self.signAbsValue(shl, lhs_ty);
4424 // emit lhs to stack to we can keep 'wrapped' on the stack also
4425 try self.emitWValue(lhs);
4446 const wrapped = try self.wrapBinOp(abs, rhs, lhs_ty, .shr);4426 const wrapped = try self.wrapBinOp(abs, rhs, lhs_ty, .shr);
4447 break :blk try self.cmp(lhs, wrapped, lhs_ty, .neq);4427 break :blk try self.cmp(.{ .stack = {} }, wrapped, lhs_ty, .neq);
4448 } else blk: {4428 } else blk: {
4449 const shr = try (try self.binOp(result, rhs, lhs_ty, .shr)).toLocal(self, lhs_ty);4429 const shr = try (try self.binOp(result, rhs, lhs_ty, .shr)).toLocal(self, lhs_ty);
4450 break :blk try self.cmp(lhs, shr, lhs_ty, .neq);4430 break :blk try self.cmp(lhs, shr, lhs_ty, .neq);
...@@ -4499,7 +4479,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4499,7 +4479,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4499 const wrap = try self.intcast(shr, new_ty, lhs_ty);4479 const wrap = try self.intcast(shr, new_ty, lhs_ty);
4500 _ = try self.cmp(wrap, zero, lhs_ty, .neq);4480 _ = try self.cmp(wrap, zero, lhs_ty, .neq);
4501 try self.addLabel(.local_set, overflow_bit.local);4481 try self.addLabel(.local_set, overflow_bit.local);
4502 break :blk try (try self.intcast(bin_op, new_ty, lhs_ty)).toLocal(self, lhs_ty);4482 break :blk try self.intcast(bin_op, new_ty, lhs_ty);
4503 } else {4483 } else {
4504 const down_cast = try (try self.intcast(bin_op, new_ty, lhs_ty)).toLocal(self, lhs_ty);4484 const down_cast = try (try self.intcast(bin_op, new_ty, lhs_ty)).toLocal(self, lhs_ty);
4505 const shr = try (try self.binOp(down_cast, .{ .imm32 = int_info.bits - 1 }, lhs_ty, .shr)).toLocal(self, lhs_ty);4485 const shr = try (try self.binOp(down_cast, .{ .imm32 = int_info.bits - 1 }, lhs_ty, .shr)).toLocal(self, lhs_ty);
...@@ -4529,9 +4509,10 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4529,9 +4509,10 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4529 try self.addLabel(.local_set, overflow_bit.local);4509 try self.addLabel(.local_set, overflow_bit.local);
4530 break :blk try self.wrapOperand(bin_op, lhs_ty);4510 break :blk try self.wrapOperand(bin_op, lhs_ty);
4531 };4511 };
4512 const bin_op_local = try bin_op.toLocal(self, lhs_ty);
45324513
4533 const result_ptr = try self.allocStack(self.air.typeOfIndex(inst));4514 const result_ptr = try self.allocStack(self.air.typeOfIndex(inst));
4534 try self.store(result_ptr, bin_op, lhs_ty, 0);4515 try self.store(result_ptr, bin_op_local, lhs_ty, 0);
4535 const offset = @intCast(u32, lhs_ty.abiSize(self.target));4516 const offset = @intCast(u32, lhs_ty.abiSize(self.target));
4536 try self.store(result_ptr, overflow_bit, Type.initTag(.u1), offset);4517 try self.store(result_ptr, overflow_bit, Type.initTag(.u1), offset);
45374518
...@@ -4854,29 +4835,29 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4854,29 +4835,29 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4854 switch (int_info.bits) {4835 switch (int_info.bits) {
4855 16 => {4836 16 => {
4856 const shl_res = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shl);4837 const shl_res = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shl);
4857 const lhs = try (try self.binOp(shl_res, .{ .imm32 = 0xFF00 }, ty, .@"and")).toLocal(self, ty);4838 const lhs = try self.binOp(shl_res, .{ .imm32 = 0xFF00 }, ty, .@"and");
4858 const shr_res = try (try self.binOp(operand, .{ .imm32 = 8 }, ty, .shr)).toLocal(self, ty);4839 const shr_res = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shr);
4859 const res = if (int_info.signedness == .signed) blk: {4840 const res = if (int_info.signedness == .signed) blk: {
4860 break :blk try self.wrapOperand(shr_res, Type.u8);4841 break :blk try self.wrapOperand(shr_res, Type.u8);
4861 } else shr_res;4842 } else shr_res;
4862 return (try self.binOp(lhs, res, ty, .@"or")).toLocal(self, ty);4843 return (try self.binOp(lhs, res, ty, .@"or")).toLocal(self, ty);
4863 },4844 },
4864 24 => {4845 24 => {
4865 const msb = try self.wrapOperand(operand, Type.u16);4846 const msb = try (try self.wrapOperand(operand, Type.u16)).toLocal(self, Type.u16);
4866 const lsb = try self.wrapBinOp(operand, .{ .imm32 = 16 }, Type.u8, .shr);
48674847
4868 const shl_res = try self.binOp(msb, .{ .imm32 = 8 }, Type.u16, .shl);4848 const shl_res = try self.binOp(msb, .{ .imm32 = 8 }, Type.u16, .shl);
4869 const lhs = try (try self.binOp(shl_res, .{ .imm32 = 0xFF0000 }, Type.u16, .@"and")).toLocal(self, Type.u16);4849 const lhs = try self.binOp(shl_res, .{ .imm32 = 0xFF0000 }, Type.u16, .@"and");
4870 const shr_res = try (try self.binOp(msb, .{ .imm32 = 8 }, ty, .shr)).toLocal(self, ty);4850 const shr_res = try self.binOp(msb, .{ .imm32 = 8 }, ty, .shr);
48714851
4872 const res = if (int_info.signedness == .signed) blk: {4852 const res = if (int_info.signedness == .signed) blk: {
4873 break :blk try self.wrapOperand(shr_res, Type.u8);4853 break :blk try self.wrapOperand(shr_res, Type.u8);
4874 } else shr_res;4854 } else shr_res;
4875 const lhs_tmp = try self.binOp(lhs, res, ty, .@"or");4855 const lhs_tmp = try self.binOp(lhs, res, ty, .@"or");
4876 const lhs_result = try (try self.binOp(lhs_tmp, .{ .imm32 = 8 }, ty, .shr)).toLocal(self, ty);4856 const lhs_result = try self.binOp(lhs_tmp, .{ .imm32 = 8 }, ty, .shr);
4877 const rhs_wrap = try self.wrapOperand(msb, Type.u8);4857 const rhs_wrap = try self.wrapOperand(msb, Type.u8);
4878 const rhs_result = try (try self.binOp(rhs_wrap, .{ .imm32 = 16 }, ty, .shl)).toLocal(self, ty);4858 const rhs_result = try self.binOp(rhs_wrap, .{ .imm32 = 16 }, ty, .shl);
48794859
4860 const lsb = try self.wrapBinOp(operand, .{ .imm32 = 16 }, Type.u8, .shr);
4880 const tmp = try self.binOp(lhs_result, rhs_result, ty, .@"or");4861 const tmp = try self.binOp(lhs_result, rhs_result, ty, .@"or");
4881 return (try self.binOp(tmp, lsb, ty, .@"or")).toLocal(self, ty);4862 return (try self.binOp(tmp, lsb, ty, .@"or")).toLocal(self, ty);
4882 },4863 },
...@@ -4887,11 +4868,11 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4887,11 +4868,11 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4887 const rhs = try (try self.binOp(shr_tmp, .{ .imm32 = 0xFF00FF }, ty, .@"and")).toLocal(self, ty);4868 const rhs = try (try self.binOp(shr_tmp, .{ .imm32 = 0xFF00FF }, ty, .@"and")).toLocal(self, ty);
4888 const tmp_or = try (try self.binOp(lhs, rhs, ty, .@"or")).toLocal(self, ty);4869 const tmp_or = try (try self.binOp(lhs, rhs, ty, .@"or")).toLocal(self, ty);
48894870
4890 const shr = try (try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shr)).toLocal(self, ty);4871 const shl = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shl);
4872 const shr = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shr);
4891 const res = if (int_info.signedness == .signed) blk: {4873 const res = if (int_info.signedness == .signed) blk: {
4892 break :blk try self.wrapOperand(shr, Type.u16);4874 break :blk try self.wrapOperand(shr, Type.u16);
4893 } else shr;4875 } else shr;
4894 const shl = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shl);
4895 return (try self.binOp(shl, res, ty, .@"or")).toLocal(self, ty);4876 return (try self.binOp(shl, res, ty, .@"or")).toLocal(self, ty);
4896 },4877 },
4897 else => return self.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits}),4878 else => return self.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits}),
...@@ -5178,7 +5159,7 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op...@@ -5178,7 +5159,7 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op
5178 _ = try self.cmp(bin_result, min_wvalue, ty, .gt);5159 _ = try self.cmp(bin_result, min_wvalue, ty, .gt);
5179 try self.addTag(.select);5160 try self.addTag(.select);
5180 try self.addLabel(.local_set, bin_result.local); // re-use local5161 try self.addLabel(.local_set, bin_result.local); // re-use local
5181 return self.wrapOperand(bin_result, ty);5162 return (try self.wrapOperand(bin_result, ty)).toLocal(self, ty);
5182 } else {5163 } else {
5183 const zero = switch (wasm_bits) {5164 const zero = switch (wasm_bits) {
5184 32 => WValue{ .imm32 = 0 },5165 32 => WValue{ .imm32 = 0 },
...@@ -5289,11 +5270,11 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -5289,11 +5270,11 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
5289 _ = try self.cmp(shl_res, shr, ty, .neq);5270 _ = try self.cmp(shl_res, shr, ty, .neq);
5290 try self.addTag(.select);5271 try self.addTag(.select);
5291 try self.addLabel(.local_set, result.local);5272 try self.addLabel(.local_set, result.local);
5292 const shift_result = try (try self.binOp(result, shift_value, ty, .shr)).toLocal(self, ty);5273 var shift_result = try self.binOp(result, shift_value, ty, .shr);
5293 if (is_signed) {5274 if (is_signed) {
5294 return self.wrapOperand(shift_result, ty);5275 shift_result = try self.wrapOperand(shift_result, ty);
5295 }5276 }
5296 return shift_result;5277 return try shift_result.toLocal(self, ty);
5297 }5278 }
5298}5279}
52995280