| ... | ... | @@ -3801,6 +3801,7 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std |
| 3801 | 3801 | /// Compares big integers by checking both its high bits and low bits. |
| 3802 | 3802 | /// TODO: Lower this to compiler_rt call when bitsize > 128 |
| 3803 | 3803 | fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue { |
| 3804 | assert(operand_ty.abiSize(self.target) >= 16); |
| 3804 | 3805 | if (operand_ty.intInfo(self.target).bits > 128) { |
| 3805 | 3806 | return self.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.intInfo(self.target).bits}); |
| 3806 | 3807 | } |
| ... | ... | @@ -4093,6 +4094,10 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W |
| 4093 | 4094 | return self.fail("TODO: Implement {{add/sub}}_with_overflow for integer bitsize: {d}", .{int_info.bits}); |
| 4094 | 4095 | }; |
| 4095 | 4096 | |
| 4097 | if (wasm_bits == 128) { |
| 4098 | return self.airAddSubWithOverflowBigInt(lhs_op, rhs_op, lhs_ty, self.air.typeOfIndex(inst), op); |
| 4099 | } |
| 4100 | |
| 4096 | 4101 | const zero = switch (wasm_bits) { |
| 4097 | 4102 | 32 => WValue{ .imm32 = 0 }, |
| 4098 | 4103 | 64 => WValue{ .imm64 = 0 }, |
| ... | ... | @@ -4144,6 +4149,64 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W |
| 4144 | 4149 | return result_ptr; |
| 4145 | 4150 | } |
| 4146 | 4151 | |
| 4152 | fn airAddSubWithOverflowBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, result_ty: Type, op: Op) InnerError!WValue { |
| 4153 | assert(op == .add or op == .sub); |
| 4154 | const int_info = ty.intInfo(self.target); |
| 4155 | const is_signed = int_info.signedness == .signed; |
| 4156 | if (int_info.bits != 128) { |
| 4157 | return self.fail("TODO: Implement @{{add/sub}}WithOverflow for integer bitsize '{d}'", .{int_info.bits}); |
| 4158 | } |
| 4159 | |
| 4160 | const lhs_high_bit = try self.load(lhs, Type.u64, 0); |
| 4161 | const lhs_low_bit = try self.load(lhs, Type.u64, 8); |
| 4162 | const rhs_high_bit = try self.load(rhs, Type.u64, 0); |
| 4163 | const rhs_low_bit = try self.load(rhs, Type.u64, 8); |
| 4164 | |
| 4165 | const low_op_res = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op); |
| 4166 | const high_op_res = try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op); |
| 4167 | |
| 4168 | const lt = if (op == .add) blk: { |
| 4169 | break :blk try self.cmp(high_op_res, lhs_high_bit, Type.u64, .lt); |
| 4170 | } else if (op == .sub) blk: { |
| 4171 | break :blk try self.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt); |
| 4172 | } else unreachable; |
| 4173 | const tmp = try self.intcast(lt, Type.u32, Type.u64); |
| 4174 | const tmp_op = try self.binOp(low_op_res, tmp, Type.u64, op); |
| 4175 | |
| 4176 | const overflow_bit = if (is_signed) blk: { |
| 4177 | const xor_op = try self.binOp(lhs_low_bit, tmp_op, Type.u64, .xor); |
| 4178 | const xor_low = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor); |
| 4179 | const to_wrap = if (op == .add) wrap: { |
| 4180 | break :wrap try self.binOp(xor_low, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor); |
| 4181 | } else xor_low; |
| 4182 | const wrap = try self.binOp(to_wrap, xor_op, Type.u64, .@"and"); |
| 4183 | break :blk try self.cmp(wrap, .{ .imm64 = 0 }, Type.i64, .lt); // i64 because signed |
| 4184 | } else blk: { |
| 4185 | const eq = try self.cmp(tmp_op, lhs_low_bit, Type.u64, .eq); |
| 4186 | const op_eq = try self.cmp(tmp_op, lhs_low_bit, Type.u64, if (op == .add) .lt else .gt); |
| 4187 | |
| 4188 | const first_arg = if (op == .sub) arg: { |
| 4189 | break :arg try self.cmp(high_op_res, lhs_high_bit, Type.u64, .gt); |
| 4190 | } else lt; |
| 4191 | |
| 4192 | try self.emitWValue(first_arg); |
| 4193 | try self.emitWValue(op_eq); |
| 4194 | try self.emitWValue(eq); |
| 4195 | try self.addTag(.select); |
| 4196 | |
| 4197 | const overflow_bit = try self.allocLocal(Type.initTag(.u1)); |
| 4198 | try self.addLabel(.local_set, overflow_bit.local); |
| 4199 | break :blk overflow_bit; |
| 4200 | }; |
| 4201 | |
| 4202 | const result_ptr = try self.allocStack(result_ty); |
| 4203 | try self.store(result_ptr, high_op_res, Type.u64, 0); |
| 4204 | try self.store(result_ptr, tmp_op, Type.u64, 8); |
| 4205 | try self.store(result_ptr, overflow_bit, Type.initTag(.u1), 16); |
| 4206 | |
| 4207 | return result_ptr; |
| 4208 | } |
| 4209 | |
| 4147 | 4210 | fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4148 | 4211 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 4149 | 4212 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |