| author | |
| committer | |
| log | c47ed0c912d2f445710fe4486fa071dd63601989 |
| tree | 3272549828e1ca5fbb65b43a6cad1ea6e200cbd4 |
| parent | ddd2ef822f99979d3ea61583a91ab236942e6367 |
13 files changed, 164 insertions(+), 37 deletions(-)
src/Air.zig+9-1| ... | ... | @@ -141,6 +141,12 @@ pub const Inst = struct { |
| 141 | 141 | /// of the operation. |
| 142 | 142 | /// Uses the `pl_op` field with payload `Bin`. |
| 143 | 143 | add_with_overflow, |
| 144 | /// Integer multiplication with overflow. Both operands are guaranteed to be the same type, | |
| 145 | /// and the result is bool. The wrapped value is written to the pointer given by the in | |
| 146 | /// operand of the `pl_op` field. Payload is `Bin` with `lhs` and `rhs` the relevant types | |
| 147 | /// of the operation. | |
| 148 | /// Uses the `pl_op` field with payload `Bin`. | |
| 149 | mul_with_overflow, | |
| 144 | 150 | /// Allocates stack local memory. |
| 145 | 151 | /// Uses the `ty` field. |
| 146 | 152 | alloc, |
| ... | ... | @@ -815,7 +821,9 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 815 | 821 | return ptr_ty.elemType(); |
| 816 | 822 | }, |
| 817 | 823 | |
| 818 | .add_with_overflow => return Type.initTag(.bool), | |
| 824 | .add_with_overflow, | |
| 825 | .mul_with_overflow, | |
| 826 | => return Type.initTag(.bool), | |
| 819 | 827 | } |
| 820 | 828 | } |
| 821 | 829 |
src/Liveness.zig+1-1| ... | ... | @@ -382,7 +382,7 @@ fn analyzeInst( |
| 382 | 382 | const extra = a.air.extraData(Air.AtomicRmw, pl_op.payload).data; |
| 383 | 383 | return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.operand, .none }); |
| 384 | 384 | }, |
| 385 | .memset, .memcpy, .add_with_overflow => { | |
| 385 | .memset, .memcpy, .add_with_overflow, .mul_with_overflow => { | |
| 386 | 386 | const pl_op = inst_datas[inst].pl_op; |
| 387 | 387 | const extra = a.air.extraData(Air.Bin, pl_op.payload).data; |
| 388 | 388 | return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.lhs, extra.rhs }); |
src/Sema.zig+52-4| ... | ... | @@ -7343,8 +7343,8 @@ fn zirOverflowArithmetic( |
| 7343 | 7343 | overflowed: enum { yes, no, undef }, |
| 7344 | 7344 | wrapped: Air.Inst.Ref, |
| 7345 | 7345 | } = result: { |
| 7346 | const air_tag: Air.Inst.Tag = switch (zir_tag) { | |
| 7347 | .add_with_overflow => blk: { | |
| 7346 | switch (zir_tag) { | |
| 7347 | .add_with_overflow => { | |
| 7348 | 7348 | // If either of the arguments is zero, `false` is returned and the other is stored |
| 7349 | 7349 | // to the result, even if it is undefined.. |
| 7350 | 7350 | // Otherwise, if either of the argument is undefined, undefined is returned. |
| ... | ... | @@ -7377,14 +7377,62 @@ fn zirOverflowArithmetic( |
| 7377 | 7377 | } |
| 7378 | 7378 | } |
| 7379 | 7379 | } |
| 7380 | }, | |
| 7381 | .mul_with_overflow => { | |
| 7382 | // If either of the arguments is zero, the result is zero and no overflow occured. | |
| 7383 | // If either of the arguments is one, the result is the other and no overflow occured. | |
| 7384 | // Otherwise, if either of the arguments is undefined, both results are undefined. | |
| 7385 | ||
| 7386 | if (maybe_lhs_val) |lhs_val| { | |
| 7387 | if (!lhs_val.isUndef()) { | |
| 7388 | if (lhs_val.compareWithZero(.eq)) { | |
| 7389 | break :result .{ .overflowed = .no, .wrapped = lhs }; | |
| 7390 | } else if (lhs_val.compare(.eq, Value.one, dest_ty)) { | |
| 7391 | break :result .{ .overflowed = .no, .wrapped = rhs }; | |
| 7392 | } | |
| 7393 | } | |
| 7394 | } | |
| 7380 | 7395 | |
| 7381 | break :blk .add_with_overflow; | |
| 7396 | if (maybe_rhs_val) |rhs_val| { | |
| 7397 | if (!rhs_val.isUndef()) { | |
| 7398 | if (rhs_val.compareWithZero(.eq)) { | |
| 7399 | break :result .{ .overflowed = .no, .wrapped = rhs }; | |
| 7400 | } else if (rhs_val.compare(.eq, Value.one, dest_ty)) { | |
| 7401 | break :result .{ .overflowed = .no, .wrapped = lhs }; | |
| 7402 | } | |
| 7403 | } | |
| 7404 | } | |
| 7405 | ||
| 7406 | if (maybe_lhs_val) |lhs_val| { | |
| 7407 | if (maybe_rhs_val) |rhs_val| { | |
| 7408 | if (lhs_val.isUndef() or rhs_val.isUndef()) { | |
| 7409 | break :result .{ .overflowed = .undef, .wrapped = try sema.addConstUndef(dest_ty) }; | |
| 7410 | } | |
| 7411 | ||
| 7412 | const result = try lhs_val.intMulWithOverflow(rhs_val, dest_ty, sema.arena, target); | |
| 7413 | const inst = try sema.addConstant( | |
| 7414 | dest_ty, | |
| 7415 | result.wrapped_result, | |
| 7416 | ); | |
| 7417 | ||
| 7418 | if (result.overflowed) { | |
| 7419 | break :result .{ .overflowed = .yes, .wrapped = inst }; | |
| 7420 | } else { | |
| 7421 | break :result .{ .overflowed = .no, .wrapped = inst }; | |
| 7422 | } | |
| 7423 | } | |
| 7424 | } | |
| 7382 | 7425 | }, |
| 7383 | 7426 | .sub_with_overflow, |
| 7384 | .mul_with_overflow, | |
| 7385 | 7427 | .shl_with_overflow, |
| 7386 | 7428 | => return sema.fail(block, src, "TODO implement Sema.zirOverflowArithmetic for {}", .{zir_tag}), |
| 7387 | 7429 | else => unreachable, |
| 7430 | } | |
| 7431 | ||
| 7432 | const air_tag: Air.Inst.Tag = switch (zir_tag) { | |
| 7433 | .add_with_overflow => .add_with_overflow, | |
| 7434 | .mul_with_overflow => .mul_with_overflow, | |
| 7435 | else => return sema.fail(block, src, "TODO implement runtime Sema.zirOverflowArithmetic for {}", .{zir_tag}), | |
| 7388 | 7436 | }; |
| 7389 | 7437 | |
| 7390 | 7438 | try sema.requireRuntimeBlock(block, src); |
src/arch/aarch64/CodeGen.zig+6| ... | ... | @@ -522,6 +522,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 522 | 522 | .slice => try self.airSlice(inst), |
| 523 | 523 | |
| 524 | 524 | .add_with_overflow => try self.airAddWithOverflow(inst), |
| 525 | .mul_with_overflow => try self.airMulWithOverflow(inst), | |
| 525 | 526 | |
| 526 | 527 | .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), |
| 527 | 528 | |
| ... | ... | @@ -976,6 +977,11 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 976 | 977 | return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch}); |
| 977 | 978 | } |
| 978 | 979 | |
| 980 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | |
| 981 | _ = inst; | |
| 982 | return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch}); | |
| 983 | } | |
| 984 | ||
| 979 | 985 | fn airDiv(self: *Self, inst: Air.Inst.Index) !void { |
| 980 | 986 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 981 | 987 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement div for {}", .{self.target.cpu.arch}); |
src/arch/arm/CodeGen.zig+6| ... | ... | @@ -520,6 +520,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 520 | 520 | .slice => try self.airSlice(inst), |
| 521 | 521 | |
| 522 | 522 | .add_with_overflow => try self.airAddWithOverflow(inst), |
| 523 | .mul_with_overflow => try self.airMulWithOverflow(inst), | |
| 523 | 524 | |
| 524 | 525 | .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), |
| 525 | 526 | |
| ... | ... | @@ -1006,6 +1007,11 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1006 | 1007 | return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch}); |
| 1007 | 1008 | } |
| 1008 | 1009 | |
| 1010 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | |
| 1011 | _ = inst; | |
| 1012 | return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch}); | |
| 1013 | } | |
| 1014 | ||
| 1009 | 1015 | fn airDiv(self: *Self, inst: Air.Inst.Index) !void { |
| 1010 | 1016 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1011 | 1017 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement div for {}", .{self.target.cpu.arch}); |
src/arch/riscv64/CodeGen.zig+6| ... | ... | @@ -501,6 +501,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 501 | 501 | .slice => try self.airSlice(inst), |
| 502 | 502 | |
| 503 | 503 | .add_with_overflow => try self.airAddWithOverflow(inst), |
| 504 | .mul_with_overflow => try self.airMulWithOverflow(inst), | |
| 504 | 505 | |
| 505 | 506 | .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), |
| 506 | 507 | |
| ... | ... | @@ -921,6 +922,11 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 921 | 922 | return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch}); |
| 922 | 923 | } |
| 923 | 924 | |
| 925 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | |
| 926 | _ = inst; | |
| 927 | return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch}); | |
| 928 | } | |
| 929 | ||
| 924 | 930 | fn airDiv(self: *Self, inst: Air.Inst.Index) !void { |
| 925 | 931 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 926 | 932 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement div for {}", .{self.target.cpu.arch}); |
src/arch/x86_64/CodeGen.zig+6| ... | ... | @@ -554,6 +554,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 554 | 554 | .slice => try self.airSlice(inst), |
| 555 | 555 | |
| 556 | 556 | .add_with_overflow => try self.airAddWithOverflow(inst), |
| 557 | .mul_with_overflow => try self.airMulWithOverflow(inst), | |
| 557 | 558 | |
| 558 | 559 | .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), |
| 559 | 560 | |
| ... | ... | @@ -1035,6 +1036,11 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1035 | 1036 | return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch}); |
| 1036 | 1037 | } |
| 1037 | 1038 | |
| 1039 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | |
| 1040 | _ = inst; | |
| 1041 | return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch}); | |
| 1042 | } | |
| 1043 | ||
| 1038 | 1044 | fn airDiv(self: *Self, inst: Air.Inst.Index) !void { |
| 1039 | 1045 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1040 | 1046 | const result: MCValue = if (self.liveness.isUnused(inst)) |
src/codegen/c.zig+7| ... | ... | @@ -1157,6 +1157,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 1157 | 1157 | .shl_sat => try airSatOp(f, inst, "shls_"), |
| 1158 | 1158 | |
| 1159 | 1159 | .add_with_overflow => try airAddWithOverflow(f, inst), |
| 1160 | .mul_with_overflow => try airMulWithOverflow(f, inst), | |
| 1160 | 1161 | |
| 1161 | 1162 | .min => try airMinMax(f, inst, "<"), |
| 1162 | 1163 | .max => try airMinMax(f, inst, ">"), |
| ... | ... | @@ -1873,6 +1874,12 @@ fn airAddWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1873 | 1874 | return f.fail("TODO add with overflow", .{}); |
| 1874 | 1875 | } |
| 1875 | 1876 | |
| 1877 | fn airMulWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue { | |
| 1878 | _ = f; | |
| 1879 | _ = inst; | |
| 1880 | return f.fail("TODO mul with overflow", .{}); | |
| 1881 | } | |
| 1882 | ||
| 1876 | 1883 | fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1877 | 1884 | if (f.liveness.isUnused(inst)) |
| 1878 | 1885 | return CValue.none; |
src/codegen/llvm.zig+9-6| ... | ... | @@ -1714,7 +1714,8 @@ pub const FuncGen = struct { |
| 1714 | 1714 | .max => try self.airMax(inst), |
| 1715 | 1715 | .slice => try self.airSlice(inst), |
| 1716 | 1716 | |
| 1717 | .add_with_overflow => try self.airAddWithOverflow(inst), | |
| 1717 | .add_with_overflow => try self.airOverflow(inst, "llvm.sadd.with.overflow", "llvm.uadd.with.overflow"), | |
| 1718 | .mul_with_overflow => try self.airOverflow(inst, "llvm.smul.with.overflow", "llvm.umul.with.overflow"), | |
| 1718 | 1719 | |
| 1719 | 1720 | .bit_and, .bool_and => try self.airAnd(inst), |
| 1720 | 1721 | .bit_or, .bool_or => try self.airOr(inst), |
| ... | ... | @@ -3136,7 +3137,12 @@ pub const FuncGen = struct { |
| 3136 | 3137 | } |
| 3137 | 3138 | } |
| 3138 | 3139 | |
| 3139 | fn airAddWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | |
| 3140 | fn airOverflow( | |
| 3141 | self: *FuncGen, | |
| 3142 | inst: Air.Inst.Index, | |
| 3143 | signed_intrinsic: []const u8, | |
| 3144 | unsigned_intrinsic: []const u8, | |
| 3145 | ) !?*const llvm.Value { | |
| 3140 | 3146 | if (self.liveness.isUnused(inst)) |
| 3141 | 3147 | return null; |
| 3142 | 3148 | |
| ... | ... | @@ -3150,10 +3156,7 @@ pub const FuncGen = struct { |
| 3150 | 3156 | const ptr_ty = self.air.typeOf(pl_op.operand); |
| 3151 | 3157 | const lhs_ty = self.air.typeOf(extra.lhs); |
| 3152 | 3158 | |
| 3153 | const intrinsic_name: []const u8 = if (lhs_ty.isSignedInt()) | |
| 3154 | "llvm.sadd.with.overflow" | |
| 3155 | else | |
| 3156 | "llvm.uadd.with.overflow"; | |
| 3159 | const intrinsic_name = if (lhs_ty.isSignedInt()) signed_intrinsic else unsigned_intrinsic; | |
| 3157 | 3160 | |
| 3158 | 3161 | const llvm_lhs_ty = try self.dg.llvmType(lhs_ty); |
| 3159 | 3162 |
src/print_air.zig+5-2| ... | ... | @@ -229,7 +229,10 @@ const Writer = struct { |
| 229 | 229 | .atomic_rmw => try w.writeAtomicRmw(s, inst), |
| 230 | 230 | .memcpy => try w.writeMemcpy(s, inst), |
| 231 | 231 | .memset => try w.writeMemset(s, inst), |
| 232 | .add_with_overflow => try w.writeAddWithOverflow(s, inst), | |
| 232 | ||
| 233 | .add_with_overflow, | |
| 234 | .mul_with_overflow, | |
| 235 | => try w.writeOverflow(s, inst), | |
| 233 | 236 | } |
| 234 | 237 | } |
| 235 | 238 | |
| ... | ... | @@ -350,7 +353,7 @@ const Writer = struct { |
| 350 | 353 | try s.print(", {s}, {s}", .{ @tagName(extra.op()), @tagName(extra.ordering()) }); |
| 351 | 354 | } |
| 352 | 355 | |
| 353 | fn writeAddWithOverflow(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { | |
| 356 | fn writeOverflow(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { | |
| 354 | 357 | const pl_op = w.air.instructions.items(.data)[inst].pl_op; |
| 355 | 358 | const extra = w.air.extraData(Air.Bin, pl_op.payload).data; |
| 356 | 359 |
src/value.zig+33-15| ... | ... | @@ -2130,20 +2130,13 @@ pub const Value = extern union { |
| 2130 | 2130 | return fromBigInt(arena, result_bigint.toConst()); |
| 2131 | 2131 | } |
| 2132 | 2132 | |
| 2133 | /// Supports both floats and ints; handles undefined. | |
| 2134 | pub fn numberMulWrap( | |
| 2133 | pub fn intMulWithOverflow( | |
| 2135 | 2134 | lhs: Value, |
| 2136 | 2135 | rhs: Value, |
| 2137 | 2136 | ty: Type, |
| 2138 | 2137 | arena: Allocator, |
| 2139 | 2138 | target: Target, |
| 2140 | ) !Value { | |
| 2141 | if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); | |
| 2142 | ||
| 2143 | if (ty.isAnyFloat()) { | |
| 2144 | return floatMul(lhs, rhs, ty, arena); | |
| 2145 | } | |
| 2146 | ||
| 2139 | ) !OverflowArithmeticResult { | |
| 2147 | 2140 | const info = ty.intInfo(target); |
| 2148 | 2141 | |
| 2149 | 2142 | var lhs_space: Value.BigIntSpace = undefined; |
| ... | ... | @@ -2152,16 +2145,42 @@ pub const Value = extern union { |
| 2152 | 2145 | const rhs_bigint = rhs.toBigInt(&rhs_space); |
| 2153 | 2146 | const limbs = try arena.alloc( |
| 2154 | 2147 | std.math.big.Limb, |
| 2155 | std.math.big.int.calcTwosCompLimbCount(info.bits), | |
| 2148 | lhs_bigint.limbs.len + rhs_bigint.limbs.len, | |
| 2156 | 2149 | ); |
| 2157 | 2150 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 2158 | 2151 | var limbs_buffer = try arena.alloc( |
| 2159 | 2152 | std.math.big.Limb, |
| 2160 | std.math.big.int.calcMulWrapLimbsBufferLen(info.bits, lhs_bigint.limbs.len, rhs_bigint.limbs.len, 1), | |
| 2153 | std.math.big.int.calcMulLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len, 1), | |
| 2161 | 2154 | ); |
| 2162 | defer arena.free(limbs_buffer); | |
| 2163 | result_bigint.mulWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits, limbs_buffer, arena); | |
| 2164 | return fromBigInt(arena, result_bigint.toConst()); | |
| 2155 | result_bigint.mul(lhs_bigint, rhs_bigint, limbs_buffer, arena); | |
| 2156 | ||
| 2157 | const overflowed = !result_bigint.toConst().fitsInTwosComp(info.signedness, info.bits); | |
| 2158 | if (overflowed) { | |
| 2159 | result_bigint.truncate(result_bigint.toConst(), info.signedness, info.bits); | |
| 2160 | } | |
| 2161 | ||
| 2162 | return OverflowArithmeticResult{ | |
| 2163 | .overflowed = overflowed, | |
| 2164 | .wrapped_result = try fromBigInt(arena, result_bigint.toConst()), | |
| 2165 | }; | |
| 2166 | } | |
| 2167 | ||
| 2168 | /// Supports both floats and ints; handles undefined. | |
| 2169 | pub fn numberMulWrap( | |
| 2170 | lhs: Value, | |
| 2171 | rhs: Value, | |
| 2172 | ty: Type, | |
| 2173 | arena: Allocator, | |
| 2174 | target: Target, | |
| 2175 | ) !Value { | |
| 2176 | if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); | |
| 2177 | ||
| 2178 | if (ty.isAnyFloat()) { | |
| 2179 | return floatMul(lhs, rhs, ty, arena); | |
| 2180 | } | |
| 2181 | ||
| 2182 | const overflow_result = try intMulWithOverflow(lhs, rhs, ty, arena, target); | |
| 2183 | return overflow_result.wrapped_result; | |
| 2165 | 2184 | } |
| 2166 | 2185 | |
| 2167 | 2186 | /// Supports integers only; asserts neither operand is undefined. |
| ... | ... | @@ -2194,7 +2213,6 @@ pub const Value = extern union { |
| 2194 | 2213 | std.math.big.Limb, |
| 2195 | 2214 | std.math.big.int.calcMulLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len, 1), |
| 2196 | 2215 | ); |
| 2197 | defer arena.free(limbs_buffer); | |
| 2198 | 2216 | result_bigint.mul(lhs_bigint, rhs_bigint, limbs_buffer, arena); |
| 2199 | 2217 | result_bigint.saturate(result_bigint.toConst(), info.signedness, info.bits); |
| 2200 | 2218 | return fromBigInt(arena, result_bigint.toConst()); |
test/behavior/math.zig+24| ... | ... | @@ -451,6 +451,14 @@ test "@addWithOverflow" { |
| 451 | 451 | try expect(result == 94); |
| 452 | 452 | try expect(!@addWithOverflow(u8, 100, 150, &result)); |
| 453 | 453 | try expect(result == 250); |
| 454 | ||
| 455 | var a: u8 = 200; | |
| 456 | var b: u8 = 99; | |
| 457 | try expect(@addWithOverflow(u8, a, b, &result)); | |
| 458 | try expect(result == 43); | |
| 459 | b = 55; | |
| 460 | try expect(!@addWithOverflow(u8, a, b, &result)); | |
| 461 | try expect(result == 255); | |
| 454 | 462 | } |
| 455 | 463 | |
| 456 | 464 | test "small int addition" { |
| ... | ... | @@ -471,3 +479,19 @@ test "small int addition" { |
| 471 | 479 | |
| 472 | 480 | try expect(result == 0); |
| 473 | 481 | } |
| 482 | ||
| 483 | test "@mulWithOverflow" { | |
| 484 | var result: u8 = undefined; | |
| 485 | try expect(@mulWithOverflow(u8, 86, 3, &result)); | |
| 486 | try expect(result == 2); | |
| 487 | try expect(!@mulWithOverflow(u8, 85, 3, &result)); | |
| 488 | try expect(result == 255); | |
| 489 | ||
| 490 | var a: u8 = 123; | |
| 491 | var b: u8 = 2; | |
| 492 | try expect(!@mulWithOverflow(u8, a, b, &result)); | |
| 493 | try expect(result == 246); | |
| 494 | b = 4; | |
| 495 | try expect(@mulWithOverflow(u8, a, b, &result)); | |
| 496 | try expect(result == 236); | |
| 497 | } |
test/behavior/math_stage1.zig-8| ... | ... | @@ -6,14 +6,6 @@ const maxInt = std.math.maxInt; |
| 6 | 6 | const minInt = std.math.minInt; |
| 7 | 7 | const mem = std.mem; |
| 8 | 8 | |
| 9 | test "@mulWithOverflow" { | |
| 10 | var result: u8 = undefined; | |
| 11 | try expect(@mulWithOverflow(u8, 86, 3, &result)); | |
| 12 | try expect(result == 2); | |
| 13 | try expect(!@mulWithOverflow(u8, 85, 3, &result)); | |
| 14 | try expect(result == 255); | |
| 15 | } | |
| 16 | ||
| 17 | 9 | test "@subWithOverflow" { |
| 18 | 10 | var result: u8 = undefined; |
| 19 | 11 | try expect(@subWithOverflow(u8, 1, 2, &result)); |