| author | |
| committer | |
| log | d29dd5834b9d7386bb88e44bd2852428863cae81 |
| tree | 6a1f15d341c00be937ef9308ec750b35c308a5c0 |
| parent | af12596e8d728423e361e4755a6078c5ef8faf69 |
These are now supported enough that this example code hits the
limitations of the register allocator:
fn add(a: u32, b: u32) void {
const c = a + b; // 7
const d = a + c; // 10
const e = d + b; // 14
assert(e == 14);
}
// error: TODO implement copyToNewRegister
So now the next step is to implement register allocation as planned.5 files changed, 72 insertions(+), 36 deletions(-)
src-self-hosted/Module.zig+33-10| ... | @@ -700,19 +700,22 @@ pub const Scope = struct { | ... | @@ -700,19 +700,22 @@ pub const Scope = struct { |
| 700 | pub const GenZIR = struct { | 700 | pub const GenZIR = struct { |
| 701 | pub const base_tag: Tag = .gen_zir; | 701 | pub const base_tag: Tag = .gen_zir; |
| 702 | base: Scope = Scope{ .tag = base_tag }, | 702 | base: Scope = Scope{ .tag = base_tag }, |
| 703 | /// Parents can be: `GenZIR`, `ZIRModule`, `File` | ||
| 704 | parent: *Scope, | ||
| 703 | decl: *Decl, | 705 | decl: *Decl, |
| 704 | arena: *Allocator, | 706 | arena: *Allocator, |
| 707 | /// The first N instructions in a function body ZIR are arg instructions. | ||
| 705 | instructions: std.ArrayListUnmanaged(*zir.Inst) = .{}, | 708 | instructions: std.ArrayListUnmanaged(*zir.Inst) = .{}, |
| 706 | }; | 709 | }; |
| 707 | 710 | ||
| 708 | /// This structure lives as long as the AST generation of the Block | 711 | /// This structure lives as long as the AST generation of the Block |
| 709 | /// node that contains the variable. This struct's parents can be | 712 | /// node that contains the variable. |
| 710 | /// other `LocalVar` and finally a `GenZIR` at the top. | ||
| 711 | pub const LocalVar = struct { | 713 | pub const LocalVar = struct { |
| 712 | pub const base_tag: Tag = .local_var; | 714 | pub const base_tag: Tag = .local_var; |
| 713 | base: Scope = Scope{ .tag = base_tag }, | 715 | base: Scope = Scope{ .tag = base_tag }, |
| 714 | gen_zir: *GenZIR, | 716 | /// Parents can be: `LocalVar`, `GenZIR`. |
| 715 | parent: *Scope, | 717 | parent: *Scope, |
| 718 | gen_zir: *GenZIR, | ||
| 716 | name: []const u8, | 719 | name: []const u8, |
| 717 | inst: *zir.Inst, | 720 | inst: *zir.Inst, |
| 718 | }; | 721 | }; |
| ... | @@ -1164,6 +1167,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1164,6 +1167,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1164 | var fn_type_scope: Scope.GenZIR = .{ | 1167 | var fn_type_scope: Scope.GenZIR = .{ |
| 1165 | .decl = decl, | 1168 | .decl = decl, |
| 1166 | .arena = &fn_type_scope_arena.allocator, | 1169 | .arena = &fn_type_scope_arena.allocator, |
| 1170 | .parent = decl.scope, | ||
| 1167 | }; | 1171 | }; |
| 1168 | defer fn_type_scope.instructions.deinit(self.gpa); | 1172 | defer fn_type_scope.instructions.deinit(self.gpa); |
| 1169 | 1173 | ||
| ... | @@ -1241,12 +1245,32 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1241,12 +1245,32 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1241 | var gen_scope: Scope.GenZIR = .{ | 1245 | var gen_scope: Scope.GenZIR = .{ |
| 1242 | .decl = decl, | 1246 | .decl = decl, |
| 1243 | .arena = &gen_scope_arena.allocator, | 1247 | .arena = &gen_scope_arena.allocator, |
| 1248 | .parent = decl.scope, | ||
| 1244 | }; | 1249 | }; |
| 1245 | defer gen_scope.instructions.deinit(self.gpa); | 1250 | defer gen_scope.instructions.deinit(self.gpa); |
| 1246 | 1251 | ||
| 1252 | // We need an instruction for each parameter, and they must be first in the body. | ||
| 1253 | try gen_scope.instructions.resize(self.gpa, fn_proto.params_len); | ||
| 1254 | var params_scope = &gen_scope.base; | ||
| 1255 | for (fn_proto.params()) |param, i| { | ||
| 1256 | const name_token = param.name_token.?; | ||
| 1257 | const src = tree.token_locs[name_token].start; | ||
| 1258 | const param_name = tree.tokenSlice(name_token); | ||
| 1259 | const arg = try newZIRInst(&gen_scope_arena.allocator, src, zir.Inst.Arg, .{}, .{}); | ||
| 1260 | gen_scope.instructions.items[i] = &arg.base; | ||
| 1261 | const sub_scope = try gen_scope_arena.allocator.create(Scope.LocalVar); | ||
| 1262 | sub_scope.* = .{ | ||
| 1263 | .parent = params_scope, | ||
| 1264 | .gen_zir = &gen_scope, | ||
| 1265 | .name = param_name, | ||
| 1266 | .inst = &arg.base, | ||
| 1267 | }; | ||
| 1268 | params_scope = &sub_scope.base; | ||
| 1269 | } | ||
| 1270 | |||
| 1247 | const body_block = body_node.cast(ast.Node.Block).?; | 1271 | const body_block = body_node.cast(ast.Node.Block).?; |
| 1248 | 1272 | ||
| 1249 | try astgen.blockExpr(self, &gen_scope.base, body_block); | 1273 | try astgen.blockExpr(self, params_scope, body_block); |
| 1250 | 1274 | ||
| 1251 | if (!fn_type.fnReturnType().isNoReturn() and (gen_scope.instructions.items.len == 0 or | 1275 | if (!fn_type.fnReturnType().isNoReturn() and (gen_scope.instructions.items.len == 0 or |
| 1252 | !gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn())) | 1276 | !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 | ... | @@ -2236,17 +2260,16 @@ fn analyzeInstCompileError(self: *Module, scope: *Scope, inst: *zir.Inst.Compile |
| 2236 | fn analyzeInstArg(self: *Module, scope: *Scope, inst: *zir.Inst.Arg) InnerError!*Inst { | 2260 | fn analyzeInstArg(self: *Module, scope: *Scope, inst: *zir.Inst.Arg) InnerError!*Inst { |
| 2237 | const b = try self.requireRuntimeBlock(scope, inst.base.src); | 2261 | const b = try self.requireRuntimeBlock(scope, inst.base.src); |
| 2238 | const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty; | 2262 | const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty; |
| 2263 | const param_index = b.instructions.items.len; | ||
| 2239 | const param_count = fn_ty.fnParamLen(); | 2264 | const param_count = fn_ty.fnParamLen(); |
| 2240 | if (inst.positionals.index >= param_count) { | 2265 | if (param_index >= param_count) { |
| 2241 | return self.fail(scope, inst.base.src, "parameter index {} outside list of length {}", .{ | 2266 | return self.fail(scope, inst.base.src, "parameter index {} outside list of length {}", .{ |
| 2242 | inst.positionals.index, | 2267 | param_index, |
| 2243 | param_count, | 2268 | param_count, |
| 2244 | }); | 2269 | }); |
| 2245 | } | 2270 | } |
| 2246 | const param_type = fn_ty.fnParamType(inst.positionals.index); | 2271 | const param_type = fn_ty.fnParamType(param_index); |
| 2247 | return self.addNewInstArgs(b, inst.base.src, param_type, Inst.Arg, .{ | 2272 | return self.addNewInstArgs(b, inst.base.src, param_type, Inst.Arg, {}); |
| 2248 | .index = inst.positionals.index, | ||
| 2249 | }); | ||
| 2250 | } | 2273 | } |
| 2251 | 2274 | ||
| 2252 | fn analyzeInstBlock(self: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst { | 2275 | fn analyzeInstBlock(self: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst { |
src-self-hosted/astgen.zig+25-14| ... | @@ -160,6 +160,7 @@ fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.In | ... | @@ -160,6 +160,7 @@ fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.In |
| 160 | } | 160 | } |
| 161 | } | 161 | } |
| 162 | var block_scope: Scope.GenZIR = .{ | 162 | var block_scope: Scope.GenZIR = .{ |
| 163 | .parent = scope, | ||
| 163 | .decl = scope.decl().?, | 164 | .decl = scope.decl().?, |
| 164 | .arena = scope.arena(), | 165 | .arena = scope.arena(), |
| 165 | .instructions = .{}, | 166 | .instructions = .{}, |
| ... | @@ -180,6 +181,7 @@ fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.In | ... | @@ -180,6 +181,7 @@ fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.In |
| 180 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), | 181 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), |
| 181 | }); | 182 | }); |
| 182 | var then_scope: Scope.GenZIR = .{ | 183 | var then_scope: Scope.GenZIR = .{ |
| 184 | .parent = scope, | ||
| 183 | .decl = block_scope.decl, | 185 | .decl = block_scope.decl, |
| 184 | .arena = block_scope.arena, | 186 | .arena = block_scope.arena, |
| 185 | .instructions = .{}, | 187 | .instructions = .{}, |
| ... | @@ -199,6 +201,7 @@ fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.In | ... | @@ -199,6 +201,7 @@ fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.In |
| 199 | }; | 201 | }; |
| 200 | 202 | ||
| 201 | var else_scope: Scope.GenZIR = .{ | 203 | var else_scope: Scope.GenZIR = .{ |
| 204 | .parent = scope, | ||
| 202 | .decl = block_scope.decl, | 205 | .decl = block_scope.decl, |
| 203 | .arena = block_scope.arena, | 206 | .arena = block_scope.arena, |
| 204 | .instructions = .{}, | 207 | .instructions = .{}, |
| ... | @@ -250,7 +253,11 @@ fn controlFlowExpr( | ... | @@ -250,7 +253,11 @@ fn controlFlowExpr( |
| 250 | } | 253 | } |
| 251 | 254 | ||
| 252 | fn identifier(mod: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerError!*zir.Inst { | 255 | fn identifier(mod: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerError!*zir.Inst { |
| 256 | const tracy = trace(@src()); | ||
| 257 | defer tracy.end(); | ||
| 258 | |||
| 253 | const tree = scope.tree(); | 259 | const tree = scope.tree(); |
| 260 | // TODO implement @"aoeu" identifiers | ||
| 254 | const ident_name = tree.tokenSlice(ident.token); | 261 | const ident_name = tree.tokenSlice(ident.token); |
| 255 | const src = tree.token_locs[ident.token].start; | 262 | const src = tree.token_locs[ident.token].start; |
| 256 | if (mem.eql(u8, ident_name, "_")) { | 263 | if (mem.eql(u8, ident_name, "_")) { |
| ... | @@ -288,23 +295,27 @@ fn identifier(mod: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerErr | ... | @@ -288,23 +295,27 @@ fn identifier(mod: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerErr |
| 288 | } | 295 | } |
| 289 | } | 296 | } |
| 290 | 297 | ||
| 291 | if (mod.lookupDeclName(scope, ident_name)) |decl| { | 298 | // Local variables, including function parameters. |
| 292 | return try mod.addZIRInst(scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{}); | 299 | { |
| 300 | var s = scope; | ||
| 301 | while (true) switch (s.tag) { | ||
| 302 | .local_var => { | ||
| 303 | const local_var = s.cast(Scope.LocalVar).?; | ||
| 304 | if (mem.eql(u8, local_var.name, ident_name)) { | ||
| 305 | return local_var.inst; | ||
| 306 | } | ||
| 307 | s = local_var.parent; | ||
| 308 | }, | ||
| 309 | .gen_zir => s = s.cast(Scope.GenZIR).?.parent, | ||
| 310 | else => break, | ||
| 311 | }; | ||
| 293 | } | 312 | } |
| 294 | 313 | ||
| 295 | // Function parameter | 314 | if (mod.lookupDeclName(scope, ident_name)) |decl| { |
| 296 | if (scope.decl()) |decl| { | 315 | return try mod.addZIRInst(scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{}); |
| 297 | if (tree.root_node.decls()[decl.src_index].cast(ast.Node.FnProto)) |fn_proto| { | ||
| 298 | for (fn_proto.params()) |param, i| { | ||
| 299 | const param_name = tree.tokenSlice(param.name_token.?); | ||
| 300 | if (mem.eql(u8, param_name, ident_name)) { | ||
| 301 | return try mod.addZIRInst(scope, src, zir.Inst.Arg, .{ .index = i }, .{}); | ||
| 302 | } | ||
| 303 | } | ||
| 304 | } | ||
| 305 | } | 316 | } |
| 306 | 317 | ||
| 307 | return mod.failNode(scope, &ident.base, "TODO implement local variable identifier lookup", .{}); | 318 | return mod.failNode(scope, &ident.base, "use of undeclared identifier '{}'", .{ident_name}); |
| 308 | } | 319 | } |
| 309 | 320 | ||
| 310 | fn stringLiteral(mod: *Module, scope: *Scope, str_lit: *ast.Node.StringLiteral) InnerError!*zir.Inst { | 321 | 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 | ... | @@ -434,7 +445,7 @@ fn callExpr(mod: *Module, scope: *Scope, node: *ast.Node.Call) InnerError!*zir.I |
| 434 | const lhs = try expr(mod, scope, node.lhs); | 445 | const lhs = try expr(mod, scope, node.lhs); |
| 435 | 446 | ||
| 436 | const param_nodes = node.params(); | 447 | const param_nodes = node.params(); |
| 437 | const args = try scope.cast(Scope.GenZIR).?.arena.alloc(*zir.Inst, param_nodes.len); | 448 | const args = try scope.getGenZIR().arena.alloc(*zir.Inst, param_nodes.len); |
| 438 | for (param_nodes) |param_node, i| { | 449 | for (param_nodes) |param_node, i| { |
| 439 | args[i] = try expr(mod, scope, param_node); | 450 | args[i] = try expr(mod, scope, param_node); |
| 440 | } | 451 | } |
src-self-hosted/codegen.zig+5-1| ... | @@ -73,6 +73,7 @@ pub fn generateSymbol( | ... | @@ -73,6 +73,7 @@ pub fn generateSymbol( |
| 73 | .code = code, | 73 | .code = code, |
| 74 | .err_msg = null, | 74 | .err_msg = null, |
| 75 | .args = mc_args, | 75 | .args = mc_args, |
| 76 | .arg_index = 0, | ||
| 76 | .branch_stack = &branch_stack, | 77 | .branch_stack = &branch_stack, |
| 77 | .src = src, | 78 | .src = src, |
| 78 | }; | 79 | }; |
| ... | @@ -255,6 +256,7 @@ const Function = struct { | ... | @@ -255,6 +256,7 @@ const Function = struct { |
| 255 | code: *std.ArrayList(u8), | 256 | code: *std.ArrayList(u8), |
| 256 | err_msg: ?*ErrorMsg, | 257 | err_msg: ?*ErrorMsg, |
| 257 | args: []MCValue, | 258 | args: []MCValue, |
| 259 | arg_index: usize, | ||
| 258 | src: usize, | 260 | src: usize, |
| 259 | 261 | ||
| 260 | /// Whenever there is a runtime branch, we push a Branch onto this stack, | 262 | /// Whenever there is a runtime branch, we push a Branch onto this stack, |
| ... | @@ -603,7 +605,9 @@ const Function = struct { | ... | @@ -603,7 +605,9 @@ const Function = struct { |
| 603 | } | 605 | } |
| 604 | 606 | ||
| 605 | fn genArg(self: *Function, inst: *ir.Inst.Arg) !MCValue { | 607 | fn genArg(self: *Function, inst: *ir.Inst.Arg) !MCValue { |
| 606 | return self.args[inst.args.index]; | 608 | const i = self.arg_index; |
| 609 | self.arg_index += 1; | ||
| 610 | return self.args[i]; | ||
| 607 | } | 611 | } |
| 608 | 612 | ||
| 609 | fn genBreakpoint(self: *Function, src: usize, comptime arch: std.Target.Cpu.Arch) !MCValue { | 613 | fn genBreakpoint(self: *Function, src: usize, comptime arch: std.Target.Cpu.Arch) !MCValue { |
src-self-hosted/ir.zig+1-4| ... | @@ -101,10 +101,7 @@ pub const Inst = struct { | ... | @@ -101,10 +101,7 @@ pub const Inst = struct { |
| 101 | pub const Arg = struct { | 101 | pub const Arg = struct { |
| 102 | pub const base_tag = Tag.arg; | 102 | pub const base_tag = Tag.arg; |
| 103 | base: Inst, | 103 | base: Inst, |
| 104 | 104 | args: void, | |
| 105 | args: struct { | ||
| 106 | index: usize, | ||
| 107 | }, | ||
| 108 | }; | 105 | }; |
| 109 | 106 | ||
| 110 | pub const Assembly = struct { | 107 | pub const Assembly = struct { |
src-self-hosted/zir.zig+8-7| ... | @@ -34,7 +34,8 @@ pub const Inst = struct { | ... | @@ -34,7 +34,8 @@ pub const Inst = struct { |
| 34 | 34 | ||
| 35 | /// These names are used directly as the instruction names in the text format. | 35 | /// These names are used directly as the instruction names in the text format. |
| 36 | pub const Tag = enum { | 36 | pub const Tag = enum { |
| 37 | /// Function parameter value. | 37 | /// Function parameter value. These must be first in a function's main block, |
| 38 | /// in respective order with the parameters. | ||
| 38 | arg, | 39 | arg, |
| 39 | /// A labeled block of code, which can return a value. | 40 | /// A labeled block of code, which can return a value. |
| 40 | block, | 41 | block, |
| ... | @@ -184,9 +185,7 @@ pub const Inst = struct { | ... | @@ -184,9 +185,7 @@ pub const Inst = struct { |
| 184 | pub const base_tag = Tag.arg; | 185 | pub const base_tag = Tag.arg; |
| 185 | base: Inst, | 186 | base: Inst, |
| 186 | 187 | ||
| 187 | positionals: struct { | 188 | positionals: struct {}, |
| 188 | index: usize, | ||
| 189 | }, | ||
| 190 | kw_args: struct {}, | 189 | kw_args: struct {}, |
| 191 | }; | 190 | }; |
| 192 | 191 | ||
| ... | @@ -1384,15 +1383,17 @@ const EmitZIR = struct { | ... | @@ -1384,15 +1383,17 @@ const EmitZIR = struct { |
| 1384 | for (src_decls.items) |ir_decl| { | 1383 | for (src_decls.items) |ir_decl| { |
| 1385 | switch (ir_decl.analysis) { | 1384 | switch (ir_decl.analysis) { |
| 1386 | .unreferenced => continue, | 1385 | .unreferenced => continue, |
| 1386 | |||
| 1387 | .complete => {}, | 1387 | .complete => {}, |
| 1388 | .codegen_failure => {}, // We still can emit the ZIR. | ||
| 1389 | .codegen_failure_retryable => {}, // We still can emit the ZIR. | ||
| 1390 | |||
| 1388 | .in_progress => unreachable, | 1391 | .in_progress => unreachable, |
| 1389 | .outdated => unreachable, | 1392 | .outdated => unreachable, |
| 1390 | 1393 | ||
| 1391 | .sema_failure, | 1394 | .sema_failure, |
| 1392 | .sema_failure_retryable, | 1395 | .sema_failure_retryable, |
| 1393 | .codegen_failure, | ||
| 1394 | .dependency_failure, | 1396 | .dependency_failure, |
| 1395 | .codegen_failure_retryable, | ||
| 1396 | => if (self.old_module.failed_decls.get(ir_decl)) |err_msg| { | 1397 | => if (self.old_module.failed_decls.get(ir_decl)) |err_msg| { |
| 1397 | const fail_inst = try self.arena.allocator.create(Inst.CompileError); | 1398 | const fail_inst = try self.arena.allocator.create(Inst.CompileError); |
| 1398 | fail_inst.* = .{ | 1399 | fail_inst.* = .{ |
| ... | @@ -1728,7 +1729,7 @@ const EmitZIR = struct { | ... | @@ -1728,7 +1729,7 @@ const EmitZIR = struct { |
| 1728 | .src = inst.src, | 1729 | .src = inst.src, |
| 1729 | .tag = Inst.Arg.base_tag, | 1730 | .tag = Inst.Arg.base_tag, |
| 1730 | }, | 1731 | }, |
| 1731 | .positionals = .{ .index = old_inst.args.index }, | 1732 | .positionals = .{}, |
| 1732 | .kw_args = .{}, | 1733 | .kw_args = .{}, |
| 1733 | }; | 1734 | }; |
| 1734 | break :blk &new_inst.base; | 1735 | break :blk &new_inst.base; |