Commit d29dd5834b
Changed files (5)
src-self-hosted
src-self-hosted/astgen.zig
@@ -160,6 +160,7 @@ fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.In
}
}
var block_scope: Scope.GenZIR = .{
+ .parent = scope,
.decl = scope.decl().?,
.arena = scope.arena(),
.instructions = .{},
@@ -180,6 +181,7 @@ fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.In
.instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
});
var then_scope: Scope.GenZIR = .{
+ .parent = scope,
.decl = block_scope.decl,
.arena = block_scope.arena,
.instructions = .{},
@@ -199,6 +201,7 @@ fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.In
};
var else_scope: Scope.GenZIR = .{
+ .parent = scope,
.decl = block_scope.decl,
.arena = block_scope.arena,
.instructions = .{},
@@ -250,7 +253,11 @@ fn controlFlowExpr(
}
fn identifier(mod: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerError!*zir.Inst {
+ const tracy = trace(@src());
+ defer tracy.end();
+
const tree = scope.tree();
+ // TODO implement @"aoeu" identifiers
const ident_name = tree.tokenSlice(ident.token);
const src = tree.token_locs[ident.token].start;
if (mem.eql(u8, ident_name, "_")) {
@@ -288,23 +295,27 @@ fn identifier(mod: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerErr
}
}
- if (mod.lookupDeclName(scope, ident_name)) |decl| {
- return try mod.addZIRInst(scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{});
+ // Local variables, including function parameters.
+ {
+ var s = scope;
+ while (true) switch (s.tag) {
+ .local_var => {
+ const local_var = s.cast(Scope.LocalVar).?;
+ if (mem.eql(u8, local_var.name, ident_name)) {
+ return local_var.inst;
+ }
+ s = local_var.parent;
+ },
+ .gen_zir => s = s.cast(Scope.GenZIR).?.parent,
+ else => break,
+ };
}
- // Function parameter
- if (scope.decl()) |decl| {
- if (tree.root_node.decls()[decl.src_index].cast(ast.Node.FnProto)) |fn_proto| {
- for (fn_proto.params()) |param, i| {
- const param_name = tree.tokenSlice(param.name_token.?);
- if (mem.eql(u8, param_name, ident_name)) {
- return try mod.addZIRInst(scope, src, zir.Inst.Arg, .{ .index = i }, .{});
- }
- }
- }
+ if (mod.lookupDeclName(scope, ident_name)) |decl| {
+ return try mod.addZIRInst(scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{});
}
- return mod.failNode(scope, &ident.base, "TODO implement local variable identifier lookup", .{});
+ return mod.failNode(scope, &ident.base, "use of undeclared identifier '{}'", .{ident_name});
}
fn stringLiteral(mod: *Module, scope: *Scope, str_lit: *ast.Node.StringLiteral) InnerError!*zir.Inst {
@@ -434,7 +445,7 @@ fn callExpr(mod: *Module, scope: *Scope, node: *ast.Node.Call) InnerError!*zir.I
const lhs = try expr(mod, scope, node.lhs);
const param_nodes = node.params();
- const args = try scope.cast(Scope.GenZIR).?.arena.alloc(*zir.Inst, param_nodes.len);
+ const args = try scope.getGenZIR().arena.alloc(*zir.Inst, param_nodes.len);
for (param_nodes) |param_node, i| {
args[i] = try expr(mod, scope, param_node);
}
src-self-hosted/codegen.zig
@@ -73,6 +73,7 @@ pub fn generateSymbol(
.code = code,
.err_msg = null,
.args = mc_args,
+ .arg_index = 0,
.branch_stack = &branch_stack,
.src = src,
};
@@ -255,6 +256,7 @@ const Function = struct {
code: *std.ArrayList(u8),
err_msg: ?*ErrorMsg,
args: []MCValue,
+ arg_index: usize,
src: usize,
/// Whenever there is a runtime branch, we push a Branch onto this stack,
@@ -603,7 +605,9 @@ const Function = struct {
}
fn genArg(self: *Function, inst: *ir.Inst.Arg) !MCValue {
- return self.args[inst.args.index];
+ const i = self.arg_index;
+ self.arg_index += 1;
+ return self.args[i];
}
fn genBreakpoint(self: *Function, src: usize, comptime arch: std.Target.Cpu.Arch) !MCValue {
src-self-hosted/ir.zig
@@ -101,10 +101,7 @@ pub const Inst = struct {
pub const Arg = struct {
pub const base_tag = Tag.arg;
base: Inst,
-
- args: struct {
- index: usize,
- },
+ args: void,
};
pub const Assembly = struct {
src-self-hosted/Module.zig
@@ -700,19 +700,22 @@ pub const Scope = struct {
pub const GenZIR = struct {
pub const base_tag: Tag = .gen_zir;
base: Scope = Scope{ .tag = base_tag },
+ /// Parents can be: `GenZIR`, `ZIRModule`, `File`
+ parent: *Scope,
decl: *Decl,
arena: *Allocator,
+ /// The first N instructions in a function body ZIR are arg instructions.
instructions: std.ArrayListUnmanaged(*zir.Inst) = .{},
};
/// This structure lives as long as the AST generation of the Block
- /// node that contains the variable. This struct's parents can be
- /// other `LocalVar` and finally a `GenZIR` at the top.
+ /// node that contains the variable.
pub const LocalVar = struct {
pub const base_tag: Tag = .local_var;
base: Scope = Scope{ .tag = base_tag },
- gen_zir: *GenZIR,
+ /// Parents can be: `LocalVar`, `GenZIR`.
parent: *Scope,
+ gen_zir: *GenZIR,
name: []const u8,
inst: *zir.Inst,
};
@@ -1164,6 +1167,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
var fn_type_scope: Scope.GenZIR = .{
.decl = decl,
.arena = &fn_type_scope_arena.allocator,
+ .parent = decl.scope,
};
defer fn_type_scope.instructions.deinit(self.gpa);
@@ -1241,12 +1245,32 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
var gen_scope: Scope.GenZIR = .{
.decl = decl,
.arena = &gen_scope_arena.allocator,
+ .parent = decl.scope,
};
defer gen_scope.instructions.deinit(self.gpa);
+ // We need an instruction for each parameter, and they must be first in the body.
+ try gen_scope.instructions.resize(self.gpa, fn_proto.params_len);
+ var params_scope = &gen_scope.base;
+ for (fn_proto.params()) |param, i| {
+ const name_token = param.name_token.?;
+ const src = tree.token_locs[name_token].start;
+ const param_name = tree.tokenSlice(name_token);
+ const arg = try newZIRInst(&gen_scope_arena.allocator, src, zir.Inst.Arg, .{}, .{});
+ gen_scope.instructions.items[i] = &arg.base;
+ const sub_scope = try gen_scope_arena.allocator.create(Scope.LocalVar);
+ sub_scope.* = .{
+ .parent = params_scope,
+ .gen_zir = &gen_scope,
+ .name = param_name,
+ .inst = &arg.base,
+ };
+ params_scope = &sub_scope.base;
+ }
+
const body_block = body_node.cast(ast.Node.Block).?;
- try astgen.blockExpr(self, &gen_scope.base, body_block);
+ try astgen.blockExpr(self, params_scope, body_block);
if (!fn_type.fnReturnType().isNoReturn() and (gen_scope.instructions.items.len == 0 or
!gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn()))
@@ -2236,17 +2260,16 @@ fn analyzeInstCompileError(self: *Module, scope: *Scope, inst: *zir.Inst.Compile
fn analyzeInstArg(self: *Module, scope: *Scope, inst: *zir.Inst.Arg) InnerError!*Inst {
const b = try self.requireRuntimeBlock(scope, inst.base.src);
const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
+ const param_index = b.instructions.items.len;
const param_count = fn_ty.fnParamLen();
- if (inst.positionals.index >= param_count) {
+ if (param_index >= param_count) {
return self.fail(scope, inst.base.src, "parameter index {} outside list of length {}", .{
- inst.positionals.index,
+ param_index,
param_count,
});
}
- const param_type = fn_ty.fnParamType(inst.positionals.index);
- return self.addNewInstArgs(b, inst.base.src, param_type, Inst.Arg, .{
- .index = inst.positionals.index,
- });
+ const param_type = fn_ty.fnParamType(param_index);
+ return self.addNewInstArgs(b, inst.base.src, param_type, Inst.Arg, {});
}
fn analyzeInstBlock(self: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst {
src-self-hosted/zir.zig
@@ -34,7 +34,8 @@ pub const Inst = struct {
/// These names are used directly as the instruction names in the text format.
pub const Tag = enum {
- /// Function parameter value.
+ /// Function parameter value. These must be first in a function's main block,
+ /// in respective order with the parameters.
arg,
/// A labeled block of code, which can return a value.
block,
@@ -184,9 +185,7 @@ pub const Inst = struct {
pub const base_tag = Tag.arg;
base: Inst,
- positionals: struct {
- index: usize,
- },
+ positionals: struct {},
kw_args: struct {},
};
@@ -1384,15 +1383,17 @@ const EmitZIR = struct {
for (src_decls.items) |ir_decl| {
switch (ir_decl.analysis) {
.unreferenced => continue,
+
.complete => {},
+ .codegen_failure => {}, // We still can emit the ZIR.
+ .codegen_failure_retryable => {}, // We still can emit the ZIR.
+
.in_progress => unreachable,
.outdated => unreachable,
.sema_failure,
.sema_failure_retryable,
- .codegen_failure,
.dependency_failure,
- .codegen_failure_retryable,
=> if (self.old_module.failed_decls.get(ir_decl)) |err_msg| {
const fail_inst = try self.arena.allocator.create(Inst.CompileError);
fail_inst.* = .{
@@ -1728,7 +1729,7 @@ const EmitZIR = struct {
.src = inst.src,
.tag = Inst.Arg.base_tag,
},
- .positionals = .{ .index = old_inst.args.index },
+ .positionals = .{},
.kw_args = .{},
};
break :blk &new_inst.base;