authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-05-06 19:23:21-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-05-06 19:23:21-07:00
log6131b3716322d60cf26f7aad1a654dc6c4414051
tree4074ccc95115627bd87d319880526c5278fe7e09
parent9db45ac36230c80c68af7b66827b6c73fc96c147

fix eval integer wrapping and add tests

See #46

5 files changed, 269 insertions(+), 98 deletions(-)

src/analyze.cpp+16-8
......@@ -105,11 +105,25 @@ static AstNode *first_executing_node(AstNode *node) {
105105 zig_unreachable();
106106}
107107
108static void mark_impure_fn(BlockContext *context) {
109 if (context->fn_entry) {
110 context->fn_entry->is_pure = false;
111 }
112}
113
108114ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
109115 // if this assert fails, then parseh generated code that
110116 // failed semantic analysis, which isn't supposed to happen
111117 assert(!node->owner->c_import_node);
112118
119 // if an error occurs in a function then it becomes impure
120 if (node->block_context) {
121 FnTableEntry *fn_entry = node->block_context->fn_entry;
122 if (fn_entry) {
123 fn_entry->is_pure = false;
124 }
125 }
126
113127 ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column,
114128 node->owner->source_code, node->owner->line_offsets, msg);
115129
......@@ -2620,12 +2634,6 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import,
26202634 return return_type;
26212635}
26222636
2623static void mark_impure_fn(BlockContext *context) {
2624 if (context->fn_entry) {
2625 context->fn_entry->is_pure = false;
2626 }
2627}
2628
26292637static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
26302638 AstNode *node)
26312639{
......@@ -5149,7 +5157,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
51495157 }
51505158 case PrefixOpNegation:
51515159 {
5152 TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type, *expr_node);
5160 TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, *expr_node);
51535161 if (expr_type->id == TypeTableEntryIdInvalid) {
51545162 return expr_type;
51555163 } else if ((expr_type->id == TypeTableEntryIdInt &&
......@@ -5762,6 +5770,7 @@ static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEn
57625770{
57635771 assert(!expected_type || expected_type->id != TypeTableEntryIdInvalid);
57645772 TypeTableEntry *return_type = nullptr;
5773 node->block_context = context;
57655774 switch (node->type) {
57665775 case NodeTypeBlock:
57675776 return_type = analyze_block_expr(g, import, context, expected_type, node);
......@@ -5889,7 +5898,6 @@ static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEn
58895898
58905899 Expr *expr = get_resolved_expr(node);
58915900 expr->type_entry = return_type;
5892 node->block_context = context;
58935901
58945902 add_global_const_expr(g, node);
58955903
src/bignum.cpp+14-3
......@@ -45,11 +45,21 @@ bool bignum_fits_in_bits(BigNum *bn, int bit_count, bool is_signed) {
4545 assert(bn->kind == BigNumKindInt);
4646
4747 if (is_signed) {
48 if (bn->data.x_uint <= ((uint64_t)(INT8_MAX)) + 1) {
48 if (bn->is_negative) {
49 if (bn->data.x_uint <= ((uint64_t)INT8_MAX) + 1) {
50 return bit_count >= 8;
51 } else if (bn->data.x_uint <= ((uint64_t)INT16_MAX) + 1) {
52 return bit_count >= 16;
53 } else if (bn->data.x_uint <= ((uint64_t)INT32_MAX) + 1) {
54 return bit_count >= 32;
55 } else {
56 return bit_count >= 64;
57 }
58 } else if (bn->data.x_uint <= (uint64_t)INT8_MAX) {
4959 return bit_count >= 8;
50 } else if (bn->data.x_uint <= ((uint64_t)(INT16_MAX)) + 1) {
60 } else if (bn->data.x_uint <= (uint64_t)INT16_MAX) {
5161 return bit_count >= 16;
52 } else if (bn->data.x_uint <= ((uint64_t)(INT32_MAX)) + 1) {
62 } else if (bn->data.x_uint <= (uint64_t)INT32_MAX) {
5363 return bit_count >= 32;
5464 } else {
5565 return bit_count >= 64;
......@@ -98,6 +108,7 @@ bool bignum_add(BigNum *dest, BigNum *op1, BigNum *op2) {
98108 }
99109
100110 if (op1->is_negative == op2->is_negative) {
111 dest->is_negative = op1->is_negative;
101112 return __builtin_uaddll_overflow(op1->data.x_uint, op2->data.x_uint, &dest->data.x_uint);
102113 } else if (!op1->is_negative && op2->is_negative) {
103114 if (__builtin_usubll_overflow(op1->data.x_uint, op2->data.x_uint, &dest->data.x_uint)) {
src/eval.cpp+152-53
......@@ -99,14 +99,78 @@ static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) {
9999 }
100100}
101101
102static uint64_t max_unsigned_val(TypeTableEntry *type_entry) {
103 assert(type_entry->id == TypeTableEntryIdInt);
104 if (type_entry->data.integral.bit_count == 64) {
105 return UINT64_MAX;
106 } else if (type_entry->data.integral.bit_count == 32) {
107 return UINT32_MAX;
108 } else if (type_entry->data.integral.bit_count == 16) {
109 return UINT16_MAX;
110 } else if (type_entry->data.integral.bit_count == 8) {
111 return UINT8_MAX;
112 } else {
113 zig_unreachable();
114 }
115}
116
117static int64_t max_signed_val(TypeTableEntry *type_entry) {
118 assert(type_entry->id == TypeTableEntryIdInt);
119 if (type_entry->data.integral.bit_count == 64) {
120 return INT64_MAX;
121 } else if (type_entry->data.integral.bit_count == 32) {
122 return INT32_MAX;
123 } else if (type_entry->data.integral.bit_count == 16) {
124 return INT16_MAX;
125 } else if (type_entry->data.integral.bit_count == 8) {
126 return INT8_MAX;
127 } else {
128 zig_unreachable();
129 }
130}
131
132static int64_t min_signed_val(TypeTableEntry *type_entry) {
133 assert(type_entry->id == TypeTableEntryIdInt);
134 if (type_entry->data.integral.bit_count == 64) {
135 return INT64_MIN;
136 } else if (type_entry->data.integral.bit_count == 32) {
137 return INT32_MIN;
138 } else if (type_entry->data.integral.bit_count == 16) {
139 return INT16_MIN;
140 } else if (type_entry->data.integral.bit_count == 8) {
141 return INT8_MIN;
142 } else {
143 zig_unreachable();
144 }
145}
146
102147static int eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val,
103 ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *))
148 ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *),
149 TypeTableEntry *type)
104150{
105151 bool overflow = bignum_fn(&out_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum);
106152 if (overflow) {
107153 return ErrorOverflow;
108154 }
109155
156 if (type->id == TypeTableEntryIdInt && !bignum_fits_in_bits(&out_val->data.x_bignum,
157 type->data.integral.bit_count, type->data.integral.is_signed))
158 {
159 if (type->data.integral.is_wrapping) {
160 if (type->data.integral.is_signed) {
161 out_val->data.x_bignum.data.x_uint = max_unsigned_val(type) - out_val->data.x_bignum.data.x_uint + 1;
162 out_val->data.x_bignum.is_negative = !out_val->data.x_bignum.is_negative;
163 } else if (out_val->data.x_bignum.is_negative) {
164 out_val->data.x_bignum.data.x_uint = max_unsigned_val(type) - out_val->data.x_bignum.data.x_uint + 1;
165 out_val->data.x_bignum.is_negative = false;
166 } else {
167 bignum_truncate(&out_val->data.x_bignum, type->data.integral.bit_count);
168 }
169 } else {
170 return ErrorOverflow;
171 }
172 }
173
110174 out_val->ok = true;
111175 out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
112176 return 0;
......@@ -117,6 +181,8 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
117181{
118182 assert(op1_val->ok);
119183 assert(op2_val->ok);
184 assert(op1_type->id != TypeTableEntryIdInvalid);
185 assert(op2_type->id != TypeTableEntryIdInvalid);
120186
121187 switch (bin_op) {
122188 case BinOpTypeAssign:
......@@ -132,8 +198,7 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
132198 case BinOpTypeAssignBitOr:
133199 case BinOpTypeAssignBoolAnd:
134200 case BinOpTypeAssignBoolOr:
135 out_val->ok = true;
136 return 0;
201 zig_unreachable();
137202 case BinOpTypeBoolOr:
138203 case BinOpTypeBoolAnd:
139204 assert(op1_type->id == TypeTableEntryIdBool);
......@@ -191,21 +256,21 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
191256 return 0;
192257 }
193258 case BinOpTypeAdd:
194 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add);
259 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add, op1_type);
195260 case BinOpTypeBinOr:
196 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_or);
261 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_or, op1_type);
197262 case BinOpTypeBinXor:
198 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_xor);
263 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_xor, op1_type);
199264 case BinOpTypeBinAnd:
200 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_and);
265 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_and, op1_type);
201266 case BinOpTypeBitShiftLeft:
202 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shl);
267 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type);
203268 case BinOpTypeBitShiftRight:
204 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shr);
269 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shr, op1_type);
205270 case BinOpTypeSub:
206 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_sub);
271 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type);
207272 case BinOpTypeMult:
208 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mul);
273 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type);
209274 case BinOpTypeDiv:
210275 {
211276 bool is_int = false;
......@@ -224,11 +289,11 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
224289 {
225290 return ErrorDivByZero;
226291 } else {
227 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_div);
292 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_div, op1_type);
228293 }
229294 }
230295 case BinOpTypeMod:
231 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mod);
296 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mod, op1_type);
232297 case BinOpTypeUnwrapMaybe:
233298 zig_panic("TODO");
234299 case BinOpTypeStrCat:
......@@ -244,18 +309,61 @@ static bool eval_bin_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val)
244309
245310 AstNode *op1 = node->data.bin_op_expr.op1;
246311 AstNode *op2 = node->data.bin_op_expr.op2;
312 BinOpType bin_op = node->data.bin_op_expr.bin_op;
313
314 switch (bin_op) {
315 case BinOpTypeAssign:
316 case BinOpTypeAssignTimes:
317 case BinOpTypeAssignDiv:
318 case BinOpTypeAssignMod:
319 case BinOpTypeAssignPlus:
320 case BinOpTypeAssignMinus:
321 case BinOpTypeAssignBitShiftLeft:
322 case BinOpTypeAssignBitShiftRight:
323 case BinOpTypeAssignBitAnd:
324 case BinOpTypeAssignBitXor:
325 case BinOpTypeAssignBitOr:
326 case BinOpTypeAssignBoolAnd:
327 case BinOpTypeAssignBoolOr:
328 zig_panic("TODO");
329 case BinOpTypeBoolOr:
330 case BinOpTypeBoolAnd:
331 case BinOpTypeCmpEq:
332 case BinOpTypeCmpNotEq:
333 case BinOpTypeCmpLessThan:
334 case BinOpTypeCmpGreaterThan:
335 case BinOpTypeCmpLessOrEq:
336 case BinOpTypeCmpGreaterOrEq:
337 case BinOpTypeBinOr:
338 case BinOpTypeBinXor:
339 case BinOpTypeBinAnd:
340 case BinOpTypeBitShiftLeft:
341 case BinOpTypeBitShiftRight:
342 case BinOpTypeAdd:
343 case BinOpTypeSub:
344 case BinOpTypeMult:
345 case BinOpTypeDiv:
346 case BinOpTypeMod:
347 case BinOpTypeUnwrapMaybe:
348 case BinOpTypeStrCat:
349 case BinOpTypeArrayMult:
350 break;
351 case BinOpTypeInvalid:
352 zig_unreachable();
353 }
247354
248355 TypeTableEntry *op1_type = get_resolved_expr(op1)->type_entry;
249356 TypeTableEntry *op2_type = get_resolved_expr(op2)->type_entry;
250357
358 assert(op1_type);
359 assert(op2_type);
360
251361 ConstExprValue op1_val = {0};
252362 if (eval_expr(ef, op1, &op1_val)) return true;
253363
254364 ConstExprValue op2_val = {0};
255365 if (eval_expr(ef, op2, &op2_val)) return true;
256366
257 BinOpType bin_op = node->data.bin_op_expr.bin_op;
258
259367 int err;
260368 if ((err = eval_const_expr_bin_op(&op1_val, op1_type, bin_op, &op2_val, op2_type, out_val))) {
261369 ef->root->abort = true;
......@@ -568,48 +676,15 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *
568676 const_val->depends_on_compile_var = int_type_depends_on_compile_var(g, type_entry);
569677 if (is_max) {
570678 if (type_entry->data.integral.is_signed) {
571 int64_t val;
572 if (type_entry->data.integral.bit_count == 64) {
573 val = INT64_MAX;
574 } else if (type_entry->data.integral.bit_count == 32) {
575 val = INT32_MAX;
576 } else if (type_entry->data.integral.bit_count == 16) {
577 val = INT16_MAX;
578 } else if (type_entry->data.integral.bit_count == 8) {
579 val = INT8_MAX;
580 } else {
581 zig_unreachable();
582 }
679 int64_t val = max_signed_val(type_entry);
583680 bignum_init_signed(&const_val->data.x_bignum, val);
584681 } else {
585 uint64_t val;
586 if (type_entry->data.integral.bit_count == 64) {
587 val = UINT64_MAX;
588 } else if (type_entry->data.integral.bit_count == 32) {
589 val = UINT32_MAX;
590 } else if (type_entry->data.integral.bit_count == 16) {
591 val = UINT16_MAX;
592 } else if (type_entry->data.integral.bit_count == 8) {
593 val = UINT8_MAX;
594 } else {
595 zig_unreachable();
596 }
682 uint64_t val = max_unsigned_val(type_entry);
597683 bignum_init_unsigned(&const_val->data.x_bignum, val);
598684 }
599685 } else {
600686 if (type_entry->data.integral.is_signed) {
601 int64_t val;
602 if (type_entry->data.integral.bit_count == 64) {
603 val = INT64_MIN;
604 } else if (type_entry->data.integral.bit_count == 32) {
605 val = INT32_MIN;
606 } else if (type_entry->data.integral.bit_count == 16) {
607 val = INT16_MIN;
608 } else if (type_entry->data.integral.bit_count == 8) {
609 val = INT8_MIN;
610 } else {
611 zig_unreachable();
612 }
687 int64_t val = min_signed_val(type_entry);
613688 bignum_init_signed(&const_val->data.x_bignum, val);
614689 } else {
615690 bignum_init_unsigned(&const_val->data.x_bignum, 0);
......@@ -687,6 +762,8 @@ static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_
687762 return eval_fn_with_overflow(ef, node, out_val, bignum_add);
688763 case BuiltinFnIdSubWithOverflow:
689764 return eval_fn_with_overflow(ef, node, out_val, bignum_sub);
765 case BuiltinFnIdShlWithOverflow:
766 return eval_fn_with_overflow(ef, node, out_val, bignum_shl);
690767 case BuiltinFnIdFence:
691768 return false;
692769 case BuiltinFnIdMemcpy:
......@@ -707,7 +784,6 @@ static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_
707784 case BuiltinFnIdErrName:
708785 case BuiltinFnIdEmbedFile:
709786 case BuiltinFnIdCmpExchange:
710 case BuiltinFnIdShlWithOverflow:
711787 zig_panic("TODO");
712788 case BuiltinFnIdBreakpoint:
713789 case BuiltinFnIdInvalid:
......@@ -962,8 +1038,31 @@ static bool eval_prefix_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_v
9621038 out_val->ok = true;
9631039 break;
9641040 }
965 case PrefixOpBinNot:
9661041 case PrefixOpNegation:
1042 if (expr_type->id == TypeTableEntryIdInt) {
1043 assert(expr_type->data.integral.is_signed);
1044 bignum_negate(&out_val->data.x_bignum, &expr_val.data.x_bignum);
1045 out_val->ok = true;
1046 bool overflow = !bignum_fits_in_bits(&out_val->data.x_bignum,
1047 expr_type->data.integral.bit_count, expr_type->data.integral.is_signed);
1048 if (expr_type->data.integral.is_wrapping) {
1049 if (overflow) {
1050 out_val->data.x_bignum.is_negative = true;
1051 }
1052 } else if (overflow) {
1053 ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node,
1054 buf_sprintf("function evaluation caused overflow"));
1055 add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here"));
1056 add_error_note(ef->root->codegen, msg, node, buf_sprintf("overflow occurred here"));
1057 return true;
1058 }
1059 } else if (expr_type->id == TypeTableEntryIdFloat) {
1060 zig_panic("TODO");
1061 } else {
1062 zig_unreachable();
1063 }
1064 break;
1065 case PrefixOpBinNot:
9671066 case PrefixOpMaybe:
9681067 case PrefixOpError:
9691068 case PrefixOpUnwrapError:
test/run_tests.cpp+49
......@@ -1305,6 +1305,55 @@ fn f() {
13051305 )SOURCE", 2,
13061306 ".tmp_source.zig:4:72: error: failure atomic ordering must be no stricter than success",
13071307 ".tmp_source.zig:5:49: error: success atomic ordering must be Monotonic or stricter");
1308
1309 add_compile_fail_case("negation overflow in function evaluation", R"SOURCE(
1310fn f() {
1311 const x = neg(-128);
1312}
1313fn neg(x: i8) -> i8 {
1314 -x
1315}
1316 )SOURCE", 3,
1317 ".tmp_source.zig:5:1: error: function evaluation caused overflow",
1318 ".tmp_source.zig:3:18: note: called from here",
1319 ".tmp_source.zig:6:5: note: overflow occurred here");
1320
1321 add_compile_fail_case("add overflow in function evaluation", R"SOURCE(
1322fn f() {
1323 const x = add(65530, 10);
1324}
1325fn add(a: u16, b: u16) -> u16 {
1326 a + b
1327}
1328 )SOURCE", 3,
1329 ".tmp_source.zig:5:1: error: function evaluation caused overflow",
1330 ".tmp_source.zig:3:18: note: called from here",
1331 ".tmp_source.zig:6:7: note: overflow occurred here");
1332
1333
1334 add_compile_fail_case("sub overflow in function evaluation", R"SOURCE(
1335fn f() {
1336 const x = sub(10, 20);
1337}
1338fn sub(a: u16, b: u16) -> u16 {
1339 a - b
1340}
1341 )SOURCE", 3,
1342 ".tmp_source.zig:5:1: error: function evaluation caused overflow",
1343 ".tmp_source.zig:3:18: note: called from here",
1344 ".tmp_source.zig:6:7: note: overflow occurred here");
1345
1346 add_compile_fail_case("mul overflow in function evaluation", R"SOURCE(
1347fn f() {
1348 const x = mul(300, 6000);
1349}
1350fn mul(a: u16, b: u16) -> u16 {
1351 a * b
1352}
1353 )SOURCE", 3,
1354 ".tmp_source.zig:5:1: error: function evaluation caused overflow",
1355 ".tmp_source.zig:3:18: note: called from here",
1356 ".tmp_source.zig:6:7: note: overflow occurred here");
13081357}
13091358
13101359//////////////////////////////////////////////////////////////////////////////
test/self_hosted.zig+38-34
......@@ -1459,68 +1459,72 @@ fn fence() {
14591459
14601460#attribute("test")
14611461fn unsigned_wrapping() {
1462 var x_u32: u32w = @max_value(u32);
1463 x_u32 += 1;
1464 assert(x_u32 == 0);
1465 x_u32 -= 1;
1466 assert(x_u32 == @max_value(u32));
1462 test_unsigned_wrapping_eval(@max_value(u32));
14671463 test_unsigned_wrapping_noeval(@max_value(u32));
14681464}
1465fn test_unsigned_wrapping_eval(x: u32w) {
1466 const zero = x + 1;
1467 assert(zero == 0);
1468 const orig = zero - 1;
1469 assert(orig == @max_value(u32));
1470}
14691471#static_eval_enable(false)
14701472fn test_unsigned_wrapping_noeval(x: u32w) {
1471 var x_u32 = x;
1472 x_u32 += 1;
1473 assert(x_u32 == 0);
1474 x_u32 -= 1;
1475 assert(x_u32 == @max_value(u32));
1473 const zero = x + 1;
1474 assert(zero == 0);
1475 const orig = zero - 1;
1476 assert(orig == @max_value(u32));
14761477}
14771478
14781479#attribute("test")
14791480fn signed_wrapping() {
1480 var x_i32: i32w = @max_value(i32);
1481 x_i32 += 1;
1482 assert(x_i32 == @min_value(i32));
1483 x_i32 -= 1;
1484 assert(x_i32 == @max_value(i32));
1481 test_signed_wrapping_eval(@max_value(i32));
14851482 test_signed_wrapping_noeval(@max_value(i32));
14861483}
1484fn test_signed_wrapping_eval(x: i32w) {
1485 const min_val = x + 1;
1486 assert(min_val == @min_value(i32));
1487 const max_val = min_val - 1;
1488 assert(max_val == @max_value(i32));
1489}
14871490#static_eval_enable(false)
14881491fn test_signed_wrapping_noeval(x: i32w) {
1489 var x_i32 = x;
1490 x_i32 += 1;
1491 assert(x_i32 == @min_value(i32));
1492 x_i32 -= 1;
1493 assert(x_i32 == @max_value(i32));
1492 const min_val = x + 1;
1493 assert(min_val == @min_value(i32));
1494 const max_val = min_val - 1;
1495 assert(max_val == @max_value(i32));
14941496}
14951497
14961498#attribute("test")
14971499fn negation_wrapping() {
1498 var x_i16 = @min_value(i16w);
1499 assert(x_i16 == -32768);
1500 x_i16 = -x_i16;
1501 assert(x_i16 == -32768);
1500 test_negation_wrapping_eval(@min_value(i16));
15021501 test_negation_wrapping_noeval(@min_value(i16));
15031502}
1503fn test_negation_wrapping_eval(x: i16w) {
1504 assert(x == -32768);
1505 const neg = -x;
1506 assert(neg == -32768);
1507}
15041508#static_eval_enable(false)
15051509fn test_negation_wrapping_noeval(x: i16w) {
1506 var x_i16 = x;
1507 assert(x_i16 == -32768);
1508 x_i16 = -x_i16;
1509 assert(x_i16 == -32768);
1510 assert(x == -32768);
1511 const neg = -x;
1512 assert(neg == -32768);
15101513}
15111514
15121515#attribute("test")
15131516fn shl_wrapping() {
1514 var x_u16 = @max_value(u16w);
1515 x_u16 <<= 1;
1516 assert(x_u16 == 65534);
1517 test_shl_wrapping_eval(@max_value(u16));
15171518 test_shl_wrapping_noeval(@max_value(u16));
15181519}
1520fn test_shl_wrapping_eval(x: u16w) {
1521 const shifted = x << 1;
1522 assert(shifted == 65534);
1523}
15191524#static_eval_enable(false)
15201525fn test_shl_wrapping_noeval(x: u16w) {
1521 var x_u16 = x;
1522 x_u16 <<= 1;
1523 assert(x_u16 == 65534);
1526 const shifted = x << 1;
1527 assert(shifted == 65534);
15241528}
15251529
15261530#attribute("test")