mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
saturating arithmetic supports integers only
This commit is contained in:
parent
cf90cb7218
commit
51a40f9a66
4 changed files with 22 additions and 31 deletions
|
|
@ -130,7 +130,7 @@ pub const Inst = struct {
|
||||||
/// it shifts out any bits that disagree with the resultant sign bit.
|
/// it shifts out any bits that disagree with the resultant sign bit.
|
||||||
/// Uses the `bin_op` field.
|
/// Uses the `bin_op` field.
|
||||||
shl_exact,
|
shl_exact,
|
||||||
/// Shift left saturating. `<<|`
|
/// Saturating integer shift left. `<<|`
|
||||||
/// Uses the `bin_op` field.
|
/// Uses the `bin_op` field.
|
||||||
shl_sat,
|
shl_sat,
|
||||||
/// Bitwise XOR. `^`
|
/// Bitwise XOR. `^`
|
||||||
|
|
|
||||||
14
src/Sema.zig
14
src/Sema.zig
|
|
@ -6380,7 +6380,7 @@ fn analyzeArithmetic(
|
||||||
} else break :rs .{ .src = rhs_src, .air_tag = .addwrap };
|
} else break :rs .{ .src = rhs_src, .air_tag = .addwrap };
|
||||||
},
|
},
|
||||||
.add_sat => {
|
.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 zero, then the other operand is returned.
|
||||||
// If either of the operands are undefined, the result is undefined.
|
// If either of the operands are undefined, the result is undefined.
|
||||||
if (maybe_lhs_val) |lhs_val| {
|
if (maybe_lhs_val) |lhs_val| {
|
||||||
|
|
@ -6398,7 +6398,7 @@ fn analyzeArithmetic(
|
||||||
if (maybe_lhs_val) |lhs_val| {
|
if (maybe_lhs_val) |lhs_val| {
|
||||||
return sema.addConstant(
|
return sema.addConstant(
|
||||||
scalar_type,
|
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 = lhs_src, .air_tag = .add_sat };
|
||||||
} else break :rs .{ .src = rhs_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 };
|
} else break :rs .{ .src = lhs_src, .air_tag = .subwrap };
|
||||||
},
|
},
|
||||||
.sub_sat => {
|
.sub_sat => {
|
||||||
// For both integers and floats:
|
// Integers only; floats are checked above.
|
||||||
// If the RHS is zero, result is LHS.
|
// If the RHS is zero, result is LHS.
|
||||||
// If either of the operands are undefined, result is undefined.
|
// If either of the operands are undefined, result is undefined.
|
||||||
if (maybe_rhs_val) |rhs_val| {
|
if (maybe_rhs_val) |rhs_val| {
|
||||||
|
|
@ -6489,7 +6489,7 @@ fn analyzeArithmetic(
|
||||||
if (maybe_rhs_val) |rhs_val| {
|
if (maybe_rhs_val) |rhs_val| {
|
||||||
return sema.addConstant(
|
return sema.addConstant(
|
||||||
scalar_type,
|
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 = rhs_src, .air_tag = .sub_sat };
|
||||||
} else break :rs .{ .src = lhs_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 };
|
} else break :rs .{ .src = rhs_src, .air_tag = .mulwrap };
|
||||||
},
|
},
|
||||||
.mul_sat => {
|
.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 zero, result is zero.
|
||||||
// If either of the operands are one, result is the other operand.
|
// If either of the operands are one, result is the other operand.
|
||||||
// If either of the operands are undefined, result is undefined.
|
// If either of the operands are undefined, result is undefined.
|
||||||
|
|
@ -6677,7 +6677,7 @@ fn analyzeArithmetic(
|
||||||
}
|
}
|
||||||
return sema.addConstant(
|
return sema.addConstant(
|
||||||
scalar_type,
|
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 = lhs_src, .air_tag = .mul_sat };
|
||||||
} else break :rs .{ .src = rhs_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 {
|
fn floatOpAllowed(tag: Zir.Inst.Tag) bool {
|
||||||
// extend this swich as additional operators are implemented
|
// extend this swich as additional operators are implemented
|
||||||
return switch (tag) {
|
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,
|
else => false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1588,20 +1588,17 @@ pub const Value = extern union {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Supports both floats and ints; handles undefined.
|
/// Supports integers only; asserts neither operand is undefined.
|
||||||
pub fn numberAddSat(
|
pub fn intAddSat(
|
||||||
lhs: Value,
|
lhs: Value,
|
||||||
rhs: Value,
|
rhs: Value,
|
||||||
ty: Type,
|
ty: Type,
|
||||||
arena: *Allocator,
|
arena: *Allocator,
|
||||||
target: Target,
|
target: Target,
|
||||||
) !Value {
|
) !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 result = try intAdd(lhs, rhs, arena);
|
||||||
|
|
||||||
const max = try ty.maxInt(arena, target);
|
const max = try ty.maxInt(arena, target);
|
||||||
|
|
@ -1645,20 +1642,17 @@ pub const Value = extern union {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Supports both floats and ints; handles undefined.
|
/// Supports integers only; asserts neither operand is undefined.
|
||||||
pub fn numberSubSat(
|
pub fn intSubSat(
|
||||||
lhs: Value,
|
lhs: Value,
|
||||||
rhs: Value,
|
rhs: Value,
|
||||||
ty: Type,
|
ty: Type,
|
||||||
arena: *Allocator,
|
arena: *Allocator,
|
||||||
target: Target,
|
target: Target,
|
||||||
) !Value {
|
) !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 result = try intSub(lhs, rhs, arena);
|
||||||
|
|
||||||
const max = try ty.maxInt(arena, target);
|
const max = try ty.maxInt(arena, target);
|
||||||
|
|
@ -1702,20 +1696,17 @@ pub const Value = extern union {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Supports both floats and ints; handles undefined.
|
/// Supports integers only; asserts neither operand is undefined.
|
||||||
pub fn numberMulSat(
|
pub fn intMulSat(
|
||||||
lhs: Value,
|
lhs: Value,
|
||||||
rhs: Value,
|
rhs: Value,
|
||||||
ty: Type,
|
ty: Type,
|
||||||
arena: *Allocator,
|
arena: *Allocator,
|
||||||
target: Target,
|
target: Target,
|
||||||
) !Value {
|
) !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 result = try intMul(lhs, rhs, arena);
|
||||||
|
|
||||||
const max = try ty.maxInt(arena, target);
|
const max = try ty.maxInt(arena, target);
|
||||||
|
|
|
||||||
|
|
@ -8859,9 +8859,9 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||||
"tmp.zig:3:12: note: crosses namespace boundary here",
|
"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 {
|
\\pub fn main() !void {
|
||||||
\\ _ = @addWithSaturation(@as(f32, 1.0), @as(f32, 1.0));
|
\\ _ = @as(f32, 1.0) +| @as(f32, 1.0);
|
||||||
\\}
|
\\}
|
||||||
, &[_][]const u8{
|
, &[_][]const u8{
|
||||||
"error: invalid operands to binary expression: 'f32' and 'f32'",
|
"error: invalid operands to binary expression: 'f32' and 'f32'",
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue