mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
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
This commit is contained in:
parent
79bc5891c1
commit
29f41896ed
@ -396,6 +396,7 @@ pub fn firstToken(tree: Tree, node: Node.Index) TokenIndex {
|
|||||||
.assign_add,
|
.assign_add,
|
||||||
.assign_sub,
|
.assign_sub,
|
||||||
.assign_bit_shift_left,
|
.assign_bit_shift_left,
|
||||||
|
.assign_bit_shift_left_sat,
|
||||||
.assign_bit_shift_right,
|
.assign_bit_shift_right,
|
||||||
.assign_bit_and,
|
.assign_bit_and,
|
||||||
.assign_bit_xor,
|
.assign_bit_xor,
|
||||||
@ -403,6 +404,9 @@ pub fn firstToken(tree: Tree, node: Node.Index) TokenIndex {
|
|||||||
.assign_mul_wrap,
|
.assign_mul_wrap,
|
||||||
.assign_add_wrap,
|
.assign_add_wrap,
|
||||||
.assign_sub_wrap,
|
.assign_sub_wrap,
|
||||||
|
.assign_mul_sat,
|
||||||
|
.assign_add_sat,
|
||||||
|
.assign_sub_sat,
|
||||||
.assign,
|
.assign,
|
||||||
.merge_error_sets,
|
.merge_error_sets,
|
||||||
.mul,
|
.mul,
|
||||||
@ -410,12 +414,16 @@ pub fn firstToken(tree: Tree, node: Node.Index) TokenIndex {
|
|||||||
.mod,
|
.mod,
|
||||||
.array_mult,
|
.array_mult,
|
||||||
.mul_wrap,
|
.mul_wrap,
|
||||||
|
.mul_sat,
|
||||||
.add,
|
.add,
|
||||||
.sub,
|
.sub,
|
||||||
.array_cat,
|
.array_cat,
|
||||||
.add_wrap,
|
.add_wrap,
|
||||||
.sub_wrap,
|
.sub_wrap,
|
||||||
|
.add_sat,
|
||||||
|
.sub_sat,
|
||||||
.bit_shift_left,
|
.bit_shift_left,
|
||||||
|
.bit_shift_left_sat,
|
||||||
.bit_shift_right,
|
.bit_shift_right,
|
||||||
.bit_and,
|
.bit_and,
|
||||||
.bit_xor,
|
.bit_xor,
|
||||||
@ -652,6 +660,7 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex {
|
|||||||
.assign_add,
|
.assign_add,
|
||||||
.assign_sub,
|
.assign_sub,
|
||||||
.assign_bit_shift_left,
|
.assign_bit_shift_left,
|
||||||
|
.assign_bit_shift_left_sat,
|
||||||
.assign_bit_shift_right,
|
.assign_bit_shift_right,
|
||||||
.assign_bit_and,
|
.assign_bit_and,
|
||||||
.assign_bit_xor,
|
.assign_bit_xor,
|
||||||
@ -659,6 +668,9 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex {
|
|||||||
.assign_mul_wrap,
|
.assign_mul_wrap,
|
||||||
.assign_add_wrap,
|
.assign_add_wrap,
|
||||||
.assign_sub_wrap,
|
.assign_sub_wrap,
|
||||||
|
.assign_mul_sat,
|
||||||
|
.assign_add_sat,
|
||||||
|
.assign_sub_sat,
|
||||||
.assign,
|
.assign,
|
||||||
.merge_error_sets,
|
.merge_error_sets,
|
||||||
.mul,
|
.mul,
|
||||||
@ -666,12 +678,16 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex {
|
|||||||
.mod,
|
.mod,
|
||||||
.array_mult,
|
.array_mult,
|
||||||
.mul_wrap,
|
.mul_wrap,
|
||||||
|
.mul_sat,
|
||||||
.add,
|
.add,
|
||||||
.sub,
|
.sub,
|
||||||
.array_cat,
|
.array_cat,
|
||||||
.add_wrap,
|
.add_wrap,
|
||||||
.sub_wrap,
|
.sub_wrap,
|
||||||
|
.add_sat,
|
||||||
|
.sub_sat,
|
||||||
.bit_shift_left,
|
.bit_shift_left,
|
||||||
|
.bit_shift_left_sat,
|
||||||
.bit_shift_right,
|
.bit_shift_right,
|
||||||
.bit_and,
|
.bit_and,
|
||||||
.bit_xor,
|
.bit_xor,
|
||||||
@ -2525,6 +2541,8 @@ pub const Node = struct {
|
|||||||
assign_sub,
|
assign_sub,
|
||||||
/// `lhs <<= rhs`. main_token is op.
|
/// `lhs <<= rhs`. main_token is op.
|
||||||
assign_bit_shift_left,
|
assign_bit_shift_left,
|
||||||
|
/// `lhs <<|= rhs`. main_token is op.
|
||||||
|
assign_bit_shift_left_sat,
|
||||||
/// `lhs >>= rhs`. main_token is op.
|
/// `lhs >>= rhs`. main_token is op.
|
||||||
assign_bit_shift_right,
|
assign_bit_shift_right,
|
||||||
/// `lhs &= rhs`. main_token is op.
|
/// `lhs &= rhs`. main_token is op.
|
||||||
@ -2539,6 +2557,12 @@ pub const Node = struct {
|
|||||||
assign_add_wrap,
|
assign_add_wrap,
|
||||||
/// `lhs -%= rhs`. main_token is op.
|
/// `lhs -%= rhs`. main_token is op.
|
||||||
assign_sub_wrap,
|
assign_sub_wrap,
|
||||||
|
/// `lhs *|= rhs`. main_token is op.
|
||||||
|
assign_mul_sat,
|
||||||
|
/// `lhs +|= rhs`. main_token is op.
|
||||||
|
assign_add_sat,
|
||||||
|
/// `lhs -|= rhs`. main_token is op.
|
||||||
|
assign_sub_sat,
|
||||||
/// `lhs = rhs`. main_token is op.
|
/// `lhs = rhs`. main_token is op.
|
||||||
assign,
|
assign,
|
||||||
/// `lhs || rhs`. main_token is the `||`.
|
/// `lhs || rhs`. main_token is the `||`.
|
||||||
@ -2553,6 +2577,8 @@ pub const Node = struct {
|
|||||||
array_mult,
|
array_mult,
|
||||||
/// `lhs *% rhs`. main_token is the `*%`.
|
/// `lhs *% rhs`. main_token is the `*%`.
|
||||||
mul_wrap,
|
mul_wrap,
|
||||||
|
/// `lhs *| rhs`. main_token is the `*%`.
|
||||||
|
mul_sat,
|
||||||
/// `lhs + rhs`. main_token is the `+`.
|
/// `lhs + rhs`. main_token is the `+`.
|
||||||
add,
|
add,
|
||||||
/// `lhs - rhs`. main_token is the `-`.
|
/// `lhs - rhs`. main_token is the `-`.
|
||||||
@ -2563,8 +2589,14 @@ pub const Node = struct {
|
|||||||
add_wrap,
|
add_wrap,
|
||||||
/// `lhs -% rhs`. main_token is the `-%`.
|
/// `lhs -% rhs`. main_token is the `-%`.
|
||||||
sub_wrap,
|
sub_wrap,
|
||||||
|
/// `lhs +| rhs`. main_token is the `+|`.
|
||||||
|
add_sat,
|
||||||
|
/// `lhs -| rhs`. main_token is the `-|`.
|
||||||
|
sub_sat,
|
||||||
/// `lhs << rhs`. main_token is the `<<`.
|
/// `lhs << rhs`. main_token is the `<<`.
|
||||||
bit_shift_left,
|
bit_shift_left,
|
||||||
|
/// `lhs <<| rhs`. main_token is the `<<|`.
|
||||||
|
bit_shift_left_sat,
|
||||||
/// `lhs >> rhs`. main_token is the `>>`.
|
/// `lhs >> rhs`. main_token is the `>>`.
|
||||||
bit_shift_right,
|
bit_shift_right,
|
||||||
/// `lhs & rhs`. main_token is the `&`.
|
/// `lhs & rhs`. main_token is the `&`.
|
||||||
|
|||||||
@ -1269,6 +1269,7 @@ const Parser = struct {
|
|||||||
.plus_equal => .assign_add,
|
.plus_equal => .assign_add,
|
||||||
.minus_equal => .assign_sub,
|
.minus_equal => .assign_sub,
|
||||||
.angle_bracket_angle_bracket_left_equal => .assign_bit_shift_left,
|
.angle_bracket_angle_bracket_left_equal => .assign_bit_shift_left,
|
||||||
|
.angle_bracket_angle_bracket_left_pipe_equal => .assign_bit_shift_left_sat,
|
||||||
.angle_bracket_angle_bracket_right_equal => .assign_bit_shift_right,
|
.angle_bracket_angle_bracket_right_equal => .assign_bit_shift_right,
|
||||||
.ampersand_equal => .assign_bit_and,
|
.ampersand_equal => .assign_bit_and,
|
||||||
.caret_equal => .assign_bit_xor,
|
.caret_equal => .assign_bit_xor,
|
||||||
@ -1276,6 +1277,9 @@ const Parser = struct {
|
|||||||
.asterisk_percent_equal => .assign_mul_wrap,
|
.asterisk_percent_equal => .assign_mul_wrap,
|
||||||
.plus_percent_equal => .assign_add_wrap,
|
.plus_percent_equal => .assign_add_wrap,
|
||||||
.minus_percent_equal => .assign_sub_wrap,
|
.minus_percent_equal => .assign_sub_wrap,
|
||||||
|
.asterisk_pipe_equal => .assign_mul_sat,
|
||||||
|
.plus_pipe_equal => .assign_add_sat,
|
||||||
|
.minus_pipe_equal => .assign_sub_sat,
|
||||||
.equal => .assign,
|
.equal => .assign,
|
||||||
else => return expr,
|
else => return expr,
|
||||||
};
|
};
|
||||||
@ -1343,6 +1347,7 @@ const Parser = struct {
|
|||||||
.keyword_catch = .{ .prec = 40, .tag = .@"catch" },
|
.keyword_catch = .{ .prec = 40, .tag = .@"catch" },
|
||||||
|
|
||||||
.angle_bracket_angle_bracket_left = .{ .prec = 50, .tag = .bit_shift_left },
|
.angle_bracket_angle_bracket_left = .{ .prec = 50, .tag = .bit_shift_left },
|
||||||
|
.angle_bracket_angle_bracket_left_pipe = .{ .prec = 50, .tag = .bit_shift_left_sat },
|
||||||
.angle_bracket_angle_bracket_right = .{ .prec = 50, .tag = .bit_shift_right },
|
.angle_bracket_angle_bracket_right = .{ .prec = 50, .tag = .bit_shift_right },
|
||||||
|
|
||||||
.plus = .{ .prec = 60, .tag = .add },
|
.plus = .{ .prec = 60, .tag = .add },
|
||||||
@ -1350,6 +1355,8 @@ const Parser = struct {
|
|||||||
.plus_plus = .{ .prec = 60, .tag = .array_cat },
|
.plus_plus = .{ .prec = 60, .tag = .array_cat },
|
||||||
.plus_percent = .{ .prec = 60, .tag = .add_wrap },
|
.plus_percent = .{ .prec = 60, .tag = .add_wrap },
|
||||||
.minus_percent = .{ .prec = 60, .tag = .sub_wrap },
|
.minus_percent = .{ .prec = 60, .tag = .sub_wrap },
|
||||||
|
.plus_pipe = .{ .prec = 60, .tag = .add_sat },
|
||||||
|
.minus_pipe = .{ .prec = 60, .tag = .sub_sat },
|
||||||
|
|
||||||
.pipe_pipe = .{ .prec = 70, .tag = .merge_error_sets },
|
.pipe_pipe = .{ .prec = 70, .tag = .merge_error_sets },
|
||||||
.asterisk = .{ .prec = 70, .tag = .mul },
|
.asterisk = .{ .prec = 70, .tag = .mul },
|
||||||
@ -1357,6 +1364,7 @@ const Parser = struct {
|
|||||||
.percent = .{ .prec = 70, .tag = .mod },
|
.percent = .{ .prec = 70, .tag = .mod },
|
||||||
.asterisk_asterisk = .{ .prec = 70, .tag = .array_mult },
|
.asterisk_asterisk = .{ .prec = 70, .tag = .array_mult },
|
||||||
.asterisk_percent = .{ .prec = 70, .tag = .mul_wrap },
|
.asterisk_percent = .{ .prec = 70, .tag = .mul_wrap },
|
||||||
|
.asterisk_pipe = .{ .prec = 70, .tag = .mul_sat },
|
||||||
});
|
});
|
||||||
|
|
||||||
fn parseExprPrecedence(p: *Parser, min_prec: i32) Error!Node.Index {
|
fn parseExprPrecedence(p: *Parser, min_prec: i32) Error!Node.Index {
|
||||||
|
|||||||
@ -333,26 +333,32 @@ fn renderExpression(gpa: *Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
|
|||||||
|
|
||||||
.add,
|
.add,
|
||||||
.add_wrap,
|
.add_wrap,
|
||||||
|
.add_sat,
|
||||||
.array_cat,
|
.array_cat,
|
||||||
.array_mult,
|
.array_mult,
|
||||||
.assign,
|
.assign,
|
||||||
.assign_bit_and,
|
.assign_bit_and,
|
||||||
.assign_bit_or,
|
.assign_bit_or,
|
||||||
.assign_bit_shift_left,
|
.assign_bit_shift_left,
|
||||||
|
.assign_bit_shift_left_sat,
|
||||||
.assign_bit_shift_right,
|
.assign_bit_shift_right,
|
||||||
.assign_bit_xor,
|
.assign_bit_xor,
|
||||||
.assign_div,
|
.assign_div,
|
||||||
.assign_sub,
|
.assign_sub,
|
||||||
.assign_sub_wrap,
|
.assign_sub_wrap,
|
||||||
|
.assign_sub_sat,
|
||||||
.assign_mod,
|
.assign_mod,
|
||||||
.assign_add,
|
.assign_add,
|
||||||
.assign_add_wrap,
|
.assign_add_wrap,
|
||||||
|
.assign_add_sat,
|
||||||
.assign_mul,
|
.assign_mul,
|
||||||
.assign_mul_wrap,
|
.assign_mul_wrap,
|
||||||
|
.assign_mul_sat,
|
||||||
.bang_equal,
|
.bang_equal,
|
||||||
.bit_and,
|
.bit_and,
|
||||||
.bit_or,
|
.bit_or,
|
||||||
.bit_shift_left,
|
.bit_shift_left,
|
||||||
|
.bit_shift_left_sat,
|
||||||
.bit_shift_right,
|
.bit_shift_right,
|
||||||
.bit_xor,
|
.bit_xor,
|
||||||
.bool_and,
|
.bool_and,
|
||||||
@ -367,8 +373,10 @@ fn renderExpression(gpa: *Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
|
|||||||
.mod,
|
.mod,
|
||||||
.mul,
|
.mul,
|
||||||
.mul_wrap,
|
.mul_wrap,
|
||||||
|
.mul_sat,
|
||||||
.sub,
|
.sub,
|
||||||
.sub_wrap,
|
.sub_wrap,
|
||||||
|
.sub_sat,
|
||||||
.@"orelse",
|
.@"orelse",
|
||||||
=> {
|
=> {
|
||||||
const infix = datas[node];
|
const infix = datas[node];
|
||||||
|
|||||||
@ -103,15 +103,21 @@ pub const Token = struct {
|
|||||||
plus_equal,
|
plus_equal,
|
||||||
plus_percent,
|
plus_percent,
|
||||||
plus_percent_equal,
|
plus_percent_equal,
|
||||||
|
plus_pipe,
|
||||||
|
plus_pipe_equal,
|
||||||
minus,
|
minus,
|
||||||
minus_equal,
|
minus_equal,
|
||||||
minus_percent,
|
minus_percent,
|
||||||
minus_percent_equal,
|
minus_percent_equal,
|
||||||
|
minus_pipe,
|
||||||
|
minus_pipe_equal,
|
||||||
asterisk,
|
asterisk,
|
||||||
asterisk_equal,
|
asterisk_equal,
|
||||||
asterisk_asterisk,
|
asterisk_asterisk,
|
||||||
asterisk_percent,
|
asterisk_percent,
|
||||||
asterisk_percent_equal,
|
asterisk_percent_equal,
|
||||||
|
asterisk_pipe,
|
||||||
|
asterisk_pipe_equal,
|
||||||
arrow,
|
arrow,
|
||||||
colon,
|
colon,
|
||||||
slash,
|
slash,
|
||||||
@ -124,6 +130,8 @@ pub const Token = struct {
|
|||||||
angle_bracket_left_equal,
|
angle_bracket_left_equal,
|
||||||
angle_bracket_angle_bracket_left,
|
angle_bracket_angle_bracket_left,
|
||||||
angle_bracket_angle_bracket_left_equal,
|
angle_bracket_angle_bracket_left_equal,
|
||||||
|
angle_bracket_angle_bracket_left_pipe,
|
||||||
|
angle_bracket_angle_bracket_left_pipe_equal,
|
||||||
angle_bracket_right,
|
angle_bracket_right,
|
||||||
angle_bracket_right_equal,
|
angle_bracket_right_equal,
|
||||||
angle_bracket_angle_bracket_right,
|
angle_bracket_angle_bracket_right,
|
||||||
@ -227,15 +235,21 @@ pub const Token = struct {
|
|||||||
.plus_equal => "+=",
|
.plus_equal => "+=",
|
||||||
.plus_percent => "+%",
|
.plus_percent => "+%",
|
||||||
.plus_percent_equal => "+%=",
|
.plus_percent_equal => "+%=",
|
||||||
|
.plus_pipe => "+|",
|
||||||
|
.plus_pipe_equal => "+|=",
|
||||||
.minus => "-",
|
.minus => "-",
|
||||||
.minus_equal => "-=",
|
.minus_equal => "-=",
|
||||||
.minus_percent => "-%",
|
.minus_percent => "-%",
|
||||||
.minus_percent_equal => "-%=",
|
.minus_percent_equal => "-%=",
|
||||||
|
.minus_pipe => "-|",
|
||||||
|
.minus_pipe_equal => "-|=",
|
||||||
.asterisk => "*",
|
.asterisk => "*",
|
||||||
.asterisk_equal => "*=",
|
.asterisk_equal => "*=",
|
||||||
.asterisk_asterisk => "**",
|
.asterisk_asterisk => "**",
|
||||||
.asterisk_percent => "*%",
|
.asterisk_percent => "*%",
|
||||||
.asterisk_percent_equal => "*%=",
|
.asterisk_percent_equal => "*%=",
|
||||||
|
.asterisk_pipe => "*|",
|
||||||
|
.asterisk_pipe_equal => "*|=",
|
||||||
.arrow => "->",
|
.arrow => "->",
|
||||||
.colon => ":",
|
.colon => ":",
|
||||||
.slash => "/",
|
.slash => "/",
|
||||||
@ -248,6 +262,8 @@ pub const Token = struct {
|
|||||||
.angle_bracket_left_equal => "<=",
|
.angle_bracket_left_equal => "<=",
|
||||||
.angle_bracket_angle_bracket_left => "<<",
|
.angle_bracket_angle_bracket_left => "<<",
|
||||||
.angle_bracket_angle_bracket_left_equal => "<<=",
|
.angle_bracket_angle_bracket_left_equal => "<<=",
|
||||||
|
.angle_bracket_angle_bracket_left_pipe => "<<|",
|
||||||
|
.angle_bracket_angle_bracket_left_pipe_equal => "<<|=",
|
||||||
.angle_bracket_right => ">",
|
.angle_bracket_right => ">",
|
||||||
.angle_bracket_right_equal => ">=",
|
.angle_bracket_right_equal => ">=",
|
||||||
.angle_bracket_angle_bracket_right => ">>",
|
.angle_bracket_angle_bracket_right => ">>",
|
||||||
@ -352,8 +368,10 @@ pub const Tokenizer = struct {
|
|||||||
pipe,
|
pipe,
|
||||||
minus,
|
minus,
|
||||||
minus_percent,
|
minus_percent,
|
||||||
|
minus_pipe,
|
||||||
asterisk,
|
asterisk,
|
||||||
asterisk_percent,
|
asterisk_percent,
|
||||||
|
asterisk_pipe,
|
||||||
slash,
|
slash,
|
||||||
line_comment_start,
|
line_comment_start,
|
||||||
line_comment,
|
line_comment,
|
||||||
@ -382,8 +400,10 @@ pub const Tokenizer = struct {
|
|||||||
percent,
|
percent,
|
||||||
plus,
|
plus,
|
||||||
plus_percent,
|
plus_percent,
|
||||||
|
plus_pipe,
|
||||||
angle_bracket_left,
|
angle_bracket_left,
|
||||||
angle_bracket_angle_bracket_left,
|
angle_bracket_angle_bracket_left,
|
||||||
|
angle_bracket_angle_bracket_left_pipe,
|
||||||
angle_bracket_right,
|
angle_bracket_right,
|
||||||
angle_bracket_angle_bracket_right,
|
angle_bracket_angle_bracket_right,
|
||||||
period,
|
period,
|
||||||
@ -584,6 +604,9 @@ pub const Tokenizer = struct {
|
|||||||
'%' => {
|
'%' => {
|
||||||
state = .asterisk_percent;
|
state = .asterisk_percent;
|
||||||
},
|
},
|
||||||
|
'|' => {
|
||||||
|
state = .asterisk_pipe;
|
||||||
|
},
|
||||||
else => {
|
else => {
|
||||||
result.tag = .asterisk;
|
result.tag = .asterisk;
|
||||||
break;
|
break;
|
||||||
@ -602,6 +625,18 @@ pub const Tokenizer = struct {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
.asterisk_pipe => switch (c) {
|
||||||
|
'=' => {
|
||||||
|
result.tag = .asterisk_pipe_equal;
|
||||||
|
self.index += 1;
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
result.tag = .asterisk_pipe;
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
.percent => switch (c) {
|
.percent => switch (c) {
|
||||||
'=' => {
|
'=' => {
|
||||||
result.tag = .percent_equal;
|
result.tag = .percent_equal;
|
||||||
@ -628,6 +663,9 @@ pub const Tokenizer = struct {
|
|||||||
'%' => {
|
'%' => {
|
||||||
state = .plus_percent;
|
state = .plus_percent;
|
||||||
},
|
},
|
||||||
|
'|' => {
|
||||||
|
state = .plus_pipe;
|
||||||
|
},
|
||||||
else => {
|
else => {
|
||||||
result.tag = .plus;
|
result.tag = .plus;
|
||||||
break;
|
break;
|
||||||
@ -646,6 +684,18 @@ pub const Tokenizer = struct {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
.plus_pipe => switch (c) {
|
||||||
|
'=' => {
|
||||||
|
result.tag = .plus_pipe_equal;
|
||||||
|
self.index += 1;
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
result.tag = .plus_pipe;
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
.caret => switch (c) {
|
.caret => switch (c) {
|
||||||
'=' => {
|
'=' => {
|
||||||
result.tag = .caret_equal;
|
result.tag = .caret_equal;
|
||||||
@ -903,6 +953,9 @@ pub const Tokenizer = struct {
|
|||||||
'%' => {
|
'%' => {
|
||||||
state = .minus_percent;
|
state = .minus_percent;
|
||||||
},
|
},
|
||||||
|
'|' => {
|
||||||
|
state = .minus_pipe;
|
||||||
|
},
|
||||||
else => {
|
else => {
|
||||||
result.tag = .minus;
|
result.tag = .minus;
|
||||||
break;
|
break;
|
||||||
@ -920,6 +973,17 @@ pub const Tokenizer = struct {
|
|||||||
break;
|
break;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
.minus_pipe => switch (c) {
|
||||||
|
'=' => {
|
||||||
|
result.tag = .minus_pipe_equal;
|
||||||
|
self.index += 1;
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
result.tag = .minus_pipe;
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
.angle_bracket_left => switch (c) {
|
.angle_bracket_left => switch (c) {
|
||||||
'<' => {
|
'<' => {
|
||||||
@ -942,12 +1006,27 @@ pub const Tokenizer = struct {
|
|||||||
self.index += 1;
|
self.index += 1;
|
||||||
break;
|
break;
|
||||||
},
|
},
|
||||||
|
'|' => {
|
||||||
|
result.tag = .angle_bracket_angle_bracket_left_pipe;
|
||||||
|
},
|
||||||
else => {
|
else => {
|
||||||
result.tag = .angle_bracket_angle_bracket_left;
|
result.tag = .angle_bracket_angle_bracket_left;
|
||||||
break;
|
break;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
.angle_bracket_angle_bracket_left_pipe => switch (c) {
|
||||||
|
'=' => {
|
||||||
|
result.tag = .angle_bracket_angle_bracket_left_pipe_equal;
|
||||||
|
self.index += 1;
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
result.tag = .angle_bracket_angle_bracket_left_pipe;
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
.angle_bracket_right => switch (c) {
|
.angle_bracket_right => switch (c) {
|
||||||
'>' => {
|
'>' => {
|
||||||
state = .angle_bracket_angle_bracket_right;
|
state = .angle_bracket_angle_bracket_right;
|
||||||
|
|||||||
22
src/Air.zig
22
src/Air.zig
@ -44,6 +44,11 @@ pub const Inst = struct {
|
|||||||
/// is the same as both operands.
|
/// is the same as both operands.
|
||||||
/// Uses the `bin_op` field.
|
/// Uses the `bin_op` field.
|
||||||
addwrap,
|
addwrap,
|
||||||
|
/// Saturating integer addition.
|
||||||
|
/// Both operands are guaranteed to be the same type, and the result type
|
||||||
|
/// is the same as both operands.
|
||||||
|
/// Uses the `bin_op` field.
|
||||||
|
addsat,
|
||||||
/// Float or integer subtraction. For integers, wrapping is undefined behavior.
|
/// Float or integer subtraction. For integers, wrapping is undefined behavior.
|
||||||
/// Both operands are guaranteed to be the same type, and the result type
|
/// Both operands are guaranteed to be the same type, and the result type
|
||||||
/// is the same as both operands.
|
/// is the same as both operands.
|
||||||
@ -54,6 +59,11 @@ pub const Inst = struct {
|
|||||||
/// is the same as both operands.
|
/// is the same as both operands.
|
||||||
/// Uses the `bin_op` field.
|
/// Uses the `bin_op` field.
|
||||||
subwrap,
|
subwrap,
|
||||||
|
/// Saturating integer subtraction.
|
||||||
|
/// Both operands are guaranteed to be the same type, and the result type
|
||||||
|
/// is the same as both operands.
|
||||||
|
/// Uses the `bin_op` field.
|
||||||
|
subsat,
|
||||||
/// Float or integer multiplication. For integers, wrapping is undefined behavior.
|
/// Float or integer multiplication. For integers, wrapping is undefined behavior.
|
||||||
/// Both operands are guaranteed to be the same type, and the result type
|
/// Both operands are guaranteed to be the same type, and the result type
|
||||||
/// is the same as both operands.
|
/// is the same as both operands.
|
||||||
@ -64,6 +74,11 @@ pub const Inst = struct {
|
|||||||
/// is the same as both operands.
|
/// is the same as both operands.
|
||||||
/// Uses the `bin_op` field.
|
/// Uses the `bin_op` field.
|
||||||
mulwrap,
|
mulwrap,
|
||||||
|
/// Saturating integer multiplication.
|
||||||
|
/// Both operands are guaranteed to be the same type, and the result type
|
||||||
|
/// is the same as both operands.
|
||||||
|
/// Uses the `bin_op` field.
|
||||||
|
mulsat,
|
||||||
/// Integer or float division. For integers, wrapping is undefined behavior.
|
/// Integer or float division. For integers, wrapping is undefined behavior.
|
||||||
/// Both operands are guaranteed to be the same type, and the result type
|
/// Both operands are guaranteed to be the same type, and the result type
|
||||||
/// is the same as both operands.
|
/// is the same as both operands.
|
||||||
@ -110,6 +125,9 @@ pub const Inst = struct {
|
|||||||
/// Shift left. `<<`
|
/// Shift left. `<<`
|
||||||
/// Uses the `bin_op` field.
|
/// Uses the `bin_op` field.
|
||||||
shl,
|
shl,
|
||||||
|
/// Shift left saturating. `<<|`
|
||||||
|
/// Uses the `bin_op` field.
|
||||||
|
shl_sat,
|
||||||
/// Bitwise XOR. `^`
|
/// Bitwise XOR. `^`
|
||||||
/// Uses the `bin_op` field.
|
/// Uses the `bin_op` field.
|
||||||
xor,
|
xor,
|
||||||
@ -568,10 +586,13 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
|
|||||||
|
|
||||||
.add,
|
.add,
|
||||||
.addwrap,
|
.addwrap,
|
||||||
|
.addsat,
|
||||||
.sub,
|
.sub,
|
||||||
.subwrap,
|
.subwrap,
|
||||||
|
.subsat,
|
||||||
.mul,
|
.mul,
|
||||||
.mulwrap,
|
.mulwrap,
|
||||||
|
.mulsat,
|
||||||
.div,
|
.div,
|
||||||
.rem,
|
.rem,
|
||||||
.mod,
|
.mod,
|
||||||
@ -582,6 +603,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
|
|||||||
.ptr_sub,
|
.ptr_sub,
|
||||||
.shr,
|
.shr,
|
||||||
.shl,
|
.shl,
|
||||||
|
.shl_sat,
|
||||||
=> return air.typeOf(datas[inst].bin_op.lhs),
|
=> return air.typeOf(datas[inst].bin_op.lhs),
|
||||||
|
|
||||||
.cmp_lt,
|
.cmp_lt,
|
||||||
|
|||||||
120
src/AstGen.zig
120
src/AstGen.zig
@ -318,27 +318,35 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Ins
|
|||||||
.assign_bit_and,
|
.assign_bit_and,
|
||||||
.assign_bit_or,
|
.assign_bit_or,
|
||||||
.assign_bit_shift_left,
|
.assign_bit_shift_left,
|
||||||
|
.assign_bit_shift_left_sat,
|
||||||
.assign_bit_shift_right,
|
.assign_bit_shift_right,
|
||||||
.assign_bit_xor,
|
.assign_bit_xor,
|
||||||
.assign_div,
|
.assign_div,
|
||||||
.assign_sub,
|
.assign_sub,
|
||||||
.assign_sub_wrap,
|
.assign_sub_wrap,
|
||||||
|
.assign_sub_sat,
|
||||||
.assign_mod,
|
.assign_mod,
|
||||||
.assign_add,
|
.assign_add,
|
||||||
.assign_add_wrap,
|
.assign_add_wrap,
|
||||||
|
.assign_add_sat,
|
||||||
.assign_mul,
|
.assign_mul,
|
||||||
.assign_mul_wrap,
|
.assign_mul_wrap,
|
||||||
|
.assign_mul_sat,
|
||||||
.add,
|
.add,
|
||||||
.add_wrap,
|
.add_wrap,
|
||||||
|
.add_sat,
|
||||||
.sub,
|
.sub,
|
||||||
.sub_wrap,
|
.sub_wrap,
|
||||||
|
.sub_sat,
|
||||||
.mul,
|
.mul,
|
||||||
.mul_wrap,
|
.mul_wrap,
|
||||||
|
.mul_sat,
|
||||||
.div,
|
.div,
|
||||||
.mod,
|
.mod,
|
||||||
.bit_and,
|
.bit_and,
|
||||||
.bit_or,
|
.bit_or,
|
||||||
.bit_shift_left,
|
.bit_shift_left,
|
||||||
|
.bit_shift_left_sat,
|
||||||
.bit_shift_right,
|
.bit_shift_right,
|
||||||
.bit_xor,
|
.bit_xor,
|
||||||
.bang_equal,
|
.bang_equal,
|
||||||
@ -526,6 +534,10 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
|
|||||||
try assignShift(gz, scope, node, .shl);
|
try assignShift(gz, scope, node, .shl);
|
||||||
return rvalue(gz, rl, .void_value, node);
|
return rvalue(gz, rl, .void_value, node);
|
||||||
},
|
},
|
||||||
|
.assign_bit_shift_left_sat => {
|
||||||
|
try assignBinOpExt(gz, scope, node, .shl_with_saturation);
|
||||||
|
return rvalue(gz, rl, .void_value, node);
|
||||||
|
},
|
||||||
.assign_bit_shift_right => {
|
.assign_bit_shift_right => {
|
||||||
try assignShift(gz, scope, node, .shr);
|
try assignShift(gz, scope, node, .shr);
|
||||||
return rvalue(gz, rl, .void_value, node);
|
return rvalue(gz, rl, .void_value, node);
|
||||||
@ -555,6 +567,10 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
|
|||||||
try assignOp(gz, scope, node, .subwrap);
|
try assignOp(gz, scope, node, .subwrap);
|
||||||
return rvalue(gz, rl, .void_value, node);
|
return rvalue(gz, rl, .void_value, node);
|
||||||
},
|
},
|
||||||
|
.assign_sub_sat => {
|
||||||
|
try assignBinOpExt(gz, scope, node, .sub_with_saturation);
|
||||||
|
return rvalue(gz, rl, .void_value, node);
|
||||||
|
},
|
||||||
.assign_mod => {
|
.assign_mod => {
|
||||||
try assignOp(gz, scope, node, .mod_rem);
|
try assignOp(gz, scope, node, .mod_rem);
|
||||||
return rvalue(gz, rl, .void_value, node);
|
return rvalue(gz, rl, .void_value, node);
|
||||||
@ -567,6 +583,10 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
|
|||||||
try assignOp(gz, scope, node, .addwrap);
|
try assignOp(gz, scope, node, .addwrap);
|
||||||
return rvalue(gz, rl, .void_value, node);
|
return rvalue(gz, rl, .void_value, node);
|
||||||
},
|
},
|
||||||
|
.assign_add_sat => {
|
||||||
|
try assignBinOpExt(gz, scope, node, .add_with_saturation);
|
||||||
|
return rvalue(gz, rl, .void_value, node);
|
||||||
|
},
|
||||||
.assign_mul => {
|
.assign_mul => {
|
||||||
try assignOp(gz, scope, node, .mul);
|
try assignOp(gz, scope, node, .mul);
|
||||||
return rvalue(gz, rl, .void_value, node);
|
return rvalue(gz, rl, .void_value, node);
|
||||||
@ -575,17 +595,25 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
|
|||||||
try assignOp(gz, scope, node, .mulwrap);
|
try assignOp(gz, scope, node, .mulwrap);
|
||||||
return rvalue(gz, rl, .void_value, node);
|
return rvalue(gz, rl, .void_value, node);
|
||||||
},
|
},
|
||||||
|
.assign_mul_sat => {
|
||||||
|
try assignBinOpExt(gz, scope, node, .mul_with_saturation);
|
||||||
|
return rvalue(gz, rl, .void_value, node);
|
||||||
|
},
|
||||||
|
|
||||||
// zig fmt: off
|
// zig fmt: off
|
||||||
.bit_shift_left => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shl),
|
.bit_shift_left => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shl),
|
||||||
|
.bit_shift_left_sat => return binOpExt(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shl_with_saturation),
|
||||||
.bit_shift_right => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shr),
|
.bit_shift_right => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shr),
|
||||||
|
|
||||||
.add => return simpleBinOp(gz, scope, rl, node, .add),
|
.add => return simpleBinOp(gz, scope, rl, node, .add),
|
||||||
.add_wrap => return simpleBinOp(gz, scope, rl, node, .addwrap),
|
.add_wrap => return simpleBinOp(gz, scope, rl, node, .addwrap),
|
||||||
|
.add_sat => return binOpExt(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .add_with_saturation),
|
||||||
.sub => return simpleBinOp(gz, scope, rl, node, .sub),
|
.sub => return simpleBinOp(gz, scope, rl, node, .sub),
|
||||||
.sub_wrap => return simpleBinOp(gz, scope, rl, node, .subwrap),
|
.sub_wrap => return simpleBinOp(gz, scope, rl, node, .subwrap),
|
||||||
|
.sub_sat => return binOpExt(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .sub_with_saturation),
|
||||||
.mul => return simpleBinOp(gz, scope, rl, node, .mul),
|
.mul => return simpleBinOp(gz, scope, rl, node, .mul),
|
||||||
.mul_wrap => return simpleBinOp(gz, scope, rl, node, .mulwrap),
|
.mul_wrap => return simpleBinOp(gz, scope, rl, node, .mulwrap),
|
||||||
|
.mul_sat => return binOpExt(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .mul_with_saturation),
|
||||||
.div => return simpleBinOp(gz, scope, rl, node, .div),
|
.div => return simpleBinOp(gz, scope, rl, node, .div),
|
||||||
.mod => return simpleBinOp(gz, scope, rl, node, .mod_rem),
|
.mod => return simpleBinOp(gz, scope, rl, node, .mod_rem),
|
||||||
.bit_and => {
|
.bit_and => {
|
||||||
@ -2685,6 +2713,31 @@ fn assignOp(
|
|||||||
_ = try gz.addBin(.store, lhs_ptr, result);
|
_ = try gz.addBin(.store, lhs_ptr, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: is there an existing method to accomplish this?
|
||||||
|
// TODO: likely rename this to indicate rhs type coercion or add more params to make it more general
|
||||||
|
fn assignBinOpExt(
|
||||||
|
gz: *GenZir,
|
||||||
|
scope: *Scope,
|
||||||
|
infix_node: Ast.Node.Index,
|
||||||
|
op_inst_tag: Zir.Inst.Extended,
|
||||||
|
) InnerError!void {
|
||||||
|
try emitDbgNode(gz, infix_node);
|
||||||
|
const astgen = gz.astgen;
|
||||||
|
const tree = astgen.tree;
|
||||||
|
const node_datas = tree.nodes.items(.data);
|
||||||
|
|
||||||
|
const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs);
|
||||||
|
const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node);
|
||||||
|
const lhs_type = try gz.addUnNode(.typeof, lhs, infix_node);
|
||||||
|
const rhs = try expr(gz, scope, .{ .coerced_ty = lhs_type }, node_datas[infix_node].rhs);
|
||||||
|
const result = try gz.addExtendedPayload(op_inst_tag, Zir.Inst.BinNode{
|
||||||
|
.node = gz.nodeIndexToRelative(infix_node),
|
||||||
|
.lhs = lhs,
|
||||||
|
.rhs = rhs,
|
||||||
|
});
|
||||||
|
_ = try gz.addBin(.store, lhs_ptr, result);
|
||||||
|
}
|
||||||
|
|
||||||
fn assignShift(
|
fn assignShift(
|
||||||
gz: *GenZir,
|
gz: *GenZir,
|
||||||
scope: *Scope,
|
scope: *Scope,
|
||||||
@ -2708,6 +2761,29 @@ fn assignShift(
|
|||||||
_ = try gz.addBin(.store, lhs_ptr, result);
|
_ = try gz.addBin(.store, lhs_ptr, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn assignShiftSat(
|
||||||
|
gz: *GenZir,
|
||||||
|
scope: *Scope,
|
||||||
|
infix_node: ast.Node.Index,
|
||||||
|
op_inst_tag: Zir.Inst.Tag,
|
||||||
|
) InnerError!void {
|
||||||
|
try emitDbgNode(gz, infix_node);
|
||||||
|
const astgen = gz.astgen;
|
||||||
|
const tree = astgen.tree;
|
||||||
|
const node_datas = tree.nodes.items(.data);
|
||||||
|
|
||||||
|
const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs);
|
||||||
|
const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node);
|
||||||
|
const rhs_type = try gz.addUnNode(.typeof, lhs, infix_node);
|
||||||
|
const rhs = try expr(gz, scope, .{ .ty = rhs_type }, node_datas[infix_node].rhs);
|
||||||
|
|
||||||
|
const result = try gz.addPlNode(op_inst_tag, infix_node, Zir.Inst.Bin{
|
||||||
|
.lhs = lhs,
|
||||||
|
.rhs = rhs,
|
||||||
|
});
|
||||||
|
_ = try gz.addBin(.store, lhs_ptr, result);
|
||||||
|
}
|
||||||
|
|
||||||
fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir.Inst.Ref {
|
fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir.Inst.Ref {
|
||||||
const astgen = gz.astgen;
|
const astgen = gz.astgen;
|
||||||
const tree = astgen.tree;
|
const tree = astgen.tree;
|
||||||
@ -7827,6 +7903,26 @@ fn shiftOp(
|
|||||||
return rvalue(gz, rl, result, node);
|
return rvalue(gz, rl, result, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: is there an existing way to do this?
|
||||||
|
// TODO: likely rename this to reflect result_loc == .none or add more params to make it more general
|
||||||
|
fn binOpExt(
|
||||||
|
gz: *GenZir,
|
||||||
|
scope: *Scope,
|
||||||
|
rl: ResultLoc,
|
||||||
|
node: Ast.Node.Index,
|
||||||
|
lhs_node: Ast.Node.Index,
|
||||||
|
rhs_node: Ast.Node.Index,
|
||||||
|
tag: Zir.Inst.Extended,
|
||||||
|
) InnerError!Zir.Inst.Ref {
|
||||||
|
const lhs = try expr(gz, scope, .none, lhs_node);
|
||||||
|
const rhs = try expr(gz, scope, .none, rhs_node);
|
||||||
|
const result = try gz.addExtendedPayload(tag, Zir.Inst.Bin{
|
||||||
|
.lhs = lhs,
|
||||||
|
.rhs = rhs,
|
||||||
|
});
|
||||||
|
return rvalue(gz, rl, result, node);
|
||||||
|
}
|
||||||
|
|
||||||
fn cImport(
|
fn cImport(
|
||||||
gz: *GenZir,
|
gz: *GenZir,
|
||||||
scope: *Scope,
|
scope: *Scope,
|
||||||
@ -8119,26 +8215,32 @@ fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index) bool
|
|||||||
.asm_simple,
|
.asm_simple,
|
||||||
.add,
|
.add,
|
||||||
.add_wrap,
|
.add_wrap,
|
||||||
|
.add_sat,
|
||||||
.array_cat,
|
.array_cat,
|
||||||
.array_mult,
|
.array_mult,
|
||||||
.assign,
|
.assign,
|
||||||
.assign_bit_and,
|
.assign_bit_and,
|
||||||
.assign_bit_or,
|
.assign_bit_or,
|
||||||
.assign_bit_shift_left,
|
.assign_bit_shift_left,
|
||||||
|
.assign_bit_shift_left_sat,
|
||||||
.assign_bit_shift_right,
|
.assign_bit_shift_right,
|
||||||
.assign_bit_xor,
|
.assign_bit_xor,
|
||||||
.assign_div,
|
.assign_div,
|
||||||
.assign_sub,
|
.assign_sub,
|
||||||
.assign_sub_wrap,
|
.assign_sub_wrap,
|
||||||
|
.assign_sub_sat,
|
||||||
.assign_mod,
|
.assign_mod,
|
||||||
.assign_add,
|
.assign_add,
|
||||||
.assign_add_wrap,
|
.assign_add_wrap,
|
||||||
|
.assign_add_sat,
|
||||||
.assign_mul,
|
.assign_mul,
|
||||||
.assign_mul_wrap,
|
.assign_mul_wrap,
|
||||||
|
.assign_mul_sat,
|
||||||
.bang_equal,
|
.bang_equal,
|
||||||
.bit_and,
|
.bit_and,
|
||||||
.bit_or,
|
.bit_or,
|
||||||
.bit_shift_left,
|
.bit_shift_left,
|
||||||
|
.bit_shift_left_sat,
|
||||||
.bit_shift_right,
|
.bit_shift_right,
|
||||||
.bit_xor,
|
.bit_xor,
|
||||||
.bool_and,
|
.bool_and,
|
||||||
@ -8154,10 +8256,12 @@ fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index) bool
|
|||||||
.mod,
|
.mod,
|
||||||
.mul,
|
.mul,
|
||||||
.mul_wrap,
|
.mul_wrap,
|
||||||
|
.mul_sat,
|
||||||
.switch_range,
|
.switch_range,
|
||||||
.field_access,
|
.field_access,
|
||||||
.sub,
|
.sub,
|
||||||
.sub_wrap,
|
.sub_wrap,
|
||||||
|
.sub_sat,
|
||||||
.slice,
|
.slice,
|
||||||
.slice_open,
|
.slice_open,
|
||||||
.slice_sentinel,
|
.slice_sentinel,
|
||||||
@ -8352,26 +8456,32 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) enum { never
|
|||||||
.tagged_union_enum_tag_trailing,
|
.tagged_union_enum_tag_trailing,
|
||||||
.add,
|
.add,
|
||||||
.add_wrap,
|
.add_wrap,
|
||||||
|
.add_sat,
|
||||||
.array_cat,
|
.array_cat,
|
||||||
.array_mult,
|
.array_mult,
|
||||||
.assign,
|
.assign,
|
||||||
.assign_bit_and,
|
.assign_bit_and,
|
||||||
.assign_bit_or,
|
.assign_bit_or,
|
||||||
.assign_bit_shift_left,
|
.assign_bit_shift_left,
|
||||||
|
.assign_bit_shift_left_sat,
|
||||||
.assign_bit_shift_right,
|
.assign_bit_shift_right,
|
||||||
.assign_bit_xor,
|
.assign_bit_xor,
|
||||||
.assign_div,
|
.assign_div,
|
||||||
.assign_sub,
|
.assign_sub,
|
||||||
.assign_sub_wrap,
|
.assign_sub_wrap,
|
||||||
|
.assign_sub_sat,
|
||||||
.assign_mod,
|
.assign_mod,
|
||||||
.assign_add,
|
.assign_add,
|
||||||
.assign_add_wrap,
|
.assign_add_wrap,
|
||||||
|
.assign_add_sat,
|
||||||
.assign_mul,
|
.assign_mul,
|
||||||
.assign_mul_wrap,
|
.assign_mul_wrap,
|
||||||
|
.assign_mul_sat,
|
||||||
.bang_equal,
|
.bang_equal,
|
||||||
.bit_and,
|
.bit_and,
|
||||||
.bit_or,
|
.bit_or,
|
||||||
.bit_shift_left,
|
.bit_shift_left,
|
||||||
|
.bit_shift_left_sat,
|
||||||
.bit_shift_right,
|
.bit_shift_right,
|
||||||
.bit_xor,
|
.bit_xor,
|
||||||
.bool_and,
|
.bool_and,
|
||||||
@ -8387,9 +8497,11 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) enum { never
|
|||||||
.mod,
|
.mod,
|
||||||
.mul,
|
.mul,
|
||||||
.mul_wrap,
|
.mul_wrap,
|
||||||
|
.mul_sat,
|
||||||
.switch_range,
|
.switch_range,
|
||||||
.sub,
|
.sub,
|
||||||
.sub_wrap,
|
.sub_wrap,
|
||||||
|
.sub_sat,
|
||||||
.slice,
|
.slice,
|
||||||
.slice_open,
|
.slice_open,
|
||||||
.slice_sentinel,
|
.slice_sentinel,
|
||||||
@ -8524,26 +8636,32 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
|
|||||||
.asm_simple,
|
.asm_simple,
|
||||||
.add,
|
.add,
|
||||||
.add_wrap,
|
.add_wrap,
|
||||||
|
.add_sat,
|
||||||
.array_cat,
|
.array_cat,
|
||||||
.array_mult,
|
.array_mult,
|
||||||
.assign,
|
.assign,
|
||||||
.assign_bit_and,
|
.assign_bit_and,
|
||||||
.assign_bit_or,
|
.assign_bit_or,
|
||||||
.assign_bit_shift_left,
|
.assign_bit_shift_left,
|
||||||
|
.assign_bit_shift_left_sat,
|
||||||
.assign_bit_shift_right,
|
.assign_bit_shift_right,
|
||||||
.assign_bit_xor,
|
.assign_bit_xor,
|
||||||
.assign_div,
|
.assign_div,
|
||||||
.assign_sub,
|
.assign_sub,
|
||||||
.assign_sub_wrap,
|
.assign_sub_wrap,
|
||||||
|
.assign_sub_sat,
|
||||||
.assign_mod,
|
.assign_mod,
|
||||||
.assign_add,
|
.assign_add,
|
||||||
.assign_add_wrap,
|
.assign_add_wrap,
|
||||||
|
.assign_add_sat,
|
||||||
.assign_mul,
|
.assign_mul,
|
||||||
.assign_mul_wrap,
|
.assign_mul_wrap,
|
||||||
|
.assign_mul_sat,
|
||||||
.bang_equal,
|
.bang_equal,
|
||||||
.bit_and,
|
.bit_and,
|
||||||
.bit_or,
|
.bit_or,
|
||||||
.bit_shift_left,
|
.bit_shift_left,
|
||||||
|
.bit_shift_left_sat,
|
||||||
.bit_shift_right,
|
.bit_shift_right,
|
||||||
.bit_xor,
|
.bit_xor,
|
||||||
.bool_and,
|
.bool_and,
|
||||||
@ -8559,10 +8677,12 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
|
|||||||
.mod,
|
.mod,
|
||||||
.mul,
|
.mul,
|
||||||
.mul_wrap,
|
.mul_wrap,
|
||||||
|
.mul_sat,
|
||||||
.switch_range,
|
.switch_range,
|
||||||
.field_access,
|
.field_access,
|
||||||
.sub,
|
.sub,
|
||||||
.sub_wrap,
|
.sub_wrap,
|
||||||
|
.sub_sat,
|
||||||
.slice,
|
.slice,
|
||||||
.slice_open,
|
.slice_open,
|
||||||
.slice_sentinel,
|
.slice_sentinel,
|
||||||
|
|||||||
@ -226,10 +226,13 @@ fn analyzeInst(
|
|||||||
switch (inst_tags[inst]) {
|
switch (inst_tags[inst]) {
|
||||||
.add,
|
.add,
|
||||||
.addwrap,
|
.addwrap,
|
||||||
|
.addsat,
|
||||||
.sub,
|
.sub,
|
||||||
.subwrap,
|
.subwrap,
|
||||||
|
.subsat,
|
||||||
.mul,
|
.mul,
|
||||||
.mulwrap,
|
.mulwrap,
|
||||||
|
.mulsat,
|
||||||
.div,
|
.div,
|
||||||
.rem,
|
.rem,
|
||||||
.mod,
|
.mod,
|
||||||
@ -252,6 +255,7 @@ fn analyzeInst(
|
|||||||
.ptr_elem_val,
|
.ptr_elem_val,
|
||||||
.ptr_ptr_elem_val,
|
.ptr_ptr_elem_val,
|
||||||
.shl,
|
.shl,
|
||||||
|
.shl_sat,
|
||||||
.shr,
|
.shr,
|
||||||
.atomic_store_unordered,
|
.atomic_store_unordered,
|
||||||
.atomic_store_monotonic,
|
.atomic_store_monotonic,
|
||||||
|
|||||||
@ -826,10 +826,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
|||||||
// zig fmt: off
|
// zig fmt: off
|
||||||
.add, .ptr_add => try self.airAdd(inst),
|
.add, .ptr_add => try self.airAdd(inst),
|
||||||
.addwrap => try self.airAddWrap(inst),
|
.addwrap => try self.airAddWrap(inst),
|
||||||
|
.addsat => try self.airArithmeticOpSat(inst, "addsat"),
|
||||||
.sub, .ptr_sub => try self.airSub(inst),
|
.sub, .ptr_sub => try self.airSub(inst),
|
||||||
.subwrap => try self.airSubWrap(inst),
|
.subwrap => try self.airSubWrap(inst),
|
||||||
|
.subsat => try self.airArithmeticOpSat(inst, "subsat"),
|
||||||
.mul => try self.airMul(inst),
|
.mul => try self.airMul(inst),
|
||||||
.mulwrap => try self.airMulWrap(inst),
|
.mulwrap => try self.airMulWrap(inst),
|
||||||
|
.mulsat => try self.airArithmeticOpSat(inst, "mulsat"),
|
||||||
.div => try self.airDiv(inst),
|
.div => try self.airDiv(inst),
|
||||||
.rem => try self.airRem(inst),
|
.rem => try self.airRem(inst),
|
||||||
.mod => try self.airMod(inst),
|
.mod => try self.airMod(inst),
|
||||||
@ -848,6 +851,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
|||||||
.xor => try self.airXor(inst),
|
.xor => try self.airXor(inst),
|
||||||
.shr => try self.airShr(inst),
|
.shr => try self.airShr(inst),
|
||||||
.shl => try self.airShl(inst),
|
.shl => try self.airShl(inst),
|
||||||
|
.shl_sat => try self.airArithmeticOpSat(inst, "shl_sat"),
|
||||||
|
|
||||||
.alloc => try self.airAlloc(inst),
|
.alloc => try self.airAlloc(inst),
|
||||||
.arg => try self.airArg(inst),
|
.arg => try self.airArg(inst),
|
||||||
@ -1320,6 +1324,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
|||||||
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn airArithmeticOpSat(self: *Self, inst: Air.Inst.Index, comptime name: []const u8) !void {
|
||||||
|
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||||
|
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
|
||||||
|
else => return self.fail("TODO implement " ++ name ++ " for {}", .{self.target.cpu.arch}),
|
||||||
|
};
|
||||||
|
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||||
|
}
|
||||||
|
|
||||||
fn airMul(self: *Self, inst: Air.Inst.Index) !void {
|
fn airMul(self: *Self, inst: Air.Inst.Index) !void {
|
||||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||||
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
|
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
|
||||||
|
|||||||
@ -885,14 +885,17 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
|
|||||||
// that wrapping is UB.
|
// that wrapping is UB.
|
||||||
.add, .ptr_add => try airBinOp( f, inst, " + "),
|
.add, .ptr_add => try airBinOp( f, inst, " + "),
|
||||||
.addwrap => try airWrapOp(f, inst, " + ", "addw_"),
|
.addwrap => try airWrapOp(f, inst, " + ", "addw_"),
|
||||||
|
.addsat => return o.dg.fail("TODO: C backend: implement codegen for addsat", .{}),
|
||||||
// TODO use a different strategy for sub that communicates to the optimizer
|
// TODO use a different strategy for sub that communicates to the optimizer
|
||||||
// that wrapping is UB.
|
// that wrapping is UB.
|
||||||
.sub, .ptr_sub => try airBinOp( f, inst, " - "),
|
.sub, .ptr_sub => try airBinOp( f, inst, " - "),
|
||||||
.subwrap => try airWrapOp(f, inst, " - ", "subw_"),
|
.subwrap => try airWrapOp(f, inst, " - ", "subw_"),
|
||||||
|
.subsat => return o.dg.fail("TODO: C backend: implement codegen for subsat", .{}),
|
||||||
// TODO use a different strategy for mul that communicates to the optimizer
|
// TODO use a different strategy for mul that communicates to the optimizer
|
||||||
// that wrapping is UB.
|
// that wrapping is UB.
|
||||||
.mul => try airBinOp( f, inst, " * "),
|
.mul => try airBinOp( f, inst, " * "),
|
||||||
.mulwrap => try airWrapOp(f, inst, " * ", "mulw_"),
|
.mulwrap => try airWrapOp(f, inst, " * ", "mulw_"),
|
||||||
|
.mulsat => return o.dg.fail("TODO: C backend: implement codegen for mulsat", .{}),
|
||||||
// TODO use a different strategy for div that communicates to the optimizer
|
// TODO use a different strategy for div that communicates to the optimizer
|
||||||
// that wrapping is UB.
|
// that wrapping is UB.
|
||||||
.div => try airBinOp( f, inst, " / "),
|
.div => try airBinOp( f, inst, " / "),
|
||||||
|
|||||||
@ -1236,12 +1236,15 @@ pub const FuncGen = struct {
|
|||||||
for (body) |inst| {
|
for (body) |inst| {
|
||||||
const opt_value: ?*const llvm.Value = switch (air_tags[inst]) {
|
const opt_value: ?*const llvm.Value = switch (air_tags[inst]) {
|
||||||
// zig fmt: off
|
// zig fmt: off
|
||||||
.add => try self.airAdd(inst, false),
|
.add => try self.airAdd(inst, .standard),
|
||||||
.addwrap => try self.airAdd(inst, true),
|
.addwrap => try self.airAdd(inst, .wrapping),
|
||||||
.sub => try self.airSub(inst, false),
|
.addsat => try self.airAdd(inst, .saturated),
|
||||||
.subwrap => try self.airSub(inst, true),
|
.sub => try self.airSub(inst, .standard),
|
||||||
.mul => try self.airMul(inst, false),
|
.subwrap => try self.airSub(inst, .wrapping),
|
||||||
.mulwrap => try self.airMul(inst, true),
|
.subsat => try self.airSub(inst, .saturated),
|
||||||
|
.mul => try self.airMul(inst, .standard),
|
||||||
|
.mulwrap => try self.airMul(inst, .wrapping),
|
||||||
|
.mulsat => try self.airMul(inst, .saturated),
|
||||||
.div => try self.airDiv(inst),
|
.div => try self.airDiv(inst),
|
||||||
.rem => try self.airRem(inst),
|
.rem => try self.airRem(inst),
|
||||||
.mod => try self.airMod(inst),
|
.mod => try self.airMod(inst),
|
||||||
@ -1252,7 +1255,8 @@ pub const FuncGen = struct {
|
|||||||
.bit_or, .bool_or => try self.airOr(inst),
|
.bit_or, .bool_or => try self.airOr(inst),
|
||||||
.xor => try self.airXor(inst),
|
.xor => try self.airXor(inst),
|
||||||
|
|
||||||
.shl => try self.airShl(inst),
|
.shl => try self.airShl(inst, false),
|
||||||
|
.shl_sat => try self.airShl(inst, true),
|
||||||
.shr => try self.airShr(inst),
|
.shr => try self.airShr(inst),
|
||||||
|
|
||||||
.cmp_eq => try self.airCmp(inst, .eq),
|
.cmp_eq => try self.airCmp(inst, .eq),
|
||||||
@ -2024,7 +2028,8 @@ pub const FuncGen = struct {
|
|||||||
return self.todo("implement llvm codegen for 'airWrapErrUnionErr'", .{});
|
return self.todo("implement llvm codegen for 'airWrapErrUnionErr'", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn airAdd(self: *FuncGen, inst: Air.Inst.Index, wrap: bool) !?*const llvm.Value {
|
const ArithmeticType = enum { standard, wrapping, saturated };
|
||||||
|
fn airAdd(self: *FuncGen, inst: Air.Inst.Index, ty: ArithmeticType) !?*const llvm.Value {
|
||||||
if (self.liveness.isUnused(inst))
|
if (self.liveness.isUnused(inst))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -2033,13 +2038,20 @@ pub const FuncGen = struct {
|
|||||||
const rhs = try self.resolveInst(bin_op.rhs);
|
const rhs = try self.resolveInst(bin_op.rhs);
|
||||||
const inst_ty = self.air.typeOfIndex(inst);
|
const inst_ty = self.air.typeOfIndex(inst);
|
||||||
|
|
||||||
if (inst_ty.isRuntimeFloat()) return self.builder.buildFAdd(lhs, rhs, "");
|
if (inst_ty.isFloat()) return self.builder.buildFAdd(lhs, rhs, "");
|
||||||
if (wrap) return self.builder.buildAdd(lhs, rhs, "");
|
if (ty == .wrapping)
|
||||||
|
return self.builder.buildAdd(lhs, rhs, "")
|
||||||
|
else if (ty == .saturated) {
|
||||||
|
if (inst_ty.isSignedInt())
|
||||||
|
return self.builder.buildSAddSat(lhs, rhs, "")
|
||||||
|
else
|
||||||
|
return self.builder.buildUAddSat(lhs, rhs, "");
|
||||||
|
}
|
||||||
if (inst_ty.isSignedInt()) return self.builder.buildNSWAdd(lhs, rhs, "");
|
if (inst_ty.isSignedInt()) return self.builder.buildNSWAdd(lhs, rhs, "");
|
||||||
return self.builder.buildNUWAdd(lhs, rhs, "");
|
return self.builder.buildNUWAdd(lhs, rhs, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn airSub(self: *FuncGen, inst: Air.Inst.Index, wrap: bool) !?*const llvm.Value {
|
fn airSub(self: *FuncGen, inst: Air.Inst.Index, ty: ArithmeticType) !?*const llvm.Value {
|
||||||
if (self.liveness.isUnused(inst))
|
if (self.liveness.isUnused(inst))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -2048,13 +2060,20 @@ pub const FuncGen = struct {
|
|||||||
const rhs = try self.resolveInst(bin_op.rhs);
|
const rhs = try self.resolveInst(bin_op.rhs);
|
||||||
const inst_ty = self.air.typeOfIndex(inst);
|
const inst_ty = self.air.typeOfIndex(inst);
|
||||||
|
|
||||||
if (inst_ty.isRuntimeFloat()) return self.builder.buildFSub(lhs, rhs, "");
|
if (inst_ty.isFloat()) return self.builder.buildFSub(lhs, rhs, "");
|
||||||
if (wrap) return self.builder.buildSub(lhs, rhs, "");
|
if (ty == .wrapping)
|
||||||
|
return self.builder.buildSub(lhs, rhs, "")
|
||||||
|
else if (ty == .saturated) {
|
||||||
|
if (inst_ty.isSignedInt())
|
||||||
|
return self.builder.buildSSubSat(lhs, rhs, "")
|
||||||
|
else
|
||||||
|
return self.builder.buildUSubSat(lhs, rhs, "");
|
||||||
|
}
|
||||||
if (inst_ty.isSignedInt()) return self.builder.buildNSWSub(lhs, rhs, "");
|
if (inst_ty.isSignedInt()) return self.builder.buildNSWSub(lhs, rhs, "");
|
||||||
return self.builder.buildNUWSub(lhs, rhs, "");
|
return self.builder.buildNUWSub(lhs, rhs, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn airMul(self: *FuncGen, inst: Air.Inst.Index, wrap: bool) !?*const llvm.Value {
|
fn airMul(self: *FuncGen, inst: Air.Inst.Index, ty: ArithmeticType) !?*const llvm.Value {
|
||||||
if (self.liveness.isUnused(inst))
|
if (self.liveness.isUnused(inst))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -2063,8 +2082,15 @@ pub const FuncGen = struct {
|
|||||||
const rhs = try self.resolveInst(bin_op.rhs);
|
const rhs = try self.resolveInst(bin_op.rhs);
|
||||||
const inst_ty = self.air.typeOfIndex(inst);
|
const inst_ty = self.air.typeOfIndex(inst);
|
||||||
|
|
||||||
if (inst_ty.isRuntimeFloat()) return self.builder.buildFMul(lhs, rhs, "");
|
if (inst_ty.isFloat()) return self.builder.buildFMul(lhs, rhs, "");
|
||||||
if (wrap) return self.builder.buildMul(lhs, rhs, "");
|
if (ty == .wrapping)
|
||||||
|
return self.builder.buildMul(lhs, rhs, "")
|
||||||
|
else if (ty == .saturated) {
|
||||||
|
if (inst_ty.isSignedInt())
|
||||||
|
return self.builder.buildSMulFixSat(lhs, rhs, "")
|
||||||
|
else
|
||||||
|
return self.builder.buildUMulFixSat(lhs, rhs, "");
|
||||||
|
}
|
||||||
if (inst_ty.isSignedInt()) return self.builder.buildNSWMul(lhs, rhs, "");
|
if (inst_ty.isSignedInt()) return self.builder.buildNSWMul(lhs, rhs, "");
|
||||||
return self.builder.buildNUWMul(lhs, rhs, "");
|
return self.builder.buildNUWMul(lhs, rhs, "");
|
||||||
}
|
}
|
||||||
@ -2174,7 +2200,7 @@ pub const FuncGen = struct {
|
|||||||
return self.builder.buildXor(lhs, rhs, "");
|
return self.builder.buildXor(lhs, rhs, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn airShl(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
fn airShl(self: *FuncGen, inst: Air.Inst.Index, sat: bool) !?*const llvm.Value {
|
||||||
if (self.liveness.isUnused(inst))
|
if (self.liveness.isUnused(inst))
|
||||||
return null;
|
return null;
|
||||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||||
@ -2186,6 +2212,12 @@ pub const FuncGen = struct {
|
|||||||
self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")
|
self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")
|
||||||
else
|
else
|
||||||
rhs;
|
rhs;
|
||||||
|
if (sat) {
|
||||||
|
return if (lhs_type.isSignedInt())
|
||||||
|
self.builder.buildSShlSat(lhs, casted_rhs, "")
|
||||||
|
else
|
||||||
|
self.builder.buildUShlSat(lhs, casted_rhs, "");
|
||||||
|
}
|
||||||
return self.builder.buildShl(lhs, casted_rhs, "");
|
return self.builder.buildShl(lhs, casted_rhs, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -397,6 +397,12 @@ pub const Builder = opaque {
|
|||||||
pub const buildNUWAdd = LLVMBuildNUWAdd;
|
pub const buildNUWAdd = LLVMBuildNUWAdd;
|
||||||
extern fn LLVMBuildNUWAdd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
extern fn LLVMBuildNUWAdd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||||
|
|
||||||
|
pub const buildSAddSat = ZigLLVMBuildSAddSat;
|
||||||
|
extern fn ZigLLVMBuildSAddSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||||
|
|
||||||
|
pub const buildUAddSat = ZigLLVMBuildUAddSat;
|
||||||
|
extern fn ZigLLVMBuildUAddSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||||
|
|
||||||
pub const buildFSub = LLVMBuildFSub;
|
pub const buildFSub = LLVMBuildFSub;
|
||||||
extern fn LLVMBuildFSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
extern fn LLVMBuildFSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||||
|
|
||||||
@ -409,6 +415,12 @@ pub const Builder = opaque {
|
|||||||
pub const buildNUWSub = LLVMBuildNUWSub;
|
pub const buildNUWSub = LLVMBuildNUWSub;
|
||||||
extern fn LLVMBuildNUWSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
extern fn LLVMBuildNUWSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||||
|
|
||||||
|
pub const buildSSubSat = ZigLLVMBuildSSubSat;
|
||||||
|
extern fn ZigLLVMBuildSSubSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||||
|
|
||||||
|
pub const buildUSubSat = ZigLLVMBuildUSubSat;
|
||||||
|
extern fn ZigLLVMBuildUSubSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||||
|
|
||||||
pub const buildFMul = LLVMBuildFMul;
|
pub const buildFMul = LLVMBuildFMul;
|
||||||
extern fn LLVMBuildFMul(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
extern fn LLVMBuildFMul(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||||
|
|
||||||
@ -421,6 +433,12 @@ pub const Builder = opaque {
|
|||||||
pub const buildNUWMul = LLVMBuildNUWMul;
|
pub const buildNUWMul = LLVMBuildNUWMul;
|
||||||
extern fn LLVMBuildNUWMul(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
extern fn LLVMBuildNUWMul(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||||
|
|
||||||
|
pub const buildSMulFixSat = ZigLLVMBuildSMulFixSat;
|
||||||
|
extern fn ZigLLVMBuildSMulFixSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||||
|
|
||||||
|
pub const buildUMulFixSat = ZigLLVMBuildUMulFixSat;
|
||||||
|
extern fn ZigLLVMBuildUMulFixSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||||
|
|
||||||
pub const buildUDiv = LLVMBuildUDiv;
|
pub const buildUDiv = LLVMBuildUDiv;
|
||||||
extern fn LLVMBuildUDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
extern fn LLVMBuildUDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||||
|
|
||||||
@ -451,6 +469,12 @@ pub const Builder = opaque {
|
|||||||
pub const buildShl = LLVMBuildShl;
|
pub const buildShl = LLVMBuildShl;
|
||||||
extern fn LLVMBuildShl(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
extern fn LLVMBuildShl(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||||
|
|
||||||
|
pub const buildSShlSat = ZigLLVMBuildSShlSat;
|
||||||
|
extern fn ZigLLVMBuildSShlSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||||
|
|
||||||
|
pub const buildUShlSat = ZigLLVMBuildUShlSat;
|
||||||
|
extern fn ZigLLVMBuildUShlSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||||
|
|
||||||
pub const buildOr = LLVMBuildOr;
|
pub const buildOr = LLVMBuildOr;
|
||||||
extern fn LLVMBuildOr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
extern fn LLVMBuildOr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||||
|
|
||||||
|
|||||||
@ -104,10 +104,13 @@ const Writer = struct {
|
|||||||
|
|
||||||
.add,
|
.add,
|
||||||
.addwrap,
|
.addwrap,
|
||||||
|
.addsat,
|
||||||
.sub,
|
.sub,
|
||||||
.subwrap,
|
.subwrap,
|
||||||
|
.subsat,
|
||||||
.mul,
|
.mul,
|
||||||
.mulwrap,
|
.mulwrap,
|
||||||
|
.mulsat,
|
||||||
.div,
|
.div,
|
||||||
.rem,
|
.rem,
|
||||||
.mod,
|
.mod,
|
||||||
@ -130,6 +133,7 @@ const Writer = struct {
|
|||||||
.ptr_elem_val,
|
.ptr_elem_val,
|
||||||
.ptr_ptr_elem_val,
|
.ptr_ptr_elem_val,
|
||||||
.shl,
|
.shl,
|
||||||
|
.shl_sat,
|
||||||
.shr,
|
.shr,
|
||||||
.set_union_tag,
|
.set_union_tag,
|
||||||
=> try w.writeBinOp(s, inst),
|
=> try w.writeBinOp(s, inst),
|
||||||
|
|||||||
@ -812,14 +812,18 @@ enum BinOpType {
|
|||||||
BinOpTypeInvalid,
|
BinOpTypeInvalid,
|
||||||
BinOpTypeAssign,
|
BinOpTypeAssign,
|
||||||
BinOpTypeAssignTimes,
|
BinOpTypeAssignTimes,
|
||||||
|
BinOpTypeAssignTimesSat,
|
||||||
BinOpTypeAssignTimesWrap,
|
BinOpTypeAssignTimesWrap,
|
||||||
BinOpTypeAssignDiv,
|
BinOpTypeAssignDiv,
|
||||||
BinOpTypeAssignMod,
|
BinOpTypeAssignMod,
|
||||||
BinOpTypeAssignPlus,
|
BinOpTypeAssignPlus,
|
||||||
|
BinOpTypeAssignPlusSat,
|
||||||
BinOpTypeAssignPlusWrap,
|
BinOpTypeAssignPlusWrap,
|
||||||
BinOpTypeAssignMinus,
|
BinOpTypeAssignMinus,
|
||||||
|
BinOpTypeAssignMinusSat,
|
||||||
BinOpTypeAssignMinusWrap,
|
BinOpTypeAssignMinusWrap,
|
||||||
BinOpTypeAssignBitShiftLeft,
|
BinOpTypeAssignBitShiftLeft,
|
||||||
|
BinOpTypeAssignBitShiftLeftSat,
|
||||||
BinOpTypeAssignBitShiftRight,
|
BinOpTypeAssignBitShiftRight,
|
||||||
BinOpTypeAssignBitAnd,
|
BinOpTypeAssignBitAnd,
|
||||||
BinOpTypeAssignBitXor,
|
BinOpTypeAssignBitXor,
|
||||||
@ -836,12 +840,16 @@ enum BinOpType {
|
|||||||
BinOpTypeBinXor,
|
BinOpTypeBinXor,
|
||||||
BinOpTypeBinAnd,
|
BinOpTypeBinAnd,
|
||||||
BinOpTypeBitShiftLeft,
|
BinOpTypeBitShiftLeft,
|
||||||
|
BinOpTypeBitShiftLeftSat,
|
||||||
BinOpTypeBitShiftRight,
|
BinOpTypeBitShiftRight,
|
||||||
BinOpTypeAdd,
|
BinOpTypeAdd,
|
||||||
|
BinOpTypeAddSat,
|
||||||
BinOpTypeAddWrap,
|
BinOpTypeAddWrap,
|
||||||
BinOpTypeSub,
|
BinOpTypeSub,
|
||||||
|
BinOpTypeSubSat,
|
||||||
BinOpTypeSubWrap,
|
BinOpTypeSubWrap,
|
||||||
BinOpTypeMult,
|
BinOpTypeMult,
|
||||||
|
BinOpTypeMultSat,
|
||||||
BinOpTypeMultWrap,
|
BinOpTypeMultWrap,
|
||||||
BinOpTypeDiv,
|
BinOpTypeDiv,
|
||||||
BinOpTypeMod,
|
BinOpTypeMod,
|
||||||
@ -2958,10 +2966,10 @@ enum IrBinOp {
|
|||||||
IrBinOpArrayMult,
|
IrBinOpArrayMult,
|
||||||
IrBinOpMaximum,
|
IrBinOpMaximum,
|
||||||
IrBinOpMinimum,
|
IrBinOpMinimum,
|
||||||
IrBinOpSatAdd,
|
IrBinOpAddSat,
|
||||||
IrBinOpSatSub,
|
IrBinOpSubSat,
|
||||||
IrBinOpSatMul,
|
IrBinOpMultSat,
|
||||||
IrBinOpSatShl,
|
IrBinOpShlSat,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Stage1ZirInstBinOp {
|
struct Stage1ZirInstBinOp {
|
||||||
|
|||||||
@ -3672,6 +3672,8 @@ static Stage1ZirInst *astgen_bin_op(Stage1AstGen *ag, Scope *scope, AstNode *nod
|
|||||||
return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpMult), lval, result_loc);
|
return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpMult), lval, result_loc);
|
||||||
case BinOpTypeAssignTimesWrap:
|
case BinOpTypeAssignTimesWrap:
|
||||||
return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpMultWrap), lval, result_loc);
|
return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpMultWrap), lval, result_loc);
|
||||||
|
case BinOpTypeAssignTimesSat:
|
||||||
|
return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpMultSat), lval, result_loc);
|
||||||
case BinOpTypeAssignDiv:
|
case BinOpTypeAssignDiv:
|
||||||
return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpDivUnspecified), lval, result_loc);
|
return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpDivUnspecified), lval, result_loc);
|
||||||
case BinOpTypeAssignMod:
|
case BinOpTypeAssignMod:
|
||||||
@ -3680,12 +3682,18 @@ static Stage1ZirInst *astgen_bin_op(Stage1AstGen *ag, Scope *scope, AstNode *nod
|
|||||||
return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpAdd), lval, result_loc);
|
return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpAdd), lval, result_loc);
|
||||||
case BinOpTypeAssignPlusWrap:
|
case BinOpTypeAssignPlusWrap:
|
||||||
return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpAddWrap), lval, result_loc);
|
return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpAddWrap), lval, result_loc);
|
||||||
|
case BinOpTypeAssignPlusSat:
|
||||||
|
return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpAddSat), lval, result_loc);
|
||||||
case BinOpTypeAssignMinus:
|
case BinOpTypeAssignMinus:
|
||||||
return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpSub), lval, result_loc);
|
return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpSub), lval, result_loc);
|
||||||
case BinOpTypeAssignMinusWrap:
|
case BinOpTypeAssignMinusWrap:
|
||||||
return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpSubWrap), lval, result_loc);
|
return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpSubWrap), lval, result_loc);
|
||||||
|
case BinOpTypeAssignMinusSat:
|
||||||
|
return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpSubSat), lval, result_loc);
|
||||||
case BinOpTypeAssignBitShiftLeft:
|
case BinOpTypeAssignBitShiftLeft:
|
||||||
return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpBitShiftLeftLossy), lval, result_loc);
|
return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpBitShiftLeftLossy), lval, result_loc);
|
||||||
|
case BinOpTypeAssignBitShiftLeftSat:
|
||||||
|
return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpShlSat), lval, result_loc);
|
||||||
case BinOpTypeAssignBitShiftRight:
|
case BinOpTypeAssignBitShiftRight:
|
||||||
return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpBitShiftRightLossy), lval, result_loc);
|
return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpBitShiftRightLossy), lval, result_loc);
|
||||||
case BinOpTypeAssignBitAnd:
|
case BinOpTypeAssignBitAnd:
|
||||||
@ -3718,20 +3726,28 @@ static Stage1ZirInst *astgen_bin_op(Stage1AstGen *ag, Scope *scope, AstNode *nod
|
|||||||
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpBinAnd), lval, result_loc);
|
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpBinAnd), lval, result_loc);
|
||||||
case BinOpTypeBitShiftLeft:
|
case BinOpTypeBitShiftLeft:
|
||||||
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpBitShiftLeftLossy), lval, result_loc);
|
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpBitShiftLeftLossy), lval, result_loc);
|
||||||
|
case BinOpTypeBitShiftLeftSat:
|
||||||
|
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpShlSat), lval, result_loc);
|
||||||
case BinOpTypeBitShiftRight:
|
case BinOpTypeBitShiftRight:
|
||||||
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpBitShiftRightLossy), lval, result_loc);
|
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpBitShiftRightLossy), lval, result_loc);
|
||||||
case BinOpTypeAdd:
|
case BinOpTypeAdd:
|
||||||
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpAdd), lval, result_loc);
|
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpAdd), lval, result_loc);
|
||||||
case BinOpTypeAddWrap:
|
case BinOpTypeAddWrap:
|
||||||
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpAddWrap), lval, result_loc);
|
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpAddWrap), lval, result_loc);
|
||||||
|
case BinOpTypeAddSat:
|
||||||
|
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpAddSat), lval, result_loc);
|
||||||
case BinOpTypeSub:
|
case BinOpTypeSub:
|
||||||
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpSub), lval, result_loc);
|
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpSub), lval, result_loc);
|
||||||
case BinOpTypeSubWrap:
|
case BinOpTypeSubWrap:
|
||||||
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpSubWrap), lval, result_loc);
|
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpSubWrap), lval, result_loc);
|
||||||
|
case BinOpTypeSubSat:
|
||||||
|
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpSubSat), lval, result_loc);
|
||||||
case BinOpTypeMult:
|
case BinOpTypeMult:
|
||||||
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpMult), lval, result_loc);
|
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpMult), lval, result_loc);
|
||||||
case BinOpTypeMultWrap:
|
case BinOpTypeMultWrap:
|
||||||
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpMultWrap), lval, result_loc);
|
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpMultWrap), lval, result_loc);
|
||||||
|
case BinOpTypeMultSat:
|
||||||
|
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpMultSat), lval, result_loc);
|
||||||
case BinOpTypeDiv:
|
case BinOpTypeDiv:
|
||||||
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpDivUnspecified), lval, result_loc);
|
return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpDivUnspecified), lval, result_loc);
|
||||||
case BinOpTypeMod:
|
case BinOpTypeMod:
|
||||||
@ -4716,7 +4732,7 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast
|
|||||||
if (arg1_value == ag->codegen->invalid_inst_src)
|
if (arg1_value == ag->codegen->invalid_inst_src)
|
||||||
return arg1_value;
|
return arg1_value;
|
||||||
|
|
||||||
Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpSatAdd, arg0_value, arg1_value, true);
|
Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpAddSat, arg0_value, arg1_value, true);
|
||||||
return ir_lval_wrap(ag, scope, bin_op, lval, result_loc);
|
return ir_lval_wrap(ag, scope, bin_op, lval, result_loc);
|
||||||
}
|
}
|
||||||
case BuiltinFnIdSatSub:
|
case BuiltinFnIdSatSub:
|
||||||
@ -4731,7 +4747,7 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast
|
|||||||
if (arg1_value == ag->codegen->invalid_inst_src)
|
if (arg1_value == ag->codegen->invalid_inst_src)
|
||||||
return arg1_value;
|
return arg1_value;
|
||||||
|
|
||||||
Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpSatSub, arg0_value, arg1_value, true);
|
Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpSubSat, arg0_value, arg1_value, true);
|
||||||
return ir_lval_wrap(ag, scope, bin_op, lval, result_loc);
|
return ir_lval_wrap(ag, scope, bin_op, lval, result_loc);
|
||||||
}
|
}
|
||||||
case BuiltinFnIdSatMul:
|
case BuiltinFnIdSatMul:
|
||||||
@ -4746,7 +4762,7 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast
|
|||||||
if (arg1_value == ag->codegen->invalid_inst_src)
|
if (arg1_value == ag->codegen->invalid_inst_src)
|
||||||
return arg1_value;
|
return arg1_value;
|
||||||
|
|
||||||
Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpSatMul, arg0_value, arg1_value, true);
|
Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpMultSat, arg0_value, arg1_value, true);
|
||||||
return ir_lval_wrap(ag, scope, bin_op, lval, result_loc);
|
return ir_lval_wrap(ag, scope, bin_op, lval, result_loc);
|
||||||
}
|
}
|
||||||
case BuiltinFnIdSatShl:
|
case BuiltinFnIdSatShl:
|
||||||
@ -4761,7 +4777,7 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast
|
|||||||
if (arg1_value == ag->codegen->invalid_inst_src)
|
if (arg1_value == ag->codegen->invalid_inst_src)
|
||||||
return arg1_value;
|
return arg1_value;
|
||||||
|
|
||||||
Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpSatShl, arg0_value, arg1_value, true);
|
Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpShlSat, arg0_value, arg1_value, true);
|
||||||
return ir_lval_wrap(ag, scope, bin_op, lval, result_loc);
|
return ir_lval_wrap(ag, scope, bin_op, lval, result_loc);
|
||||||
}
|
}
|
||||||
case BuiltinFnIdMemcpy:
|
case BuiltinFnIdMemcpy:
|
||||||
|
|||||||
@ -3333,7 +3333,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,
|
|||||||
} else {
|
} else {
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
case IrBinOpSatAdd:
|
case IrBinOpAddSat:
|
||||||
if (scalar_type->id == ZigTypeIdInt) {
|
if (scalar_type->id == ZigTypeIdInt) {
|
||||||
if (scalar_type->data.integral.is_signed) {
|
if (scalar_type->data.integral.is_signed) {
|
||||||
return ZigLLVMBuildSAddSat(g->builder, op1_value, op2_value, "");
|
return ZigLLVMBuildSAddSat(g->builder, op1_value, op2_value, "");
|
||||||
@ -3343,7 +3343,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,
|
|||||||
} else {
|
} else {
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
case IrBinOpSatSub:
|
case IrBinOpSubSat:
|
||||||
if (scalar_type->id == ZigTypeIdInt) {
|
if (scalar_type->id == ZigTypeIdInt) {
|
||||||
if (scalar_type->data.integral.is_signed) {
|
if (scalar_type->data.integral.is_signed) {
|
||||||
return ZigLLVMBuildSSubSat(g->builder, op1_value, op2_value, "");
|
return ZigLLVMBuildSSubSat(g->builder, op1_value, op2_value, "");
|
||||||
@ -3353,7 +3353,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,
|
|||||||
} else {
|
} else {
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
case IrBinOpSatMul:
|
case IrBinOpMultSat:
|
||||||
if (scalar_type->id == ZigTypeIdInt) {
|
if (scalar_type->id == ZigTypeIdInt) {
|
||||||
if (scalar_type->data.integral.is_signed) {
|
if (scalar_type->data.integral.is_signed) {
|
||||||
return ZigLLVMBuildSMulFixSat(g->builder, op1_value, op2_value, "");
|
return ZigLLVMBuildSMulFixSat(g->builder, op1_value, op2_value, "");
|
||||||
@ -3363,7 +3363,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,
|
|||||||
} else {
|
} else {
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
case IrBinOpSatShl:
|
case IrBinOpShlSat:
|
||||||
if (scalar_type->id == ZigTypeIdInt) {
|
if (scalar_type->id == ZigTypeIdInt) {
|
||||||
if (scalar_type->data.integral.is_signed) {
|
if (scalar_type->data.integral.is_signed) {
|
||||||
return ZigLLVMBuildSShlSat(g->builder, op1_value, op2_value, "");
|
return ZigLLVMBuildSShlSat(g->builder, op1_value, op2_value, "");
|
||||||
|
|||||||
@ -9820,28 +9820,28 @@ static ErrorMsg *ir_eval_math_op_scalar(IrAnalyze *ira, Scope *scope, AstNode *s
|
|||||||
float_min(out_val, op1_val, op2_val);
|
float_min(out_val, op1_val, op2_val);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IrBinOpSatAdd:
|
case IrBinOpAddSat:
|
||||||
if (is_int) {
|
if (is_int) {
|
||||||
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);
|
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);
|
||||||
} else {
|
} else {
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IrBinOpSatSub:
|
case IrBinOpSubSat:
|
||||||
if (is_int) {
|
if (is_int) {
|
||||||
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);
|
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);
|
||||||
} else {
|
} else {
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IrBinOpSatMul:
|
case IrBinOpMultSat:
|
||||||
if (is_int) {
|
if (is_int) {
|
||||||
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);
|
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);
|
||||||
} else {
|
} else {
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IrBinOpSatShl:
|
case IrBinOpShlSat:
|
||||||
if (is_int) {
|
if (is_int) {
|
||||||
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);
|
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);
|
||||||
} else {
|
} else {
|
||||||
@ -10069,10 +10069,10 @@ static bool ok_float_op(IrBinOp op) {
|
|||||||
case IrBinOpBitShiftRightExact:
|
case IrBinOpBitShiftRightExact:
|
||||||
case IrBinOpAddWrap:
|
case IrBinOpAddWrap:
|
||||||
case IrBinOpSubWrap:
|
case IrBinOpSubWrap:
|
||||||
case IrBinOpSatAdd:
|
case IrBinOpAddSat:
|
||||||
case IrBinOpSatSub:
|
case IrBinOpSubSat:
|
||||||
case IrBinOpSatMul:
|
case IrBinOpMultSat:
|
||||||
case IrBinOpSatShl:
|
case IrBinOpShlSat:
|
||||||
case IrBinOpMultWrap:
|
case IrBinOpMultWrap:
|
||||||
case IrBinOpArrayCat:
|
case IrBinOpArrayCat:
|
||||||
case IrBinOpArrayMult:
|
case IrBinOpArrayMult:
|
||||||
@ -11046,10 +11046,10 @@ static Stage1AirInst *ir_analyze_instruction_bin_op(IrAnalyze *ira, Stage1ZirIns
|
|||||||
case IrBinOpRemMod:
|
case IrBinOpRemMod:
|
||||||
case IrBinOpMaximum:
|
case IrBinOpMaximum:
|
||||||
case IrBinOpMinimum:
|
case IrBinOpMinimum:
|
||||||
case IrBinOpSatAdd:
|
case IrBinOpAddSat:
|
||||||
case IrBinOpSatSub:
|
case IrBinOpSubSat:
|
||||||
case IrBinOpSatMul:
|
case IrBinOpMultSat:
|
||||||
case IrBinOpSatShl:
|
case IrBinOpShlSat:
|
||||||
return ir_analyze_bin_op_math(ira, bin_op_instruction);
|
return ir_analyze_bin_op_math(ira, bin_op_instruction);
|
||||||
case IrBinOpArrayCat:
|
case IrBinOpArrayCat:
|
||||||
return ir_analyze_array_cat(ira, bin_op_instruction);
|
return ir_analyze_array_cat(ira, bin_op_instruction);
|
||||||
|
|||||||
@ -737,13 +737,13 @@ static const char *ir_bin_op_id_str(IrBinOp op_id) {
|
|||||||
return "@maximum";
|
return "@maximum";
|
||||||
case IrBinOpMinimum:
|
case IrBinOpMinimum:
|
||||||
return "@minimum";
|
return "@minimum";
|
||||||
case IrBinOpSatAdd:
|
case IrBinOpAddSat:
|
||||||
return "@addWithSaturation";
|
return "@addWithSaturation";
|
||||||
case IrBinOpSatSub:
|
case IrBinOpSubSat:
|
||||||
return "@subWithSaturation";
|
return "@subWithSaturation";
|
||||||
case IrBinOpSatMul:
|
case IrBinOpMultSat:
|
||||||
return "@mulWithSaturation";
|
return "@mulWithSaturation";
|
||||||
case IrBinOpSatShl:
|
case IrBinOpShlSat:
|
||||||
return "@shlWithSaturation";
|
return "@shlWithSaturation";
|
||||||
}
|
}
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
|
|||||||
@ -2381,6 +2381,7 @@ static AstNode *ast_parse_switch_item(ParseContext *pc) {
|
|||||||
// / PLUSEQUAL
|
// / PLUSEQUAL
|
||||||
// / MINUSEQUAL
|
// / MINUSEQUAL
|
||||||
// / LARROW2EQUAL
|
// / LARROW2EQUAL
|
||||||
|
// / LARROW2PIPEEQUAL
|
||||||
// / RARROW2EQUAL
|
// / RARROW2EQUAL
|
||||||
// / AMPERSANDEQUAL
|
// / AMPERSANDEQUAL
|
||||||
// / CARETEQUAL
|
// / CARETEQUAL
|
||||||
@ -2388,6 +2389,9 @@ static AstNode *ast_parse_switch_item(ParseContext *pc) {
|
|||||||
// / ASTERISKPERCENTEQUAL
|
// / ASTERISKPERCENTEQUAL
|
||||||
// / PLUSPERCENTEQUAL
|
// / PLUSPERCENTEQUAL
|
||||||
// / MINUSPERCENTEQUAL
|
// / MINUSPERCENTEQUAL
|
||||||
|
// / ASTERISKPIPEEQUAL
|
||||||
|
// / PLUSPIPEEQUAL
|
||||||
|
// / MINUSPIPEEQUAL
|
||||||
// / EQUAL
|
// / EQUAL
|
||||||
static AstNode *ast_parse_assign_op(ParseContext *pc) {
|
static AstNode *ast_parse_assign_op(ParseContext *pc) {
|
||||||
// In C, we have `T arr[N] = {[i] = T{}};` but it doesn't
|
// 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) {
|
|||||||
table[TokenIdBitAndEq] = BinOpTypeAssignBitAnd;
|
table[TokenIdBitAndEq] = BinOpTypeAssignBitAnd;
|
||||||
table[TokenIdBitOrEq] = BinOpTypeAssignBitOr;
|
table[TokenIdBitOrEq] = BinOpTypeAssignBitOr;
|
||||||
table[TokenIdBitShiftLeftEq] = BinOpTypeAssignBitShiftLeft;
|
table[TokenIdBitShiftLeftEq] = BinOpTypeAssignBitShiftLeft;
|
||||||
|
table[TokenIdBitShiftLeftPipeEq] = BinOpTypeAssignBitShiftLeftSat;
|
||||||
table[TokenIdBitShiftRightEq] = BinOpTypeAssignBitShiftRight;
|
table[TokenIdBitShiftRightEq] = BinOpTypeAssignBitShiftRight;
|
||||||
table[TokenIdBitXorEq] = BinOpTypeAssignBitXor;
|
table[TokenIdBitXorEq] = BinOpTypeAssignBitXor;
|
||||||
table[TokenIdDivEq] = BinOpTypeAssignDiv;
|
table[TokenIdDivEq] = BinOpTypeAssignDiv;
|
||||||
table[TokenIdEq] = BinOpTypeAssign;
|
table[TokenIdEq] = BinOpTypeAssign;
|
||||||
table[TokenIdMinusEq] = BinOpTypeAssignMinus;
|
table[TokenIdMinusEq] = BinOpTypeAssignMinus;
|
||||||
table[TokenIdMinusPercentEq] = BinOpTypeAssignMinusWrap;
|
table[TokenIdMinusPercentEq] = BinOpTypeAssignMinusWrap;
|
||||||
|
table[TokenIdMinusPipeEq] = BinOpTypeAssignMinusSat;
|
||||||
table[TokenIdModEq] = BinOpTypeAssignMod;
|
table[TokenIdModEq] = BinOpTypeAssignMod;
|
||||||
table[TokenIdPlusEq] = BinOpTypeAssignPlus;
|
table[TokenIdPlusEq] = BinOpTypeAssignPlus;
|
||||||
table[TokenIdPlusPercentEq] = BinOpTypeAssignPlusWrap;
|
table[TokenIdPlusPercentEq] = BinOpTypeAssignPlusWrap;
|
||||||
|
table[TokenIdPlusPipeEq] = BinOpTypeAssignPlusSat;
|
||||||
table[TokenIdTimesEq] = BinOpTypeAssignTimes;
|
table[TokenIdTimesEq] = BinOpTypeAssignTimes;
|
||||||
table[TokenIdTimesPercentEq] = BinOpTypeAssignTimesWrap;
|
table[TokenIdTimesPercentEq] = BinOpTypeAssignTimesWrap;
|
||||||
|
table[TokenIdTimesPipeEq] = BinOpTypeAssignTimesSat;
|
||||||
|
|
||||||
BinOpType op = table[pc->token_ids[pc->current_token]];
|
BinOpType op = table[pc->token_ids[pc->current_token]];
|
||||||
if (op != BinOpTypeInvalid) {
|
if (op != BinOpTypeInvalid) {
|
||||||
@ -2483,10 +2491,12 @@ static AstNode *ast_parse_bitwise_op(ParseContext *pc) {
|
|||||||
|
|
||||||
// BitShiftOp
|
// BitShiftOp
|
||||||
// <- LARROW2
|
// <- LARROW2
|
||||||
|
// / LARROW2PIPE
|
||||||
// / RARROW2
|
// / RARROW2
|
||||||
static AstNode *ast_parse_bit_shift_op(ParseContext *pc) {
|
static AstNode *ast_parse_bit_shift_op(ParseContext *pc) {
|
||||||
BinOpType table[TokenIdCount] = {};
|
BinOpType table[TokenIdCount] = {};
|
||||||
table[TokenIdBitShiftLeft] = BinOpTypeBitShiftLeft;
|
table[TokenIdBitShiftLeft] = BinOpTypeBitShiftLeft;
|
||||||
|
table[TokenIdBitShiftLeftPipe] = BinOpTypeBitShiftLeftSat;
|
||||||
table[TokenIdBitShiftRight] = BinOpTypeBitShiftRight;
|
table[TokenIdBitShiftRight] = BinOpTypeBitShiftRight;
|
||||||
|
|
||||||
BinOpType op = table[pc->token_ids[pc->current_token]];
|
BinOpType op = table[pc->token_ids[pc->current_token]];
|
||||||
@ -2506,6 +2516,8 @@ static AstNode *ast_parse_bit_shift_op(ParseContext *pc) {
|
|||||||
// / PLUS2
|
// / PLUS2
|
||||||
// / PLUSPERCENT
|
// / PLUSPERCENT
|
||||||
// / MINUSPERCENT
|
// / MINUSPERCENT
|
||||||
|
// / PLUSPIPE
|
||||||
|
// / MINUSPIPE
|
||||||
static AstNode *ast_parse_addition_op(ParseContext *pc) {
|
static AstNode *ast_parse_addition_op(ParseContext *pc) {
|
||||||
BinOpType table[TokenIdCount] = {};
|
BinOpType table[TokenIdCount] = {};
|
||||||
table[TokenIdPlus] = BinOpTypeAdd;
|
table[TokenIdPlus] = BinOpTypeAdd;
|
||||||
@ -2513,6 +2525,8 @@ static AstNode *ast_parse_addition_op(ParseContext *pc) {
|
|||||||
table[TokenIdPlusPlus] = BinOpTypeArrayCat;
|
table[TokenIdPlusPlus] = BinOpTypeArrayCat;
|
||||||
table[TokenIdPlusPercent] = BinOpTypeAddWrap;
|
table[TokenIdPlusPercent] = BinOpTypeAddWrap;
|
||||||
table[TokenIdMinusPercent] = BinOpTypeSubWrap;
|
table[TokenIdMinusPercent] = BinOpTypeSubWrap;
|
||||||
|
table[TokenIdPlusPipe] = BinOpTypeAddSat;
|
||||||
|
table[TokenIdMinusPipe] = BinOpTypeSubSat;
|
||||||
|
|
||||||
BinOpType op = table[pc->token_ids[pc->current_token]];
|
BinOpType op = table[pc->token_ids[pc->current_token]];
|
||||||
if (op != BinOpTypeInvalid) {
|
if (op != BinOpTypeInvalid) {
|
||||||
@ -2532,6 +2546,7 @@ static AstNode *ast_parse_addition_op(ParseContext *pc) {
|
|||||||
// / PERCENT
|
// / PERCENT
|
||||||
// / ASTERISK2
|
// / ASTERISK2
|
||||||
// / ASTERISKPERCENT
|
// / ASTERISKPERCENT
|
||||||
|
// / ASTERISKPIPE
|
||||||
static AstNode *ast_parse_multiply_op(ParseContext *pc) {
|
static AstNode *ast_parse_multiply_op(ParseContext *pc) {
|
||||||
BinOpType table[TokenIdCount] = {};
|
BinOpType table[TokenIdCount] = {};
|
||||||
table[TokenIdBarBar] = BinOpTypeMergeErrorSets;
|
table[TokenIdBarBar] = BinOpTypeMergeErrorSets;
|
||||||
@ -2540,6 +2555,7 @@ static AstNode *ast_parse_multiply_op(ParseContext *pc) {
|
|||||||
table[TokenIdPercent] = BinOpTypeMod;
|
table[TokenIdPercent] = BinOpTypeMod;
|
||||||
table[TokenIdStarStar] = BinOpTypeArrayMult;
|
table[TokenIdStarStar] = BinOpTypeArrayMult;
|
||||||
table[TokenIdTimesPercent] = BinOpTypeMultWrap;
|
table[TokenIdTimesPercent] = BinOpTypeMultWrap;
|
||||||
|
table[TokenIdTimesPipe] = BinOpTypeMultSat;
|
||||||
|
|
||||||
BinOpType op = table[pc->token_ids[pc->current_token]];
|
BinOpType op = table[pc->token_ids[pc->current_token]];
|
||||||
if (op != BinOpTypeInvalid) {
|
if (op != BinOpTypeInvalid) {
|
||||||
|
|||||||
@ -226,8 +226,10 @@ enum TokenizeState {
|
|||||||
TokenizeState_pipe,
|
TokenizeState_pipe,
|
||||||
TokenizeState_minus,
|
TokenizeState_minus,
|
||||||
TokenizeState_minus_percent,
|
TokenizeState_minus_percent,
|
||||||
|
TokenizeState_minus_pipe,
|
||||||
TokenizeState_asterisk,
|
TokenizeState_asterisk,
|
||||||
TokenizeState_asterisk_percent,
|
TokenizeState_asterisk_percent,
|
||||||
|
TokenizeState_asterisk_pipe,
|
||||||
TokenizeState_slash,
|
TokenizeState_slash,
|
||||||
TokenizeState_line_comment_start,
|
TokenizeState_line_comment_start,
|
||||||
TokenizeState_line_comment,
|
TokenizeState_line_comment,
|
||||||
@ -257,8 +259,10 @@ enum TokenizeState {
|
|||||||
TokenizeState_percent,
|
TokenizeState_percent,
|
||||||
TokenizeState_plus,
|
TokenizeState_plus,
|
||||||
TokenizeState_plus_percent,
|
TokenizeState_plus_percent,
|
||||||
|
TokenizeState_plus_pipe,
|
||||||
TokenizeState_angle_bracket_left,
|
TokenizeState_angle_bracket_left,
|
||||||
TokenizeState_angle_bracket_angle_bracket_left,
|
TokenizeState_angle_bracket_angle_bracket_left,
|
||||||
|
TokenizeState_angle_bracket_angle_bracket_left_pipe,
|
||||||
TokenizeState_angle_bracket_right,
|
TokenizeState_angle_bracket_right,
|
||||||
TokenizeState_angle_bracket_angle_bracket_right,
|
TokenizeState_angle_bracket_angle_bracket_right,
|
||||||
TokenizeState_period,
|
TokenizeState_period,
|
||||||
@ -548,6 +552,9 @@ void tokenize(const char *source, Tokenization *out) {
|
|||||||
case '%':
|
case '%':
|
||||||
t.state = TokenizeState_asterisk_percent;
|
t.state = TokenizeState_asterisk_percent;
|
||||||
break;
|
break;
|
||||||
|
case '|':
|
||||||
|
t.state = TokenizeState_asterisk_pipe;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
t.state = TokenizeState_start;
|
t.state = TokenizeState_start;
|
||||||
continue;
|
continue;
|
||||||
@ -568,6 +575,21 @@ void tokenize(const char *source, Tokenization *out) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case TokenizeState_asterisk_pipe:
|
||||||
|
switch (c) {
|
||||||
|
case 0:
|
||||||
|
t.out->ids.last() = TokenIdTimesPipe;
|
||||||
|
goto eof;
|
||||||
|
case '=':
|
||||||
|
t.out->ids.last() = TokenIdTimesPipeEq;
|
||||||
|
t.state = TokenizeState_start;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
t.out->ids.last() = TokenIdTimesPipe;
|
||||||
|
t.state = TokenizeState_start;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case TokenizeState_percent:
|
case TokenizeState_percent:
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -596,6 +618,9 @@ void tokenize(const char *source, Tokenization *out) {
|
|||||||
case '%':
|
case '%':
|
||||||
t.state = TokenizeState_plus_percent;
|
t.state = TokenizeState_plus_percent;
|
||||||
break;
|
break;
|
||||||
|
case '|':
|
||||||
|
t.state = TokenizeState_plus_pipe;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
t.state = TokenizeState_start;
|
t.state = TokenizeState_start;
|
||||||
continue;
|
continue;
|
||||||
@ -616,6 +641,21 @@ void tokenize(const char *source, Tokenization *out) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case TokenizeState_plus_pipe:
|
||||||
|
switch (c) {
|
||||||
|
case 0:
|
||||||
|
t.out->ids.last() = TokenIdPlusPipe;
|
||||||
|
goto eof;
|
||||||
|
case '=':
|
||||||
|
t.out->ids.last() = TokenIdPlusPipeEq;
|
||||||
|
t.state = TokenizeState_start;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
t.out->ids.last() = TokenIdPlusPipe;
|
||||||
|
t.state = TokenizeState_start;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case TokenizeState_caret:
|
case TokenizeState_caret:
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -891,6 +931,9 @@ void tokenize(const char *source, Tokenization *out) {
|
|||||||
case '%':
|
case '%':
|
||||||
t.state = TokenizeState_minus_percent;
|
t.state = TokenizeState_minus_percent;
|
||||||
break;
|
break;
|
||||||
|
case '|':
|
||||||
|
t.state = TokenizeState_minus_pipe;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
t.state = TokenizeState_start;
|
t.state = TokenizeState_start;
|
||||||
continue;
|
continue;
|
||||||
@ -911,6 +954,21 @@ void tokenize(const char *source, Tokenization *out) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case TokenizeState_minus_pipe:
|
||||||
|
switch (c) {
|
||||||
|
case 0:
|
||||||
|
t.out->ids.last() = TokenIdMinusPipe;
|
||||||
|
goto eof;
|
||||||
|
case '=':
|
||||||
|
t.out->ids.last() = TokenIdMinusPipeEq;
|
||||||
|
t.state = TokenizeState_start;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
t.out->ids.last() = TokenIdMinusPipe;
|
||||||
|
t.state = TokenizeState_start;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case TokenizeState_angle_bracket_left:
|
case TokenizeState_angle_bracket_left:
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -936,12 +994,31 @@ void tokenize(const char *source, Tokenization *out) {
|
|||||||
t.out->ids.last() = TokenIdBitShiftLeftEq;
|
t.out->ids.last() = TokenIdBitShiftLeftEq;
|
||||||
t.state = TokenizeState_start;
|
t.state = TokenizeState_start;
|
||||||
break;
|
break;
|
||||||
|
case '|':
|
||||||
|
// t.out->ids.last() = TokenIdBitShiftLeftPipe;
|
||||||
|
t.state = TokenizeState_angle_bracket_angle_bracket_left_pipe;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
t.out->ids.last() = TokenIdBitShiftLeft;
|
t.out->ids.last() = TokenIdBitShiftLeft;
|
||||||
t.state = TokenizeState_start;
|
t.state = TokenizeState_start;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case TokenizeState_angle_bracket_angle_bracket_left_pipe:
|
||||||
|
switch (c) {
|
||||||
|
case 0:
|
||||||
|
t.out->ids.last() = TokenIdBitShiftLeftPipe;
|
||||||
|
goto eof;
|
||||||
|
case '=':
|
||||||
|
t.out->ids.last() = TokenIdBitShiftLeftPipeEq;
|
||||||
|
t.state = TokenizeState_start;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
t.out->ids.last() = TokenIdBitShiftLeftPipe;
|
||||||
|
t.state = TokenizeState_start;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case TokenizeState_angle_bracket_right:
|
case TokenizeState_angle_bracket_right:
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -1437,6 +1514,8 @@ const char * token_name(TokenId id) {
|
|||||||
case TokenIdBitOrEq: return "|=";
|
case TokenIdBitOrEq: return "|=";
|
||||||
case TokenIdBitShiftLeft: return "<<";
|
case TokenIdBitShiftLeft: return "<<";
|
||||||
case TokenIdBitShiftLeftEq: return "<<=";
|
case TokenIdBitShiftLeftEq: return "<<=";
|
||||||
|
case TokenIdBitShiftLeftPipe: return "<<|";
|
||||||
|
case TokenIdBitShiftLeftPipeEq: return "<<|=";
|
||||||
case TokenIdBitShiftRight: return ">>";
|
case TokenIdBitShiftRight: return ">>";
|
||||||
case TokenIdBitShiftRightEq: return ">>=";
|
case TokenIdBitShiftRightEq: return ">>=";
|
||||||
case TokenIdBitXorEq: return "^=";
|
case TokenIdBitXorEq: return "^=";
|
||||||
@ -1521,12 +1600,16 @@ const char * token_name(TokenId id) {
|
|||||||
case TokenIdMinusEq: return "-=";
|
case TokenIdMinusEq: return "-=";
|
||||||
case TokenIdMinusPercent: return "-%";
|
case TokenIdMinusPercent: return "-%";
|
||||||
case TokenIdMinusPercentEq: return "-%=";
|
case TokenIdMinusPercentEq: return "-%=";
|
||||||
|
case TokenIdMinusPipe: return "-|";
|
||||||
|
case TokenIdMinusPipeEq: return "-|=";
|
||||||
case TokenIdModEq: return "%=";
|
case TokenIdModEq: return "%=";
|
||||||
case TokenIdPercent: return "%";
|
case TokenIdPercent: return "%";
|
||||||
case TokenIdPlus: return "+";
|
case TokenIdPlus: return "+";
|
||||||
case TokenIdPlusEq: return "+=";
|
case TokenIdPlusEq: return "+=";
|
||||||
case TokenIdPlusPercent: return "+%";
|
case TokenIdPlusPercent: return "+%";
|
||||||
case TokenIdPlusPercentEq: return "+%=";
|
case TokenIdPlusPercentEq: return "+%=";
|
||||||
|
case TokenIdPlusPipe: return "+|";
|
||||||
|
case TokenIdPlusPipeEq: return "+|=";
|
||||||
case TokenIdPlusPlus: return "++";
|
case TokenIdPlusPlus: return "++";
|
||||||
case TokenIdRBrace: return "}";
|
case TokenIdRBrace: return "}";
|
||||||
case TokenIdRBracket: return "]";
|
case TokenIdRBracket: return "]";
|
||||||
@ -1542,6 +1625,8 @@ const char * token_name(TokenId id) {
|
|||||||
case TokenIdTimesEq: return "*=";
|
case TokenIdTimesEq: return "*=";
|
||||||
case TokenIdTimesPercent: return "*%";
|
case TokenIdTimesPercent: return "*%";
|
||||||
case TokenIdTimesPercentEq: return "*%=";
|
case TokenIdTimesPercentEq: return "*%=";
|
||||||
|
case TokenIdTimesPipe: return "*|";
|
||||||
|
case TokenIdTimesPipeEq: return "*|=";
|
||||||
case TokenIdBuiltin: return "Builtin";
|
case TokenIdBuiltin: return "Builtin";
|
||||||
case TokenIdCount:
|
case TokenIdCount:
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
|
|||||||
@ -23,6 +23,8 @@ enum TokenId : uint8_t {
|
|||||||
TokenIdBitOrEq,
|
TokenIdBitOrEq,
|
||||||
TokenIdBitShiftLeft,
|
TokenIdBitShiftLeft,
|
||||||
TokenIdBitShiftLeftEq,
|
TokenIdBitShiftLeftEq,
|
||||||
|
TokenIdBitShiftLeftPipe,
|
||||||
|
TokenIdBitShiftLeftPipeEq,
|
||||||
TokenIdBitShiftRight,
|
TokenIdBitShiftRight,
|
||||||
TokenIdBitShiftRightEq,
|
TokenIdBitShiftRightEq,
|
||||||
TokenIdBitXorEq,
|
TokenIdBitXorEq,
|
||||||
@ -108,12 +110,16 @@ enum TokenId : uint8_t {
|
|||||||
TokenIdMinusEq,
|
TokenIdMinusEq,
|
||||||
TokenIdMinusPercent,
|
TokenIdMinusPercent,
|
||||||
TokenIdMinusPercentEq,
|
TokenIdMinusPercentEq,
|
||||||
|
TokenIdMinusPipe,
|
||||||
|
TokenIdMinusPipeEq,
|
||||||
TokenIdModEq,
|
TokenIdModEq,
|
||||||
TokenIdPercent,
|
TokenIdPercent,
|
||||||
TokenIdPlus,
|
TokenIdPlus,
|
||||||
TokenIdPlusEq,
|
TokenIdPlusEq,
|
||||||
TokenIdPlusPercent,
|
TokenIdPlusPercent,
|
||||||
TokenIdPlusPercentEq,
|
TokenIdPlusPercentEq,
|
||||||
|
TokenIdPlusPipe,
|
||||||
|
TokenIdPlusPipeEq,
|
||||||
TokenIdPlusPlus,
|
TokenIdPlusPlus,
|
||||||
TokenIdRBrace,
|
TokenIdRBrace,
|
||||||
TokenIdRBracket,
|
TokenIdRBracket,
|
||||||
@ -129,6 +135,8 @@ enum TokenId : uint8_t {
|
|||||||
TokenIdTimesEq,
|
TokenIdTimesEq,
|
||||||
TokenIdTimesPercent,
|
TokenIdTimesPercent,
|
||||||
TokenIdTimesPercentEq,
|
TokenIdTimesPercentEq,
|
||||||
|
TokenIdTimesPipe,
|
||||||
|
TokenIdTimesPipeEq,
|
||||||
|
|
||||||
TokenIdCount,
|
TokenIdCount,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -11,6 +11,7 @@ fn testSaturatingOp(comptime op: Op, comptime T: type, test_data: [3]T) !void {
|
|||||||
const a = test_data[0];
|
const a = test_data[0];
|
||||||
const b = test_data[1];
|
const b = test_data[1];
|
||||||
const expected = test_data[2];
|
const expected = test_data[2];
|
||||||
|
{
|
||||||
const actual = switch (op) {
|
const actual = switch (op) {
|
||||||
.add => @addWithSaturation(a, b),
|
.add => @addWithSaturation(a, b),
|
||||||
.sub => @subWithSaturation(a, b),
|
.sub => @subWithSaturation(a, b),
|
||||||
@ -18,6 +19,26 @@ fn testSaturatingOp(comptime op: Op, comptime T: type, test_data: [3]T) !void {
|
|||||||
.shl => @shlWithSaturation(a, b),
|
.shl => @shlWithSaturation(a, b),
|
||||||
};
|
};
|
||||||
try expectEqual(expected, actual);
|
try expectEqual(expected, actual);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const actual = switch (op) {
|
||||||
|
.add => a +| b,
|
||||||
|
.sub => a -| b,
|
||||||
|
.mul => a *| b,
|
||||||
|
.shl => a <<| b,
|
||||||
|
};
|
||||||
|
try expectEqual(expected, actual);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
var actual = a;
|
||||||
|
switch (op) {
|
||||||
|
.add => actual +|= b,
|
||||||
|
.sub => actual -|= b,
|
||||||
|
.mul => actual *|= b,
|
||||||
|
.shl => actual <<|= b,
|
||||||
|
}
|
||||||
|
try expectEqual(expected, actual);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "@addWithSaturation" {
|
test "@addWithSaturation" {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user