diff options
| author | Travis Staloch <twostepted@gmail.com> | 2021-09-02 13:50:24 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-09-28 17:02:43 -0700 |
| commit | 29f41896ed9d99e82a88f4b63efa182ca0d2f93c (patch) | |
| tree | 1e6eb1159df89f79b04f050da662653925c77b1c /src/AstGen.zig | |
| parent | 79bc5891c1c4cde0592fe1b10b6c9a85914155cf (diff) | |
| download | zig-29f41896ed9d99e82a88f4b63efa182ca0d2f93c.tar.gz zig-29f41896ed9d99e82a88f4b63efa182ca0d2f93c.zip | |
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
Diffstat (limited to 'src/AstGen.zig')
| -rw-r--r-- | src/AstGen.zig | 124 |
1 files changed, 122 insertions, 2 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig index 15594ac27c..b3af3eb86b 100644 --- a/src/AstGen.zig +++ b/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_or, .assign_bit_shift_left, + .assign_bit_shift_left_sat, .assign_bit_shift_right, .assign_bit_xor, .assign_div, .assign_sub, .assign_sub_wrap, + .assign_sub_sat, .assign_mod, .assign_add, .assign_add_wrap, + .assign_add_sat, .assign_mul, .assign_mul_wrap, + .assign_mul_sat, .add, .add_wrap, + .add_sat, .sub, .sub_wrap, + .sub_sat, .mul, .mul_wrap, + .mul_sat, .div, .mod, .bit_and, .bit_or, .bit_shift_left, + .bit_shift_left_sat, .bit_shift_right, .bit_xor, .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); 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 => { try assignShift(gz, scope, node, .shr); 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); 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 => { try assignOp(gz, scope, node, .mod_rem); 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); 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 => { try assignOp(gz, scope, node, .mul); 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); 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 - .bit_shift_left => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shl), - .bit_shift_right => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shr), + .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), .add => return simpleBinOp(gz, scope, rl, node, .add), .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_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_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), .mod => return simpleBinOp(gz, scope, rl, node, .mod_rem), .bit_and => { @@ -2685,6 +2713,31 @@ fn assignOp( _ = 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( gz: *GenZir, scope: *Scope, @@ -2708,6 +2761,29 @@ fn assignShift( _ = 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 { const astgen = gz.astgen; const tree = astgen.tree; @@ -7827,6 +7903,26 @@ fn shiftOp( 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( gz: *GenZir, scope: *Scope, @@ -8119,26 +8215,32 @@ fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index) bool .asm_simple, .add, .add_wrap, + .add_sat, .array_cat, .array_mult, .assign, .assign_bit_and, .assign_bit_or, .assign_bit_shift_left, + .assign_bit_shift_left_sat, .assign_bit_shift_right, .assign_bit_xor, .assign_div, .assign_sub, .assign_sub_wrap, + .assign_sub_sat, .assign_mod, .assign_add, .assign_add_wrap, + .assign_add_sat, .assign_mul, .assign_mul_wrap, + .assign_mul_sat, .bang_equal, .bit_and, .bit_or, .bit_shift_left, + .bit_shift_left_sat, .bit_shift_right, .bit_xor, .bool_and, @@ -8154,10 +8256,12 @@ fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index) bool .mod, .mul, .mul_wrap, + .mul_sat, .switch_range, .field_access, .sub, .sub_wrap, + .sub_sat, .slice, .slice_open, .slice_sentinel, @@ -8352,26 +8456,32 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) enum { never .tagged_union_enum_tag_trailing, .add, .add_wrap, + .add_sat, .array_cat, .array_mult, .assign, .assign_bit_and, .assign_bit_or, .assign_bit_shift_left, + .assign_bit_shift_left_sat, .assign_bit_shift_right, .assign_bit_xor, .assign_div, .assign_sub, .assign_sub_wrap, + .assign_sub_sat, .assign_mod, .assign_add, .assign_add_wrap, + .assign_add_sat, .assign_mul, .assign_mul_wrap, + .assign_mul_sat, .bang_equal, .bit_and, .bit_or, .bit_shift_left, + .bit_shift_left_sat, .bit_shift_right, .bit_xor, .bool_and, @@ -8387,9 +8497,11 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) enum { never .mod, .mul, .mul_wrap, + .mul_sat, .switch_range, .sub, .sub_wrap, + .sub_sat, .slice, .slice_open, .slice_sentinel, @@ -8524,26 +8636,32 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool { .asm_simple, .add, .add_wrap, + .add_sat, .array_cat, .array_mult, .assign, .assign_bit_and, .assign_bit_or, .assign_bit_shift_left, + .assign_bit_shift_left_sat, .assign_bit_shift_right, .assign_bit_xor, .assign_div, .assign_sub, .assign_sub_wrap, + .assign_sub_sat, .assign_mod, .assign_add, .assign_add_wrap, + .assign_add_sat, .assign_mul, .assign_mul_wrap, + .assign_mul_sat, .bang_equal, .bit_and, .bit_or, .bit_shift_left, + .bit_shift_left_sat, .bit_shift_right, .bit_xor, .bool_and, @@ -8559,10 +8677,12 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool { .mod, .mul, .mul_wrap, + .mul_sat, .switch_range, .field_access, .sub, .sub_wrap, + .sub_sat, .slice, .slice_open, .slice_sentinel, |
