authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-31 23:00:00-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-31 23:00:00-07:00
logc9e31febf811286580792265efe20ccfa76c0fcf
tree23204dcead9078d0c97df6de753beec39cdbea91
parentb27d0526768a5be715eeb9381a61d335e9a05e9e

stage2: finish implementation of LazySrcLoc


5 files changed, 284 insertions(+), 56 deletions(-)

BRANCH_TODO deleted-35
...@@ -1,35 +0,0 @@
1this is my WIP branch scratch pad, to be deleted before merging into master
2
3Merge TODO list:
4 * finish implementing SrcLoc byteOffset function
5 * audit all the .unneeded src locations
6 * audit the calls in codegen toSrcLocWithDecl specifically if there is inlined function
7 calls from other files.
8
9Performance optimizations to look into:
10 * don't store end index for blocks; rely on last instruction being noreturn
11 * look into not storing the field name of field access as a string in zir
12 instructions. or, look into introducing interning to string_bytes (local
13 to the owner Decl), or, look into allowing field access based on a token/node
14 and have it reference source code bytes. Another idea: null terminated
15 string variants which avoid having to store the length.
16 - Look into this for enum literals too
17 * make ret_type and ret_ptr instructions be implied indexes; no need to have
18 tags associated with them.
19 * use a smaller encoding for the auto generated return void at the end of
20 function ZIR.
21 * enum literals can use small strings
22 * string literals can use small strings
23 * don't need the Sema coercion on condbr condition, it's done with result locations
24 * astgen for loops using pointer arithmetic because it's faster and if the programmer
25 wants an index capture, that will just be a convenience variable that zig sets up
26 independently.
27 * in astgen, if a decl_val would be to a const variable or to a function, there could be
28 a special zir.Inst.Ref form that means to refer to a decl as the operand. This
29 would elide all the decl_val instructions in the ZIR.
30 * don't have an explicit dbg_stmt zir instruction - instead merge it with
31 var decl and assignment instructions, etc.
32 - make it set sema.src where appropriate
33 * look into not emitting redundant dbg stmts to TZIR
34 * make decl references in ZIR be u32 indexes to the Decl dependencies array hash map
35 instead of duplicating *Decl entries in zir.Code.
src/AstGen.zig+2
...@@ -3476,6 +3476,8 @@ fn asmExpr(...@@ -3476,6 +3476,8 @@ fn asmExpr(
3476 const asm_source = try expr(gz, scope, .{ .ty = .const_slice_u8_type }, full.ast.template);3476 const asm_source = try expr(gz, scope, .{ .ty = .const_slice_u8_type }, full.ast.template);
34773477
3478 if (full.outputs.len != 0) {3478 if (full.outputs.len != 0) {
3479 // when implementing this be sure to add test coverage for the asm return type
3480 // not resolving into a type (the node_offset_asm_ret_ty field of LazySrcLoc)
3479 return mod.failTok(scope, full.ast.asm_token, "TODO implement asm with an output", .{});3481 return mod.failTok(scope, full.ast.asm_token, "TODO implement asm with an output", .{});
3480 }3482 }
34813483
src/Module.zig+234-21
...@@ -1525,7 +1525,6 @@ pub const SrcLoc = struct {...@@ -1525,7 +1525,6 @@ pub const SrcLoc = struct {
1525 .node_offset_for_cond,1525 .node_offset_for_cond,
1526 .node_offset_builtin_call_arg0,1526 .node_offset_builtin_call_arg0,
1527 .node_offset_builtin_call_arg1,1527 .node_offset_builtin_call_arg1,
1528 .node_offset_builtin_call_argn,
1529 .node_offset_array_access_index,1528 .node_offset_array_access_index,
1530 .node_offset_slice_sentinel,1529 .node_offset_slice_sentinel,
1531 .node_offset_call_func,1530 .node_offset_call_func,
...@@ -1620,15 +1619,129 @@ pub const SrcLoc = struct {...@@ -1620,15 +1619,129 @@ pub const SrcLoc = struct {
1620 const token_starts = tree.tokens.items(.start);1619 const token_starts = tree.tokens.items(.start);
1621 return token_starts[tok_index];1620 return token_starts[tok_index];
1622 },1621 },
1623 .node_offset_builtin_call_arg1 => @panic("TODO"),1622 .node_offset_builtin_call_arg1 => |node_off| {
1624 .node_offset_builtin_call_argn => unreachable, // Handled specially in `Sema`.1623 const decl = src_loc.container.decl;
1625 .node_offset_array_access_index => @panic("TODO"),1624 const tree = decl.container.file_scope.base.tree();
1626 .node_offset_slice_sentinel => @panic("TODO"),1625 const node_datas = tree.nodes.items(.data);
1627 .node_offset_call_func => @panic("TODO"),1626 const node_tags = tree.nodes.items(.tag);
1628 .node_offset_field_name => @panic("TODO"),1627 const node = decl.relativeToNodeIndex(node_off);
1629 .node_offset_deref_ptr => @panic("TODO"),1628 const param = switch (node_tags[node]) {
1630 .node_offset_asm_source => @panic("TODO"),1629 .builtin_call_two, .builtin_call_two_comma => node_datas[node].rhs,
1631 .node_offset_asm_ret_ty => @panic("TODO"),1630 .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + 1],
1631 else => unreachable,
1632 };
1633 const main_tokens = tree.nodes.items(.main_token);
1634 const tok_index = main_tokens[param];
1635 const token_starts = tree.tokens.items(.start);
1636 return token_starts[tok_index];
1637 },
1638 .node_offset_array_access_index => |node_off| {
1639 const decl = src_loc.container.decl;
1640 const tree = decl.container.file_scope.base.tree();
1641 const node_datas = tree.nodes.items(.data);
1642 const node_tags = tree.nodes.items(.tag);
1643 const node = decl.relativeToNodeIndex(node_off);
1644 const main_tokens = tree.nodes.items(.main_token);
1645 const tok_index = main_tokens[node_datas[node].rhs];
1646 const token_starts = tree.tokens.items(.start);
1647 return token_starts[tok_index];
1648 },
1649 .node_offset_slice_sentinel => |node_off| {
1650 const decl = src_loc.container.decl;
1651 const tree = decl.container.file_scope.base.tree();
1652 const node_datas = tree.nodes.items(.data);
1653 const node_tags = tree.nodes.items(.tag);
1654 const node = decl.relativeToNodeIndex(node_off);
1655 const full = switch (node_tags[node]) {
1656 .slice_open => tree.sliceOpen(node),
1657 .slice => tree.slice(node),
1658 .slice_sentinel => tree.sliceSentinel(node),
1659 else => unreachable,
1660 };
1661 const main_tokens = tree.nodes.items(.main_token);
1662 const tok_index = main_tokens[full.ast.sentinel];
1663 const token_starts = tree.tokens.items(.start);
1664 return token_starts[tok_index];
1665 },
1666 .node_offset_call_func => |node_off| {
1667 const decl = src_loc.container.decl;
1668 const tree = decl.container.file_scope.base.tree();
1669 const node_datas = tree.nodes.items(.data);
1670 const node_tags = tree.nodes.items(.tag);
1671 const node = decl.relativeToNodeIndex(node_off);
1672 var params: [1]ast.Node.Index = undefined;
1673 const full = switch (node_tags[node]) {
1674 .call_one,
1675 .call_one_comma,
1676 .async_call_one,
1677 .async_call_one_comma,
1678 => tree.callOne(&params, node),
1679
1680 .call,
1681 .call_comma,
1682 .async_call,
1683 .async_call_comma,
1684 => tree.callFull(node),
1685
1686 else => unreachable,
1687 };
1688 const main_tokens = tree.nodes.items(.main_token);
1689 const tok_index = main_tokens[full.ast.fn_expr];
1690 const token_starts = tree.tokens.items(.start);
1691 return token_starts[tok_index];
1692 },
1693 .node_offset_field_name => |node_off| {
1694 const decl = src_loc.container.decl;
1695 const tree = decl.container.file_scope.base.tree();
1696 const node_datas = tree.nodes.items(.data);
1697 const node_tags = tree.nodes.items(.tag);
1698 const node = decl.relativeToNodeIndex(node_off);
1699 const tok_index = node_datas[node].rhs;
1700 const token_starts = tree.tokens.items(.start);
1701 return token_starts[tok_index];
1702 },
1703 .node_offset_deref_ptr => |node_off| {
1704 const decl = src_loc.container.decl;
1705 const tree = decl.container.file_scope.base.tree();
1706 const node_datas = tree.nodes.items(.data);
1707 const node_tags = tree.nodes.items(.tag);
1708 const node = decl.relativeToNodeIndex(node_off);
1709 const tok_index = node_datas[node].lhs;
1710 const token_starts = tree.tokens.items(.start);
1711 return token_starts[tok_index];
1712 },
1713 .node_offset_asm_source => |node_off| {
1714 const decl = src_loc.container.decl;
1715 const tree = decl.container.file_scope.base.tree();
1716 const node_datas = tree.nodes.items(.data);
1717 const node_tags = tree.nodes.items(.tag);
1718 const node = decl.relativeToNodeIndex(node_off);
1719 const full = switch (node_tags[node]) {
1720 .asm_simple => tree.asmSimple(node),
1721 .@"asm" => tree.asmFull(node),
1722 else => unreachable,
1723 };
1724 const main_tokens = tree.nodes.items(.main_token);
1725 const tok_index = main_tokens[full.ast.template];
1726 const token_starts = tree.tokens.items(.start);
1727 return token_starts[tok_index];
1728 },
1729 .node_offset_asm_ret_ty => |node_off| {
1730 const decl = src_loc.container.decl;
1731 const tree = decl.container.file_scope.base.tree();
1732 const node_datas = tree.nodes.items(.data);
1733 const node_tags = tree.nodes.items(.tag);
1734 const node = decl.relativeToNodeIndex(node_off);
1735 const full = switch (node_tags[node]) {
1736 .asm_simple => tree.asmSimple(node),
1737 .@"asm" => tree.asmFull(node),
1738 else => unreachable,
1739 };
1740 const main_tokens = tree.nodes.items(.main_token);
1741 const tok_index = main_tokens[full.outputs[0]];
1742 const token_starts = tree.tokens.items(.start);
1743 return token_starts[tok_index];
1744 },
16321745
1633 .node_offset_for_cond, .node_offset_if_cond => |node_off| {1746 .node_offset_for_cond, .node_offset_if_cond => |node_off| {
1634 const decl = src_loc.container.decl;1747 const decl = src_loc.container.decl;
...@@ -1672,11 +1785,116 @@ pub const SrcLoc = struct {...@@ -1672,11 +1785,116 @@ pub const SrcLoc = struct {
1672 const token_starts = tree.tokens.items(.start);1785 const token_starts = tree.tokens.items(.start);
1673 return token_starts[tok_index];1786 return token_starts[tok_index];
1674 },1787 },
1675 .node_offset_switch_operand => @panic("TODO"),1788
1676 .node_offset_switch_special_prong => @panic("TODO"),1789 .node_offset_switch_operand => |node_off| {
1677 .node_offset_switch_range => @panic("TODO"),1790 const decl = src_loc.container.decl;
1678 .node_offset_fn_type_cc => @panic("TODO"),1791 const node = decl.relativeToNodeIndex(node_off);
1679 .node_offset_fn_type_ret_ty => @panic("TODO"),1792 const tree = decl.container.file_scope.base.tree();
1793 const node_datas = tree.nodes.items(.data);
1794 const src_node = node_datas[node].lhs;
1795 const main_tokens = tree.nodes.items(.main_token);
1796 const tok_index = main_tokens[src_node];
1797 const token_starts = tree.tokens.items(.start);
1798 return token_starts[tok_index];
1799 },
1800
1801 .node_offset_switch_special_prong => |node_off| {
1802 const decl = src_loc.container.decl;
1803 const switch_node = decl.relativeToNodeIndex(node_off);
1804 const tree = decl.container.file_scope.base.tree();
1805 const node_datas = tree.nodes.items(.data);
1806 const node_tags = tree.nodes.items(.tag);
1807 const main_tokens = tree.nodes.items(.main_token);
1808 const extra = tree.extraData(node_datas[switch_node].rhs, ast.Node.SubRange);
1809 const case_nodes = tree.extra_data[extra.start..extra.end];
1810 for (case_nodes) |case_node| {
1811 const case = switch (node_tags[case_node]) {
1812 .switch_case_one => tree.switchCaseOne(case_node),
1813 .switch_case => tree.switchCase(case_node),
1814 else => unreachable,
1815 };
1816 const is_special = (case.ast.values.len == 0) or
1817 (case.ast.values.len == 1 and
1818 node_tags[case.ast.values[0]] == .identifier and
1819 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"));
1820 if (!is_special) continue;
1821
1822 const tok_index = main_tokens[case_node];
1823 const token_starts = tree.tokens.items(.start);
1824 return token_starts[tok_index];
1825 } else unreachable;
1826 },
1827
1828 .node_offset_switch_range => |node_off| {
1829 const decl = src_loc.container.decl;
1830 const switch_node = decl.relativeToNodeIndex(node_off);
1831 const tree = decl.container.file_scope.base.tree();
1832 const node_datas = tree.nodes.items(.data);
1833 const node_tags = tree.nodes.items(.tag);
1834 const main_tokens = tree.nodes.items(.main_token);
1835 const extra = tree.extraData(node_datas[switch_node].rhs, ast.Node.SubRange);
1836 const case_nodes = tree.extra_data[extra.start..extra.end];
1837 for (case_nodes) |case_node| {
1838 const case = switch (node_tags[case_node]) {
1839 .switch_case_one => tree.switchCaseOne(case_node),
1840 .switch_case => tree.switchCase(case_node),
1841 else => unreachable,
1842 };
1843 const is_special = (case.ast.values.len == 0) or
1844 (case.ast.values.len == 1 and
1845 node_tags[case.ast.values[0]] == .identifier and
1846 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"));
1847 if (is_special) continue;
1848
1849 for (case.ast.values) |item_node| {
1850 if (node_tags[item_node] == .switch_range) {
1851 const tok_index = main_tokens[item_node];
1852 const token_starts = tree.tokens.items(.start);
1853 return token_starts[tok_index];
1854 }
1855 }
1856 } else unreachable;
1857 },
1858
1859 .node_offset_fn_type_cc => |node_off| {
1860 const decl = src_loc.container.decl;
1861 const tree = decl.container.file_scope.base.tree();
1862 const node_datas = tree.nodes.items(.data);
1863 const node_tags = tree.nodes.items(.tag);
1864 const node = decl.relativeToNodeIndex(node_off);
1865 var params: [1]ast.Node.Index = undefined;
1866 const full = switch (node_tags[node]) {
1867 .fn_proto_simple => tree.fnProtoSimple(&params, node),
1868 .fn_proto_multi => tree.fnProtoMulti(node),
1869 .fn_proto_one => tree.fnProtoOne(&params, node),
1870 .fn_proto => tree.fnProto(node),
1871 else => unreachable,
1872 };
1873 const main_tokens = tree.nodes.items(.main_token);
1874 const tok_index = main_tokens[full.ast.callconv_expr];
1875 const token_starts = tree.tokens.items(.start);
1876 return token_starts[tok_index];
1877 },
1878
1879 .node_offset_fn_type_ret_ty => |node_off| {
1880 const decl = src_loc.container.decl;
1881 const tree = decl.container.file_scope.base.tree();
1882 const node_datas = tree.nodes.items(.data);
1883 const node_tags = tree.nodes.items(.tag);
1884 const node = decl.relativeToNodeIndex(node_off);
1885 var params: [1]ast.Node.Index = undefined;
1886 const full = switch (node_tags[node]) {
1887 .fn_proto_simple => tree.fnProtoSimple(&params, node),
1888 .fn_proto_multi => tree.fnProtoMulti(node),
1889 .fn_proto_one => tree.fnProtoOne(&params, node),
1890 .fn_proto => tree.fnProto(node),
1891 else => unreachable,
1892 };
1893 const main_tokens = tree.nodes.items(.main_token);
1894 const tok_index = main_tokens[full.ast.return_type];
1895 const token_starts = tree.tokens.items(.start);
1896 return token_starts[tok_index];
1897 },
1680 }1898 }
1681 }1899 }
1682};1900};
...@@ -1739,9 +1957,6 @@ pub const LazySrcLoc = union(enum) {...@@ -1739,9 +1957,6 @@ pub const LazySrcLoc = union(enum) {
1739 node_offset_builtin_call_arg0: i32,1957 node_offset_builtin_call_arg0: i32,
1740 /// Same as `node_offset_builtin_call_arg0` except arg index 1.1958 /// Same as `node_offset_builtin_call_arg0` except arg index 1.
1741 node_offset_builtin_call_arg1: i32,1959 node_offset_builtin_call_arg1: i32,
1742 /// Same as `node_offset_builtin_call_arg0` except the arg index is contextually
1743 /// determined.
1744 node_offset_builtin_call_argn: i32,
1745 /// The source location points to the index expression of an array access1960 /// The source location points to the index expression of an array access
1746 /// expression, found by taking this AST node index offset from the containing1961 /// expression, found by taking this AST node index offset from the containing
1747 /// Decl AST node, which points to an array access AST node. Next, navigate1962 /// Decl AST node, which points to an array access AST node. Next, navigate
...@@ -1852,7 +2067,6 @@ pub const LazySrcLoc = union(enum) {...@@ -1852,7 +2067,6 @@ pub const LazySrcLoc = union(enum) {
1852 .node_offset_for_cond,2067 .node_offset_for_cond,
1853 .node_offset_builtin_call_arg0,2068 .node_offset_builtin_call_arg0,
1854 .node_offset_builtin_call_arg1,2069 .node_offset_builtin_call_arg1,
1855 .node_offset_builtin_call_argn,
1856 .node_offset_array_access_index,2070 .node_offset_array_access_index,
1857 .node_offset_slice_sentinel,2071 .node_offset_slice_sentinel,
1858 .node_offset_call_func,2072 .node_offset_call_func,
...@@ -1895,7 +2109,6 @@ pub const LazySrcLoc = union(enum) {...@@ -1895,7 +2109,6 @@ pub const LazySrcLoc = union(enum) {
1895 .node_offset_for_cond,2109 .node_offset_for_cond,
1896 .node_offset_builtin_call_arg0,2110 .node_offset_builtin_call_arg0,
1897 .node_offset_builtin_call_arg1,2111 .node_offset_builtin_call_arg1,
1898 .node_offset_builtin_call_argn,
1899 .node_offset_array_access_index,2112 .node_offset_array_access_index,
1900 .node_offset_slice_sentinel,2113 .node_offset_slice_sentinel,
1901 .node_offset_call_func,2114 .node_offset_call_func,
...@@ -2393,7 +2606,7 @@ fn astgenAndSemaFn(...@@ -2393,7 +2606,7 @@ fn astgenAndSemaFn(
2393 .src_decl = decl,2606 .src_decl = decl,
2394 .instructions = .{},2607 .instructions = .{},
2395 .inlining = null,2608 .inlining = null,
2396 .is_comptime = false,2609 .is_comptime = true,
2397 };2610 };
2398 defer block_scope.instructions.deinit(mod.gpa);2611 defer block_scope.instructions.deinit(mod.gpa);
23992612
src/Sema.zig+1
...@@ -76,6 +76,7 @@ pub fn rootAsRef(sema: *Sema, root_block: *Scope.Block) !zir.Inst.Ref {...@@ -76,6 +76,7 @@ pub fn rootAsRef(sema: *Sema, root_block: *Scope.Block) !zir.Inst.Ref {
7676
77/// Assumes that `root_block` ends with `break_inline`.77/// Assumes that `root_block` ends with `break_inline`.
78pub fn rootAsType(sema: *Sema, root_block: *Scope.Block) !Type {78pub fn rootAsType(sema: *Sema, root_block: *Scope.Block) !Type {
79 assert(root_block.is_comptime);
79 const zir_inst_ref = try sema.rootAsRef(root_block);80 const zir_inst_ref = try sema.rootAsRef(root_block);
80 // Source location is unneeded because resolveConstValue must have already81 // Source location is unneeded because resolveConstValue must have already
81 // been successfully called when coercing the value to a type, from the82 // been successfully called when coercing the value to a type, from the
test/stage2/cbe.zig+47
...@@ -39,6 +39,21 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -39,6 +39,21 @@ pub fn addCases(ctx: *TestContext) !void {
39 \\}39 \\}
40 \\fn unused() void {}40 \\fn unused() void {}
41 , "yo!" ++ std.cstr.line_sep);41 , "yo!" ++ std.cstr.line_sep);
42
43 // Comptime return type and calling convention expected.
44 case.addError(
45 \\var x: i32 = 1234;
46 \\export fn main() x {
47 \\ return 0;
48 \\}
49 \\export fn foo() callconv(y) c_int {
50 \\ return 0;
51 \\}
52 \\var y: i32 = 1234;
53 , &.{
54 ":2:18: error: unable to resolve comptime value",
55 ":5:26: error: unable to resolve comptime value",
56 });
42 }57 }
4358
44 {59 {
...@@ -375,6 +390,38 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -375,6 +390,38 @@ pub fn addCases(ctx: *TestContext) !void {
375 ":6:14: error: duplicate switch value",390 ":6:14: error: duplicate switch value",
376 ":4:9: note: previous value here",391 ":4:9: note: previous value here",
377 });392 });
393
394 // Ranges not allowed for some kinds of switches.
395 case.addError(
396 \\export fn main() c_int {
397 \\ const A: type = i32;
398 \\ const b: c_int = switch (A) {
399 \\ i32 => 1,
400 \\ bool => 2,
401 \\ f16...f64 => 3,
402 \\ else => 4,
403 \\ };
404 \\}
405 , &.{
406 ":3:30: error: ranges not allowed when switching on type 'type'",
407 ":6:12: note: range here",
408 });
409
410 // Switch expression has unreachable else prong.
411 case.addError(
412 \\export fn main() c_int {
413 \\ var a: u2 = 0;
414 \\ const b: i32 = switch (a) {
415 \\ 0 => 10,
416 \\ 1 => 20,
417 \\ 2 => 30,
418 \\ 3 => 40,
419 \\ else => 50,
420 \\ };
421 \\}
422 , &.{
423 ":8:14: error: unreachable else prong; all cases already handled",
424 });
378 }425 }
379 //{426 //{
380 // var case = ctx.exeFromCompiledC("optionals", .{});427 // var case = ctx.exeFromCompiledC("optionals", .{});