Commit 51a40f9a66

Andrew Kelley <andrew@ziglang.org>
2021-09-29 05:27:28
saturating arithmetic supports integers only
1 parent cf90cb7
src/Air.zig
@@ -130,7 +130,7 @@ pub const Inst = struct {
         /// it shifts out any bits that disagree with the resultant sign bit.
         /// Uses the `bin_op` field.
         shl_exact,
-        /// Shift left saturating. `<<|`
+        /// Saturating integer shift left. `<<|`
         /// Uses the `bin_op` field.
         shl_sat,
         /// Bitwise XOR. `^`
src/Sema.zig
@@ -6380,7 +6380,7 @@ fn analyzeArithmetic(
                 } else break :rs .{ .src = rhs_src, .air_tag = .addwrap };
             },
             .add_sat => {
-                // For both integers and floats:
+                // Integers only; floats are checked above.
                 // If either of the operands are zero, then the other operand is returned.
                 // If either of the operands are undefined, the result is undefined.
                 if (maybe_lhs_val) |lhs_val| {
@@ -6398,7 +6398,7 @@ fn analyzeArithmetic(
                     if (maybe_lhs_val) |lhs_val| {
                         return sema.addConstant(
                             scalar_type,
-                            try lhs_val.numberAddSat(rhs_val, scalar_type, sema.arena, target),
+                            try lhs_val.intAddSat(rhs_val, scalar_type, sema.arena, target),
                         );
                     } else break :rs .{ .src = lhs_src, .air_tag = .add_sat };
                 } else break :rs .{ .src = rhs_src, .air_tag = .add_sat };
@@ -6471,7 +6471,7 @@ fn analyzeArithmetic(
                 } else break :rs .{ .src = lhs_src, .air_tag = .subwrap };
             },
             .sub_sat => {
-                // For both integers and floats:
+                // Integers only; floats are checked above.
                 // If the RHS is zero, result is LHS.
                 // If either of the operands are undefined, result is undefined.
                 if (maybe_rhs_val) |rhs_val| {
@@ -6489,7 +6489,7 @@ fn analyzeArithmetic(
                     if (maybe_rhs_val) |rhs_val| {
                         return sema.addConstant(
                             scalar_type,
-                            try lhs_val.numberSubSat(rhs_val, scalar_type, sema.arena, target),
+                            try lhs_val.intSubSat(rhs_val, scalar_type, sema.arena, target),
                         );
                     } else break :rs .{ .src = rhs_src, .air_tag = .sub_sat };
                 } else break :rs .{ .src = lhs_src, .air_tag = .sub_sat };
@@ -6647,7 +6647,7 @@ fn analyzeArithmetic(
                 } else break :rs .{ .src = rhs_src, .air_tag = .mulwrap };
             },
             .mul_sat => {
-                // For both integers and floats:
+                // Integers only; floats are checked above.
                 // If either of the operands are zero, result is zero.
                 // If either of the operands are one, result is the other operand.
                 // If either of the operands are undefined, result is undefined.
@@ -6677,7 +6677,7 @@ fn analyzeArithmetic(
                         }
                         return sema.addConstant(
                             scalar_type,
-                            try lhs_val.numberMulSat(rhs_val, scalar_type, sema.arena, target),
+                            try lhs_val.intMulSat(rhs_val, scalar_type, sema.arena, target),
                         );
                     } else break :rs .{ .src = lhs_src, .air_tag = .mul_sat };
                 } else break :rs .{ .src = rhs_src, .air_tag = .mul_sat };
@@ -7931,7 +7931,7 @@ fn analyzeRet(
 fn floatOpAllowed(tag: Zir.Inst.Tag) bool {
     // extend this swich as additional operators are implemented
     return switch (tag) {
-        .add, .add_sat, .sub, .sub_sat, .mul, .mul_sat, .div, .mod, .rem, .mod_rem => true,
+        .add, .sub, .mul, .div, .mod, .rem, .mod_rem => true,
         else => false,
     };
 }
src/value.zig
@@ -1588,20 +1588,17 @@ pub const Value = extern union {
         return result;
     }
 
-    /// Supports both floats and ints; handles undefined.
-    pub fn numberAddSat(
+    /// Supports integers only; asserts neither operand is undefined.
+    pub fn intAddSat(
         lhs: Value,
         rhs: Value,
         ty: Type,
         arena: *Allocator,
         target: Target,
     ) !Value {
-        if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
+        assert(!lhs.isUndef());
+        assert(!rhs.isUndef());
 
-        if (ty.isAnyFloat()) {
-            // TODO: handle outside float range
-            return floatAdd(lhs, rhs, ty, arena);
-        }
         const result = try intAdd(lhs, rhs, arena);
 
         const max = try ty.maxInt(arena, target);
@@ -1645,20 +1642,17 @@ pub const Value = extern union {
         return result;
     }
 
-    /// Supports both floats and ints; handles undefined.
-    pub fn numberSubSat(
+    /// Supports integers only; asserts neither operand is undefined.
+    pub fn intSubSat(
         lhs: Value,
         rhs: Value,
         ty: Type,
         arena: *Allocator,
         target: Target,
     ) !Value {
-        if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
+        assert(!lhs.isUndef());
+        assert(!rhs.isUndef());
 
-        if (ty.isAnyFloat()) {
-            // TODO: handle outside float range
-            return floatSub(lhs, rhs, ty, arena);
-        }
         const result = try intSub(lhs, rhs, arena);
 
         const max = try ty.maxInt(arena, target);
@@ -1702,20 +1696,17 @@ pub const Value = extern union {
         return result;
     }
 
-    /// Supports both floats and ints; handles undefined.
-    pub fn numberMulSat(
+    /// Supports integers only; asserts neither operand is undefined.
+    pub fn intMulSat(
         lhs: Value,
         rhs: Value,
         ty: Type,
         arena: *Allocator,
         target: Target,
     ) !Value {
-        if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
+        assert(!lhs.isUndef());
+        assert(!rhs.isUndef());
 
-        if (ty.isAnyFloat()) {
-            // TODO: handle outside float range
-            return floatMul(lhs, rhs, ty, arena);
-        }
         const result = try intMul(lhs, rhs, arena);
 
         const max = try ty.maxInt(arena, target);
test/compile_errors.zig
@@ -8859,9 +8859,9 @@ pub fn addCases(ctx: *TestContext) !void {
         "tmp.zig:3:12: note: crosses namespace boundary here",
     });
 
-    ctx.objErrStage1("Issue #9619: saturating arithmetic builtins should fail to compile when given floats",
+    ctx.objErrStage1("saturating arithmetic does not allow floats",
         \\pub fn main() !void {
-        \\    _ = @addWithSaturation(@as(f32, 1.0), @as(f32, 1.0));
+        \\    _ = @as(f32, 1.0) +| @as(f32, 1.0);
         \\}
     , &[_][]const u8{
         "error: invalid operands to binary expression: 'f32' and 'f32'",