authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-28 20:27:28-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-28 20:27:28-07:00
log51a40f9a666085b53353f65f017bcf9bf18daaa3
tree64b9886e75ebaf65e59d66b218c411b15c677561
parentcf90cb7218d1baa56586477bab50e88fdb6be0bb

saturating arithmetic supports integers only


4 files changed, 22 insertions(+), 31 deletions(-)

src/Air.zig+1-1
......@@ -130,7 +130,7 @@ pub const Inst = struct {
130130 /// it shifts out any bits that disagree with the resultant sign bit.
131131 /// Uses the `bin_op` field.
132132 shl_exact,
133 /// Shift left saturating. `<<|`
133 /// Saturating integer shift left. `<<|`
134134 /// Uses the `bin_op` field.
135135 shl_sat,
136136 /// Bitwise XOR. `^`
src/Sema.zig+7-7
......@@ -6380,7 +6380,7 @@ fn analyzeArithmetic(
63806380 } else break :rs .{ .src = rhs_src, .air_tag = .addwrap };
63816381 },
63826382 .add_sat => {
6383 // For both integers and floats:
6383 // Integers only; floats are checked above.
63846384 // If either of the operands are zero, then the other operand is returned.
63856385 // If either of the operands are undefined, the result is undefined.
63866386 if (maybe_lhs_val) |lhs_val| {
......@@ -6398,7 +6398,7 @@ fn analyzeArithmetic(
63986398 if (maybe_lhs_val) |lhs_val| {
63996399 return sema.addConstant(
64006400 scalar_type,
6401 try lhs_val.numberAddSat(rhs_val, scalar_type, sema.arena, target),
6401 try lhs_val.intAddSat(rhs_val, scalar_type, sema.arena, target),
64026402 );
64036403 } else break :rs .{ .src = lhs_src, .air_tag = .add_sat };
64046404 } else break :rs .{ .src = rhs_src, .air_tag = .add_sat };
......@@ -6471,7 +6471,7 @@ fn analyzeArithmetic(
64716471 } else break :rs .{ .src = lhs_src, .air_tag = .subwrap };
64726472 },
64736473 .sub_sat => {
6474 // For both integers and floats:
6474 // Integers only; floats are checked above.
64756475 // If the RHS is zero, result is LHS.
64766476 // If either of the operands are undefined, result is undefined.
64776477 if (maybe_rhs_val) |rhs_val| {
......@@ -6489,7 +6489,7 @@ fn analyzeArithmetic(
64896489 if (maybe_rhs_val) |rhs_val| {
64906490 return sema.addConstant(
64916491 scalar_type,
6492 try lhs_val.numberSubSat(rhs_val, scalar_type, sema.arena, target),
6492 try lhs_val.intSubSat(rhs_val, scalar_type, sema.arena, target),
64936493 );
64946494 } else break :rs .{ .src = rhs_src, .air_tag = .sub_sat };
64956495 } else break :rs .{ .src = lhs_src, .air_tag = .sub_sat };
......@@ -6647,7 +6647,7 @@ fn analyzeArithmetic(
66476647 } else break :rs .{ .src = rhs_src, .air_tag = .mulwrap };
66486648 },
66496649 .mul_sat => {
6650 // For both integers and floats:
6650 // Integers only; floats are checked above.
66516651 // If either of the operands are zero, result is zero.
66526652 // If either of the operands are one, result is the other operand.
66536653 // If either of the operands are undefined, result is undefined.
......@@ -6677,7 +6677,7 @@ fn analyzeArithmetic(
66776677 }
66786678 return sema.addConstant(
66796679 scalar_type,
6680 try lhs_val.numberMulSat(rhs_val, scalar_type, sema.arena, target),
6680 try lhs_val.intMulSat(rhs_val, scalar_type, sema.arena, target),
66816681 );
66826682 } else break :rs .{ .src = lhs_src, .air_tag = .mul_sat };
66836683 } else break :rs .{ .src = rhs_src, .air_tag = .mul_sat };
......@@ -7931,7 +7931,7 @@ fn analyzeRet(
79317931fn floatOpAllowed(tag: Zir.Inst.Tag) bool {
79327932 // extend this swich as additional operators are implemented
79337933 return switch (tag) {
7934 .add, .add_sat, .sub, .sub_sat, .mul, .mul_sat, .div, .mod, .rem, .mod_rem => true,
7934 .add, .sub, .mul, .div, .mod, .rem, .mod_rem => true,
79357935 else => false,
79367936 };
79377937}
src/value.zig+12-21
......@@ -1588,20 +1588,17 @@ pub const Value = extern union {
15881588 return result;
15891589 }
15901590
1591 /// Supports both floats and ints; handles undefined.
1592 pub fn numberAddSat(
1591 /// Supports integers only; asserts neither operand is undefined.
1592 pub fn intAddSat(
15931593 lhs: Value,
15941594 rhs: Value,
15951595 ty: Type,
15961596 arena: *Allocator,
15971597 target: Target,
15981598 ) !Value {
1599 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
1599 assert(!lhs.isUndef());
1600 assert(!rhs.isUndef());
16001601
1601 if (ty.isAnyFloat()) {
1602 // TODO: handle outside float range
1603 return floatAdd(lhs, rhs, ty, arena);
1604 }
16051602 const result = try intAdd(lhs, rhs, arena);
16061603
16071604 const max = try ty.maxInt(arena, target);
......@@ -1645,20 +1642,17 @@ pub const Value = extern union {
16451642 return result;
16461643 }
16471644
1648 /// Supports both floats and ints; handles undefined.
1649 pub fn numberSubSat(
1645 /// Supports integers only; asserts neither operand is undefined.
1646 pub fn intSubSat(
16501647 lhs: Value,
16511648 rhs: Value,
16521649 ty: Type,
16531650 arena: *Allocator,
16541651 target: Target,
16551652 ) !Value {
1656 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
1653 assert(!lhs.isUndef());
1654 assert(!rhs.isUndef());
16571655
1658 if (ty.isAnyFloat()) {
1659 // TODO: handle outside float range
1660 return floatSub(lhs, rhs, ty, arena);
1661 }
16621656 const result = try intSub(lhs, rhs, arena);
16631657
16641658 const max = try ty.maxInt(arena, target);
......@@ -1702,20 +1696,17 @@ pub const Value = extern union {
17021696 return result;
17031697 }
17041698
1705 /// Supports both floats and ints; handles undefined.
1706 pub fn numberMulSat(
1699 /// Supports integers only; asserts neither operand is undefined.
1700 pub fn intMulSat(
17071701 lhs: Value,
17081702 rhs: Value,
17091703 ty: Type,
17101704 arena: *Allocator,
17111705 target: Target,
17121706 ) !Value {
1713 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
1707 assert(!lhs.isUndef());
1708 assert(!rhs.isUndef());
17141709
1715 if (ty.isAnyFloat()) {
1716 // TODO: handle outside float range
1717 return floatMul(lhs, rhs, ty, arena);
1718 }
17191710 const result = try intMul(lhs, rhs, arena);
17201711
17211712 const max = try ty.maxInt(arena, target);
test/compile_errors.zig+2-2
......@@ -8859,9 +8859,9 @@ pub fn addCases(ctx: *TestContext) !void {
88598859 "tmp.zig:3:12: note: crosses namespace boundary here",
88608860 });
88618861
8862 ctx.objErrStage1("Issue #9619: saturating arithmetic builtins should fail to compile when given floats",
8862 ctx.objErrStage1("saturating arithmetic does not allow floats",
88638863 \\pub fn main() !void {
8864 \\ _ = @addWithSaturation(@as(f32, 1.0), @as(f32, 1.0));
8864 \\ _ = @as(f32, 1.0) +| @as(f32, 1.0);
88658865 \\}
88668866 , &[_][]const u8{
88678867 "error: invalid operands to binary expression: 'f32' and 'f32'",