authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-30 21:43:18-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-30 21:43:18-07:00
log077b8d3def537b9a36330c14c39bfa77b2e122bc
tree4a90916b4a0f6813c82b4fadf7a59b62b082cf41
parentdb7acd83d2fb18fc0fbd1b58e0638f2afaa595fb

stage2: introduce new ZIR instruction: arg

* AstGen: LocalVal and LocalPtr use string table indexes for their names. This is more efficient because local variable declarations do need to include the variable names so that semantic analysis can emit a compile error if a declaration is shadowed. So we take advantage of this fact by comparing string table indexes when resolving names. * The arg ZIR instructions are needed for the above reasoning, as well as to emit equivalent AIR instructions for debug info. Now that we have these arg instructions, get rid of the special `Zir.Inst.Ref` range for parameters. ZIR instructions now refer to the arg instructions for parameters. * Move identAsString and strLitAsString from Module.GenZir to AstGen where they belong.

4 files changed, 167 insertions(+), 155 deletions(-)

src/AstGen.zig+111-52
......@@ -1367,7 +1367,7 @@ pub fn structInitExprRlNone(
13671367
13681368 for (struct_init.ast.fields) |field_init, i| {
13691369 const name_token = tree.firstToken(field_init) - 2;
1370 const str_index = try gz.identAsString(name_token);
1370 const str_index = try astgen.identAsString(name_token);
13711371
13721372 fields_list[i] = .{
13731373 .field_name = str_index,
......@@ -1402,7 +1402,7 @@ pub fn structInitExprRlPtr(
14021402
14031403 for (struct_init.ast.fields) |field_init, i| {
14041404 const name_token = tree.firstToken(field_init) - 2;
1405 const str_index = try gz.identAsString(name_token);
1405 const str_index = try astgen.identAsString(name_token);
14061406 const field_ptr = try gz.addPlNode(.field_ptr, field_init, Zir.Inst.Field{
14071407 .lhs = result_ptr,
14081408 .field_name_start = str_index,
......@@ -1435,7 +1435,7 @@ pub fn structInitExprRlTy(
14351435
14361436 for (struct_init.ast.fields) |field_init, i| {
14371437 const name_token = tree.firstToken(field_init) - 2;
1438 const str_index = try gz.identAsString(name_token);
1438 const str_index = try astgen.identAsString(name_token);
14391439
14401440 const field_ty_inst = try gz.addPlNode(.field_type, field_init, Zir.Inst.FieldType{
14411441 .container_type = ty_inst,
......@@ -1832,6 +1832,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
18321832 // ZIR instructions that might be a type other than `noreturn` or `void`.
18331833 .add,
18341834 .addwrap,
1835 .arg,
18351836 .alloc,
18361837 .alloc_mut,
18371838 .alloc_comptime,
......@@ -2163,7 +2164,7 @@ fn varDecl(
21632164 const token_tags = tree.tokens.items(.tag);
21642165
21652166 const name_token = var_decl.ast.mut_token + 1;
2166 const ident_name = try astgen.identifierTokenString(name_token);
2167 const ident_name = try astgen.identAsString(name_token);
21672168
21682169 // Local variables shadowing detection, including function parameters.
21692170 {
......@@ -2171,9 +2172,9 @@ fn varDecl(
21712172 while (true) switch (s.tag) {
21722173 .local_val => {
21732174 const local_val = s.cast(Scope.LocalVal).?;
2174 if (mem.eql(u8, local_val.name, ident_name)) {
2175 if (local_val.name == ident_name) {
21752176 return astgen.failTokNotes(name_token, "redeclaration of '{s}'", .{
2176 ident_name,
2177 @ptrCast([*:0]const u8, astgen.string_bytes.items.ptr) + ident_name,
21772178 }, &[_]u32{
21782179 try astgen.errNoteTok(
21792180 local_val.token_src,
......@@ -2186,9 +2187,9 @@ fn varDecl(
21862187 },
21872188 .local_ptr => {
21882189 const local_ptr = s.cast(Scope.LocalPtr).?;
2189 if (mem.eql(u8, local_ptr.name, ident_name)) {
2190 if (local_ptr.name == ident_name) {
21902191 return astgen.failTokNotes(name_token, "redeclaration of '{s}'", .{
2191 ident_name,
2192 @ptrCast([*:0]const u8, astgen.string_bytes.items.ptr) + ident_name,
21922193 }, &[_]u32{
21932194 try astgen.errNoteTok(
21942195 local_ptr.token_src,
......@@ -2690,7 +2691,6 @@ fn fnDecl(
26902691 .decl_node_index = fn_proto.ast.proto_node,
26912692 .parent = &gz.base,
26922693 .astgen = astgen,
2693 .ref_start_index = @intCast(u32, Zir.Inst.Ref.typed_value_map.len),
26942694 };
26952695 defer decl_gz.instructions.deinit(gpa);
26962696
......@@ -2757,7 +2757,7 @@ fn fnDecl(
27572757 }
27582758
27592759 const lib_name: u32 = if (fn_proto.lib_name) |lib_name_token| blk: {
2760 const lib_name_str = try decl_gz.strLitAsString(lib_name_token);
2760 const lib_name_str = try astgen.strLitAsString(lib_name_token);
27612761 break :blk lib_name_str.index;
27622762 } else 0;
27632763
......@@ -2812,7 +2812,6 @@ fn fnDecl(
28122812 .decl_node_index = fn_proto.ast.proto_node,
28132813 .parent = &decl_gz.base,
28142814 .astgen = astgen,
2815 .ref_start_index = @intCast(u32, Zir.Inst.Ref.typed_value_map.len + param_count),
28162815 };
28172816 defer fn_gz.instructions.deinit(gpa);
28182817
......@@ -2832,21 +2831,24 @@ fn fnDecl(
28322831 const name_token = param.name_token orelse {
28332832 return astgen.failNode(param.type_expr, "missing parameter name", .{});
28342833 };
2835 const param_name = try astgen.identifierTokenString(name_token);
2834 const param_name = try astgen.identAsString(name_token);
2835 // Create an arg instruction. This is needed to emit a semantic analysis
2836 // error for shadowing decls.
2837 // TODO emit a compile error here for shadowing locals.
2838 const arg_inst = try fn_gz.addStrTok(.arg, param_name, name_token);
28362839 const sub_scope = try astgen.arena.create(Scope.LocalVal);
28372840 sub_scope.* = .{
28382841 .parent = params_scope,
28392842 .gen_zir = &fn_gz,
28402843 .name = param_name,
2841 // Implicit const list first, then implicit arg list.
2842 .inst = @intToEnum(Zir.Inst.Ref, @intCast(u32, Zir.Inst.Ref.typed_value_map.len + i)),
2844 .inst = arg_inst,
28432845 .token_src = name_token,
28442846 };
28452847 params_scope = &sub_scope.base;
28462848
28472849 // Additionally put the param name into `string_bytes` and reference it with
28482850 // `extra` so that we have access to the data in codegen, for debug info.
2849 const str_index = try fn_gz.identAsString(name_token);
2851 const str_index = try astgen.identAsString(name_token);
28502852 astgen.extra.appendAssumeCapacity(str_index);
28512853 }
28522854
......@@ -2880,7 +2882,7 @@ fn fnDecl(
28802882 const fn_name_token = fn_proto.name_token orelse {
28812883 return astgen.failTok(fn_proto.ast.fn_token, "missing function name", .{});
28822884 };
2883 const fn_name_str_index = try decl_gz.identAsString(fn_name_token);
2885 const fn_name_str_index = try astgen.identAsString(fn_name_token);
28842886
28852887 // We add this at the end so that its instruction index marks the end range
28862888 // of the top level declaration.
......@@ -2953,7 +2955,7 @@ fn globalVarDecl(
29532955 } else false;
29542956
29552957 const lib_name: u32 = if (var_decl.lib_name) |lib_name_token| blk: {
2956 const lib_name_str = try gz.strLitAsString(lib_name_token);
2958 const lib_name_str = try astgen.strLitAsString(lib_name_token);
29572959 break :blk lib_name_str.index;
29582960 } else 0;
29592961
......@@ -3020,7 +3022,7 @@ fn globalVarDecl(
30203022 try block_scope.setBlockBody(block_inst);
30213023
30223024 const name_token = var_decl.ast.mut_token + 1;
3023 const name_str_index = try gz.identAsString(name_token);
3025 const name_str_index = try astgen.identAsString(name_token);
30243026
30253027 try wip_decls.payload.ensureUnusedCapacity(gpa, 8);
30263028 {
......@@ -3156,7 +3158,7 @@ fn testDecl(
31563158 const test_token = main_tokens[node];
31573159 const str_lit_token = test_token + 1;
31583160 if (token_tags[str_lit_token] == .string_literal) {
3159 break :blk (try decl_block.strLitAsString(str_lit_token)).index;
3161 break :blk (try astgen.strLitAsString(str_lit_token)).index;
31603162 }
31613163 // String table index 1 has a special meaning here of test decl with no name.
31623164 break :blk 1;
......@@ -3344,7 +3346,7 @@ fn structDeclInner(
33443346 }
33453347 try fields_data.ensureUnusedCapacity(gpa, 4);
33463348
3347 const field_name = try gz.identAsString(member.ast.name_token);
3349 const field_name = try astgen.identAsString(member.ast.name_token);
33483350 fields_data.appendAssumeCapacity(field_name);
33493351
33503352 const field_type: Zir.Inst.Ref = if (node_tags[member.ast.type_expr] == .@"anytype")
......@@ -3558,7 +3560,7 @@ fn unionDeclInner(
35583560 }
35593561 try fields_data.ensureUnusedCapacity(gpa, 4);
35603562
3561 const field_name = try gz.identAsString(member.ast.name_token);
3563 const field_name = try astgen.identAsString(member.ast.name_token);
35623564 fields_data.appendAssumeCapacity(field_name);
35633565
35643566 const have_type = member.ast.type_expr != 0;
......@@ -3906,7 +3908,7 @@ fn containerDecl(
39063908 assert(member.ast.type_expr == 0);
39073909 assert(member.ast.align_expr == 0);
39083910
3909 const field_name = try gz.identAsString(member.ast.name_token);
3911 const field_name = try astgen.identAsString(member.ast.name_token);
39103912 fields_data.appendAssumeCapacity(field_name);
39113913
39123914 const have_value = member.ast.value_expr != 0;
......@@ -4115,7 +4117,7 @@ fn errorSetDecl(
41154117 switch (token_tags[tok_i]) {
41164118 .doc_comment, .comma => {},
41174119 .identifier => {
4118 const str_index = try gz.identAsString(tok_i);
4120 const str_index = try astgen.identAsString(tok_i);
41194121 try field_names.append(gpa, str_index);
41204122 field_i += 1;
41214123 },
......@@ -4255,7 +4257,7 @@ fn orelseCatchExpr(
42554257 if (mem.eql(u8, tree.tokenSlice(payload), "_")) {
42564258 return astgen.failTok(payload, "discard of error capture; omit it instead", .{});
42574259 }
4258 const err_name = try astgen.identifierTokenString(payload);
4260 const err_name = try astgen.identAsString(payload);
42594261 err_val_scope = .{
42604262 .parent = &then_scope.base,
42614263 .gen_zir = &then_scope,
......@@ -4386,7 +4388,7 @@ pub fn fieldAccess(
43864388 const object_node = node_datas[node].lhs;
43874389 const dot_token = main_tokens[node];
43884390 const field_ident = dot_token + 1;
4389 const str_index = try gz.identAsString(field_ident);
4391 const str_index = try astgen.identAsString(field_ident);
43904392 switch (rl) {
43914393 .ref => return gz.addPlNode(.field_ptr, node, Zir.Inst.Field{
43924394 .lhs = try expr(gz, scope, .ref, object_node),
......@@ -4449,7 +4451,8 @@ fn simpleStrTok(
44494451 node: ast.Node.Index,
44504452 op_inst_tag: Zir.Inst.Tag,
44514453) InnerError!Zir.Inst.Ref {
4452 const str_index = try gz.identAsString(ident_token);
4454 const astgen = gz.astgen;
4455 const str_index = try astgen.identAsString(ident_token);
44534456 const result = try gz.addStrTok(op_inst_tag, str_index, ident_token);
44544457 return rvalue(gz, scope, rl, result, node);
44554458}
......@@ -4545,7 +4548,7 @@ fn ifExpr(
45454548 else
45464549 .err_union_payload_unsafe;
45474550 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node);
4548 const ident_name = try astgen.identifierTokenString(error_token);
4551 const ident_name = try astgen.identAsString(error_token);
45494552 payload_val_scope = .{
45504553 .parent = &then_scope.base,
45514554 .gen_zir = &then_scope,
......@@ -4561,7 +4564,7 @@ fn ifExpr(
45614564 else
45624565 .optional_payload_unsafe;
45634566 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node);
4564 const ident_name = try astgen.identifierTokenString(ident_token);
4567 const ident_name = try astgen.identAsString(ident_token);
45654568 payload_val_scope = .{
45664569 .parent = &then_scope.base,
45674570 .gen_zir = &then_scope,
......@@ -4597,7 +4600,7 @@ fn ifExpr(
45974600 else
45984601 .err_union_code;
45994602 const payload_inst = try else_scope.addUnNode(tag, cond.inst, node);
4600 const ident_name = try astgen.identifierTokenString(error_token);
4603 const ident_name = try astgen.identAsString(error_token);
46014604 payload_val_scope = .{
46024605 .parent = &else_scope.base,
46034606 .gen_zir = &else_scope,
......@@ -4804,7 +4807,7 @@ fn whileExpr(
48044807 else
48054808 .err_union_payload_unsafe;
48064809 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node);
4807 const ident_name = try astgen.identifierTokenString(error_token);
4810 const ident_name = try astgen.identAsString(error_token);
48084811 payload_val_scope = .{
48094812 .parent = &then_scope.base,
48104813 .gen_zir = &then_scope,
......@@ -4820,7 +4823,7 @@ fn whileExpr(
48204823 else
48214824 .optional_payload_unsafe;
48224825 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node);
4823 const ident_name = try astgen.identifierTokenString(ident_token);
4826 const ident_name = try astgen.identAsString(ident_token);
48244827 payload_val_scope = .{
48254828 .parent = &then_scope.base,
48264829 .gen_zir = &then_scope,
......@@ -4853,7 +4856,7 @@ fn whileExpr(
48534856 else
48544857 .err_union_code;
48554858 const payload_inst = try else_scope.addUnNode(tag, cond.inst, node);
4856 const ident_name = try astgen.identifierTokenString(error_token);
4859 const ident_name = try astgen.identAsString(error_token);
48574860 payload_val_scope = .{
48584861 .parent = &else_scope.base,
48594862 .gen_zir = &else_scope,
......@@ -4988,12 +4991,13 @@ fn forExpr(
49884991 const value_name = tree.tokenSlice(ident);
49894992 var payload_sub_scope: *Scope = undefined;
49904993 if (!mem.eql(u8, value_name, "_")) {
4994 const name_str_index = try astgen.identAsString(ident);
49914995 const tag: Zir.Inst.Tag = if (is_ptr) .elem_ptr else .elem_val;
49924996 const payload_inst = try then_scope.addBin(tag, array_ptr, index);
49934997 payload_val_scope = .{
49944998 .parent = &then_scope.base,
49954999 .gen_zir = &then_scope,
4996 .name = value_name,
5000 .name = name_str_index,
49975001 .inst = payload_inst,
49985002 .token_src = ident,
49995003 };
......@@ -5011,7 +5015,7 @@ fn forExpr(
50115015 if (mem.eql(u8, tree.tokenSlice(index_token), "_")) {
50125016 return astgen.failTok(index_token, "discard of index capture; omit it instead", .{});
50135017 }
5014 const index_name = try astgen.identifierTokenString(index_token);
5018 const index_name = try astgen.identAsString(index_token);
50155019 index_scope = .{
50165020 .parent = payload_sub_scope,
50175021 .gen_zir = &then_scope,
......@@ -5364,7 +5368,7 @@ fn switchExpr(
53645368 .prong_index = undefined,
53655369 } },
53665370 });
5367 const capture_name = try astgen.identifierTokenString(payload_token);
5371 const capture_name = try astgen.identAsString(payload_token);
53685372 capture_val_scope = .{
53695373 .parent = &case_scope.base,
53705374 .gen_zir = &case_scope,
......@@ -5456,7 +5460,7 @@ fn switchExpr(
54565460 .prong_index = capture_index,
54575461 } },
54585462 });
5459 const capture_name = try astgen.identifierTokenString(ident);
5463 const capture_name = try astgen.identAsString(ident);
54605464 capture_val_scope = .{
54615465 .parent = &case_scope.base,
54625466 .gen_zir = &case_scope,
......@@ -5810,7 +5814,7 @@ fn identifier(
58105814 const ident_token = main_tokens[ident];
58115815 const ident_name = try astgen.identifierTokenString(ident_token);
58125816 if (mem.eql(u8, ident_name, "_")) {
5813 return astgen.failNode(ident, "TODO implement '_' identifier", .{});
5817 return astgen.failNode(ident, "'_' may not be used as an identifier", .{});
58145818 }
58155819
58165820 if (simple_types.get(ident_name)) |zir_const_ref| {
......@@ -5845,19 +5849,20 @@ fn identifier(
58455849 }
58465850
58475851 // Local variables, including function parameters.
5852 const name_str_index = try astgen.identAsString(ident_token);
58485853 {
58495854 var s = scope;
58505855 while (true) switch (s.tag) {
58515856 .local_val => {
58525857 const local_val = s.cast(Scope.LocalVal).?;
5853 if (mem.eql(u8, local_val.name, ident_name)) {
5858 if (local_val.name == name_str_index) {
58545859 return rvalue(gz, scope, rl, local_val.inst, ident);
58555860 }
58565861 s = local_val.parent;
58575862 },
58585863 .local_ptr => {
58595864 const local_ptr = s.cast(Scope.LocalPtr).?;
5860 if (mem.eql(u8, local_ptr.name, ident_name)) {
5865 if (local_ptr.name == name_str_index) {
58615866 switch (rl) {
58625867 .ref, .none_or_ref => return local_ptr.ptr,
58635868 else => {
......@@ -5876,11 +5881,10 @@ fn identifier(
58765881 // We can't look up Decls until Sema because the same ZIR code is supposed to be
58775882 // used for multiple generic instantiations, and this may refer to a different Decl
58785883 // depending on the scope, determined by the generic instantiation.
5879 const str_index = try gz.identAsString(ident_token);
58805884 switch (rl) {
5881 .ref, .none_or_ref => return gz.addStrTok(.decl_ref, str_index, ident_token),
5885 .ref, .none_or_ref => return gz.addStrTok(.decl_ref, name_str_index, ident_token),
58825886 else => {
5883 const result = try gz.addStrTok(.decl_val, str_index, ident_token);
5887 const result = try gz.addStrTok(.decl_val, name_str_index, ident_token);
58845888 return rvalue(gz, scope, rl, result, ident);
58855889 },
58865890 }
......@@ -5892,10 +5896,11 @@ fn stringLiteral(
58925896 rl: ResultLoc,
58935897 node: ast.Node.Index,
58945898) InnerError!Zir.Inst.Ref {
5895 const tree = gz.astgen.file.tree;
5899 const astgen = gz.astgen;
5900 const tree = astgen.file.tree;
58965901 const main_tokens = tree.nodes.items(.main_token);
58975902 const str_lit_token = main_tokens[node];
5898 const str = try gz.strLitAsString(str_lit_token);
5903 const str = try astgen.strLitAsString(str_lit_token);
58995904 const result = try gz.add(.{
59005905 .tag = .str,
59015906 .data = .{ .str = .{
......@@ -6097,9 +6102,9 @@ fn asmExpr(
60976102
60986103 for (full.outputs) |output_node, i| {
60996104 const symbolic_name = main_tokens[output_node];
6100 const name = try gz.identAsString(symbolic_name);
6105 const name = try astgen.identAsString(symbolic_name);
61016106 const constraint_token = symbolic_name + 2;
6102 const constraint = (try gz.strLitAsString(constraint_token)).index;
6107 const constraint = (try astgen.strLitAsString(constraint_token)).index;
61036108 const has_arrow = token_tags[symbolic_name + 4] == .arrow;
61046109 if (has_arrow) {
61056110 output_type_bits |= @as(u32, 1) << @intCast(u5, i);
......@@ -6112,7 +6117,7 @@ fn asmExpr(
61126117 };
61136118 } else {
61146119 const ident_token = symbolic_name + 4;
6115 const str_index = try gz.identAsString(ident_token);
6120 const str_index = try astgen.identAsString(ident_token);
61166121 // TODO this needs extra code for local variables. Have a look at #215 and related
61176122 // issues and decide how to handle outputs. Do we want this to be identifiers?
61186123 // Or maybe we want to force this to be expressions with a pointer type.
......@@ -6134,9 +6139,9 @@ fn asmExpr(
61346139
61356140 for (full.inputs) |input_node, i| {
61366141 const symbolic_name = main_tokens[input_node];
6137 const name = try gz.identAsString(symbolic_name);
6142 const name = try astgen.identAsString(symbolic_name);
61386143 const constraint_token = symbolic_name + 2;
6139 const constraint = (try gz.strLitAsString(constraint_token)).index;
6144 const constraint = (try astgen.strLitAsString(constraint_token)).index;
61406145 const has_arrow = token_tags[symbolic_name + 4] == .arrow;
61416146 const operand = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[input_node].lhs);
61426147 inputs[i] = .{
......@@ -6156,7 +6161,7 @@ fn asmExpr(
61566161 if (clobber_i >= clobbers_buffer.len) {
61576162 return astgen.failTok(tok_i, "too many asm clobbers", .{});
61586163 }
6159 clobbers_buffer[clobber_i] = (try gz.strLitAsString(tok_i)).index;
6164 clobbers_buffer[clobber_i] = (try astgen.strLitAsString(tok_i)).index;
61606165 clobber_i += 1;
61616166 tok_i += 1;
61626167 switch (token_tags[tok_i]) {
......@@ -6409,7 +6414,7 @@ fn builtinCall(
64096414 return astgen.failNode(operand_node, "@import operand must be a string literal", .{});
64106415 }
64116416 const str_lit_token = main_tokens[operand_node];
6412 const str = try gz.strLitAsString(str_lit_token);
6417 const str = try astgen.strLitAsString(str_lit_token);
64136418 try astgen.imports.put(astgen.gpa, str.index, {});
64146419 const result = try gz.addStrTok(.import, str.index, str_lit_token);
64156420 return rvalue(gz, scope, rl, result, node);
......@@ -6451,7 +6456,7 @@ fn builtinCall(
64516456 return astgen.failNode(params[0], "the first @export parameter must be an identifier", .{});
64526457 }
64536458 const ident_token = main_tokens[params[0]];
6454 const decl_name = try gz.identAsString(ident_token);
6459 const decl_name = try astgen.identAsString(ident_token);
64556460 // TODO look for local variables in scope matching `decl_name` and emit a compile
64566461 // error. Only top-level declarations can be exported. Until this is done, the
64576462 // compile error will end up being "use of undeclared identifier" in Sema.
......@@ -7698,3 +7703,57 @@ pub fn errNoteNode(
76987703 .notes = 0,
76997704 });
77007705}
7706
7707fn identAsString(astgen: *AstGen, ident_token: ast.TokenIndex) !u32 {
7708 const gpa = astgen.gpa;
7709 const string_bytes = &astgen.string_bytes;
7710 const str_index = @intCast(u32, string_bytes.items.len);
7711 try astgen.appendIdentStr(ident_token, string_bytes);
7712 const key = string_bytes.items[str_index..];
7713 const gop = try astgen.string_table.getOrPut(gpa, key);
7714 if (gop.found_existing) {
7715 string_bytes.shrinkRetainingCapacity(str_index);
7716 return gop.entry.value;
7717 } else {
7718 // We have to dupe the key into the arena, otherwise the memory
7719 // becomes invalidated when string_bytes gets data appended.
7720 // TODO https://github.com/ziglang/zig/issues/8528
7721 gop.entry.key = try astgen.arena.dupe(u8, key);
7722 gop.entry.value = str_index;
7723 try string_bytes.append(gpa, 0);
7724 return str_index;
7725 }
7726}
7727
7728const IndexSlice = struct { index: u32, len: u32 };
7729
7730fn strLitAsString(astgen: *AstGen, str_lit_token: ast.TokenIndex) !IndexSlice {
7731 const gpa = astgen.gpa;
7732 const string_bytes = &astgen.string_bytes;
7733 const str_index = @intCast(u32, string_bytes.items.len);
7734 const token_bytes = astgen.file.tree.tokenSlice(str_lit_token);
7735 try astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0);
7736 const key = string_bytes.items[str_index..];
7737 const gop = try astgen.string_table.getOrPut(gpa, key);
7738 if (gop.found_existing) {
7739 string_bytes.shrinkRetainingCapacity(str_index);
7740 return IndexSlice{
7741 .index = gop.entry.value,
7742 .len = @intCast(u32, key.len),
7743 };
7744 } else {
7745 // We have to dupe the key into the arena, otherwise the memory
7746 // becomes invalidated when string_bytes gets data appended.
7747 // TODO https://github.com/ziglang/zig/issues/8528
7748 gop.entry.key = try astgen.arena.dupe(u8, key);
7749 gop.entry.value = str_index;
7750 // Still need a null byte because we are using the same table
7751 // to lookup null terminated strings, so if we get a match, it has to
7752 // be null terminated for that to work.
7753 try string_bytes.append(gpa, 0);
7754 return IndexSlice{
7755 .index = str_index,
7756 .len = @intCast(u32, key.len),
7757 };
7758 }
7759}
src/Module.zig+18-73
......@@ -1356,62 +1356,6 @@ pub const Scope = struct {
13561356 }
13571357 }
13581358
1359 pub fn identAsString(gz: *GenZir, ident_token: ast.TokenIndex) !u32 {
1360 const astgen = gz.astgen;
1361 const gpa = astgen.gpa;
1362 const string_bytes = &astgen.string_bytes;
1363 const str_index = @intCast(u32, string_bytes.items.len);
1364 try astgen.appendIdentStr(ident_token, string_bytes);
1365 const key = string_bytes.items[str_index..];
1366 const gop = try astgen.string_table.getOrPut(gpa, key);
1367 if (gop.found_existing) {
1368 string_bytes.shrinkRetainingCapacity(str_index);
1369 return gop.entry.value;
1370 } else {
1371 // We have to dupe the key into the arena, otherwise the memory
1372 // becomes invalidated when string_bytes gets data appended.
1373 // TODO https://github.com/ziglang/zig/issues/8528
1374 gop.entry.key = try astgen.arena.dupe(u8, key);
1375 gop.entry.value = str_index;
1376 try string_bytes.append(gpa, 0);
1377 return str_index;
1378 }
1379 }
1380
1381 pub const IndexSlice = struct { index: u32, len: u32 };
1382
1383 pub fn strLitAsString(gz: *GenZir, str_lit_token: ast.TokenIndex) !IndexSlice {
1384 const astgen = gz.astgen;
1385 const gpa = astgen.gpa;
1386 const string_bytes = &astgen.string_bytes;
1387 const str_index = @intCast(u32, string_bytes.items.len);
1388 const token_bytes = astgen.file.tree.tokenSlice(str_lit_token);
1389 try astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0);
1390 const key = string_bytes.items[str_index..];
1391 const gop = try astgen.string_table.getOrPut(gpa, key);
1392 if (gop.found_existing) {
1393 string_bytes.shrinkRetainingCapacity(str_index);
1394 return IndexSlice{
1395 .index = gop.entry.value,
1396 .len = @intCast(u32, key.len),
1397 };
1398 } else {
1399 // We have to dupe the key into the arena, otherwise the memory
1400 // becomes invalidated when string_bytes gets data appended.
1401 // TODO https://github.com/ziglang/zig/issues/8528
1402 gop.entry.key = try astgen.arena.dupe(u8, key);
1403 gop.entry.value = str_index;
1404 // Still need a null byte because we are using the same table
1405 // to lookup null terminated strings, so if we get a match, it has to
1406 // be null terminated for that to work.
1407 try string_bytes.append(gpa, 0);
1408 return IndexSlice{
1409 .index = str_index,
1410 .len = @intCast(u32, key.len),
1411 };
1412 }
1413 }
1414
14151359 pub fn addFunc(gz: *GenZir, args: struct {
14161360 src_node: ast.Node.Index,
14171361 param_types: []const Zir.Inst.Ref,
......@@ -2053,10 +1997,11 @@ pub const Scope = struct {
20531997 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`.
20541998 parent: *Scope,
20551999 gen_zir: *GenZir,
2056 name: []const u8,
20572000 inst: Zir.Inst.Ref,
20582001 /// Source location of the corresponding variable declaration.
20592002 token_src: ast.TokenIndex,
2003 /// String table index.
2004 name: u32,
20602005 };
20612006
20622007 /// This could be a `const` or `var` local. It has a pointer instead of a value.
......@@ -2068,10 +2013,11 @@ pub const Scope = struct {
20682013 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`.
20692014 parent: *Scope,
20702015 gen_zir: *GenZir,
2071 name: []const u8,
20722016 ptr: Zir.Inst.Ref,
20732017 /// Source location of the corresponding variable declaration.
20742018 token_src: ast.TokenIndex,
2019 /// String table index.
2020 name: u32,
20752021 };
20762022
20772023 pub const Defer = struct {
......@@ -4026,27 +3972,26 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !void {
40263972 const param_inst_list = try mod.gpa.alloc(*ir.Inst, fn_ty.fnParamLen());
40273973 defer mod.gpa.free(param_inst_list);
40283974
3975 for (param_inst_list) |*param_inst, param_index| {
3976 const param_type = fn_ty.fnParamType(param_index);
3977 const arg_inst = try arena.allocator.create(ir.Inst.Arg);
3978 arg_inst.* = .{
3979 .base = .{
3980 .tag = .arg,
3981 .ty = param_type,
3982 .src = .unneeded,
3983 },
3984 .name = undefined, // Set in the semantic analysis of the arg instruction.
3985 };
3986 param_inst.* = &arg_inst.base;
3987 }
3988
40293989 var f = false;
40303990 if (f) {
40313991 return error.AnalysisFail;
40323992 }
40333993 @panic("TODO reimplement analyzeFnBody now that ZIR is whole-file");
40343994
4035 //for (param_inst_list) |*param_inst, param_index| {
4036 // const param_type = fn_ty.fnParamType(param_index);
4037 // const name = func.zir.nullTerminatedString(func.zir.extra[param_index]);
4038 // const arg_inst = try arena.allocator.create(ir.Inst.Arg);
4039 // arg_inst.* = .{
4040 // .base = .{
4041 // .tag = .arg,
4042 // .ty = param_type,
4043 // .src = .unneeded,
4044 // },
4045 // .name = name,
4046 // };
4047 // param_inst.* = &arg_inst.base;
4048 //}
4049
40503995 //var sema: Sema = .{
40513996 // .mod = mod,
40523997 // .gpa = mod.gpa,
src/Sema.zig+26-11
......@@ -40,6 +40,7 @@ branch_count: u32 = 0,
4040/// access to the source location set by the previous instruction which did
4141/// contain a mapped source location.
4242src: LazySrcLoc = .{ .token_offset = 0 },
43next_arg_index: usize = 0,
4344
4445const std = @import("std");
4546const mem = std.mem;
......@@ -110,6 +111,7 @@ pub fn analyzeBody(
110111 const inst = body[i];
111112 map[inst] = switch (tags[inst]) {
112113 // zig fmt: off
114 .arg => try sema.zirArg(block, inst),
113115 .alloc => try sema.zirAlloc(block, inst),
114116 .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),
115117 .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),
......@@ -521,12 +523,6 @@ pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) error{OutOfMemory}!*ir.In
521523 }
522524 i -= Zir.Inst.Ref.typed_value_map.len;
523525
524 // Next section of indexes correspond to function parameters, if any.
525 if (i < sema.param_inst_list.len) {
526 return sema.param_inst_list[i];
527 }
528 i -= sema.param_inst_list.len;
529
530526 // Finally, the last section of indexes refers to the map of ZIR=>AIR.
531527 return sema.inst_map[i];
532528}
......@@ -1110,6 +1106,25 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) In
11101106 return sema.analyzeLoad(block, src, result_ptr, result_ptr.src);
11111107}
11121108
1109fn zirArg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
1110 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
1111 const src = inst_data.src();
1112 const arg_name = inst_data.get(sema.code);
1113 const arg_index = sema.next_arg_index;
1114 sema.next_arg_index += 1;
1115
1116 // TODO check if arg_name shadows a Decl
1117
1118 if (block.inlining) |inlining| {
1119 return sema.param_inst_list[arg_index];
1120 }
1121
1122 // Need to set the name of the Air.Arg instruction.
1123 const air_arg = sema.param_inst_list[arg_index].castTag(.arg).?;
1124 air_arg.name = arg_name;
1125 return &air_arg.base;
1126}
1127
11131128fn zirAllocExtended(
11141129 sema: *Sema,
11151130 block: *Scope.Block,
......@@ -2038,15 +2053,13 @@ fn analyzeCall(
20382053 .block_inst = block_inst,
20392054 },
20402055 };
2041 if (true) {
2042 @panic("TODO reimplement inline fn call after whole-file astgen");
2043 }
2056 const callee_zir = module_fn.owner_decl.namespace.file_scope.zir;
20442057 var inline_sema: Sema = .{
20452058 .mod = sema.mod,
20462059 .gpa = sema.mod.gpa,
20472060 .arena = sema.arena,
2048 .code = module_fn.zir,
2049 .inst_map = try sema.gpa.alloc(*ir.Inst, module_fn.zir.instructions.len),
2061 .code = callee_zir,
2062 .inst_map = try sema.gpa.alloc(*ir.Inst, callee_zir.instructions.len),
20502063 .owner_decl = sema.owner_decl,
20512064 .namespace = sema.owner_decl.namespace,
20522065 .owner_func = sema.owner_func,
......@@ -2075,6 +2088,8 @@ fn analyzeCall(
20752088
20762089 try inline_sema.emitBackwardBranch(&child_block, call_src);
20772090
2091 if (true) @panic("TODO re-implement inline function calls");
2092
20782093 // This will have return instructions analyzed as break instructions to
20792094 // the block_inst above.
20802095 _ = try inline_sema.root(&child_block);
src/Zir.zig+12-19
......@@ -124,7 +124,6 @@ pub fn renderAsTextToFile(
124124 .code = scope_file.zir,
125125 .indent = 0,
126126 .parent_decl_node = 0,
127 .param_count = 0,
128127 };
129128
130129 const main_struct_inst = scope_file.zir.extra[@enumToInt(ExtraIndex.main_struct)] -
......@@ -159,6 +158,11 @@ pub const Inst = struct {
159158 /// Twos complement wrapping integer addition.
160159 /// Uses the `pl_node` union field. Payload is `Bin`.
161160 addwrap,
161 /// Declares a parameter of the current function. Used for debug info and
162 /// for checking shadowing against declarations in the current namespace.
163 /// Uses the `str_tok` field. Token is the parameter name, string is the
164 /// parameter name.
165 arg,
162166 /// Array concatenation. `a ++ b`
163167 /// Uses the `pl_node` union field. Payload is `Bin`.
164168 array_cat,
......@@ -956,6 +960,7 @@ pub const Inst = struct {
956960 /// Function calls do not count.
957961 pub fn isNoReturn(tag: Tag) bool {
958962 return switch (tag) {
963 .arg,
959964 .add,
960965 .addwrap,
961966 .alloc,
......@@ -1220,6 +1225,7 @@ pub const Inst = struct {
12201225 break :list std.enums.directEnumArray(Tag, Data.FieldEnum, 0, .{
12211226 .add = .pl_node,
12221227 .addwrap = .pl_node,
1228 .arg = .str_tok,
12231229 .array_cat = .pl_node,
12241230 .array_mul = .pl_node,
12251231 .array_type = .bin,
......@@ -1587,20 +1593,15 @@ pub const Inst = struct {
15871593 /// The position of a ZIR instruction within the `Zir` instructions array.
15881594 pub const Index = u32;
15891595
1590 /// A reference to a TypedValue, parameter of the current function,
1591 /// or ZIR instruction.
1596 /// A reference to a TypedValue or ZIR instruction.
15921597 ///
15931598 /// If the Ref has a tag in this enum, it refers to a TypedValue which may be
15941599 /// retrieved with Ref.toTypedValue().
15951600 ///
1596 /// If the value of a Ref does not have a tag, it referes to either a parameter
1597 /// of the current function or a ZIR instruction.
1601 /// If the value of a Ref does not have a tag, it refers to a ZIR instruction.
15981602 ///
1599 /// The first values after the the last tag refer to parameters which may be
1600 /// derived by subtracting typed_value_map.len.
1601 ///
1602 /// All further values refer to ZIR instructions which may be derived by
1603 /// subtracting typed_value_map.len and the number of parameters.
1603 /// The first values after the the last tag refer to ZIR instructions which may
1604 /// be derived by subtracting `typed_value_map.len`.
16041605 ///
16051606 /// When adding a tag to this enum, consider adding a corresponding entry to
16061607 /// `simple_types` in astgen.
......@@ -2697,7 +2698,6 @@ const Writer = struct {
26972698 code: Zir,
26982699 indent: u32,
26992700 parent_decl_node: u32,
2700 param_count: usize,
27012701
27022702 fn relativeToNodeIndex(self: *Writer, offset: i32) ast.Node.Index {
27032703 return @bitCast(ast.Node.Index, offset + @bitCast(i32, self.parent_decl_node));
......@@ -2991,6 +2991,7 @@ const Writer = struct {
29912991 .decl_ref,
29922992 .decl_val,
29932993 .import,
2994 .arg,
29942995 => try self.writeStrTok(stream, inst),
29952996
29962997 .func => try self.writeFunc(stream, inst, false),
......@@ -4128,10 +4129,7 @@ const Writer = struct {
41284129 } else {
41294130 try stream.writeAll(", {\n");
41304131 self.indent += 2;
4131 const prev_param_count = self.param_count;
4132 self.param_count = param_types.len;
41334132 try self.writeBody(stream, body);
4134 self.param_count = prev_param_count;
41354133 self.indent -= 2;
41364134 try stream.writeByteNTimes(' ', self.indent);
41374135 try stream.writeAll("}) ");
......@@ -4153,11 +4151,6 @@ const Writer = struct {
41534151 }
41544152 i -= Inst.Ref.typed_value_map.len;
41554153
4156 if (i < self.param_count) {
4157 return stream.print("${d}", .{i});
4158 }
4159 i -= self.param_count;
4160
41614154 return self.writeInstIndex(stream, @intCast(Inst.Index, i));
41624155 }
41634156