| author | |
| committer | |
| log | a279f18bce488460f87f41545411fc964dcaa4b0 |
| tree | a8680bac63d2812ab764fe5ee4d49f60d08e0d30 |
| parent | e86a1df9f23386cc315ac8055ecfe7a6465c5ee3 |
| parent | 9ac5f9820086f6760df321b0a1ffc60ec92c8ad8 |
| signature |
stage1: Allow wrapping negation on unsigned ints at comptime5 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 | } |
| 1351 | 1351 | ||
| 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 | } |
| 1363 | 1354 |
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 | } |
| 1448 | 1448 | ||
| 1449 | void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count) { | 1449 | void 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 | } |
| 1454 | 1454 | ||
| 1455 | void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed) { | 1455 | void 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 |
| 75 | void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2); | 75 | void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2); |
| 76 | 76 | ||
| 77 | void bigint_negate(BigInt *dest, const BigInt *op); | 77 | void bigint_negate(BigInt *dest, const BigInt *op); |
| 78 | void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count); | 78 | void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed); |
| 79 | void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed); | 79 | void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed); |
| 80 | void bigint_truncate(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed); | 80 | void bigint_truncate(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed); |
| 81 | 81 |
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); |
| 21662 | 21662 | ||
| 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); |
| 21665 | 21665 | ||
| 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 | } |
| 231 | 231 | ||
| 232 | test "negation wrapping" { | 232 | test "signed negation wrapping" { |
| 233 | testNegationWrappingEval(minInt(i16)); | 233 | testSignedNegationWrappingEval(minInt(i16)); |
| 234 | comptime testNegationWrappingEval(minInt(i16)); | 234 | comptime testSignedNegationWrappingEval(minInt(i16)); |
| 235 | } | 235 | } |
| 236 | fn testNegationWrappingEval(x: i16) void { | 236 | fn 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 | } |
| 241 | 241 | ||
| 242 | test "unsigned negation wrapping" { | ||
| 243 | testUnsignedNegationWrappingEval(1); | ||
| 244 | comptime testUnsignedNegationWrappingEval(1); | ||
| 245 | } | ||
| 246 | fn testUnsignedNegationWrappingEval(x: u16) void { | ||
| 247 | expect(x == 1); | ||
| 248 | const neg = -%x; | ||
| 249 | expect(neg == maxInt(u16)); | ||
| 250 | } | ||
| 251 | |||
| 242 | test "unsigned 64-bit division" { | 252 | test "unsigned 64-bit division" { |
| 243 | test_u64_div(); | 253 | test_u64_div(); |
| 244 | comptime test_u64_div(); | 254 | comptime test_u64_div(); |