Commit cc8e49283d

LemonBoy <thatlemon@gmail.com>
2021-04-23 19:15:52
stage1: Allow wrapping negation on unsigned ints at comptime
Closes #7951 Closes #8574
1 parent 41efdc7
Changed files (4)
src
test
stage1
behavior
src/stage1/bigint.cpp
@@ -1446,10 +1446,10 @@ void bigint_negate(BigInt *dest, const BigInt *op) {
     bigint_normalize(dest);
 }
 
-void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count) {
+void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed) {
     BigInt zero;
     bigint_init_unsigned(&zero, 0);
-    bigint_sub_wrap(dest, &zero, op, bit_count, true);
+    bigint_sub_wrap(dest, &zero, op, bit_count, is_signed);
 }
 
 void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed) {
src/stage1/bigint.hpp
@@ -75,7 +75,7 @@ void bigint_shl_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t
 void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2);
 
 void bigint_negate(BigInt *dest, const BigInt *op);
-void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count);
+void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed);
 void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed);
 void bigint_truncate(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed);
 
src/stage1/ir.cpp
@@ -21660,8 +21660,8 @@ static ErrorMsg *ir_eval_negation_scalar(IrAnalyze *ira, IrInst* source_instr, Z
 {
     bool is_float = (scalar_type->id == ZigTypeIdFloat || scalar_type->id == ZigTypeIdComptimeFloat);
 
-    bool ok_type = ((scalar_type->id == ZigTypeIdInt && scalar_type->data.integral.is_signed) ||
-        scalar_type->id == ZigTypeIdComptimeInt || (is_float && !is_wrap_op));
+    bool ok_type = scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdComptimeInt ||
+            (is_float && !is_wrap_op);
 
     if (!ok_type) {
         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
         float_negate(scalar_out_val, operand_val);
     } else if (is_wrap_op) {
         bigint_negate_wrap(&scalar_out_val->data.x_bigint, &operand_val->data.x_bigint,
-                scalar_type->data.integral.bit_count);
+                scalar_type->data.integral.bit_count, scalar_type->data.integral.is_signed);
     } else {
         bigint_negate(&scalar_out_val->data.x_bigint, &operand_val->data.x_bigint);
     }
test/stage1/behavior/math.zig
@@ -229,16 +229,26 @@ fn testSignedWrappingEval(x: i32) void {
     expect(max_val == maxInt(i32));
 }
 
-test "negation wrapping" {
-    testNegationWrappingEval(minInt(i16));
-    comptime testNegationWrappingEval(minInt(i16));
+test "signed negation wrapping" {
+    testSignedNegationWrappingEval(minInt(i16));
+    comptime testSignedNegationWrappingEval(minInt(i16));
 }
-fn testNegationWrappingEval(x: i16) void {
+fn testSignedNegationWrappingEval(x: i16) void {
     expect(x == -32768);
     const neg = -%x;
     expect(neg == -32768);
 }
 
+test "unsigned negation wrapping" {
+    testUnsignedNegationWrappingEval(1);
+    comptime testUnsignedNegationWrappingEval(1);
+}
+fn testUnsignedNegationWrappingEval(x: u16) void {
+    expect(x == 1);
+    const neg = -%x;
+    expect(neg == maxInt(u16));
+}
+
 test "unsigned 64-bit division" {
     test_u64_div();
     comptime test_u64_div();