authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-05-10 22:25:14+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-05-18 07:43:33+02:00
log167d3089ea11a8f0a45d6e083b1dacb107483b04
treeabb83747eaf7ae5522ccc2df321470432bdb59fc
parent59d3714b8d7008676902b51b891c4cc153447374

wasm: Support 128bit add/sub wrapping operands


1 files changed, 37 insertions(+), 6 deletions(-)

src/arch/wasm/CodeGen.zig+37-6
......@@ -1993,22 +1993,54 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
19931993 const ty = self.air.typeOf(bin_op.lhs);
19941994 if (ty.zigTypeTag() == .Vector) {
19951995 return self.fail("TODO: Implement wrapping arithmetic for vectors", .{});
1996 } else if (ty.abiSize(self.target) > 8) {
1997 return self.fail("TODO: Implement wrapping arithmetic for bitsize > 64", .{});
1996 } else if (ty.abiSize(self.target) > 8 and op == .mul) {
1997 return self.fail("TODO: Implement wrapping multiplication for bitsize > 64", .{});
1998 } else if (ty.abiSize(self.target) > 16) {
1999 return self.fail("TODO: Implement wrapping arithmetic for bitsize > 128", .{});
19982000 }
19992001
20002002 return self.wrapBinOp(lhs, rhs, ty, op);
20012003}
20022004
20032005fn wrapBinOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
2004 try self.emitWValue(lhs);
2005 try self.emitWValue(rhs);
2006 const bit_size = ty.intInfo(self.target).bits;
2007 var wasm_bits = toWasmBits(bit_size) orelse {
2008 return self.fail("TODO: Implement wrapping arithmetic for integers with bitsize: {d}\n", .{bit_size});
2009 };
2010 if (wasm_bits == 128) {
2011 if (op == .mul) return self.fail("TODO: Implement wrapping multiplication for 128bit integers", .{});
2012 if (bit_size != wasm_bits) return self.fail("TODO: Implement wrapping arithmetic for integers > 64 & < 128", .{});
2013
2014 const result = try self.allocStack(ty);
2015 const lhs_high_bit = try self.load(lhs, Type.u64, 0);
2016 const lhs_low_bit = try self.load(lhs, Type.u64, 8);
2017 const rhs_high_bit = try self.load(rhs, Type.u64, 0);
2018 const rhs_low_bit = try self.load(rhs, Type.u64, 8);
2019
2020 const low_op_res = try self.binOp(rhs_low_bit, lhs_low_bit, Type.u64, op);
2021 const high_op_res = try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op);
2022
2023 const lt = if (op == .add) blk: {
2024 break :blk try self.binOp(high_op_res, rhs_high_bit, Type.u64, .lt);
2025 } else if (op == .sub) blk: {
2026 break :blk try self.binOp(rhs_high_bit, lhs_high_bit, Type.u64, .lt);
2027 } else unreachable;
2028 const tmp = try self.intcast(lt, Type.u32, Type.u64);
2029 const tmp_op = try self.binOp(low_op_res, tmp, Type.u64, op);
2030
2031 try self.store(result, high_op_res, Type.u64, 0);
2032 try self.store(result, tmp_op, Type.u64, 8);
2033 return result;
2034 }
20062035
20072036 const opcode: wasm.Opcode = buildOpcode(.{
20082037 .op = op,
20092038 .valtype1 = typeToValtype(ty, self.target),
20102039 .signedness = if (ty.isSignedInt()) .signed else .unsigned,
20112040 });
2041
2042 try self.emitWValue(lhs);
2043 try self.emitWValue(rhs);
20122044 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
20132045 const bin_local = try self.allocLocal(ty);
20142046 try self.addLabel(.local_set, bin_local.local);
......@@ -3721,7 +3753,6 @@ fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.ma
37213753 const rhs_high_bit = try self.load(rhs, Type.u64, 0);
37223754 const rhs_low_bit = try self.load(rhs, Type.u64, 8);
37233755
3724 try self.emitWValue(or_result);
37253756 switch (op) {
37263757 .eq, .neq => {
37273758 const xor_high = try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, .xor);
......@@ -3729,7 +3760,7 @@ fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.ma
37293760 const or_result = try self.binOp(xor_high, xor_low, Type.u64, .@"or");
37303761
37313762 switch (op) {
3732 .eq => try self.addTag(.i64_eqz),
3763 .eq => return self.cmp(or_result, .{ .imm32 = 0 }, Type.u32, .eq),
37333764 .neq => return self.cmp(or_result, .{ .imm32 = 0 }, Type.u32, .neq),
37343765 else => unreachable,
37353766 }