| ... | ... | @@ -1993,22 +1993,54 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |
| 1993 | 1993 | const ty = self.air.typeOf(bin_op.lhs); |
| 1994 | 1994 | if (ty.zigTypeTag() == .Vector) { |
| 1995 | 1995 | 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", .{}); |
| 1998 | 2000 | } |
| 1999 | 2001 | |
| 2000 | 2002 | return self.wrapBinOp(lhs, rhs, ty, op); |
| 2001 | 2003 | } |
| 2002 | 2004 | |
| 2003 | 2005 | fn 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 | } |
| 2006 | 2035 | |
| 2007 | 2036 | const opcode: wasm.Opcode = buildOpcode(.{ |
| 2008 | 2037 | .op = op, |
| 2009 | 2038 | .valtype1 = typeToValtype(ty, self.target), |
| 2010 | 2039 | .signedness = if (ty.isSignedInt()) .signed else .unsigned, |
| 2011 | 2040 | }); |
| 2041 | |
| 2042 | try self.emitWValue(lhs); |
| 2043 | try self.emitWValue(rhs); |
| 2012 | 2044 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 2013 | 2045 | const bin_local = try self.allocLocal(ty); |
| 2014 | 2046 | 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 |
| 3721 | 3753 | const rhs_high_bit = try self.load(rhs, Type.u64, 0); |
| 3722 | 3754 | const rhs_low_bit = try self.load(rhs, Type.u64, 8); |
| 3723 | 3755 | |
| 3724 | | try self.emitWValue(or_result); |
| 3725 | 3756 | switch (op) { |
| 3726 | 3757 | .eq, .neq => { |
| 3727 | 3758 | 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 |
| 3729 | 3760 | const or_result = try self.binOp(xor_high, xor_low, Type.u64, .@"or"); |
| 3730 | 3761 | |
| 3731 | 3762 | switch (op) { |
| 3732 | | .eq => try self.addTag(.i64_eqz), |
| 3763 | .eq => return self.cmp(or_result, .{ .imm32 = 0 }, Type.u32, .eq), |
| 3733 | 3764 | .neq => return self.cmp(or_result, .{ .imm32 = 0 }, Type.u32, .neq), |
| 3734 | 3765 | else => unreachable, |
| 3735 | 3766 | } |