authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-17 13:00:10-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-17 13:00:10-07:00
log5a3045b5de03fade87ccbb4191344861374ea0a4
treee3a30afe0d303c5f3e7a9f8fdcdf32b1045f9b01
parent8cf0ef27790a96e784c368d00338229f205c95d9

AstGen: implement overflow arithmetic builtins


3 files changed, 132 insertions(+), 12 deletions(-)

src/AstGen.zig+60-4
...@@ -1407,6 +1407,11 @@ fn blockExprStmts(...@@ -1407,6 +1407,11 @@ fn blockExprStmts(
1407 .fence,1407 .fence,
1408 .ret_addr,1408 .ret_addr,
1409 .builtin_src,1409 .builtin_src,
1410 .add_with_overflow,
1411 .sub_with_overflow,
1412 .mul_with_overflow,
1413 .shl_with_overflow,
1414 .log2_int_type,
1410 => break :b false,1415 => break :b false,
14111416
1412 // ZIR instructions that are always either `noreturn` or `void`.1417 // ZIR instructions that are always either `noreturn` or `void`.
...@@ -4910,7 +4915,32 @@ fn builtinCall(...@@ -4910,7 +4915,32 @@ fn builtinCall(
4910 .return_address => return rvalue(gz, scope, rl, try gz.addNode(.ret_addr, node), node),4915 .return_address => return rvalue(gz, scope, rl, try gz.addNode(.ret_addr, node), node),
4911 .src => return rvalue(gz, scope, rl, try gz.addNode(.builtin_src, node), node),4916 .src => return rvalue(gz, scope, rl, try gz.addNode(.builtin_src, node), node),
49124917
4913 .add_with_overflow,4918 .add_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .add_with_overflow),
4919 .sub_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .sub_with_overflow),
4920 .mul_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .mul_with_overflow),
4921 .shl_with_overflow => {
4922 const int_type = try typeExpr(gz, scope, params[0]);
4923 const log2_int_type = try gz.addUnNode(.log2_int_type, int_type, params[0]);
4924 const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{
4925 .ptr_type_simple = .{
4926 .is_allowzero = false,
4927 .is_mutable = true,
4928 .is_volatile = false,
4929 .size = .One,
4930 .elem_type = int_type,
4931 },
4932 } });
4933 const lhs = try expr(gz, scope, .{ .ty = int_type }, params[1]);
4934 const rhs = try expr(gz, scope, .{ .ty = log2_int_type }, params[2]);
4935 const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[3]);
4936 const result = try gz.addPlNode(.shl_with_overflow, node, Zir.Inst.OverflowArithmetic{
4937 .lhs = lhs,
4938 .rhs = rhs,
4939 .ptr = ptr,
4940 });
4941 return rvalue(gz, scope, rl, result, node);
4942 },
4943
4914 .align_cast,4944 .align_cast,
4915 .align_of,4945 .align_of,
4916 .atomic_load,4946 .atomic_load,
...@@ -4948,7 +4978,6 @@ fn builtinCall(...@@ -4948,7 +4978,6 @@ fn builtinCall(
4948 .wasm_memory_size,4978 .wasm_memory_size,
4949 .wasm_memory_grow,4979 .wasm_memory_grow,
4950 .mod,4980 .mod,
4951 .mul_with_overflow,
4952 .panic,4981 .panic,
4953 .pop_count,4982 .pop_count,
4954 .ptr_cast,4983 .ptr_cast,
...@@ -4958,7 +4987,6 @@ fn builtinCall(...@@ -4958,7 +4987,6 @@ fn builtinCall(
4958 .set_float_mode,4987 .set_float_mode,
4959 .set_runtime_safety,4988 .set_runtime_safety,
4960 .shl_exact,4989 .shl_exact,
4961 .shl_with_overflow,
4962 .shr_exact,4990 .shr_exact,
4963 .shuffle,4991 .shuffle,
4964 .splat,4992 .splat,
...@@ -4976,7 +5004,6 @@ fn builtinCall(...@@ -4976,7 +5004,6 @@ fn builtinCall(
4976 .ceil,5004 .ceil,
4977 .trunc,5005 .trunc,
4978 .round,5006 .round,
4979 .sub_with_overflow,
4980 .tag_name,5007 .tag_name,
4981 .truncate,5008 .truncate,
4982 .Type,5009 .Type,
...@@ -4993,6 +5020,35 @@ fn builtinCall(...@@ -4993,6 +5020,35 @@ fn builtinCall(
4993 }5020 }
4994}5021}
49955022
5023fn overflowArithmetic(
5024 gz: *GenZir,
5025 scope: *Scope,
5026 rl: ResultLoc,
5027 node: ast.Node.Index,
5028 params: []const ast.Node.Index,
5029 tag: Zir.Inst.Tag,
5030) InnerError!Zir.Inst.Ref {
5031 const int_type = try typeExpr(gz, scope, params[0]);
5032 const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{
5033 .ptr_type_simple = .{
5034 .is_allowzero = false,
5035 .is_mutable = true,
5036 .is_volatile = false,
5037 .size = .One,
5038 .elem_type = int_type,
5039 },
5040 } });
5041 const lhs = try expr(gz, scope, .{ .ty = int_type }, params[1]);
5042 const rhs = try expr(gz, scope, .{ .ty = int_type }, params[2]);
5043 const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[3]);
5044 const result = try gz.addPlNode(tag, node, Zir.Inst.OverflowArithmetic{
5045 .lhs = lhs,
5046 .rhs = rhs,
5047 .ptr = ptr,
5048 });
5049 return rvalue(gz, scope, rl, result, node);
5050}
5051
4996fn callExpr(5052fn callExpr(
4997 gz: *GenZir,5053 gz: *GenZir,
4998 scope: *Scope,5054 scope: *Scope,
src/Sema.zig+31-8
...@@ -133,8 +133,6 @@ pub fn analyzeBody(...@@ -133,8 +133,6 @@ pub fn analyzeBody(
133 map[inst] = switch (tags[inst]) {133 map[inst] = switch (tags[inst]) {
134 .elided => continue,134 .elided => continue,
135135
136 .add => try sema.zirArithmetic(block, inst),
137 .addwrap => try sema.zirArithmetic(block, inst),
138 .alloc => try sema.zirAlloc(block, inst),136 .alloc => try sema.zirAlloc(block, inst),
139 .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),137 .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),
140 .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),138 .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),
...@@ -173,7 +171,6 @@ pub fn analyzeBody(...@@ -173,7 +171,6 @@ pub fn analyzeBody(
173 .decl_ref => try sema.zirDeclRef(block, inst),171 .decl_ref => try sema.zirDeclRef(block, inst),
174 .decl_val => try sema.zirDeclVal(block, inst),172 .decl_val => try sema.zirDeclVal(block, inst),
175 .load => try sema.zirLoad(block, inst),173 .load => try sema.zirLoad(block, inst),
176 .div => try sema.zirArithmetic(block, inst),
177 .elem_ptr => try sema.zirElemPtr(block, inst),174 .elem_ptr => try sema.zirElemPtr(block, inst),
178 .elem_ptr_node => try sema.zirElemPtrNode(block, inst),175 .elem_ptr_node => try sema.zirElemPtrNode(block, inst),
179 .elem_val => try sema.zirElemVal(block, inst),176 .elem_val => try sema.zirElemVal(block, inst),
...@@ -217,9 +214,6 @@ pub fn analyzeBody(...@@ -217,9 +214,6 @@ pub fn analyzeBody(
217 .is_null_ptr => try sema.zirIsNullPtr(block, inst, false),214 .is_null_ptr => try sema.zirIsNullPtr(block, inst, false),
218 .loop => try sema.zirLoop(block, inst),215 .loop => try sema.zirLoop(block, inst),
219 .merge_error_sets => try sema.zirMergeErrorSets(block, inst),216 .merge_error_sets => try sema.zirMergeErrorSets(block, inst),
220 .mod_rem => try sema.zirArithmetic(block, inst),
221 .mul => try sema.zirArithmetic(block, inst),
222 .mulwrap => try sema.zirArithmetic(block, inst),
223 .negate => try sema.zirNegate(block, inst, .sub),217 .negate => try sema.zirNegate(block, inst, .sub),
224 .negate_wrap => try sema.zirNegate(block, inst, .subwrap),218 .negate_wrap => try sema.zirNegate(block, inst, .subwrap),
225 .optional_payload_safe => try sema.zirOptionalPayload(block, inst, true),219 .optional_payload_safe => try sema.zirOptionalPayload(block, inst, true),
...@@ -241,8 +235,6 @@ pub fn analyzeBody(...@@ -241,8 +235,6 @@ pub fn analyzeBody(
241 .slice_sentinel => try sema.zirSliceSentinel(block, inst),235 .slice_sentinel => try sema.zirSliceSentinel(block, inst),
242 .slice_start => try sema.zirSliceStart(block, inst),236 .slice_start => try sema.zirSliceStart(block, inst),
243 .str => try sema.zirStr(block, inst),237 .str => try sema.zirStr(block, inst),
244 .sub => try sema.zirArithmetic(block, inst),
245 .subwrap => try sema.zirArithmetic(block, inst),
246 .switch_block => try sema.zirSwitchBlock(block, inst, false, .none),238 .switch_block => try sema.zirSwitchBlock(block, inst, false, .none),
247 .switch_block_multi => try sema.zirSwitchBlockMulti(block, inst, false, .none),239 .switch_block_multi => try sema.zirSwitchBlockMulti(block, inst, false, .none),
248 .switch_block_else => try sema.zirSwitchBlock(block, inst, false, .@"else"),240 .switch_block_else => try sema.zirSwitchBlock(block, inst, false, .@"else"),
...@@ -271,6 +263,7 @@ pub fn analyzeBody(...@@ -271,6 +263,7 @@ pub fn analyzeBody(
271 .typeof => try sema.zirTypeof(block, inst),263 .typeof => try sema.zirTypeof(block, inst),
272 .typeof_elem => try sema.zirTypeofElem(block, inst),264 .typeof_elem => try sema.zirTypeofElem(block, inst),
273 .typeof_peer => try sema.zirTypeofPeer(block, inst),265 .typeof_peer => try sema.zirTypeofPeer(block, inst),
266 .log2_int_type => try sema.zirLog2IntType(block, inst),
274 .xor => try sema.zirBitwise(block, inst, .xor),267 .xor => try sema.zirBitwise(block, inst, .xor),
275 .struct_init_empty => try sema.zirStructInitEmpty(block, inst),268 .struct_init_empty => try sema.zirStructInitEmpty(block, inst),
276 .struct_init => try sema.zirStructInit(block, inst),269 .struct_init => try sema.zirStructInit(block, inst),
...@@ -284,6 +277,20 @@ pub fn analyzeBody(...@@ -284,6 +277,20 @@ pub fn analyzeBody(
284 .union_decl => try sema.zirUnionDecl(block, inst),277 .union_decl => try sema.zirUnionDecl(block, inst),
285 .opaque_decl => try sema.zirOpaqueDecl(block, inst),278 .opaque_decl => try sema.zirOpaqueDecl(block, inst),
286279
280 .add => try sema.zirArithmetic(block, inst),
281 .addwrap => try sema.zirArithmetic(block, inst),
282 .div => try sema.zirArithmetic(block, inst),
283 .mod_rem => try sema.zirArithmetic(block, inst),
284 .mul => try sema.zirArithmetic(block, inst),
285 .mulwrap => try sema.zirArithmetic(block, inst),
286 .sub => try sema.zirArithmetic(block, inst),
287 .subwrap => try sema.zirArithmetic(block, inst),
288
289 .add_with_overflow => try sema.zirOverflowArithmetic(block, inst),
290 .sub_with_overflow => try sema.zirOverflowArithmetic(block, inst),
291 .mul_with_overflow => try sema.zirOverflowArithmetic(block, inst),
292 .shl_with_overflow => try sema.zirOverflowArithmetic(block, inst),
293
287 // Instructions that we know to *always* be noreturn based solely on their tag.294 // Instructions that we know to *always* be noreturn based solely on their tag.
288 // These functions match the return type of analyzeBody so that we can295 // These functions match the return type of analyzeBody so that we can
289 // tail call them here.296 // tail call them here.
...@@ -4048,6 +4055,16 @@ fn zirArithmetic(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerEr...@@ -4048,6 +4055,16 @@ fn zirArithmetic(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerEr
4048 return sema.analyzeArithmetic(block, tag_override, lhs, rhs, src, lhs_src, rhs_src);4055 return sema.analyzeArithmetic(block, tag_override, lhs, rhs, src, lhs_src, rhs_src);
4049}4056}
40504057
4058fn zirOverflowArithmetic(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
4059 const tracy = trace(@src());
4060 defer tracy.end();
4061
4062 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
4063 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
4064
4065 return sema.mod.fail(&block.base, src, "TODO implement Sema.zirOverflowArithmetic", .{});
4066}
4067
4051fn analyzeArithmetic(4068fn analyzeArithmetic(
4052 sema: *Sema,4069 sema: *Sema,
4053 block: *Scope.Block,4070 block: *Scope.Block,
...@@ -4402,6 +4419,12 @@ fn zirTypeofElem(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerEr...@@ -4402,6 +4419,12 @@ fn zirTypeofElem(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerEr
4402 return sema.mod.constType(sema.arena, src, elem_ty);4419 return sema.mod.constType(sema.arena, src, elem_ty);
4403}4420}
44044421
4422fn zirLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
4423 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
4424 const src = inst_data.src();
4425 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirLog2IntType", .{});
4426}
4427
4405fn zirTypeofPeer(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {4428fn zirTypeofPeer(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
4406 const tracy = trace(@src());4429 const tracy = trace(@src());
4407 defer tracy.end();4430 defer tracy.end();
src/Zir.zig+41
...@@ -573,6 +573,9 @@ pub const Inst = struct {...@@ -573,6 +573,9 @@ pub const Inst = struct {
573 /// of one or more params.573 /// of one or more params.
574 /// Uses the `pl_node` field. AST node is the `@TypeOf` call. Payload is `MultiOp`.574 /// Uses the `pl_node` field. AST node is the `@TypeOf` call. Payload is `MultiOp`.
575 typeof_peer,575 typeof_peer,
576 /// Given an integer type, returns the integer type for the RHS of a shift operation.
577 /// Uses the `un_node` field.
578 log2_int_type,
576 /// Asserts control-flow will not reach this instruction (`unreachable`).579 /// Asserts control-flow will not reach this instruction (`unreachable`).
577 /// Uses the `unreachable` union field.580 /// Uses the `unreachable` union field.
578 @"unreachable",581 @"unreachable",
...@@ -729,6 +732,14 @@ pub const Inst = struct {...@@ -729,6 +732,14 @@ pub const Inst = struct {
729 ret_addr,732 ret_addr,
730 /// Implements the `@src` builtin. Uses `un_node`.733 /// Implements the `@src` builtin. Uses `un_node`.
731 builtin_src,734 builtin_src,
735 /// Implements the `@addWithOverflow` builtin. Uses `pl_node` with `OverflowArithmetic`.
736 add_with_overflow,
737 /// Implements the `@subWithOverflow` builtin. Uses `pl_node` with `OverflowArithmetic`.
738 sub_with_overflow,
739 /// Implements the `@mulWithOverflow` builtin. Uses `pl_node` with `OverflowArithmetic`.
740 mul_with_overflow,
741 /// Implements the `@shlWithOverflow` builtin. Uses `pl_node` with `OverflowArithmetic`.
742 shl_with_overflow,
732743
733 /// Returns whether the instruction is one of the control flow "noreturn" types.744 /// Returns whether the instruction is one of the control flow "noreturn" types.
734 /// Function calls do not count.745 /// Function calls do not count.
...@@ -865,6 +876,7 @@ pub const Inst = struct {...@@ -865,6 +876,7 @@ pub const Inst = struct {
865 .slice_sentinel,876 .slice_sentinel,
866 .import,877 .import,
867 .typeof_peer,878 .typeof_peer,
879 .log2_int_type,
868 .resolve_inferred_alloc,880 .resolve_inferred_alloc,
869 .set_eval_branch_quota,881 .set_eval_branch_quota,
870 .compile_log,882 .compile_log,
...@@ -900,6 +912,10 @@ pub const Inst = struct {...@@ -900,6 +912,10 @@ pub const Inst = struct {
900 .fence,912 .fence,
901 .ret_addr,913 .ret_addr,
902 .builtin_src,914 .builtin_src,
915 .add_with_overflow,
916 .sub_with_overflow,
917 .mul_with_overflow,
918 .shl_with_overflow,
903 => false,919 => false,
904920
905 .@"break",921 .@"break",
...@@ -1657,6 +1673,12 @@ pub const Inst = struct {...@@ -1657,6 +1673,12 @@ pub const Inst = struct {
1657 name_start: u32,1673 name_start: u32,
1658 };1674 };
16591675
1676 pub const OverflowArithmetic = struct {
1677 lhs: Ref,
1678 rhs: Ref,
1679 ptr: Ref,
1680 };
1681
1660 /// Trailing: `CompileErrors.Item` for each `items_len`.1682 /// Trailing: `CompileErrors.Item` for each `items_len`.
1661 pub const CompileErrors = struct {1683 pub const CompileErrors = struct {
1662 items_len: u32,1684 items_len: u32,
...@@ -1762,6 +1784,7 @@ const Writer = struct {...@@ -1762,6 +1784,7 @@ const Writer = struct {
1762 .type_info,1784 .type_info,
1763 .size_of,1785 .size_of,
1764 .bit_size_of,1786 .bit_size_of,
1787 .log2_int_type,
1765 => try self.writeUnNode(stream, inst),1788 => try self.writeUnNode(stream, inst),
17661789
1767 .ref,1790 .ref,
...@@ -1804,6 +1827,12 @@ const Writer = struct {...@@ -1804,6 +1827,12 @@ const Writer = struct {
1804 .field_type,1827 .field_type,
1805 => try self.writePlNode(stream, inst),1828 => try self.writePlNode(stream, inst),
18061829
1830 .add_with_overflow,
1831 .sub_with_overflow,
1832 .mul_with_overflow,
1833 .shl_with_overflow,
1834 => try self.writePlNodeOverflowArithmetic(stream, inst),
1835
1807 .add,1836 .add,
1808 .addwrap,1837 .addwrap,
1809 .array_cat,1838 .array_cat,
...@@ -2061,6 +2090,18 @@ const Writer = struct {...@@ -2061,6 +2090,18 @@ const Writer = struct {
2061 try self.writeSrc(stream, inst_data.src());2090 try self.writeSrc(stream, inst_data.src());
2062 }2091 }
20632092
2093 fn writePlNodeOverflowArithmetic(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2094 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2095 const extra = self.code.extraData(Inst.OverflowArithmetic, inst_data.payload_index).data;
2096 try self.writeInstRef(stream, extra.lhs);
2097 try stream.writeAll(", ");
2098 try self.writeInstRef(stream, extra.rhs);
2099 try stream.writeAll(", ");
2100 try self.writeInstRef(stream, extra.ptr);
2101 try stream.writeAll(") ");
2102 try self.writeSrc(stream, inst_data.src());
2103 }
2104
2064 fn writePlNodeCall(self: *Writer, stream: anytype, inst: Inst.Index) !void {2105 fn writePlNodeCall(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2065 const inst_data = self.code.instructions.items(.data)[inst].pl_node;2106 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2066 const extra = self.code.extraData(Inst.Call, inst_data.payload_index);2107 const extra = self.code.extraData(Inst.Call, inst_data.payload_index);