diff --git a/src/Air.zig b/src/Air.zig index f05c18e87a997bffbbde0b5e88d6fcc46c11f968..cdc5ff22874a9f49eb14d9bbb9575882947f2105 100644 --- a/src/Air.zig +++ b/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. `^` diff --git a/src/Sema.zig b/src/Sema.zig index f106d7ea9e387347913bb47cc86bedb60f816420..0fb93f3fbed66d87e7e9539ae5036e60a4ea1169 100644 --- a/src/Sema.zig +++ b/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, }; } diff --git a/src/value.zig b/src/value.zig index 73a2b3a49f0cc090cb18f7ed883427898ec6d38e..0ead2ff1d9367cc1cc7b1f64fda082baf6bd0b7f 100644 --- a/src/value.zig +++ b/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); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 0e59b0523fd1998d298366380b089eeb4cc1944a..4acd563da9719c4e20b9abdd1fe6295b51865925 100644 --- a/test/compile_errors.zig +++ b/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'",