authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-23 16:59:01-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-04-23 16:59:01-04:00
loga279f18bce488460f87f41545411fc964dcaa4b0
treea8680bac63d2812ab764fe5ee4d49f60d08e0d30
parente86a1df9f23386cc315ac8055ecfe7a6465c5ee3
parent9ac5f9820086f6760df321b0a1ffc60ec92c8ad8
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #8599 from LemonBoy/unsigned-neg

stage1: Allow wrapping negation on unsigned ints at comptime

5 files changed, 20 insertions(+), 19 deletions(-)

lib/std/math.zig-9
...@@ -1349,15 +1349,6 @@ pub fn boolMask(comptime MaskInt: type, value: bool) callconv(.Inline) MaskInt {...@@ -1349,15 +1349,6 @@ pub fn boolMask(comptime MaskInt: type, value: bool) callconv(.Inline) MaskInt {
1349 return @bitCast(i1, @as(u1, @boolToInt(value)));1349 return @bitCast(i1, @as(u1, @boolToInt(value)));
1350 }1350 }
13511351
1352 // At comptime, -% is disallowed on unsigned values.
1353 // So we need to jump through some hoops in that case.
1354 // This is a workaround for #7951
1355 if (@typeInfo(@TypeOf(.{value})).Struct.fields[0].is_comptime) {
1356 // Since it's comptime, we don't need this to generate nice code.
1357 // We can just do a branch here.
1358 return if (value) ~@as(MaskInt, 0) else 0;
1359 }
1360
1361 return -%@intCast(MaskInt, @boolToInt(value));1352 return -%@intCast(MaskInt, @boolToInt(value));
1362}1353}
13631354
src/stage1/bigint.cpp+2-2
...@@ -1446,10 +1446,10 @@ void bigint_negate(BigInt *dest, const BigInt *op) {...@@ -1446,10 +1446,10 @@ void bigint_negate(BigInt *dest, const BigInt *op) {
1446 bigint_normalize(dest);1446 bigint_normalize(dest);
1447}1447}
14481448
1449void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count) {1449void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed) {
1450 BigInt zero;1450 BigInt zero;
1451 bigint_init_unsigned(&zero, 0);1451 bigint_init_unsigned(&zero, 0);
1452 bigint_sub_wrap(dest, &zero, op, bit_count, true);1452 bigint_sub_wrap(dest, &zero, op, bit_count, is_signed);
1453}1453}
14541454
1455void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed) {1455void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed) {
src/stage1/bigint.hpp+1-1
...@@ -75,7 +75,7 @@ void bigint_shl_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t...@@ -75,7 +75,7 @@ void bigint_shl_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t
75void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2);75void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2);
7676
77void bigint_negate(BigInt *dest, const BigInt *op);77void bigint_negate(BigInt *dest, const BigInt *op);
78void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count);78void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed);
79void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed);79void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed);
80void bigint_truncate(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed);80void bigint_truncate(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed);
8181
src/stage1/ir.cpp+3-3
...@@ -21660,8 +21660,8 @@ static ErrorMsg *ir_eval_negation_scalar(IrAnalyze *ira, IrInst* source_instr, Z...@@ -21660,8 +21660,8 @@ static ErrorMsg *ir_eval_negation_scalar(IrAnalyze *ira, IrInst* source_instr, Z
21660{21660{
21661 bool is_float = (scalar_type->id == ZigTypeIdFloat || scalar_type->id == ZigTypeIdComptimeFloat);21661 bool is_float = (scalar_type->id == ZigTypeIdFloat || scalar_type->id == ZigTypeIdComptimeFloat);
2166221662
21663 bool ok_type = ((scalar_type->id == ZigTypeIdInt && scalar_type->data.integral.is_signed) ||21663 bool ok_type = scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdComptimeInt ||
21664 scalar_type->id == ZigTypeIdComptimeInt || (is_float && !is_wrap_op));21664 (is_float && !is_wrap_op);
2166521665
21666 if (!ok_type) {21666 if (!ok_type) {
21667 const char *fmt = is_wrap_op ? "invalid wrapping negation type: '%s'" : "invalid negation type: '%s'";21667 const char *fmt = is_wrap_op ? "invalid wrapping negation type: '%s'" : "invalid negation type: '%s'";
...@@ -21672,7 +21672,7 @@ static ErrorMsg *ir_eval_negation_scalar(IrAnalyze *ira, IrInst* source_instr, Z...@@ -21672,7 +21672,7 @@ static ErrorMsg *ir_eval_negation_scalar(IrAnalyze *ira, IrInst* source_instr, Z
21672 float_negate(scalar_out_val, operand_val);21672 float_negate(scalar_out_val, operand_val);
21673 } else if (is_wrap_op) {21673 } else if (is_wrap_op) {
21674 bigint_negate_wrap(&scalar_out_val->data.x_bigint, &operand_val->data.x_bigint,21674 bigint_negate_wrap(&scalar_out_val->data.x_bigint, &operand_val->data.x_bigint,
21675 scalar_type->data.integral.bit_count);21675 scalar_type->data.integral.bit_count, scalar_type->data.integral.is_signed);
21676 } else {21676 } else {
21677 bigint_negate(&scalar_out_val->data.x_bigint, &operand_val->data.x_bigint);21677 bigint_negate(&scalar_out_val->data.x_bigint, &operand_val->data.x_bigint);
21678 }21678 }
test/stage1/behavior/math.zig+14-4
...@@ -229,16 +229,26 @@ fn testSignedWrappingEval(x: i32) void {...@@ -229,16 +229,26 @@ fn testSignedWrappingEval(x: i32) void {
229 expect(max_val == maxInt(i32));229 expect(max_val == maxInt(i32));
230}230}
231231
232test "negation wrapping" {232test "signed negation wrapping" {
233 testNegationWrappingEval(minInt(i16));233 testSignedNegationWrappingEval(minInt(i16));
234 comptime testNegationWrappingEval(minInt(i16));234 comptime testSignedNegationWrappingEval(minInt(i16));
235}235}
236fn testNegationWrappingEval(x: i16) void {236fn testSignedNegationWrappingEval(x: i16) void {
237 expect(x == -32768);237 expect(x == -32768);
238 const neg = -%x;238 const neg = -%x;
239 expect(neg == -32768);239 expect(neg == -32768);
240}240}
241241
242test "unsigned negation wrapping" {
243 testUnsignedNegationWrappingEval(1);
244 comptime testUnsignedNegationWrappingEval(1);
245}
246fn testUnsignedNegationWrappingEval(x: u16) void {
247 expect(x == 1);
248 const neg = -%x;
249 expect(neg == maxInt(u16));
250}
251
242test "unsigned 64-bit division" {252test "unsigned 64-bit division" {
243 test_u64_div();253 test_u64_div();
244 comptime test_u64_div();254 comptime test_u64_div();