authorgravatar for twostepted@gmail.comTravis Staloch <twostepted@gmail.com> 2021-09-02 13:50:24-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-28 17:02:43-07:00
log29f41896ed9d99e82a88f4b63efa182ca0d2f93c
tree1e6eb1159df89f79b04f050da662653925c77b1c
parent79bc5891c1c4cde0592fe1b10b6c9a85914155cf

sat-arithmetic: add operator support

- adds initial support for the operators +|, -|, *|, <<|, +|=, -|=, *|=, <<|= - uses operators in addition to builtins in behavior test - adds binOpExt() and assignBinOpExt() to AstGen.zig. these need to be audited

21 files changed, 556 insertions(+), 54 deletions(-)

lib/std/zig/Ast.zig+32
...@@ -396,6 +396,7 @@ pub fn firstToken(tree: Tree, node: Node.Index) TokenIndex {...@@ -396,6 +396,7 @@ pub fn firstToken(tree: Tree, node: Node.Index) TokenIndex {
396 .assign_add,396 .assign_add,
397 .assign_sub,397 .assign_sub,
398 .assign_bit_shift_left,398 .assign_bit_shift_left,
399 .assign_bit_shift_left_sat,
399 .assign_bit_shift_right,400 .assign_bit_shift_right,
400 .assign_bit_and,401 .assign_bit_and,
401 .assign_bit_xor,402 .assign_bit_xor,
...@@ -403,6 +404,9 @@ pub fn firstToken(tree: Tree, node: Node.Index) TokenIndex {...@@ -403,6 +404,9 @@ pub fn firstToken(tree: Tree, node: Node.Index) TokenIndex {
403 .assign_mul_wrap,404 .assign_mul_wrap,
404 .assign_add_wrap,405 .assign_add_wrap,
405 .assign_sub_wrap,406 .assign_sub_wrap,
407 .assign_mul_sat,
408 .assign_add_sat,
409 .assign_sub_sat,
406 .assign,410 .assign,
407 .merge_error_sets,411 .merge_error_sets,
408 .mul,412 .mul,
...@@ -410,12 +414,16 @@ pub fn firstToken(tree: Tree, node: Node.Index) TokenIndex {...@@ -410,12 +414,16 @@ pub fn firstToken(tree: Tree, node: Node.Index) TokenIndex {
410 .mod,414 .mod,
411 .array_mult,415 .array_mult,
412 .mul_wrap,416 .mul_wrap,
417 .mul_sat,
413 .add,418 .add,
414 .sub,419 .sub,
415 .array_cat,420 .array_cat,
416 .add_wrap,421 .add_wrap,
417 .sub_wrap,422 .sub_wrap,
423 .add_sat,
424 .sub_sat,
418 .bit_shift_left,425 .bit_shift_left,
426 .bit_shift_left_sat,
419 .bit_shift_right,427 .bit_shift_right,
420 .bit_and,428 .bit_and,
421 .bit_xor,429 .bit_xor,
...@@ -652,6 +660,7 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex {...@@ -652,6 +660,7 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex {
652 .assign_add,660 .assign_add,
653 .assign_sub,661 .assign_sub,
654 .assign_bit_shift_left,662 .assign_bit_shift_left,
663 .assign_bit_shift_left_sat,
655 .assign_bit_shift_right,664 .assign_bit_shift_right,
656 .assign_bit_and,665 .assign_bit_and,
657 .assign_bit_xor,666 .assign_bit_xor,
...@@ -659,6 +668,9 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex {...@@ -659,6 +668,9 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex {
659 .assign_mul_wrap,668 .assign_mul_wrap,
660 .assign_add_wrap,669 .assign_add_wrap,
661 .assign_sub_wrap,670 .assign_sub_wrap,
671 .assign_mul_sat,
672 .assign_add_sat,
673 .assign_sub_sat,
662 .assign,674 .assign,
663 .merge_error_sets,675 .merge_error_sets,
664 .mul,676 .mul,
...@@ -666,12 +678,16 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex {...@@ -666,12 +678,16 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex {
666 .mod,678 .mod,
667 .array_mult,679 .array_mult,
668 .mul_wrap,680 .mul_wrap,
681 .mul_sat,
669 .add,682 .add,
670 .sub,683 .sub,
671 .array_cat,684 .array_cat,
672 .add_wrap,685 .add_wrap,
673 .sub_wrap,686 .sub_wrap,
687 .add_sat,
688 .sub_sat,
674 .bit_shift_left,689 .bit_shift_left,
690 .bit_shift_left_sat,
675 .bit_shift_right,691 .bit_shift_right,
676 .bit_and,692 .bit_and,
677 .bit_xor,693 .bit_xor,
...@@ -2525,6 +2541,8 @@ pub const Node = struct {...@@ -2525,6 +2541,8 @@ pub const Node = struct {
2525 assign_sub,2541 assign_sub,
2526 /// `lhs <<= rhs`. main_token is op.2542 /// `lhs <<= rhs`. main_token is op.
2527 assign_bit_shift_left,2543 assign_bit_shift_left,
2544 /// `lhs <<|= rhs`. main_token is op.
2545 assign_bit_shift_left_sat,
2528 /// `lhs >>= rhs`. main_token is op.2546 /// `lhs >>= rhs`. main_token is op.
2529 assign_bit_shift_right,2547 assign_bit_shift_right,
2530 /// `lhs &= rhs`. main_token is op.2548 /// `lhs &= rhs`. main_token is op.
...@@ -2539,6 +2557,12 @@ pub const Node = struct {...@@ -2539,6 +2557,12 @@ pub const Node = struct {
2539 assign_add_wrap,2557 assign_add_wrap,
2540 /// `lhs -%= rhs`. main_token is op.2558 /// `lhs -%= rhs`. main_token is op.
2541 assign_sub_wrap,2559 assign_sub_wrap,
2560 /// `lhs *|= rhs`. main_token is op.
2561 assign_mul_sat,
2562 /// `lhs +|= rhs`. main_token is op.
2563 assign_add_sat,
2564 /// `lhs -|= rhs`. main_token is op.
2565 assign_sub_sat,
2542 /// `lhs = rhs`. main_token is op.2566 /// `lhs = rhs`. main_token is op.
2543 assign,2567 assign,
2544 /// `lhs || rhs`. main_token is the `||`.2568 /// `lhs || rhs`. main_token is the `||`.
...@@ -2553,6 +2577,8 @@ pub const Node = struct {...@@ -2553,6 +2577,8 @@ pub const Node = struct {
2553 array_mult,2577 array_mult,
2554 /// `lhs *% rhs`. main_token is the `*%`.2578 /// `lhs *% rhs`. main_token is the `*%`.
2555 mul_wrap,2579 mul_wrap,
2580 /// `lhs *| rhs`. main_token is the `*%`.
2581 mul_sat,
2556 /// `lhs + rhs`. main_token is the `+`.2582 /// `lhs + rhs`. main_token is the `+`.
2557 add,2583 add,
2558 /// `lhs - rhs`. main_token is the `-`.2584 /// `lhs - rhs`. main_token is the `-`.
...@@ -2563,8 +2589,14 @@ pub const Node = struct {...@@ -2563,8 +2589,14 @@ pub const Node = struct {
2563 add_wrap,2589 add_wrap,
2564 /// `lhs -% rhs`. main_token is the `-%`.2590 /// `lhs -% rhs`. main_token is the `-%`.
2565 sub_wrap,2591 sub_wrap,
2592 /// `lhs +| rhs`. main_token is the `+|`.
2593 add_sat,
2594 /// `lhs -| rhs`. main_token is the `-|`.
2595 sub_sat,
2566 /// `lhs << rhs`. main_token is the `<<`.2596 /// `lhs << rhs`. main_token is the `<<`.
2567 bit_shift_left,2597 bit_shift_left,
2598 /// `lhs <<| rhs`. main_token is the `<<|`.
2599 bit_shift_left_sat,
2568 /// `lhs >> rhs`. main_token is the `>>`.2600 /// `lhs >> rhs`. main_token is the `>>`.
2569 bit_shift_right,2601 bit_shift_right,
2570 /// `lhs & rhs`. main_token is the `&`.2602 /// `lhs & rhs`. main_token is the `&`.
lib/std/zig/parse.zig+8
...@@ -1269,6 +1269,7 @@ const Parser = struct {...@@ -1269,6 +1269,7 @@ const Parser = struct {
1269 .plus_equal => .assign_add,1269 .plus_equal => .assign_add,
1270 .minus_equal => .assign_sub,1270 .minus_equal => .assign_sub,
1271 .angle_bracket_angle_bracket_left_equal => .assign_bit_shift_left,1271 .angle_bracket_angle_bracket_left_equal => .assign_bit_shift_left,
1272 .angle_bracket_angle_bracket_left_pipe_equal => .assign_bit_shift_left_sat,
1272 .angle_bracket_angle_bracket_right_equal => .assign_bit_shift_right,1273 .angle_bracket_angle_bracket_right_equal => .assign_bit_shift_right,
1273 .ampersand_equal => .assign_bit_and,1274 .ampersand_equal => .assign_bit_and,
1274 .caret_equal => .assign_bit_xor,1275 .caret_equal => .assign_bit_xor,
...@@ -1276,6 +1277,9 @@ const Parser = struct {...@@ -1276,6 +1277,9 @@ const Parser = struct {
1276 .asterisk_percent_equal => .assign_mul_wrap,1277 .asterisk_percent_equal => .assign_mul_wrap,
1277 .plus_percent_equal => .assign_add_wrap,1278 .plus_percent_equal => .assign_add_wrap,
1278 .minus_percent_equal => .assign_sub_wrap,1279 .minus_percent_equal => .assign_sub_wrap,
1280 .asterisk_pipe_equal => .assign_mul_sat,
1281 .plus_pipe_equal => .assign_add_sat,
1282 .minus_pipe_equal => .assign_sub_sat,
1279 .equal => .assign,1283 .equal => .assign,
1280 else => return expr,1284 else => return expr,
1281 };1285 };
...@@ -1343,6 +1347,7 @@ const Parser = struct {...@@ -1343,6 +1347,7 @@ const Parser = struct {
1343 .keyword_catch = .{ .prec = 40, .tag = .@"catch" },1347 .keyword_catch = .{ .prec = 40, .tag = .@"catch" },
13441348
1345 .angle_bracket_angle_bracket_left = .{ .prec = 50, .tag = .bit_shift_left },1349 .angle_bracket_angle_bracket_left = .{ .prec = 50, .tag = .bit_shift_left },
1350 .angle_bracket_angle_bracket_left_pipe = .{ .prec = 50, .tag = .bit_shift_left_sat },
1346 .angle_bracket_angle_bracket_right = .{ .prec = 50, .tag = .bit_shift_right },1351 .angle_bracket_angle_bracket_right = .{ .prec = 50, .tag = .bit_shift_right },
13471352
1348 .plus = .{ .prec = 60, .tag = .add },1353 .plus = .{ .prec = 60, .tag = .add },
...@@ -1350,6 +1355,8 @@ const Parser = struct {...@@ -1350,6 +1355,8 @@ const Parser = struct {
1350 .plus_plus = .{ .prec = 60, .tag = .array_cat },1355 .plus_plus = .{ .prec = 60, .tag = .array_cat },
1351 .plus_percent = .{ .prec = 60, .tag = .add_wrap },1356 .plus_percent = .{ .prec = 60, .tag = .add_wrap },
1352 .minus_percent = .{ .prec = 60, .tag = .sub_wrap },1357 .minus_percent = .{ .prec = 60, .tag = .sub_wrap },
1358 .plus_pipe = .{ .prec = 60, .tag = .add_sat },
1359 .minus_pipe = .{ .prec = 60, .tag = .sub_sat },
13531360
1354 .pipe_pipe = .{ .prec = 70, .tag = .merge_error_sets },1361 .pipe_pipe = .{ .prec = 70, .tag = .merge_error_sets },
1355 .asterisk = .{ .prec = 70, .tag = .mul },1362 .asterisk = .{ .prec = 70, .tag = .mul },
...@@ -1357,6 +1364,7 @@ const Parser = struct {...@@ -1357,6 +1364,7 @@ const Parser = struct {
1357 .percent = .{ .prec = 70, .tag = .mod },1364 .percent = .{ .prec = 70, .tag = .mod },
1358 .asterisk_asterisk = .{ .prec = 70, .tag = .array_mult },1365 .asterisk_asterisk = .{ .prec = 70, .tag = .array_mult },
1359 .asterisk_percent = .{ .prec = 70, .tag = .mul_wrap },1366 .asterisk_percent = .{ .prec = 70, .tag = .mul_wrap },
1367 .asterisk_pipe = .{ .prec = 70, .tag = .mul_sat },
1360 });1368 });
13611369
1362 fn parseExprPrecedence(p: *Parser, min_prec: i32) Error!Node.Index {1370 fn parseExprPrecedence(p: *Parser, min_prec: i32) Error!Node.Index {
lib/std/zig/render.zig+8
...@@ -333,26 +333,32 @@ fn renderExpression(gpa: *Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,...@@ -333,26 +333,32 @@ fn renderExpression(gpa: *Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
333333
334 .add,334 .add,
335 .add_wrap,335 .add_wrap,
336 .add_sat,
336 .array_cat,337 .array_cat,
337 .array_mult,338 .array_mult,
338 .assign,339 .assign,
339 .assign_bit_and,340 .assign_bit_and,
340 .assign_bit_or,341 .assign_bit_or,
341 .assign_bit_shift_left,342 .assign_bit_shift_left,
343 .assign_bit_shift_left_sat,
342 .assign_bit_shift_right,344 .assign_bit_shift_right,
343 .assign_bit_xor,345 .assign_bit_xor,
344 .assign_div,346 .assign_div,
345 .assign_sub,347 .assign_sub,
346 .assign_sub_wrap,348 .assign_sub_wrap,
349 .assign_sub_sat,
347 .assign_mod,350 .assign_mod,
348 .assign_add,351 .assign_add,
349 .assign_add_wrap,352 .assign_add_wrap,
353 .assign_add_sat,
350 .assign_mul,354 .assign_mul,
351 .assign_mul_wrap,355 .assign_mul_wrap,
356 .assign_mul_sat,
352 .bang_equal,357 .bang_equal,
353 .bit_and,358 .bit_and,
354 .bit_or,359 .bit_or,
355 .bit_shift_left,360 .bit_shift_left,
361 .bit_shift_left_sat,
356 .bit_shift_right,362 .bit_shift_right,
357 .bit_xor,363 .bit_xor,
358 .bool_and,364 .bool_and,
...@@ -367,8 +373,10 @@ fn renderExpression(gpa: *Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,...@@ -367,8 +373,10 @@ fn renderExpression(gpa: *Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
367 .mod,373 .mod,
368 .mul,374 .mul,
369 .mul_wrap,375 .mul_wrap,
376 .mul_sat,
370 .sub,377 .sub,
371 .sub_wrap,378 .sub_wrap,
379 .sub_sat,
372 .@"orelse",380 .@"orelse",
373 => {381 => {
374 const infix = datas[node];382 const infix = datas[node];
lib/std/zig/tokenizer.zig+79
...@@ -103,15 +103,21 @@ pub const Token = struct {...@@ -103,15 +103,21 @@ pub const Token = struct {
103 plus_equal,103 plus_equal,
104 plus_percent,104 plus_percent,
105 plus_percent_equal,105 plus_percent_equal,
106 plus_pipe,
107 plus_pipe_equal,
106 minus,108 minus,
107 minus_equal,109 minus_equal,
108 minus_percent,110 minus_percent,
109 minus_percent_equal,111 minus_percent_equal,
112 minus_pipe,
113 minus_pipe_equal,
110 asterisk,114 asterisk,
111 asterisk_equal,115 asterisk_equal,
112 asterisk_asterisk,116 asterisk_asterisk,
113 asterisk_percent,117 asterisk_percent,
114 asterisk_percent_equal,118 asterisk_percent_equal,
119 asterisk_pipe,
120 asterisk_pipe_equal,
115 arrow,121 arrow,
116 colon,122 colon,
117 slash,123 slash,
...@@ -124,6 +130,8 @@ pub const Token = struct {...@@ -124,6 +130,8 @@ pub const Token = struct {
124 angle_bracket_left_equal,130 angle_bracket_left_equal,
125 angle_bracket_angle_bracket_left,131 angle_bracket_angle_bracket_left,
126 angle_bracket_angle_bracket_left_equal,132 angle_bracket_angle_bracket_left_equal,
133 angle_bracket_angle_bracket_left_pipe,
134 angle_bracket_angle_bracket_left_pipe_equal,
127 angle_bracket_right,135 angle_bracket_right,
128 angle_bracket_right_equal,136 angle_bracket_right_equal,
129 angle_bracket_angle_bracket_right,137 angle_bracket_angle_bracket_right,
...@@ -227,15 +235,21 @@ pub const Token = struct {...@@ -227,15 +235,21 @@ pub const Token = struct {
227 .plus_equal => "+=",235 .plus_equal => "+=",
228 .plus_percent => "+%",236 .plus_percent => "+%",
229 .plus_percent_equal => "+%=",237 .plus_percent_equal => "+%=",
238 .plus_pipe => "+|",
239 .plus_pipe_equal => "+|=",
230 .minus => "-",240 .minus => "-",
231 .minus_equal => "-=",241 .minus_equal => "-=",
232 .minus_percent => "-%",242 .minus_percent => "-%",
233 .minus_percent_equal => "-%=",243 .minus_percent_equal => "-%=",
244 .minus_pipe => "-|",
245 .minus_pipe_equal => "-|=",
234 .asterisk => "*",246 .asterisk => "*",
235 .asterisk_equal => "*=",247 .asterisk_equal => "*=",
236 .asterisk_asterisk => "**",248 .asterisk_asterisk => "**",
237 .asterisk_percent => "*%",249 .asterisk_percent => "*%",
238 .asterisk_percent_equal => "*%=",250 .asterisk_percent_equal => "*%=",
251 .asterisk_pipe => "*|",
252 .asterisk_pipe_equal => "*|=",
239 .arrow => "->",253 .arrow => "->",
240 .colon => ":",254 .colon => ":",
241 .slash => "/",255 .slash => "/",
...@@ -248,6 +262,8 @@ pub const Token = struct {...@@ -248,6 +262,8 @@ pub const Token = struct {
248 .angle_bracket_left_equal => "<=",262 .angle_bracket_left_equal => "<=",
249 .angle_bracket_angle_bracket_left => "<<",263 .angle_bracket_angle_bracket_left => "<<",
250 .angle_bracket_angle_bracket_left_equal => "<<=",264 .angle_bracket_angle_bracket_left_equal => "<<=",
265 .angle_bracket_angle_bracket_left_pipe => "<<|",
266 .angle_bracket_angle_bracket_left_pipe_equal => "<<|=",
251 .angle_bracket_right => ">",267 .angle_bracket_right => ">",
252 .angle_bracket_right_equal => ">=",268 .angle_bracket_right_equal => ">=",
253 .angle_bracket_angle_bracket_right => ">>",269 .angle_bracket_angle_bracket_right => ">>",
...@@ -352,8 +368,10 @@ pub const Tokenizer = struct {...@@ -352,8 +368,10 @@ pub const Tokenizer = struct {
352 pipe,368 pipe,
353 minus,369 minus,
354 minus_percent,370 minus_percent,
371 minus_pipe,
355 asterisk,372 asterisk,
356 asterisk_percent,373 asterisk_percent,
374 asterisk_pipe,
357 slash,375 slash,
358 line_comment_start,376 line_comment_start,
359 line_comment,377 line_comment,
...@@ -382,8 +400,10 @@ pub const Tokenizer = struct {...@@ -382,8 +400,10 @@ pub const Tokenizer = struct {
382 percent,400 percent,
383 plus,401 plus,
384 plus_percent,402 plus_percent,
403 plus_pipe,
385 angle_bracket_left,404 angle_bracket_left,
386 angle_bracket_angle_bracket_left,405 angle_bracket_angle_bracket_left,
406 angle_bracket_angle_bracket_left_pipe,
387 angle_bracket_right,407 angle_bracket_right,
388 angle_bracket_angle_bracket_right,408 angle_bracket_angle_bracket_right,
389 period,409 period,
...@@ -584,6 +604,9 @@ pub const Tokenizer = struct {...@@ -584,6 +604,9 @@ pub const Tokenizer = struct {
584 '%' => {604 '%' => {
585 state = .asterisk_percent;605 state = .asterisk_percent;
586 },606 },
607 '|' => {
608 state = .asterisk_pipe;
609 },
587 else => {610 else => {
588 result.tag = .asterisk;611 result.tag = .asterisk;
589 break;612 break;
...@@ -602,6 +625,18 @@ pub const Tokenizer = struct {...@@ -602,6 +625,18 @@ pub const Tokenizer = struct {
602 },625 },
603 },626 },
604627
628 .asterisk_pipe => switch (c) {
629 '=' => {
630 result.tag = .asterisk_pipe_equal;
631 self.index += 1;
632 break;
633 },
634 else => {
635 result.tag = .asterisk_pipe;
636 break;
637 },
638 },
639
605 .percent => switch (c) {640 .percent => switch (c) {
606 '=' => {641 '=' => {
607 result.tag = .percent_equal;642 result.tag = .percent_equal;
...@@ -628,6 +663,9 @@ pub const Tokenizer = struct {...@@ -628,6 +663,9 @@ pub const Tokenizer = struct {
628 '%' => {663 '%' => {
629 state = .plus_percent;664 state = .plus_percent;
630 },665 },
666 '|' => {
667 state = .plus_pipe;
668 },
631 else => {669 else => {
632 result.tag = .plus;670 result.tag = .plus;
633 break;671 break;
...@@ -646,6 +684,18 @@ pub const Tokenizer = struct {...@@ -646,6 +684,18 @@ pub const Tokenizer = struct {
646 },684 },
647 },685 },
648686
687 .plus_pipe => switch (c) {
688 '=' => {
689 result.tag = .plus_pipe_equal;
690 self.index += 1;
691 break;
692 },
693 else => {
694 result.tag = .plus_pipe;
695 break;
696 },
697 },
698
649 .caret => switch (c) {699 .caret => switch (c) {
650 '=' => {700 '=' => {
651 result.tag = .caret_equal;701 result.tag = .caret_equal;
...@@ -903,6 +953,9 @@ pub const Tokenizer = struct {...@@ -903,6 +953,9 @@ pub const Tokenizer = struct {
903 '%' => {953 '%' => {
904 state = .minus_percent;954 state = .minus_percent;
905 },955 },
956 '|' => {
957 state = .minus_pipe;
958 },
906 else => {959 else => {
907 result.tag = .minus;960 result.tag = .minus;
908 break;961 break;
...@@ -920,6 +973,17 @@ pub const Tokenizer = struct {...@@ -920,6 +973,17 @@ pub const Tokenizer = struct {
920 break;973 break;
921 },974 },
922 },975 },
976 .minus_pipe => switch (c) {
977 '=' => {
978 result.tag = .minus_pipe_equal;
979 self.index += 1;
980 break;
981 },
982 else => {
983 result.tag = .minus_pipe;
984 break;
985 },
986 },
923987
924 .angle_bracket_left => switch (c) {988 .angle_bracket_left => switch (c) {
925 '<' => {989 '<' => {
...@@ -942,12 +1006,27 @@ pub const Tokenizer = struct {...@@ -942,12 +1006,27 @@ pub const Tokenizer = struct {
942 self.index += 1;1006 self.index += 1;
943 break;1007 break;
944 },1008 },
1009 '|' => {
1010 result.tag = .angle_bracket_angle_bracket_left_pipe;
1011 },
945 else => {1012 else => {
946 result.tag = .angle_bracket_angle_bracket_left;1013 result.tag = .angle_bracket_angle_bracket_left;
947 break;1014 break;
948 },1015 },
949 },1016 },
9501017
1018 .angle_bracket_angle_bracket_left_pipe => switch (c) {
1019 '=' => {
1020 result.tag = .angle_bracket_angle_bracket_left_pipe_equal;
1021 self.index += 1;
1022 break;
1023 },
1024 else => {
1025 result.tag = .angle_bracket_angle_bracket_left_pipe;
1026 break;
1027 },
1028 },
1029
951 .angle_bracket_right => switch (c) {1030 .angle_bracket_right => switch (c) {
952 '>' => {1031 '>' => {
953 state = .angle_bracket_angle_bracket_right;1032 state = .angle_bracket_angle_bracket_right;
src/Air.zig+22
...@@ -44,6 +44,11 @@ pub const Inst = struct {...@@ -44,6 +44,11 @@ pub const Inst = struct {
44 /// is the same as both operands.44 /// is the same as both operands.
45 /// Uses the `bin_op` field.45 /// Uses the `bin_op` field.
46 addwrap,46 addwrap,
47 /// Saturating integer addition.
48 /// Both operands are guaranteed to be the same type, and the result type
49 /// is the same as both operands.
50 /// Uses the `bin_op` field.
51 addsat,
47 /// Float or integer subtraction. For integers, wrapping is undefined behavior.52 /// Float or integer subtraction. For integers, wrapping is undefined behavior.
48 /// Both operands are guaranteed to be the same type, and the result type53 /// Both operands are guaranteed to be the same type, and the result type
49 /// is the same as both operands.54 /// is the same as both operands.
...@@ -54,6 +59,11 @@ pub const Inst = struct {...@@ -54,6 +59,11 @@ pub const Inst = struct {
54 /// is the same as both operands.59 /// is the same as both operands.
55 /// Uses the `bin_op` field.60 /// Uses the `bin_op` field.
56 subwrap,61 subwrap,
62 /// Saturating integer subtraction.
63 /// Both operands are guaranteed to be the same type, and the result type
64 /// is the same as both operands.
65 /// Uses the `bin_op` field.
66 subsat,
57 /// Float or integer multiplication. For integers, wrapping is undefined behavior.67 /// Float or integer multiplication. For integers, wrapping is undefined behavior.
58 /// Both operands are guaranteed to be the same type, and the result type68 /// Both operands are guaranteed to be the same type, and the result type
59 /// is the same as both operands.69 /// is the same as both operands.
...@@ -64,6 +74,11 @@ pub const Inst = struct {...@@ -64,6 +74,11 @@ pub const Inst = struct {
64 /// is the same as both operands.74 /// is the same as both operands.
65 /// Uses the `bin_op` field.75 /// Uses the `bin_op` field.
66 mulwrap,76 mulwrap,
77 /// Saturating integer multiplication.
78 /// Both operands are guaranteed to be the same type, and the result type
79 /// is the same as both operands.
80 /// Uses the `bin_op` field.
81 mulsat,
67 /// Integer or float division. For integers, wrapping is undefined behavior.82 /// Integer or float division. For integers, wrapping is undefined behavior.
68 /// Both operands are guaranteed to be the same type, and the result type83 /// Both operands are guaranteed to be the same type, and the result type
69 /// is the same as both operands.84 /// is the same as both operands.
...@@ -110,6 +125,9 @@ pub const Inst = struct {...@@ -110,6 +125,9 @@ pub const Inst = struct {
110 /// Shift left. `<<`125 /// Shift left. `<<`
111 /// Uses the `bin_op` field.126 /// Uses the `bin_op` field.
112 shl,127 shl,
128 /// Shift left saturating. `<<|`
129 /// Uses the `bin_op` field.
130 shl_sat,
113 /// Bitwise XOR. `^`131 /// Bitwise XOR. `^`
114 /// Uses the `bin_op` field.132 /// Uses the `bin_op` field.
115 xor,133 xor,
...@@ -568,10 +586,13 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -568,10 +586,13 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
568586
569 .add,587 .add,
570 .addwrap,588 .addwrap,
589 .addsat,
571 .sub,590 .sub,
572 .subwrap,591 .subwrap,
592 .subsat,
573 .mul,593 .mul,
574 .mulwrap,594 .mulwrap,
595 .mulsat,
575 .div,596 .div,
576 .rem,597 .rem,
577 .mod,598 .mod,
...@@ -582,6 +603,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -582,6 +603,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
582 .ptr_sub,603 .ptr_sub,
583 .shr,604 .shr,
584 .shl,605 .shl,
606 .shl_sat,
585 => return air.typeOf(datas[inst].bin_op.lhs),607 => return air.typeOf(datas[inst].bin_op.lhs),
586608
587 .cmp_lt,609 .cmp_lt,
src/AstGen.zig+122-2
...@@ -318,27 +318,35 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Ins...@@ -318,27 +318,35 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Ins
318 .assign_bit_and,318 .assign_bit_and,
319 .assign_bit_or,319 .assign_bit_or,
320 .assign_bit_shift_left,320 .assign_bit_shift_left,
321 .assign_bit_shift_left_sat,
321 .assign_bit_shift_right,322 .assign_bit_shift_right,
322 .assign_bit_xor,323 .assign_bit_xor,
323 .assign_div,324 .assign_div,
324 .assign_sub,325 .assign_sub,
325 .assign_sub_wrap,326 .assign_sub_wrap,
327 .assign_sub_sat,
326 .assign_mod,328 .assign_mod,
327 .assign_add,329 .assign_add,
328 .assign_add_wrap,330 .assign_add_wrap,
331 .assign_add_sat,
329 .assign_mul,332 .assign_mul,
330 .assign_mul_wrap,333 .assign_mul_wrap,
334 .assign_mul_sat,
331 .add,335 .add,
332 .add_wrap,336 .add_wrap,
337 .add_sat,
333 .sub,338 .sub,
334 .sub_wrap,339 .sub_wrap,
340 .sub_sat,
335 .mul,341 .mul,
336 .mul_wrap,342 .mul_wrap,
343 .mul_sat,
337 .div,344 .div,
338 .mod,345 .mod,
339 .bit_and,346 .bit_and,
340 .bit_or,347 .bit_or,
341 .bit_shift_left,348 .bit_shift_left,
349 .bit_shift_left_sat,
342 .bit_shift_right,350 .bit_shift_right,
343 .bit_xor,351 .bit_xor,
344 .bang_equal,352 .bang_equal,
...@@ -526,6 +534,10 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr...@@ -526,6 +534,10 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
526 try assignShift(gz, scope, node, .shl);534 try assignShift(gz, scope, node, .shl);
527 return rvalue(gz, rl, .void_value, node);535 return rvalue(gz, rl, .void_value, node);
528 },536 },
537 .assign_bit_shift_left_sat => {
538 try assignBinOpExt(gz, scope, node, .shl_with_saturation);
539 return rvalue(gz, rl, .void_value, node);
540 },
529 .assign_bit_shift_right => {541 .assign_bit_shift_right => {
530 try assignShift(gz, scope, node, .shr);542 try assignShift(gz, scope, node, .shr);
531 return rvalue(gz, rl, .void_value, node);543 return rvalue(gz, rl, .void_value, node);
...@@ -555,6 +567,10 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr...@@ -555,6 +567,10 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
555 try assignOp(gz, scope, node, .subwrap);567 try assignOp(gz, scope, node, .subwrap);
556 return rvalue(gz, rl, .void_value, node);568 return rvalue(gz, rl, .void_value, node);
557 },569 },
570 .assign_sub_sat => {
571 try assignBinOpExt(gz, scope, node, .sub_with_saturation);
572 return rvalue(gz, rl, .void_value, node);
573 },
558 .assign_mod => {574 .assign_mod => {
559 try assignOp(gz, scope, node, .mod_rem);575 try assignOp(gz, scope, node, .mod_rem);
560 return rvalue(gz, rl, .void_value, node);576 return rvalue(gz, rl, .void_value, node);
...@@ -567,6 +583,10 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr...@@ -567,6 +583,10 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
567 try assignOp(gz, scope, node, .addwrap);583 try assignOp(gz, scope, node, .addwrap);
568 return rvalue(gz, rl, .void_value, node);584 return rvalue(gz, rl, .void_value, node);
569 },585 },
586 .assign_add_sat => {
587 try assignBinOpExt(gz, scope, node, .add_with_saturation);
588 return rvalue(gz, rl, .void_value, node);
589 },
570 .assign_mul => {590 .assign_mul => {
571 try assignOp(gz, scope, node, .mul);591 try assignOp(gz, scope, node, .mul);
572 return rvalue(gz, rl, .void_value, node);592 return rvalue(gz, rl, .void_value, node);
...@@ -575,17 +595,25 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr...@@ -575,17 +595,25 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
575 try assignOp(gz, scope, node, .mulwrap);595 try assignOp(gz, scope, node, .mulwrap);
576 return rvalue(gz, rl, .void_value, node);596 return rvalue(gz, rl, .void_value, node);
577 },597 },
598 .assign_mul_sat => {
599 try assignBinOpExt(gz, scope, node, .mul_with_saturation);
600 return rvalue(gz, rl, .void_value, node);
601 },
578602
579 // zig fmt: off603 // zig fmt: off
580 .bit_shift_left => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shl),604 .bit_shift_left => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shl),
581 .bit_shift_right => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shr),605 .bit_shift_left_sat => return binOpExt(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shl_with_saturation),
606 .bit_shift_right => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shr),
582607
583 .add => return simpleBinOp(gz, scope, rl, node, .add),608 .add => return simpleBinOp(gz, scope, rl, node, .add),
584 .add_wrap => return simpleBinOp(gz, scope, rl, node, .addwrap),609 .add_wrap => return simpleBinOp(gz, scope, rl, node, .addwrap),
610 .add_sat => return binOpExt(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .add_with_saturation),
585 .sub => return simpleBinOp(gz, scope, rl, node, .sub),611 .sub => return simpleBinOp(gz, scope, rl, node, .sub),
586 .sub_wrap => return simpleBinOp(gz, scope, rl, node, .subwrap),612 .sub_wrap => return simpleBinOp(gz, scope, rl, node, .subwrap),
613 .sub_sat => return binOpExt(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .sub_with_saturation),
587 .mul => return simpleBinOp(gz, scope, rl, node, .mul),614 .mul => return simpleBinOp(gz, scope, rl, node, .mul),
588 .mul_wrap => return simpleBinOp(gz, scope, rl, node, .mulwrap),615 .mul_wrap => return simpleBinOp(gz, scope, rl, node, .mulwrap),
616 .mul_sat => return binOpExt(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .mul_with_saturation),
589 .div => return simpleBinOp(gz, scope, rl, node, .div),617 .div => return simpleBinOp(gz, scope, rl, node, .div),
590 .mod => return simpleBinOp(gz, scope, rl, node, .mod_rem),618 .mod => return simpleBinOp(gz, scope, rl, node, .mod_rem),
591 .bit_and => {619 .bit_and => {
...@@ -2685,6 +2713,31 @@ fn assignOp(...@@ -2685,6 +2713,31 @@ fn assignOp(
2685 _ = try gz.addBin(.store, lhs_ptr, result);2713 _ = try gz.addBin(.store, lhs_ptr, result);
2686}2714}
26872715
2716// TODO: is there an existing method to accomplish this?
2717// TODO: likely rename this to indicate rhs type coercion or add more params to make it more general
2718fn assignBinOpExt(
2719 gz: *GenZir,
2720 scope: *Scope,
2721 infix_node: Ast.Node.Index,
2722 op_inst_tag: Zir.Inst.Extended,
2723) InnerError!void {
2724 try emitDbgNode(gz, infix_node);
2725 const astgen = gz.astgen;
2726 const tree = astgen.tree;
2727 const node_datas = tree.nodes.items(.data);
2728
2729 const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs);
2730 const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node);
2731 const lhs_type = try gz.addUnNode(.typeof, lhs, infix_node);
2732 const rhs = try expr(gz, scope, .{ .coerced_ty = lhs_type }, node_datas[infix_node].rhs);
2733 const result = try gz.addExtendedPayload(op_inst_tag, Zir.Inst.BinNode{
2734 .node = gz.nodeIndexToRelative(infix_node),
2735 .lhs = lhs,
2736 .rhs = rhs,
2737 });
2738 _ = try gz.addBin(.store, lhs_ptr, result);
2739}
2740
2688fn assignShift(2741fn assignShift(
2689 gz: *GenZir,2742 gz: *GenZir,
2690 scope: *Scope,2743 scope: *Scope,
...@@ -2708,6 +2761,29 @@ fn assignShift(...@@ -2708,6 +2761,29 @@ fn assignShift(
2708 _ = try gz.addBin(.store, lhs_ptr, result);2761 _ = try gz.addBin(.store, lhs_ptr, result);
2709}2762}
27102763
2764fn assignShiftSat(
2765 gz: *GenZir,
2766 scope: *Scope,
2767 infix_node: ast.Node.Index,
2768 op_inst_tag: Zir.Inst.Tag,
2769) InnerError!void {
2770 try emitDbgNode(gz, infix_node);
2771 const astgen = gz.astgen;
2772 const tree = astgen.tree;
2773 const node_datas = tree.nodes.items(.data);
2774
2775 const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs);
2776 const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node);
2777 const rhs_type = try gz.addUnNode(.typeof, lhs, infix_node);
2778 const rhs = try expr(gz, scope, .{ .ty = rhs_type }, node_datas[infix_node].rhs);
2779
2780 const result = try gz.addPlNode(op_inst_tag, infix_node, Zir.Inst.Bin{
2781 .lhs = lhs,
2782 .rhs = rhs,
2783 });
2784 _ = try gz.addBin(.store, lhs_ptr, result);
2785}
2786
2711fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir.Inst.Ref {2787fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir.Inst.Ref {
2712 const astgen = gz.astgen;2788 const astgen = gz.astgen;
2713 const tree = astgen.tree;2789 const tree = astgen.tree;
...@@ -7827,6 +7903,26 @@ fn shiftOp(...@@ -7827,6 +7903,26 @@ fn shiftOp(
7827 return rvalue(gz, rl, result, node);7903 return rvalue(gz, rl, result, node);
7828}7904}
78297905
7906// TODO: is there an existing way to do this?
7907// TODO: likely rename this to reflect result_loc == .none or add more params to make it more general
7908fn binOpExt(
7909 gz: *GenZir,
7910 scope: *Scope,
7911 rl: ResultLoc,
7912 node: Ast.Node.Index,
7913 lhs_node: Ast.Node.Index,
7914 rhs_node: Ast.Node.Index,
7915 tag: Zir.Inst.Extended,
7916) InnerError!Zir.Inst.Ref {
7917 const lhs = try expr(gz, scope, .none, lhs_node);
7918 const rhs = try expr(gz, scope, .none, rhs_node);
7919 const result = try gz.addExtendedPayload(tag, Zir.Inst.Bin{
7920 .lhs = lhs,
7921 .rhs = rhs,
7922 });
7923 return rvalue(gz, rl, result, node);
7924}
7925
7830fn cImport(7926fn cImport(
7831 gz: *GenZir,7927 gz: *GenZir,
7832 scope: *Scope,7928 scope: *Scope,
...@@ -8119,26 +8215,32 @@ fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index) bool...@@ -8119,26 +8215,32 @@ fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index) bool
8119 .asm_simple,8215 .asm_simple,
8120 .add,8216 .add,
8121 .add_wrap,8217 .add_wrap,
8218 .add_sat,
8122 .array_cat,8219 .array_cat,
8123 .array_mult,8220 .array_mult,
8124 .assign,8221 .assign,
8125 .assign_bit_and,8222 .assign_bit_and,
8126 .assign_bit_or,8223 .assign_bit_or,
8127 .assign_bit_shift_left,8224 .assign_bit_shift_left,
8225 .assign_bit_shift_left_sat,
8128 .assign_bit_shift_right,8226 .assign_bit_shift_right,
8129 .assign_bit_xor,8227 .assign_bit_xor,
8130 .assign_div,8228 .assign_div,
8131 .assign_sub,8229 .assign_sub,
8132 .assign_sub_wrap,8230 .assign_sub_wrap,
8231 .assign_sub_sat,
8133 .assign_mod,8232 .assign_mod,
8134 .assign_add,8233 .assign_add,
8135 .assign_add_wrap,8234 .assign_add_wrap,
8235 .assign_add_sat,
8136 .assign_mul,8236 .assign_mul,
8137 .assign_mul_wrap,8237 .assign_mul_wrap,
8238 .assign_mul_sat,
8138 .bang_equal,8239 .bang_equal,
8139 .bit_and,8240 .bit_and,
8140 .bit_or,8241 .bit_or,
8141 .bit_shift_left,8242 .bit_shift_left,
8243 .bit_shift_left_sat,
8142 .bit_shift_right,8244 .bit_shift_right,
8143 .bit_xor,8245 .bit_xor,
8144 .bool_and,8246 .bool_and,
...@@ -8154,10 +8256,12 @@ fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index) bool...@@ -8154,10 +8256,12 @@ fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index) bool
8154 .mod,8256 .mod,
8155 .mul,8257 .mul,
8156 .mul_wrap,8258 .mul_wrap,
8259 .mul_sat,
8157 .switch_range,8260 .switch_range,
8158 .field_access,8261 .field_access,
8159 .sub,8262 .sub,
8160 .sub_wrap,8263 .sub_wrap,
8264 .sub_sat,
8161 .slice,8265 .slice,
8162 .slice_open,8266 .slice_open,
8163 .slice_sentinel,8267 .slice_sentinel,
...@@ -8352,26 +8456,32 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) enum { never...@@ -8352,26 +8456,32 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) enum { never
8352 .tagged_union_enum_tag_trailing,8456 .tagged_union_enum_tag_trailing,
8353 .add,8457 .add,
8354 .add_wrap,8458 .add_wrap,
8459 .add_sat,
8355 .array_cat,8460 .array_cat,
8356 .array_mult,8461 .array_mult,
8357 .assign,8462 .assign,
8358 .assign_bit_and,8463 .assign_bit_and,
8359 .assign_bit_or,8464 .assign_bit_or,
8360 .assign_bit_shift_left,8465 .assign_bit_shift_left,
8466 .assign_bit_shift_left_sat,
8361 .assign_bit_shift_right,8467 .assign_bit_shift_right,
8362 .assign_bit_xor,8468 .assign_bit_xor,
8363 .assign_div,8469 .assign_div,
8364 .assign_sub,8470 .assign_sub,
8365 .assign_sub_wrap,8471 .assign_sub_wrap,
8472 .assign_sub_sat,
8366 .assign_mod,8473 .assign_mod,
8367 .assign_add,8474 .assign_add,
8368 .assign_add_wrap,8475 .assign_add_wrap,
8476 .assign_add_sat,
8369 .assign_mul,8477 .assign_mul,
8370 .assign_mul_wrap,8478 .assign_mul_wrap,
8479 .assign_mul_sat,
8371 .bang_equal,8480 .bang_equal,
8372 .bit_and,8481 .bit_and,
8373 .bit_or,8482 .bit_or,
8374 .bit_shift_left,8483 .bit_shift_left,
8484 .bit_shift_left_sat,
8375 .bit_shift_right,8485 .bit_shift_right,
8376 .bit_xor,8486 .bit_xor,
8377 .bool_and,8487 .bool_and,
...@@ -8387,9 +8497,11 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) enum { never...@@ -8387,9 +8497,11 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) enum { never
8387 .mod,8497 .mod,
8388 .mul,8498 .mul,
8389 .mul_wrap,8499 .mul_wrap,
8500 .mul_sat,
8390 .switch_range,8501 .switch_range,
8391 .sub,8502 .sub,
8392 .sub_wrap,8503 .sub_wrap,
8504 .sub_sat,
8393 .slice,8505 .slice,
8394 .slice_open,8506 .slice_open,
8395 .slice_sentinel,8507 .slice_sentinel,
...@@ -8524,26 +8636,32 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {...@@ -8524,26 +8636,32 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
8524 .asm_simple,8636 .asm_simple,
8525 .add,8637 .add,
8526 .add_wrap,8638 .add_wrap,
8639 .add_sat,
8527 .array_cat,8640 .array_cat,
8528 .array_mult,8641 .array_mult,
8529 .assign,8642 .assign,
8530 .assign_bit_and,8643 .assign_bit_and,
8531 .assign_bit_or,8644 .assign_bit_or,
8532 .assign_bit_shift_left,8645 .assign_bit_shift_left,
8646 .assign_bit_shift_left_sat,
8533 .assign_bit_shift_right,8647 .assign_bit_shift_right,
8534 .assign_bit_xor,8648 .assign_bit_xor,
8535 .assign_div,8649 .assign_div,
8536 .assign_sub,8650 .assign_sub,
8537 .assign_sub_wrap,8651 .assign_sub_wrap,
8652 .assign_sub_sat,
8538 .assign_mod,8653 .assign_mod,
8539 .assign_add,8654 .assign_add,
8540 .assign_add_wrap,8655 .assign_add_wrap,
8656 .assign_add_sat,
8541 .assign_mul,8657 .assign_mul,
8542 .assign_mul_wrap,8658 .assign_mul_wrap,
8659 .assign_mul_sat,
8543 .bang_equal,8660 .bang_equal,
8544 .bit_and,8661 .bit_and,
8545 .bit_or,8662 .bit_or,
8546 .bit_shift_left,8663 .bit_shift_left,
8664 .bit_shift_left_sat,
8547 .bit_shift_right,8665 .bit_shift_right,
8548 .bit_xor,8666 .bit_xor,
8549 .bool_and,8667 .bool_and,
...@@ -8559,10 +8677,12 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {...@@ -8559,10 +8677,12 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
8559 .mod,8677 .mod,
8560 .mul,8678 .mul,
8561 .mul_wrap,8679 .mul_wrap,
8680 .mul_sat,
8562 .switch_range,8681 .switch_range,
8563 .field_access,8682 .field_access,
8564 .sub,8683 .sub,
8565 .sub_wrap,8684 .sub_wrap,
8685 .sub_sat,
8566 .slice,8686 .slice,
8567 .slice_open,8687 .slice_open,
8568 .slice_sentinel,8688 .slice_sentinel,
src/Liveness.zig+4
...@@ -226,10 +226,13 @@ fn analyzeInst(...@@ -226,10 +226,13 @@ fn analyzeInst(
226 switch (inst_tags[inst]) {226 switch (inst_tags[inst]) {
227 .add,227 .add,
228 .addwrap,228 .addwrap,
229 .addsat,
229 .sub,230 .sub,
230 .subwrap,231 .subwrap,
232 .subsat,
231 .mul,233 .mul,
232 .mulwrap,234 .mulwrap,
235 .mulsat,
233 .div,236 .div,
234 .rem,237 .rem,
235 .mod,238 .mod,
...@@ -252,6 +255,7 @@ fn analyzeInst(...@@ -252,6 +255,7 @@ fn analyzeInst(
252 .ptr_elem_val,255 .ptr_elem_val,
253 .ptr_ptr_elem_val,256 .ptr_ptr_elem_val,
254 .shl,257 .shl,
258 .shl_sat,
255 .shr,259 .shr,
256 .atomic_store_unordered,260 .atomic_store_unordered,
257 .atomic_store_monotonic,261 .atomic_store_monotonic,
src/codegen.zig+12
...@@ -826,10 +826,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -826,10 +826,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
826 // zig fmt: off826 // zig fmt: off
827 .add, .ptr_add => try self.airAdd(inst),827 .add, .ptr_add => try self.airAdd(inst),
828 .addwrap => try self.airAddWrap(inst),828 .addwrap => try self.airAddWrap(inst),
829 .addsat => try self.airArithmeticOpSat(inst, "addsat"),
829 .sub, .ptr_sub => try self.airSub(inst),830 .sub, .ptr_sub => try self.airSub(inst),
830 .subwrap => try self.airSubWrap(inst),831 .subwrap => try self.airSubWrap(inst),
832 .subsat => try self.airArithmeticOpSat(inst, "subsat"),
831 .mul => try self.airMul(inst),833 .mul => try self.airMul(inst),
832 .mulwrap => try self.airMulWrap(inst),834 .mulwrap => try self.airMulWrap(inst),
835 .mulsat => try self.airArithmeticOpSat(inst, "mulsat"),
833 .div => try self.airDiv(inst),836 .div => try self.airDiv(inst),
834 .rem => try self.airRem(inst),837 .rem => try self.airRem(inst),
835 .mod => try self.airMod(inst),838 .mod => try self.airMod(inst),
...@@ -848,6 +851,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -848,6 +851,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
848 .xor => try self.airXor(inst),851 .xor => try self.airXor(inst),
849 .shr => try self.airShr(inst),852 .shr => try self.airShr(inst),
850 .shl => try self.airShl(inst),853 .shl => try self.airShl(inst),
854 .shl_sat => try self.airArithmeticOpSat(inst, "shl_sat"),
851855
852 .alloc => try self.airAlloc(inst),856 .alloc => try self.airAlloc(inst),
853 .arg => try self.airArg(inst),857 .arg => try self.airArg(inst),
...@@ -1320,6 +1324,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1320,6 +1324,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1320 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1324 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1321 }1325 }
13221326
1327 fn airArithmeticOpSat(self: *Self, inst: Air.Inst.Index, comptime name: []const u8) !void {
1328 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1329 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
1330 else => return self.fail("TODO implement " ++ name ++ " for {}", .{self.target.cpu.arch}),
1331 };
1332 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1333 }
1334
1323 fn airMul(self: *Self, inst: Air.Inst.Index) !void {1335 fn airMul(self: *Self, inst: Air.Inst.Index) !void {
1324 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1336 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1325 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {1337 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
src/codegen/c.zig+3
...@@ -885,14 +885,17 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -885,14 +885,17 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
885 // that wrapping is UB.885 // that wrapping is UB.
886 .add, .ptr_add => try airBinOp( f, inst, " + "),886 .add, .ptr_add => try airBinOp( f, inst, " + "),
887 .addwrap => try airWrapOp(f, inst, " + ", "addw_"),887 .addwrap => try airWrapOp(f, inst, " + ", "addw_"),
888 .addsat => return o.dg.fail("TODO: C backend: implement codegen for addsat", .{}),
888 // TODO use a different strategy for sub that communicates to the optimizer889 // TODO use a different strategy for sub that communicates to the optimizer
889 // that wrapping is UB.890 // that wrapping is UB.
890 .sub, .ptr_sub => try airBinOp( f, inst, " - "),891 .sub, .ptr_sub => try airBinOp( f, inst, " - "),
891 .subwrap => try airWrapOp(f, inst, " - ", "subw_"),892 .subwrap => try airWrapOp(f, inst, " - ", "subw_"),
893 .subsat => return o.dg.fail("TODO: C backend: implement codegen for subsat", .{}),
892 // TODO use a different strategy for mul that communicates to the optimizer894 // TODO use a different strategy for mul that communicates to the optimizer
893 // that wrapping is UB.895 // that wrapping is UB.
894 .mul => try airBinOp( f, inst, " * "),896 .mul => try airBinOp( f, inst, " * "),
895 .mulwrap => try airWrapOp(f, inst, " * ", "mulw_"),897 .mulwrap => try airWrapOp(f, inst, " * ", "mulw_"),
898 .mulsat => return o.dg.fail("TODO: C backend: implement codegen for mulsat", .{}),
896 // TODO use a different strategy for div that communicates to the optimizer899 // TODO use a different strategy for div that communicates to the optimizer
897 // that wrapping is UB.900 // that wrapping is UB.
898 .div => try airBinOp( f, inst, " / "),901 .div => try airBinOp( f, inst, " / "),
src/codegen/llvm.zig+49-17
...@@ -1236,12 +1236,15 @@ pub const FuncGen = struct {...@@ -1236,12 +1236,15 @@ pub const FuncGen = struct {
1236 for (body) |inst| {1236 for (body) |inst| {
1237 const opt_value: ?*const llvm.Value = switch (air_tags[inst]) {1237 const opt_value: ?*const llvm.Value = switch (air_tags[inst]) {
1238 // zig fmt: off1238 // zig fmt: off
1239 .add => try self.airAdd(inst, false),1239 .add => try self.airAdd(inst, .standard),
1240 .addwrap => try self.airAdd(inst, true),1240 .addwrap => try self.airAdd(inst, .wrapping),
1241 .sub => try self.airSub(inst, false),1241 .addsat => try self.airAdd(inst, .saturated),
1242 .subwrap => try self.airSub(inst, true),1242 .sub => try self.airSub(inst, .standard),
1243 .mul => try self.airMul(inst, false),1243 .subwrap => try self.airSub(inst, .wrapping),
1244 .mulwrap => try self.airMul(inst, true),1244 .subsat => try self.airSub(inst, .saturated),
1245 .mul => try self.airMul(inst, .standard),
1246 .mulwrap => try self.airMul(inst, .wrapping),
1247 .mulsat => try self.airMul(inst, .saturated),
1245 .div => try self.airDiv(inst),1248 .div => try self.airDiv(inst),
1246 .rem => try self.airRem(inst),1249 .rem => try self.airRem(inst),
1247 .mod => try self.airMod(inst),1250 .mod => try self.airMod(inst),
...@@ -1252,7 +1255,8 @@ pub const FuncGen = struct {...@@ -1252,7 +1255,8 @@ pub const FuncGen = struct {
1252 .bit_or, .bool_or => try self.airOr(inst),1255 .bit_or, .bool_or => try self.airOr(inst),
1253 .xor => try self.airXor(inst),1256 .xor => try self.airXor(inst),
12541257
1255 .shl => try self.airShl(inst),1258 .shl => try self.airShl(inst, false),
1259 .shl_sat => try self.airShl(inst, true),
1256 .shr => try self.airShr(inst),1260 .shr => try self.airShr(inst),
12571261
1258 .cmp_eq => try self.airCmp(inst, .eq),1262 .cmp_eq => try self.airCmp(inst, .eq),
...@@ -2024,7 +2028,8 @@ pub const FuncGen = struct {...@@ -2024,7 +2028,8 @@ pub const FuncGen = struct {
2024 return self.todo("implement llvm codegen for 'airWrapErrUnionErr'", .{});2028 return self.todo("implement llvm codegen for 'airWrapErrUnionErr'", .{});
2025 }2029 }
20262030
2027 fn airAdd(self: *FuncGen, inst: Air.Inst.Index, wrap: bool) !?*const llvm.Value {2031 const ArithmeticType = enum { standard, wrapping, saturated };
2032 fn airAdd(self: *FuncGen, inst: Air.Inst.Index, ty: ArithmeticType) !?*const llvm.Value {
2028 if (self.liveness.isUnused(inst))2033 if (self.liveness.isUnused(inst))
2029 return null;2034 return null;
20302035
...@@ -2033,13 +2038,20 @@ pub const FuncGen = struct {...@@ -2033,13 +2038,20 @@ pub const FuncGen = struct {
2033 const rhs = try self.resolveInst(bin_op.rhs);2038 const rhs = try self.resolveInst(bin_op.rhs);
2034 const inst_ty = self.air.typeOfIndex(inst);2039 const inst_ty = self.air.typeOfIndex(inst);
20352040
2036 if (inst_ty.isRuntimeFloat()) return self.builder.buildFAdd(lhs, rhs, "");2041 if (inst_ty.isFloat()) return self.builder.buildFAdd(lhs, rhs, "");
2037 if (wrap) return self.builder.buildAdd(lhs, rhs, "");2042 if (ty == .wrapping)
2043 return self.builder.buildAdd(lhs, rhs, "")
2044 else if (ty == .saturated) {
2045 if (inst_ty.isSignedInt())
2046 return self.builder.buildSAddSat(lhs, rhs, "")
2047 else
2048 return self.builder.buildUAddSat(lhs, rhs, "");
2049 }
2038 if (inst_ty.isSignedInt()) return self.builder.buildNSWAdd(lhs, rhs, "");2050 if (inst_ty.isSignedInt()) return self.builder.buildNSWAdd(lhs, rhs, "");
2039 return self.builder.buildNUWAdd(lhs, rhs, "");2051 return self.builder.buildNUWAdd(lhs, rhs, "");
2040 }2052 }
20412053
2042 fn airSub(self: *FuncGen, inst: Air.Inst.Index, wrap: bool) !?*const llvm.Value {2054 fn airSub(self: *FuncGen, inst: Air.Inst.Index, ty: ArithmeticType) !?*const llvm.Value {
2043 if (self.liveness.isUnused(inst))2055 if (self.liveness.isUnused(inst))
2044 return null;2056 return null;
20452057
...@@ -2048,13 +2060,20 @@ pub const FuncGen = struct {...@@ -2048,13 +2060,20 @@ pub const FuncGen = struct {
2048 const rhs = try self.resolveInst(bin_op.rhs);2060 const rhs = try self.resolveInst(bin_op.rhs);
2049 const inst_ty = self.air.typeOfIndex(inst);2061 const inst_ty = self.air.typeOfIndex(inst);
20502062
2051 if (inst_ty.isRuntimeFloat()) return self.builder.buildFSub(lhs, rhs, "");2063 if (inst_ty.isFloat()) return self.builder.buildFSub(lhs, rhs, "");
2052 if (wrap) return self.builder.buildSub(lhs, rhs, "");2064 if (ty == .wrapping)
2065 return self.builder.buildSub(lhs, rhs, "")
2066 else if (ty == .saturated) {
2067 if (inst_ty.isSignedInt())
2068 return self.builder.buildSSubSat(lhs, rhs, "")
2069 else
2070 return self.builder.buildUSubSat(lhs, rhs, "");
2071 }
2053 if (inst_ty.isSignedInt()) return self.builder.buildNSWSub(lhs, rhs, "");2072 if (inst_ty.isSignedInt()) return self.builder.buildNSWSub(lhs, rhs, "");
2054 return self.builder.buildNUWSub(lhs, rhs, "");2073 return self.builder.buildNUWSub(lhs, rhs, "");
2055 }2074 }
20562075
2057 fn airMul(self: *FuncGen, inst: Air.Inst.Index, wrap: bool) !?*const llvm.Value {2076 fn airMul(self: *FuncGen, inst: Air.Inst.Index, ty: ArithmeticType) !?*const llvm.Value {
2058 if (self.liveness.isUnused(inst))2077 if (self.liveness.isUnused(inst))
2059 return null;2078 return null;
20602079
...@@ -2063,8 +2082,15 @@ pub const FuncGen = struct {...@@ -2063,8 +2082,15 @@ pub const FuncGen = struct {
2063 const rhs = try self.resolveInst(bin_op.rhs);2082 const rhs = try self.resolveInst(bin_op.rhs);
2064 const inst_ty = self.air.typeOfIndex(inst);2083 const inst_ty = self.air.typeOfIndex(inst);
20652084
2066 if (inst_ty.isRuntimeFloat()) return self.builder.buildFMul(lhs, rhs, "");2085 if (inst_ty.isFloat()) return self.builder.buildFMul(lhs, rhs, "");
2067 if (wrap) return self.builder.buildMul(lhs, rhs, "");2086 if (ty == .wrapping)
2087 return self.builder.buildMul(lhs, rhs, "")
2088 else if (ty == .saturated) {
2089 if (inst_ty.isSignedInt())
2090 return self.builder.buildSMulFixSat(lhs, rhs, "")
2091 else
2092 return self.builder.buildUMulFixSat(lhs, rhs, "");
2093 }
2068 if (inst_ty.isSignedInt()) return self.builder.buildNSWMul(lhs, rhs, "");2094 if (inst_ty.isSignedInt()) return self.builder.buildNSWMul(lhs, rhs, "");
2069 return self.builder.buildNUWMul(lhs, rhs, "");2095 return self.builder.buildNUWMul(lhs, rhs, "");
2070 }2096 }
...@@ -2174,7 +2200,7 @@ pub const FuncGen = struct {...@@ -2174,7 +2200,7 @@ pub const FuncGen = struct {
2174 return self.builder.buildXor(lhs, rhs, "");2200 return self.builder.buildXor(lhs, rhs, "");
2175 }2201 }
21762202
2177 fn airShl(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {2203 fn airShl(self: *FuncGen, inst: Air.Inst.Index, sat: bool) !?*const llvm.Value {
2178 if (self.liveness.isUnused(inst))2204 if (self.liveness.isUnused(inst))
2179 return null;2205 return null;
2180 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2206 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -2186,6 +2212,12 @@ pub const FuncGen = struct {...@@ -2186,6 +2212,12 @@ pub const FuncGen = struct {
2186 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")2212 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")
2187 else2213 else
2188 rhs;2214 rhs;
2215 if (sat) {
2216 return if (lhs_type.isSignedInt())
2217 self.builder.buildSShlSat(lhs, casted_rhs, "")
2218 else
2219 self.builder.buildUShlSat(lhs, casted_rhs, "");
2220 }
2189 return self.builder.buildShl(lhs, casted_rhs, "");2221 return self.builder.buildShl(lhs, casted_rhs, "");
2190 }2222 }
21912223
src/codegen/llvm/bindings.zig+24
...@@ -397,6 +397,12 @@ pub const Builder = opaque {...@@ -397,6 +397,12 @@ pub const Builder = opaque {
397 pub const buildNUWAdd = LLVMBuildNUWAdd;397 pub const buildNUWAdd = LLVMBuildNUWAdd;
398 extern fn LLVMBuildNUWAdd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;398 extern fn LLVMBuildNUWAdd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
399399
400 pub const buildSAddSat = ZigLLVMBuildSAddSat;
401 extern fn ZigLLVMBuildSAddSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
402
403 pub const buildUAddSat = ZigLLVMBuildUAddSat;
404 extern fn ZigLLVMBuildUAddSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
405
400 pub const buildFSub = LLVMBuildFSub;406 pub const buildFSub = LLVMBuildFSub;
401 extern fn LLVMBuildFSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;407 extern fn LLVMBuildFSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
402408
...@@ -409,6 +415,12 @@ pub const Builder = opaque {...@@ -409,6 +415,12 @@ pub const Builder = opaque {
409 pub const buildNUWSub = LLVMBuildNUWSub;415 pub const buildNUWSub = LLVMBuildNUWSub;
410 extern fn LLVMBuildNUWSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;416 extern fn LLVMBuildNUWSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
411417
418 pub const buildSSubSat = ZigLLVMBuildSSubSat;
419 extern fn ZigLLVMBuildSSubSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
420
421 pub const buildUSubSat = ZigLLVMBuildUSubSat;
422 extern fn ZigLLVMBuildUSubSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
423
412 pub const buildFMul = LLVMBuildFMul;424 pub const buildFMul = LLVMBuildFMul;
413 extern fn LLVMBuildFMul(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;425 extern fn LLVMBuildFMul(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
414426
...@@ -421,6 +433,12 @@ pub const Builder = opaque {...@@ -421,6 +433,12 @@ pub const Builder = opaque {
421 pub const buildNUWMul = LLVMBuildNUWMul;433 pub const buildNUWMul = LLVMBuildNUWMul;
422 extern fn LLVMBuildNUWMul(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;434 extern fn LLVMBuildNUWMul(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
423435
436 pub const buildSMulFixSat = ZigLLVMBuildSMulFixSat;
437 extern fn ZigLLVMBuildSMulFixSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
438
439 pub const buildUMulFixSat = ZigLLVMBuildUMulFixSat;
440 extern fn ZigLLVMBuildUMulFixSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
441
424 pub const buildUDiv = LLVMBuildUDiv;442 pub const buildUDiv = LLVMBuildUDiv;
425 extern fn LLVMBuildUDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;443 extern fn LLVMBuildUDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
426444
...@@ -451,6 +469,12 @@ pub const Builder = opaque {...@@ -451,6 +469,12 @@ pub const Builder = opaque {
451 pub const buildShl = LLVMBuildShl;469 pub const buildShl = LLVMBuildShl;
452 extern fn LLVMBuildShl(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;470 extern fn LLVMBuildShl(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
453471
472 pub const buildSShlSat = ZigLLVMBuildSShlSat;
473 extern fn ZigLLVMBuildSShlSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
474
475 pub const buildUShlSat = ZigLLVMBuildUShlSat;
476 extern fn ZigLLVMBuildUShlSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
477
454 pub const buildOr = LLVMBuildOr;478 pub const buildOr = LLVMBuildOr;
455 extern fn LLVMBuildOr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;479 extern fn LLVMBuildOr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
456480
src/print_air.zig+4
...@@ -104,10 +104,13 @@ const Writer = struct {...@@ -104,10 +104,13 @@ const Writer = struct {
104104
105 .add,105 .add,
106 .addwrap,106 .addwrap,
107 .addsat,
107 .sub,108 .sub,
108 .subwrap,109 .subwrap,
110 .subsat,
109 .mul,111 .mul,
110 .mulwrap,112 .mulwrap,
113 .mulsat,
111 .div,114 .div,
112 .rem,115 .rem,
113 .mod,116 .mod,
...@@ -130,6 +133,7 @@ const Writer = struct {...@@ -130,6 +133,7 @@ const Writer = struct {
130 .ptr_elem_val,133 .ptr_elem_val,
131 .ptr_ptr_elem_val,134 .ptr_ptr_elem_val,
132 .shl,135 .shl,
136 .shl_sat,
133 .shr,137 .shr,
134 .set_union_tag,138 .set_union_tag,
135 => try w.writeBinOp(s, inst),139 => try w.writeBinOp(s, inst),
src/stage1/all_types.hpp+12-4
...@@ -812,14 +812,18 @@ enum BinOpType {...@@ -812,14 +812,18 @@ enum BinOpType {
812 BinOpTypeInvalid,812 BinOpTypeInvalid,
813 BinOpTypeAssign,813 BinOpTypeAssign,
814 BinOpTypeAssignTimes,814 BinOpTypeAssignTimes,
815 BinOpTypeAssignTimesSat,
815 BinOpTypeAssignTimesWrap,816 BinOpTypeAssignTimesWrap,
816 BinOpTypeAssignDiv,817 BinOpTypeAssignDiv,
817 BinOpTypeAssignMod,818 BinOpTypeAssignMod,
818 BinOpTypeAssignPlus,819 BinOpTypeAssignPlus,
820 BinOpTypeAssignPlusSat,
819 BinOpTypeAssignPlusWrap,821 BinOpTypeAssignPlusWrap,
820 BinOpTypeAssignMinus,822 BinOpTypeAssignMinus,
823 BinOpTypeAssignMinusSat,
821 BinOpTypeAssignMinusWrap,824 BinOpTypeAssignMinusWrap,
822 BinOpTypeAssignBitShiftLeft,825 BinOpTypeAssignBitShiftLeft,
826 BinOpTypeAssignBitShiftLeftSat,
823 BinOpTypeAssignBitShiftRight,827 BinOpTypeAssignBitShiftRight,
824 BinOpTypeAssignBitAnd,828 BinOpTypeAssignBitAnd,
825 BinOpTypeAssignBitXor,829 BinOpTypeAssignBitXor,
...@@ -836,12 +840,16 @@ enum BinOpType {...@@ -836,12 +840,16 @@ enum BinOpType {
836 BinOpTypeBinXor,840 BinOpTypeBinXor,
837 BinOpTypeBinAnd,841 BinOpTypeBinAnd,
838 BinOpTypeBitShiftLeft,842 BinOpTypeBitShiftLeft,
843 BinOpTypeBitShiftLeftSat,
839 BinOpTypeBitShiftRight,844 BinOpTypeBitShiftRight,
840 BinOpTypeAdd,845 BinOpTypeAdd,
846 BinOpTypeAddSat,
841 BinOpTypeAddWrap,847 BinOpTypeAddWrap,
842 BinOpTypeSub,848 BinOpTypeSub,
849 BinOpTypeSubSat,
843 BinOpTypeSubWrap,850 BinOpTypeSubWrap,
844 BinOpTypeMult,851 BinOpTypeMult,
852 BinOpTypeMultSat,
845 BinOpTypeMultWrap,853 BinOpTypeMultWrap,
846 BinOpTypeDiv,854 BinOpTypeDiv,
847 BinOpTypeMod,855 BinOpTypeMod,
...@@ -2958,10 +2966,10 @@ enum IrBinOp {...@@ -2958,10 +2966,10 @@ enum IrBinOp {
2958 IrBinOpArrayMult,2966 IrBinOpArrayMult,
2959 IrBinOpMaximum,2967 IrBinOpMaximum,
2960 IrBinOpMinimum,2968 IrBinOpMinimum,
2961 IrBinOpSatAdd,2969 IrBinOpAddSat,
2962 IrBinOpSatSub,2970 IrBinOpSubSat,
2963 IrBinOpSatMul,2971 IrBinOpMultSat,
2964 IrBinOpSatShl,2972 IrBinOpShlSat,
2965};2973};
29662974
2967struct Stage1ZirInstBinOp {2975struct Stage1ZirInstBinOp {
src/stage1/astgen.cpp+20-4
...@@ -3672,6 +3672,8 @@ static Stage1ZirInst *astgen_bin_op(Stage1AstGen *ag, Scope *scope, AstNode *nod...@@ -3672,6 +3672,8 @@ static Stage1ZirInst *astgen_bin_op(Stage1AstGen *ag, Scope *scope, AstNode *nod
3672 return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpMult), lval, result_loc);3672 return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpMult), lval, result_loc);
3673 case BinOpTypeAssignTimesWrap:3673 case BinOpTypeAssignTimesWrap:
3674 return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpMultWrap), lval, result_loc);3674 return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpMultWrap), lval, result_loc);
3675 case BinOpTypeAssignTimesSat:
3676 return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpMultSat), lval, result_loc);
3675 case BinOpTypeAssignDiv:3677 case BinOpTypeAssignDiv:
3676 return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpDivUnspecified), lval, result_loc);3678 return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpDivUnspecified), lval, result_loc);
3677 case BinOpTypeAssignMod:3679 case BinOpTypeAssignMod:
...@@ -3680,12 +3682,18 @@ static Stage1ZirInst *astgen_bin_op(Stage1AstGen *ag, Scope *scope, AstNode *nod...@@ -3680,12 +3682,18 @@ static Stage1ZirInst *astgen_bin_op(Stage1AstGen *ag, Scope *scope, AstNode *nod
3680 return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpAdd), lval, result_loc);3682 return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpAdd), lval, result_loc);
3681 case BinOpTypeAssignPlusWrap:3683 case BinOpTypeAssignPlusWrap:
3682 return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpAddWrap), lval, result_loc);3684 return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpAddWrap), lval, result_loc);
3685 case BinOpTypeAssignPlusSat:
3686 return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpAddSat), lval, result_loc);
3683 case BinOpTypeAssignMinus:3687 case BinOpTypeAssignMinus:
3684 return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpSub), lval, result_loc);3688 return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpSub), lval, result_loc);
3685 case BinOpTypeAssignMinusWrap:3689 case BinOpTypeAssignMinusWrap:
3686 return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpSubWrap), lval, result_loc);3690 return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpSubWrap), lval, result_loc);
3691 case BinOpTypeAssignMinusSat:
3692 return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpSubSat), lval, result_loc);
3687 case BinOpTypeAssignBitShiftLeft:3693 case BinOpTypeAssignBitShiftLeft:
3688 return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpBitShiftLeftLossy), lval, result_loc);3694 return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpBitShiftLeftLossy), lval, result_loc);
3695 case BinOpTypeAssignBitShiftLeftSat:
3696 return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpShlSat), lval, result_loc);
3689 case BinOpTypeAssignBitShiftRight:3697 case BinOpTypeAssignBitShiftRight:
3690 return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpBitShiftRightLossy), lval, result_loc);3698 return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpBitShiftRightLossy), lval, result_loc);
3691 case BinOpTypeAssignBitAnd:3699 case BinOpTypeAssignBitAnd:
...@@ -3718,20 +3726,28 @@ static Stage1ZirInst *astgen_bin_op(Stage1AstGen *ag, Scope *scope, AstNode *nod...@@ -3718,20 +3726,28 @@ static Stage1ZirInst *astgen_bin_op(Stage1AstGen *ag, Scope *scope, AstNode *nod
3718 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpBinAnd), lval, result_loc);3726 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpBinAnd), lval, result_loc);
3719 case BinOpTypeBitShiftLeft:3727 case BinOpTypeBitShiftLeft:
3720 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpBitShiftLeftLossy), lval, result_loc);3728 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpBitShiftLeftLossy), lval, result_loc);
3729 case BinOpTypeBitShiftLeftSat:
3730 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpShlSat), lval, result_loc);
3721 case BinOpTypeBitShiftRight:3731 case BinOpTypeBitShiftRight:
3722 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpBitShiftRightLossy), lval, result_loc);3732 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpBitShiftRightLossy), lval, result_loc);
3723 case BinOpTypeAdd:3733 case BinOpTypeAdd:
3724 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpAdd), lval, result_loc);3734 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpAdd), lval, result_loc);
3725 case BinOpTypeAddWrap:3735 case BinOpTypeAddWrap:
3726 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpAddWrap), lval, result_loc);3736 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpAddWrap), lval, result_loc);
3737 case BinOpTypeAddSat:
3738 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpAddSat), lval, result_loc);
3727 case BinOpTypeSub:3739 case BinOpTypeSub:
3728 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpSub), lval, result_loc);3740 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpSub), lval, result_loc);
3729 case BinOpTypeSubWrap:3741 case BinOpTypeSubWrap:
3730 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpSubWrap), lval, result_loc);3742 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpSubWrap), lval, result_loc);
3743 case BinOpTypeSubSat:
3744 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpSubSat), lval, result_loc);
3731 case BinOpTypeMult:3745 case BinOpTypeMult:
3732 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpMult), lval, result_loc);3746 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpMult), lval, result_loc);
3733 case BinOpTypeMultWrap:3747 case BinOpTypeMultWrap:
3734 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpMultWrap), lval, result_loc);3748 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpMultWrap), lval, result_loc);
3749 case BinOpTypeMultSat:
3750 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpMultSat), lval, result_loc);
3735 case BinOpTypeDiv:3751 case BinOpTypeDiv:
3736 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpDivUnspecified), lval, result_loc);3752 return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpDivUnspecified), lval, result_loc);
3737 case BinOpTypeMod:3753 case BinOpTypeMod:
...@@ -4716,7 +4732,7 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast...@@ -4716,7 +4732,7 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast
4716 if (arg1_value == ag->codegen->invalid_inst_src)4732 if (arg1_value == ag->codegen->invalid_inst_src)
4717 return arg1_value;4733 return arg1_value;
47184734
4719 Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpSatAdd, arg0_value, arg1_value, true);4735 Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpAddSat, arg0_value, arg1_value, true);
4720 return ir_lval_wrap(ag, scope, bin_op, lval, result_loc);4736 return ir_lval_wrap(ag, scope, bin_op, lval, result_loc);
4721 }4737 }
4722 case BuiltinFnIdSatSub:4738 case BuiltinFnIdSatSub:
...@@ -4731,7 +4747,7 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast...@@ -4731,7 +4747,7 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast
4731 if (arg1_value == ag->codegen->invalid_inst_src)4747 if (arg1_value == ag->codegen->invalid_inst_src)
4732 return arg1_value;4748 return arg1_value;
47334749
4734 Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpSatSub, arg0_value, arg1_value, true);4750 Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpSubSat, arg0_value, arg1_value, true);
4735 return ir_lval_wrap(ag, scope, bin_op, lval, result_loc);4751 return ir_lval_wrap(ag, scope, bin_op, lval, result_loc);
4736 }4752 }
4737 case BuiltinFnIdSatMul:4753 case BuiltinFnIdSatMul:
...@@ -4746,7 +4762,7 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast...@@ -4746,7 +4762,7 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast
4746 if (arg1_value == ag->codegen->invalid_inst_src)4762 if (arg1_value == ag->codegen->invalid_inst_src)
4747 return arg1_value;4763 return arg1_value;
47484764
4749 Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpSatMul, arg0_value, arg1_value, true);4765 Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpMultSat, arg0_value, arg1_value, true);
4750 return ir_lval_wrap(ag, scope, bin_op, lval, result_loc);4766 return ir_lval_wrap(ag, scope, bin_op, lval, result_loc);
4751 }4767 }
4752 case BuiltinFnIdSatShl:4768 case BuiltinFnIdSatShl:
...@@ -4761,7 +4777,7 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast...@@ -4761,7 +4777,7 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast
4761 if (arg1_value == ag->codegen->invalid_inst_src)4777 if (arg1_value == ag->codegen->invalid_inst_src)
4762 return arg1_value;4778 return arg1_value;
47634779
4764 Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpSatShl, arg0_value, arg1_value, true);4780 Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpShlSat, arg0_value, arg1_value, true);
4765 return ir_lval_wrap(ag, scope, bin_op, lval, result_loc);4781 return ir_lval_wrap(ag, scope, bin_op, lval, result_loc);
4766 }4782 }
4767 case BuiltinFnIdMemcpy:4783 case BuiltinFnIdMemcpy:
src/stage1/codegen.cpp+4-4
...@@ -3333,7 +3333,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,...@@ -3333,7 +3333,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,
3333 } else {3333 } else {
3334 zig_unreachable();3334 zig_unreachable();
3335 }3335 }
3336 case IrBinOpSatAdd:3336 case IrBinOpAddSat:
3337 if (scalar_type->id == ZigTypeIdInt) {3337 if (scalar_type->id == ZigTypeIdInt) {
3338 if (scalar_type->data.integral.is_signed) {3338 if (scalar_type->data.integral.is_signed) {
3339 return ZigLLVMBuildSAddSat(g->builder, op1_value, op2_value, "");3339 return ZigLLVMBuildSAddSat(g->builder, op1_value, op2_value, "");
...@@ -3343,7 +3343,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,...@@ -3343,7 +3343,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,
3343 } else {3343 } else {
3344 zig_unreachable();3344 zig_unreachable();
3345 }3345 }
3346 case IrBinOpSatSub:3346 case IrBinOpSubSat:
3347 if (scalar_type->id == ZigTypeIdInt) {3347 if (scalar_type->id == ZigTypeIdInt) {
3348 if (scalar_type->data.integral.is_signed) {3348 if (scalar_type->data.integral.is_signed) {
3349 return ZigLLVMBuildSSubSat(g->builder, op1_value, op2_value, "");3349 return ZigLLVMBuildSSubSat(g->builder, op1_value, op2_value, "");
...@@ -3353,7 +3353,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,...@@ -3353,7 +3353,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,
3353 } else {3353 } else {
3354 zig_unreachable();3354 zig_unreachable();
3355 }3355 }
3356 case IrBinOpSatMul:3356 case IrBinOpMultSat:
3357 if (scalar_type->id == ZigTypeIdInt) {3357 if (scalar_type->id == ZigTypeIdInt) {
3358 if (scalar_type->data.integral.is_signed) {3358 if (scalar_type->data.integral.is_signed) {
3359 return ZigLLVMBuildSMulFixSat(g->builder, op1_value, op2_value, "");3359 return ZigLLVMBuildSMulFixSat(g->builder, op1_value, op2_value, "");
...@@ -3363,7 +3363,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,...@@ -3363,7 +3363,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,
3363 } else {3363 } else {
3364 zig_unreachable();3364 zig_unreachable();
3365 }3365 }
3366 case IrBinOpSatShl:3366 case IrBinOpShlSat:
3367 if (scalar_type->id == ZigTypeIdInt) {3367 if (scalar_type->id == ZigTypeIdInt) {
3368 if (scalar_type->data.integral.is_signed) {3368 if (scalar_type->data.integral.is_signed) {
3369 return ZigLLVMBuildSShlSat(g->builder, op1_value, op2_value, "");3369 return ZigLLVMBuildSShlSat(g->builder, op1_value, op2_value, "");
src/stage1/ir.cpp+12-12
...@@ -9820,28 +9820,28 @@ static ErrorMsg *ir_eval_math_op_scalar(IrAnalyze *ira, Scope *scope, AstNode *s...@@ -9820,28 +9820,28 @@ static ErrorMsg *ir_eval_math_op_scalar(IrAnalyze *ira, Scope *scope, AstNode *s
9820 float_min(out_val, op1_val, op2_val);9820 float_min(out_val, op1_val, op2_val);
9821 }9821 }
9822 break;9822 break;
9823 case IrBinOpSatAdd:9823 case IrBinOpAddSat:
9824 if (is_int) {9824 if (is_int) {
9825 bigint_add_sat(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, type_entry->data.integral.bit_count, type_entry->data.integral.is_signed);9825 bigint_add_sat(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, type_entry->data.integral.bit_count, type_entry->data.integral.is_signed);
9826 } else {9826 } else {
9827 zig_unreachable();9827 zig_unreachable();
9828 }9828 }
9829 break;9829 break;
9830 case IrBinOpSatSub:9830 case IrBinOpSubSat:
9831 if (is_int) {9831 if (is_int) {
9832 bigint_sub_sat(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, type_entry->data.integral.bit_count, type_entry->data.integral.is_signed);9832 bigint_sub_sat(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, type_entry->data.integral.bit_count, type_entry->data.integral.is_signed);
9833 } else {9833 } else {
9834 zig_unreachable();9834 zig_unreachable();
9835 }9835 }
9836 break;9836 break;
9837 case IrBinOpSatMul:9837 case IrBinOpMultSat:
9838 if (is_int) {9838 if (is_int) {
9839 bigint_mul_sat(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, type_entry->data.integral.bit_count, type_entry->data.integral.is_signed);9839 bigint_mul_sat(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, type_entry->data.integral.bit_count, type_entry->data.integral.is_signed);
9840 } else {9840 } else {
9841 zig_unreachable();9841 zig_unreachable();
9842 }9842 }
9843 break;9843 break;
9844 case IrBinOpSatShl:9844 case IrBinOpShlSat:
9845 if (is_int) {9845 if (is_int) {
9846 bigint_shl_sat(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, type_entry->data.integral.bit_count, type_entry->data.integral.is_signed);9846 bigint_shl_sat(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, type_entry->data.integral.bit_count, type_entry->data.integral.is_signed);
9847 } else {9847 } else {
...@@ -10069,10 +10069,10 @@ static bool ok_float_op(IrBinOp op) {...@@ -10069,10 +10069,10 @@ static bool ok_float_op(IrBinOp op) {
10069 case IrBinOpBitShiftRightExact:10069 case IrBinOpBitShiftRightExact:
10070 case IrBinOpAddWrap:10070 case IrBinOpAddWrap:
10071 case IrBinOpSubWrap:10071 case IrBinOpSubWrap:
10072 case IrBinOpSatAdd:10072 case IrBinOpAddSat:
10073 case IrBinOpSatSub:10073 case IrBinOpSubSat:
10074 case IrBinOpSatMul:10074 case IrBinOpMultSat:
10075 case IrBinOpSatShl:10075 case IrBinOpShlSat:
10076 case IrBinOpMultWrap:10076 case IrBinOpMultWrap:
10077 case IrBinOpArrayCat:10077 case IrBinOpArrayCat:
10078 case IrBinOpArrayMult:10078 case IrBinOpArrayMult:
...@@ -11046,10 +11046,10 @@ static Stage1AirInst *ir_analyze_instruction_bin_op(IrAnalyze *ira, Stage1ZirIns...@@ -11046,10 +11046,10 @@ static Stage1AirInst *ir_analyze_instruction_bin_op(IrAnalyze *ira, Stage1ZirIns
11046 case IrBinOpRemMod:11046 case IrBinOpRemMod:
11047 case IrBinOpMaximum:11047 case IrBinOpMaximum:
11048 case IrBinOpMinimum:11048 case IrBinOpMinimum:
11049 case IrBinOpSatAdd:11049 case IrBinOpAddSat:
11050 case IrBinOpSatSub:11050 case IrBinOpSubSat:
11051 case IrBinOpSatMul:11051 case IrBinOpMultSat:
11052 case IrBinOpSatShl:11052 case IrBinOpShlSat:
11053 return ir_analyze_bin_op_math(ira, bin_op_instruction);11053 return ir_analyze_bin_op_math(ira, bin_op_instruction);
11054 case IrBinOpArrayCat:11054 case IrBinOpArrayCat:
11055 return ir_analyze_array_cat(ira, bin_op_instruction);11055 return ir_analyze_array_cat(ira, bin_op_instruction);
src/stage1/ir_print.cpp+4-4
...@@ -737,13 +737,13 @@ static const char *ir_bin_op_id_str(IrBinOp op_id) {...@@ -737,13 +737,13 @@ static const char *ir_bin_op_id_str(IrBinOp op_id) {
737 return "@maximum";737 return "@maximum";
738 case IrBinOpMinimum:738 case IrBinOpMinimum:
739 return "@minimum";739 return "@minimum";
740 case IrBinOpSatAdd:740 case IrBinOpAddSat:
741 return "@addWithSaturation";741 return "@addWithSaturation";
742 case IrBinOpSatSub:742 case IrBinOpSubSat:
743 return "@subWithSaturation";743 return "@subWithSaturation";
744 case IrBinOpSatMul:744 case IrBinOpMultSat:
745 return "@mulWithSaturation";745 return "@mulWithSaturation";
746 case IrBinOpSatShl:746 case IrBinOpShlSat:
747 return "@shlWithSaturation";747 return "@shlWithSaturation";
748 }748 }
749 zig_unreachable();749 zig_unreachable();
src/stage1/parser.cpp+16
...@@ -2381,6 +2381,7 @@ static AstNode *ast_parse_switch_item(ParseContext *pc) {...@@ -2381,6 +2381,7 @@ static AstNode *ast_parse_switch_item(ParseContext *pc) {
2381// / PLUSEQUAL2381// / PLUSEQUAL
2382// / MINUSEQUAL2382// / MINUSEQUAL
2383// / LARROW2EQUAL2383// / LARROW2EQUAL
2384// / LARROW2PIPEEQUAL
2384// / RARROW2EQUAL2385// / RARROW2EQUAL
2385// / AMPERSANDEQUAL2386// / AMPERSANDEQUAL
2386// / CARETEQUAL2387// / CARETEQUAL
...@@ -2388,6 +2389,9 @@ static AstNode *ast_parse_switch_item(ParseContext *pc) {...@@ -2388,6 +2389,9 @@ static AstNode *ast_parse_switch_item(ParseContext *pc) {
2388// / ASTERISKPERCENTEQUAL2389// / ASTERISKPERCENTEQUAL
2389// / PLUSPERCENTEQUAL2390// / PLUSPERCENTEQUAL
2390// / MINUSPERCENTEQUAL2391// / MINUSPERCENTEQUAL
2392// / ASTERISKPIPEEQUAL
2393// / PLUSPIPEEQUAL
2394// / MINUSPIPEEQUAL
2391// / EQUAL2395// / EQUAL
2392static AstNode *ast_parse_assign_op(ParseContext *pc) {2396static AstNode *ast_parse_assign_op(ParseContext *pc) {
2393 // In C, we have `T arr[N] = {[i] = T{}};` but it doesn't2397 // In C, we have `T arr[N] = {[i] = T{}};` but it doesn't
...@@ -2396,17 +2400,21 @@ static AstNode *ast_parse_assign_op(ParseContext *pc) {...@@ -2396,17 +2400,21 @@ static AstNode *ast_parse_assign_op(ParseContext *pc) {
2396 table[TokenIdBitAndEq] = BinOpTypeAssignBitAnd;2400 table[TokenIdBitAndEq] = BinOpTypeAssignBitAnd;
2397 table[TokenIdBitOrEq] = BinOpTypeAssignBitOr;2401 table[TokenIdBitOrEq] = BinOpTypeAssignBitOr;
2398 table[TokenIdBitShiftLeftEq] = BinOpTypeAssignBitShiftLeft;2402 table[TokenIdBitShiftLeftEq] = BinOpTypeAssignBitShiftLeft;
2403 table[TokenIdBitShiftLeftPipeEq] = BinOpTypeAssignBitShiftLeftSat;
2399 table[TokenIdBitShiftRightEq] = BinOpTypeAssignBitShiftRight;2404 table[TokenIdBitShiftRightEq] = BinOpTypeAssignBitShiftRight;
2400 table[TokenIdBitXorEq] = BinOpTypeAssignBitXor;2405 table[TokenIdBitXorEq] = BinOpTypeAssignBitXor;
2401 table[TokenIdDivEq] = BinOpTypeAssignDiv;2406 table[TokenIdDivEq] = BinOpTypeAssignDiv;
2402 table[TokenIdEq] = BinOpTypeAssign;2407 table[TokenIdEq] = BinOpTypeAssign;
2403 table[TokenIdMinusEq] = BinOpTypeAssignMinus;2408 table[TokenIdMinusEq] = BinOpTypeAssignMinus;
2404 table[TokenIdMinusPercentEq] = BinOpTypeAssignMinusWrap;2409 table[TokenIdMinusPercentEq] = BinOpTypeAssignMinusWrap;
2410 table[TokenIdMinusPipeEq] = BinOpTypeAssignMinusSat;
2405 table[TokenIdModEq] = BinOpTypeAssignMod;2411 table[TokenIdModEq] = BinOpTypeAssignMod;
2406 table[TokenIdPlusEq] = BinOpTypeAssignPlus;2412 table[TokenIdPlusEq] = BinOpTypeAssignPlus;
2407 table[TokenIdPlusPercentEq] = BinOpTypeAssignPlusWrap;2413 table[TokenIdPlusPercentEq] = BinOpTypeAssignPlusWrap;
2414 table[TokenIdPlusPipeEq] = BinOpTypeAssignPlusSat;
2408 table[TokenIdTimesEq] = BinOpTypeAssignTimes;2415 table[TokenIdTimesEq] = BinOpTypeAssignTimes;
2409 table[TokenIdTimesPercentEq] = BinOpTypeAssignTimesWrap;2416 table[TokenIdTimesPercentEq] = BinOpTypeAssignTimesWrap;
2417 table[TokenIdTimesPipeEq] = BinOpTypeAssignTimesSat;
24102418
2411 BinOpType op = table[pc->token_ids[pc->current_token]];2419 BinOpType op = table[pc->token_ids[pc->current_token]];
2412 if (op != BinOpTypeInvalid) {2420 if (op != BinOpTypeInvalid) {
...@@ -2483,10 +2491,12 @@ static AstNode *ast_parse_bitwise_op(ParseContext *pc) {...@@ -2483,10 +2491,12 @@ static AstNode *ast_parse_bitwise_op(ParseContext *pc) {
24832491
2484// BitShiftOp2492// BitShiftOp
2485// <- LARROW22493// <- LARROW2
2494// / LARROW2PIPE
2486// / RARROW22495// / RARROW2
2487static AstNode *ast_parse_bit_shift_op(ParseContext *pc) {2496static AstNode *ast_parse_bit_shift_op(ParseContext *pc) {
2488 BinOpType table[TokenIdCount] = {};2497 BinOpType table[TokenIdCount] = {};
2489 table[TokenIdBitShiftLeft] = BinOpTypeBitShiftLeft;2498 table[TokenIdBitShiftLeft] = BinOpTypeBitShiftLeft;
2499 table[TokenIdBitShiftLeftPipe] = BinOpTypeBitShiftLeftSat;
2490 table[TokenIdBitShiftRight] = BinOpTypeBitShiftRight;2500 table[TokenIdBitShiftRight] = BinOpTypeBitShiftRight;
24912501
2492 BinOpType op = table[pc->token_ids[pc->current_token]];2502 BinOpType op = table[pc->token_ids[pc->current_token]];
...@@ -2506,6 +2516,8 @@ static AstNode *ast_parse_bit_shift_op(ParseContext *pc) {...@@ -2506,6 +2516,8 @@ static AstNode *ast_parse_bit_shift_op(ParseContext *pc) {
2506// / PLUS22516// / PLUS2
2507// / PLUSPERCENT2517// / PLUSPERCENT
2508// / MINUSPERCENT2518// / MINUSPERCENT
2519// / PLUSPIPE
2520// / MINUSPIPE
2509static AstNode *ast_parse_addition_op(ParseContext *pc) {2521static AstNode *ast_parse_addition_op(ParseContext *pc) {
2510 BinOpType table[TokenIdCount] = {};2522 BinOpType table[TokenIdCount] = {};
2511 table[TokenIdPlus] = BinOpTypeAdd;2523 table[TokenIdPlus] = BinOpTypeAdd;
...@@ -2513,6 +2525,8 @@ static AstNode *ast_parse_addition_op(ParseContext *pc) {...@@ -2513,6 +2525,8 @@ static AstNode *ast_parse_addition_op(ParseContext *pc) {
2513 table[TokenIdPlusPlus] = BinOpTypeArrayCat;2525 table[TokenIdPlusPlus] = BinOpTypeArrayCat;
2514 table[TokenIdPlusPercent] = BinOpTypeAddWrap;2526 table[TokenIdPlusPercent] = BinOpTypeAddWrap;
2515 table[TokenIdMinusPercent] = BinOpTypeSubWrap;2527 table[TokenIdMinusPercent] = BinOpTypeSubWrap;
2528 table[TokenIdPlusPipe] = BinOpTypeAddSat;
2529 table[TokenIdMinusPipe] = BinOpTypeSubSat;
25162530
2517 BinOpType op = table[pc->token_ids[pc->current_token]];2531 BinOpType op = table[pc->token_ids[pc->current_token]];
2518 if (op != BinOpTypeInvalid) {2532 if (op != BinOpTypeInvalid) {
...@@ -2532,6 +2546,7 @@ static AstNode *ast_parse_addition_op(ParseContext *pc) {...@@ -2532,6 +2546,7 @@ static AstNode *ast_parse_addition_op(ParseContext *pc) {
2532// / PERCENT2546// / PERCENT
2533// / ASTERISK22547// / ASTERISK2
2534// / ASTERISKPERCENT2548// / ASTERISKPERCENT
2549// / ASTERISKPIPE
2535static AstNode *ast_parse_multiply_op(ParseContext *pc) {2550static AstNode *ast_parse_multiply_op(ParseContext *pc) {
2536 BinOpType table[TokenIdCount] = {};2551 BinOpType table[TokenIdCount] = {};
2537 table[TokenIdBarBar] = BinOpTypeMergeErrorSets;2552 table[TokenIdBarBar] = BinOpTypeMergeErrorSets;
...@@ -2540,6 +2555,7 @@ static AstNode *ast_parse_multiply_op(ParseContext *pc) {...@@ -2540,6 +2555,7 @@ static AstNode *ast_parse_multiply_op(ParseContext *pc) {
2540 table[TokenIdPercent] = BinOpTypeMod;2555 table[TokenIdPercent] = BinOpTypeMod;
2541 table[TokenIdStarStar] = BinOpTypeArrayMult;2556 table[TokenIdStarStar] = BinOpTypeArrayMult;
2542 table[TokenIdTimesPercent] = BinOpTypeMultWrap;2557 table[TokenIdTimesPercent] = BinOpTypeMultWrap;
2558 table[TokenIdTimesPipe] = BinOpTypeMultSat;
25432559
2544 BinOpType op = table[pc->token_ids[pc->current_token]];2560 BinOpType op = table[pc->token_ids[pc->current_token]];
2545 if (op != BinOpTypeInvalid) {2561 if (op != BinOpTypeInvalid) {
src/stage1/tokenizer.cpp+85
...@@ -226,8 +226,10 @@ enum TokenizeState {...@@ -226,8 +226,10 @@ enum TokenizeState {
226 TokenizeState_pipe,226 TokenizeState_pipe,
227 TokenizeState_minus,227 TokenizeState_minus,
228 TokenizeState_minus_percent,228 TokenizeState_minus_percent,
229 TokenizeState_minus_pipe,
229 TokenizeState_asterisk,230 TokenizeState_asterisk,
230 TokenizeState_asterisk_percent,231 TokenizeState_asterisk_percent,
232 TokenizeState_asterisk_pipe,
231 TokenizeState_slash,233 TokenizeState_slash,
232 TokenizeState_line_comment_start,234 TokenizeState_line_comment_start,
233 TokenizeState_line_comment,235 TokenizeState_line_comment,
...@@ -257,8 +259,10 @@ enum TokenizeState {...@@ -257,8 +259,10 @@ enum TokenizeState {
257 TokenizeState_percent,259 TokenizeState_percent,
258 TokenizeState_plus,260 TokenizeState_plus,
259 TokenizeState_plus_percent,261 TokenizeState_plus_percent,
262 TokenizeState_plus_pipe,
260 TokenizeState_angle_bracket_left,263 TokenizeState_angle_bracket_left,
261 TokenizeState_angle_bracket_angle_bracket_left,264 TokenizeState_angle_bracket_angle_bracket_left,
265 TokenizeState_angle_bracket_angle_bracket_left_pipe,
262 TokenizeState_angle_bracket_right,266 TokenizeState_angle_bracket_right,
263 TokenizeState_angle_bracket_angle_bracket_right,267 TokenizeState_angle_bracket_angle_bracket_right,
264 TokenizeState_period,268 TokenizeState_period,
...@@ -548,6 +552,9 @@ void tokenize(const char *source, Tokenization *out) {...@@ -548,6 +552,9 @@ void tokenize(const char *source, Tokenization *out) {
548 case '%':552 case '%':
549 t.state = TokenizeState_asterisk_percent;553 t.state = TokenizeState_asterisk_percent;
550 break;554 break;
555 case '|':
556 t.state = TokenizeState_asterisk_pipe;
557 break;
551 default:558 default:
552 t.state = TokenizeState_start;559 t.state = TokenizeState_start;
553 continue;560 continue;
...@@ -568,6 +575,21 @@ void tokenize(const char *source, Tokenization *out) {...@@ -568,6 +575,21 @@ void tokenize(const char *source, Tokenization *out) {
568 continue;575 continue;
569 }576 }
570 break;577 break;
578 case TokenizeState_asterisk_pipe:
579 switch (c) {
580 case 0:
581 t.out->ids.last() = TokenIdTimesPipe;
582 goto eof;
583 case '=':
584 t.out->ids.last() = TokenIdTimesPipeEq;
585 t.state = TokenizeState_start;
586 break;
587 default:
588 t.out->ids.last() = TokenIdTimesPipe;
589 t.state = TokenizeState_start;
590 continue;
591 }
592 break;
571 case TokenizeState_percent:593 case TokenizeState_percent:
572 switch (c) {594 switch (c) {
573 case 0:595 case 0:
...@@ -596,6 +618,9 @@ void tokenize(const char *source, Tokenization *out) {...@@ -596,6 +618,9 @@ void tokenize(const char *source, Tokenization *out) {
596 case '%':618 case '%':
597 t.state = TokenizeState_plus_percent;619 t.state = TokenizeState_plus_percent;
598 break;620 break;
621 case '|':
622 t.state = TokenizeState_plus_pipe;
623 break;
599 default:624 default:
600 t.state = TokenizeState_start;625 t.state = TokenizeState_start;
601 continue;626 continue;
...@@ -616,6 +641,21 @@ void tokenize(const char *source, Tokenization *out) {...@@ -616,6 +641,21 @@ void tokenize(const char *source, Tokenization *out) {
616 continue;641 continue;
617 }642 }
618 break;643 break;
644 case TokenizeState_plus_pipe:
645 switch (c) {
646 case 0:
647 t.out->ids.last() = TokenIdPlusPipe;
648 goto eof;
649 case '=':
650 t.out->ids.last() = TokenIdPlusPipeEq;
651 t.state = TokenizeState_start;
652 break;
653 default:
654 t.out->ids.last() = TokenIdPlusPipe;
655 t.state = TokenizeState_start;
656 continue;
657 }
658 break;
619 case TokenizeState_caret:659 case TokenizeState_caret:
620 switch (c) {660 switch (c) {
621 case 0:661 case 0:
...@@ -891,6 +931,9 @@ void tokenize(const char *source, Tokenization *out) {...@@ -891,6 +931,9 @@ void tokenize(const char *source, Tokenization *out) {
891 case '%':931 case '%':
892 t.state = TokenizeState_minus_percent;932 t.state = TokenizeState_minus_percent;
893 break;933 break;
934 case '|':
935 t.state = TokenizeState_minus_pipe;
936 break;
894 default:937 default:
895 t.state = TokenizeState_start;938 t.state = TokenizeState_start;
896 continue;939 continue;
...@@ -911,6 +954,21 @@ void tokenize(const char *source, Tokenization *out) {...@@ -911,6 +954,21 @@ void tokenize(const char *source, Tokenization *out) {
911 continue;954 continue;
912 }955 }
913 break;956 break;
957 case TokenizeState_minus_pipe:
958 switch (c) {
959 case 0:
960 t.out->ids.last() = TokenIdMinusPipe;
961 goto eof;
962 case '=':
963 t.out->ids.last() = TokenIdMinusPipeEq;
964 t.state = TokenizeState_start;
965 break;
966 default:
967 t.out->ids.last() = TokenIdMinusPipe;
968 t.state = TokenizeState_start;
969 continue;
970 }
971 break;
914 case TokenizeState_angle_bracket_left:972 case TokenizeState_angle_bracket_left:
915 switch (c) {973 switch (c) {
916 case 0:974 case 0:
...@@ -936,12 +994,31 @@ void tokenize(const char *source, Tokenization *out) {...@@ -936,12 +994,31 @@ void tokenize(const char *source, Tokenization *out) {
936 t.out->ids.last() = TokenIdBitShiftLeftEq;994 t.out->ids.last() = TokenIdBitShiftLeftEq;
937 t.state = TokenizeState_start;995 t.state = TokenizeState_start;
938 break;996 break;
997 case '|':
998 // t.out->ids.last() = TokenIdBitShiftLeftPipe;
999 t.state = TokenizeState_angle_bracket_angle_bracket_left_pipe;
1000 break;
939 default:1001 default:
940 t.out->ids.last() = TokenIdBitShiftLeft;1002 t.out->ids.last() = TokenIdBitShiftLeft;
941 t.state = TokenizeState_start;1003 t.state = TokenizeState_start;
942 continue;1004 continue;
943 }1005 }
944 break;1006 break;
1007 case TokenizeState_angle_bracket_angle_bracket_left_pipe:
1008 switch (c) {
1009 case 0:
1010 t.out->ids.last() = TokenIdBitShiftLeftPipe;
1011 goto eof;
1012 case '=':
1013 t.out->ids.last() = TokenIdBitShiftLeftPipeEq;
1014 t.state = TokenizeState_start;
1015 break;
1016 default:
1017 t.out->ids.last() = TokenIdBitShiftLeftPipe;
1018 t.state = TokenizeState_start;
1019 continue;
1020 }
1021 break;
945 case TokenizeState_angle_bracket_right:1022 case TokenizeState_angle_bracket_right:
946 switch (c) {1023 switch (c) {
947 case 0:1024 case 0:
...@@ -1437,6 +1514,8 @@ const char * token_name(TokenId id) {...@@ -1437,6 +1514,8 @@ const char * token_name(TokenId id) {
1437 case TokenIdBitOrEq: return "|=";1514 case TokenIdBitOrEq: return "|=";
1438 case TokenIdBitShiftLeft: return "<<";1515 case TokenIdBitShiftLeft: return "<<";
1439 case TokenIdBitShiftLeftEq: return "<<=";1516 case TokenIdBitShiftLeftEq: return "<<=";
1517 case TokenIdBitShiftLeftPipe: return "<<|";
1518 case TokenIdBitShiftLeftPipeEq: return "<<|=";
1440 case TokenIdBitShiftRight: return ">>";1519 case TokenIdBitShiftRight: return ">>";
1441 case TokenIdBitShiftRightEq: return ">>=";1520 case TokenIdBitShiftRightEq: return ">>=";
1442 case TokenIdBitXorEq: return "^=";1521 case TokenIdBitXorEq: return "^=";
...@@ -1521,12 +1600,16 @@ const char * token_name(TokenId id) {...@@ -1521,12 +1600,16 @@ const char * token_name(TokenId id) {
1521 case TokenIdMinusEq: return "-=";1600 case TokenIdMinusEq: return "-=";
1522 case TokenIdMinusPercent: return "-%";1601 case TokenIdMinusPercent: return "-%";
1523 case TokenIdMinusPercentEq: return "-%=";1602 case TokenIdMinusPercentEq: return "-%=";
1603 case TokenIdMinusPipe: return "-|";
1604 case TokenIdMinusPipeEq: return "-|=";
1524 case TokenIdModEq: return "%=";1605 case TokenIdModEq: return "%=";
1525 case TokenIdPercent: return "%";1606 case TokenIdPercent: return "%";
1526 case TokenIdPlus: return "+";1607 case TokenIdPlus: return "+";
1527 case TokenIdPlusEq: return "+=";1608 case TokenIdPlusEq: return "+=";
1528 case TokenIdPlusPercent: return "+%";1609 case TokenIdPlusPercent: return "+%";
1529 case TokenIdPlusPercentEq: return "+%=";1610 case TokenIdPlusPercentEq: return "+%=";
1611 case TokenIdPlusPipe: return "+|";
1612 case TokenIdPlusPipeEq: return "+|=";
1530 case TokenIdPlusPlus: return "++";1613 case TokenIdPlusPlus: return "++";
1531 case TokenIdRBrace: return "}";1614 case TokenIdRBrace: return "}";
1532 case TokenIdRBracket: return "]";1615 case TokenIdRBracket: return "]";
...@@ -1542,6 +1625,8 @@ const char * token_name(TokenId id) {...@@ -1542,6 +1625,8 @@ const char * token_name(TokenId id) {
1542 case TokenIdTimesEq: return "*=";1625 case TokenIdTimesEq: return "*=";
1543 case TokenIdTimesPercent: return "*%";1626 case TokenIdTimesPercent: return "*%";
1544 case TokenIdTimesPercentEq: return "*%=";1627 case TokenIdTimesPercentEq: return "*%=";
1628 case TokenIdTimesPipe: return "*|";
1629 case TokenIdTimesPipeEq: return "*|=";
1545 case TokenIdBuiltin: return "Builtin";1630 case TokenIdBuiltin: return "Builtin";
1546 case TokenIdCount:1631 case TokenIdCount:
1547 zig_unreachable();1632 zig_unreachable();
src/stage1/tokenizer.hpp+8
...@@ -23,6 +23,8 @@ enum TokenId : uint8_t {...@@ -23,6 +23,8 @@ enum TokenId : uint8_t {
23 TokenIdBitOrEq,23 TokenIdBitOrEq,
24 TokenIdBitShiftLeft,24 TokenIdBitShiftLeft,
25 TokenIdBitShiftLeftEq,25 TokenIdBitShiftLeftEq,
26 TokenIdBitShiftLeftPipe,
27 TokenIdBitShiftLeftPipeEq,
26 TokenIdBitShiftRight,28 TokenIdBitShiftRight,
27 TokenIdBitShiftRightEq,29 TokenIdBitShiftRightEq,
28 TokenIdBitXorEq,30 TokenIdBitXorEq,
...@@ -108,12 +110,16 @@ enum TokenId : uint8_t {...@@ -108,12 +110,16 @@ enum TokenId : uint8_t {
108 TokenIdMinusEq,110 TokenIdMinusEq,
109 TokenIdMinusPercent,111 TokenIdMinusPercent,
110 TokenIdMinusPercentEq,112 TokenIdMinusPercentEq,
113 TokenIdMinusPipe,
114 TokenIdMinusPipeEq,
111 TokenIdModEq,115 TokenIdModEq,
112 TokenIdPercent,116 TokenIdPercent,
113 TokenIdPlus,117 TokenIdPlus,
114 TokenIdPlusEq,118 TokenIdPlusEq,
115 TokenIdPlusPercent,119 TokenIdPlusPercent,
116 TokenIdPlusPercentEq,120 TokenIdPlusPercentEq,
121 TokenIdPlusPipe,
122 TokenIdPlusPipeEq,
117 TokenIdPlusPlus,123 TokenIdPlusPlus,
118 TokenIdRBrace,124 TokenIdRBrace,
119 TokenIdRBracket,125 TokenIdRBracket,
...@@ -129,6 +135,8 @@ enum TokenId : uint8_t {...@@ -129,6 +135,8 @@ enum TokenId : uint8_t {
129 TokenIdTimesEq,135 TokenIdTimesEq,
130 TokenIdTimesPercent,136 TokenIdTimesPercent,
131 TokenIdTimesPercentEq,137 TokenIdTimesPercentEq,
138 TokenIdTimesPipe,
139 TokenIdTimesPipeEq,
132140
133 TokenIdCount,141 TokenIdCount,
134};142};
test/behavior/saturating_arithmetic.zig+28-7
...@@ -11,13 +11,34 @@ fn testSaturatingOp(comptime op: Op, comptime T: type, test_data: [3]T) !void {...@@ -11,13 +11,34 @@ fn testSaturatingOp(comptime op: Op, comptime T: type, test_data: [3]T) !void {
11 const a = test_data[0];11 const a = test_data[0];
12 const b = test_data[1];12 const b = test_data[1];
13 const expected = test_data[2];13 const expected = test_data[2];
14 const actual = switch (op) {14 {
15 .add => @addWithSaturation(a, b),15 const actual = switch (op) {
16 .sub => @subWithSaturation(a, b),16 .add => @addWithSaturation(a, b),
17 .mul => @mulWithSaturation(a, b),17 .sub => @subWithSaturation(a, b),
18 .shl => @shlWithSaturation(a, b),18 .mul => @mulWithSaturation(a, b),
19 };19 .shl => @shlWithSaturation(a, b),
20 try expectEqual(expected, actual);20 };
21 try expectEqual(expected, actual);
22 }
23 {
24 const actual = switch (op) {
25 .add => a +| b,
26 .sub => a -| b,
27 .mul => a *| b,
28 .shl => a <<| b,
29 };
30 try expectEqual(expected, actual);
31 }
32 {
33 var actual = a;
34 switch (op) {
35 .add => actual +|= b,
36 .sub => actual -|= b,
37 .mul => actual *|= b,
38 .shl => actual <<|= b,
39 }
40 try expectEqual(expected, actual);
41 }
21}42}
2243
23test "@addWithSaturation" {44test "@addWithSaturation" {