authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-02 13:40:23-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-02 19:11:55-07:00
log006e7f68056af62ae7713d7ef228841d11874735
tree0d64585b1d78040506a898140ddc619e002b2147
parent9362f382ab7023592cc1d71044217b847b122406

stage2: re-use ZIR for comptime and inline calls

Instead of freeing ZIR after semantic analysis, we keep it around so that it can be used for comptime calls, inline calls, and generic function calls. ZIR memory is now managed by the Decl arena. Debug dump() functions are conditionally compiled; only available in Debug builds of the compiler. Add a test for an inline function call.

9 files changed, 93 insertions(+), 209 deletions(-)

src/Compilation.zig+5-4
...@@ -1459,15 +1459,16 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor...@@ -1459,15 +1459,16 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
1459 const module = self.bin_file.options.module.?;1459 const module = self.bin_file.options.module.?;
1460 if (decl.typed_value.most_recent.typed_value.val.castTag(.function)) |payload| {1460 if (decl.typed_value.most_recent.typed_value.val.castTag(.function)) |payload| {
1461 const func = payload.data;1461 const func = payload.data;
1462 switch (func.bits.state) {1462 switch (func.state) {
1463 .queued => module.analyzeFnBody(decl, func) catch |err| switch (err) {1463 .queued => module.analyzeFnBody(decl, func) catch |err| switch (err) {
1464 error.AnalysisFail => {1464 error.AnalysisFail => {
1465 assert(func.bits.state != .in_progress);1465 assert(func.state != .in_progress);
1466 continue;1466 continue;
1467 },1467 },
1468 error.OutOfMemory => return error.OutOfMemory,1468 error.OutOfMemory => return error.OutOfMemory,
1469 },1469 },
1470 .in_progress => unreachable,1470 .in_progress => unreachable,
1471 .inline_only => unreachable, // don't queue work for this
1471 .sema_failure, .dependency_failure => continue,1472 .sema_failure, .dependency_failure => continue,
1472 .success => {},1473 .success => {},
1473 }1474 }
...@@ -1476,9 +1477,9 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor...@@ -1476,9 +1477,9 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
1476 var decl_arena = decl.typed_value.most_recent.arena.?.promote(module.gpa);1477 var decl_arena = decl.typed_value.most_recent.arena.?.promote(module.gpa);
1477 defer decl.typed_value.most_recent.arena.?.* = decl_arena.state;1478 defer decl.typed_value.most_recent.arena.?.* = decl_arena.state;
1478 log.debug("analyze liveness of {s}\n", .{decl.name});1479 log.debug("analyze liveness of {s}\n", .{decl.name});
1479 try liveness.analyze(module.gpa, &decl_arena.allocator, func.data.body);1480 try liveness.analyze(module.gpa, &decl_arena.allocator, func.body);
14801481
1481 if (self.verbose_ir) {1482 if (std.builtin.mode == .Debug and self.verbose_ir) {
1482 func.dump(module.*);1483 func.dump(module.*);
1483 }1484 }
1484 }1485 }
src/Module.zig+40-96
...@@ -286,75 +286,29 @@ pub const Decl = struct {...@@ -286,75 +286,29 @@ pub const Decl = struct {
286/// Extern functions do not have this data structure; they are represented by286/// Extern functions do not have this data structure; they are represented by
287/// the `Decl` only, with a `Value` tag of `extern_fn`.287/// the `Decl` only, with a `Value` tag of `extern_fn`.
288pub const Fn = struct {288pub const Fn = struct {
289 bits: packed struct {
290 /// Get and set this field via `analysis` and `setAnalysis`.
291 state: Analysis.Tag,
292 /// We carry this state into `Fn` instead of leaving it in the AST so that
293 /// analysis of function calls can happen even on functions whose AST has
294 /// been unloaded from memory.
295 is_inline: bool,
296 unused_bits: u4 = 0,
297 },
298 /// Get and set this data via `analysis` and `setAnalysis`.
299 data: union {
300 none: void,
301 zir: *ZIR,
302 body: Body,
303 },
304 owner_decl: *Decl,289 owner_decl: *Decl,
305290 /// Contains un-analyzed ZIR instructions generated from Zig source AST.
306 pub const Analysis = union(Tag) {291 /// Even after we finish analysis, the ZIR is kept in memory, so that
307 queued: *ZIR,292 /// comptime and inline function calls can happen.
293 zir: zir.Module.Body,
294 /// undefined unless analysis state is `success`.
295 body: Body,
296 state: Analysis,
297
298 pub const Analysis = enum {
299 queued,
300 /// This function intentionally only has ZIR generated because it is marked
301 /// inline, which means no runtime version of the function will be generated.
302 inline_only,
308 in_progress,303 in_progress,
304 /// There will be a corresponding ErrorMsg in Module.failed_decls
309 sema_failure,305 sema_failure,
306 /// This Fn might be OK but it depends on another Decl which did not
307 /// successfully complete semantic analysis.
310 dependency_failure,308 dependency_failure,
311 success: Body,309 success,
312
313 pub const Tag = enum(u3) {
314 queued,
315 in_progress,
316 /// There will be a corresponding ErrorMsg in Module.failed_decls
317 sema_failure,
318 /// This Fn might be OK but it depends on another Decl which did not
319 /// successfully complete semantic analysis.
320 dependency_failure,
321 success,
322 };
323 };310 };
324311
325 /// Contains un-analyzed ZIR instructions generated from Zig source AST.
326 pub const ZIR = struct {
327 body: zir.Module.Body,
328 arena: std.heap.ArenaAllocator.State,
329 };
330
331 pub fn analysis(self: Fn) Analysis {
332 return switch (self.bits.state) {
333 .queued => .{ .queued = self.data.zir },
334 .success => .{ .success = self.data.body },
335 .in_progress => .in_progress,
336 .sema_failure => .sema_failure,
337 .dependency_failure => .dependency_failure,
338 };
339 }
340
341 pub fn setAnalysis(self: *Fn, anal: Analysis) void {
342 switch (anal) {
343 .queued => |zir_ptr| {
344 self.bits.state = .queued;
345 self.data = .{ .zir = zir_ptr };
346 },
347 .success => |body| {
348 self.bits.state = .success;
349 self.data = .{ .body = body };
350 },
351 .in_progress, .sema_failure, .dependency_failure => {
352 self.bits.state = anal;
353 self.data = .{ .none = {} };
354 },
355 }
356 }
357
358 /// For debugging purposes.312 /// For debugging purposes.
359 pub fn dump(self: *Fn, mod: Module) void {313 pub fn dump(self: *Fn, mod: Module) void {
360 zir.dumpFn(mod, self);314 zir.dumpFn(mod, self);
...@@ -1124,7 +1078,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1124,7 +1078,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1124 .param_types = param_types,1078 .param_types = param_types,
1125 }, .{});1079 }, .{});
11261080
1127 if (self.comp.verbose_ir) {1081 if (std.builtin.mode == .Debug and self.comp.verbose_ir) {
1128 zir.dumpZir(self.gpa, "fn_type", decl.name, fn_type_scope.instructions.items) catch {};1082 zir.dumpZir(self.gpa, "fn_type", decl.name, fn_type_scope.instructions.items) catch {};
1129 }1083 }
11301084
...@@ -1175,14 +1129,11 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1175,14 +1129,11 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1175 const new_func = try decl_arena.allocator.create(Fn);1129 const new_func = try decl_arena.allocator.create(Fn);
1176 const fn_payload = try decl_arena.allocator.create(Value.Payload.Function);1130 const fn_payload = try decl_arena.allocator.create(Value.Payload.Function);
11771131
1178 const fn_zir = blk: {1132 const fn_zir: zir.Module.Body = blk: {
1179 // This scope's arena memory is discarded after the ZIR generation1133 // We put the ZIR inside the Decl arena.
1180 // pass completes, and semantic analysis of it completes.
1181 var gen_scope_arena = std.heap.ArenaAllocator.init(self.gpa);
1182 errdefer gen_scope_arena.deinit();
1183 var gen_scope: Scope.GenZIR = .{1134 var gen_scope: Scope.GenZIR = .{
1184 .decl = decl,1135 .decl = decl,
1185 .arena = &gen_scope_arena.allocator,1136 .arena = &decl_arena.allocator,
1186 .parent = decl.scope,1137 .parent = decl.scope,
1187 };1138 };
1188 defer gen_scope.instructions.deinit(self.gpa);1139 defer gen_scope.instructions.deinit(self.gpa);
...@@ -1194,7 +1145,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1194,7 +1145,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1194 const name_token = param.name_token.?;1145 const name_token = param.name_token.?;
1195 const src = tree.token_locs[name_token].start;1146 const src = tree.token_locs[name_token].start;
1196 const param_name = try self.identifierTokenString(&gen_scope.base, name_token);1147 const param_name = try self.identifierTokenString(&gen_scope.base, name_token);
1197 const arg = try gen_scope_arena.allocator.create(zir.Inst.Arg);1148 const arg = try decl_arena.allocator.create(zir.Inst.Arg);
1198 arg.* = .{1149 arg.* = .{
1199 .base = .{1150 .base = .{
1200 .tag = .arg,1151 .tag = .arg,
...@@ -1206,7 +1157,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1206,7 +1157,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1206 .kw_args = .{},1157 .kw_args = .{},
1207 };1158 };
1208 gen_scope.instructions.items[i] = &arg.base;1159 gen_scope.instructions.items[i] = &arg.base;
1209 const sub_scope = try gen_scope_arena.allocator.create(Scope.LocalVal);1160 const sub_scope = try decl_arena.allocator.create(Scope.LocalVal);
1210 sub_scope.* = .{1161 sub_scope.* = .{
1211 .parent = params_scope,1162 .parent = params_scope,
1212 .gen_zir = &gen_scope,1163 .gen_zir = &gen_scope,
...@@ -1227,18 +1178,13 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1227,18 +1178,13 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1227 _ = try astgen.addZIRNoOp(self, &gen_scope.base, src, .returnvoid);1178 _ = try astgen.addZIRNoOp(self, &gen_scope.base, src, .returnvoid);
1228 }1179 }
12291180
1230 if (self.comp.verbose_ir) {1181 if (std.builtin.mode == .Debug and self.comp.verbose_ir) {
1231 zir.dumpZir(self.gpa, "fn_body", decl.name, gen_scope.instructions.items) catch {};1182 zir.dumpZir(self.gpa, "fn_body", decl.name, gen_scope.instructions.items) catch {};
1232 }1183 }
12331184
1234 const fn_zir = try gen_scope_arena.allocator.create(Fn.ZIR);1185 break :blk .{
1235 fn_zir.* = .{1186 .instructions = try gen_scope.arena.dupe(*zir.Inst, gen_scope.instructions.items),
1236 .body = .{
1237 .instructions = try gen_scope.arena.dupe(*zir.Inst, gen_scope.instructions.items),
1238 },
1239 .arena = gen_scope_arena.state,
1240 };1187 };
1241 break :blk fn_zir;
1242 };1188 };
12431189
1244 const is_inline = blk: {1190 const is_inline = blk: {
...@@ -1249,13 +1195,12 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1249,13 +1195,12 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1249 }1195 }
1250 break :blk false;1196 break :blk false;
1251 };1197 };
1198 const anal_state = ([2]Fn.Analysis{ .queued, .inline_only })[@boolToInt(is_inline)];
12521199
1253 new_func.* = .{1200 new_func.* = .{
1254 .bits = .{1201 .state = anal_state,
1255 .state = .queued,1202 .zir = fn_zir,
1256 .is_inline = is_inline,1203 .body = undefined,
1257 },
1258 .data = .{ .zir = fn_zir },
1259 .owner_decl = decl,1204 .owner_decl = decl,
1260 };1205 };
1261 fn_payload.* = .{1206 fn_payload.* = .{
...@@ -1272,7 +1217,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1272,7 +1217,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1272 type_changed = !tvm.typed_value.ty.eql(fn_type);1217 type_changed = !tvm.typed_value.ty.eql(fn_type);
1273 if (tvm.typed_value.val.castTag(.function)) |payload| {1218 if (tvm.typed_value.val.castTag(.function)) |payload| {
1274 const prev_func = payload.data;1219 const prev_func = payload.data;
1275 prev_is_inline = prev_func.bits.is_inline;1220 prev_is_inline = prev_func.state == .inline_only;
1276 }1221 }
12771222
1278 tvm.deinit(self.gpa);1223 tvm.deinit(self.gpa);
...@@ -1391,7 +1336,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1391,7 +1336,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
13911336
1392 const src = tree.token_locs[init_node.firstToken()].start;1337 const src = tree.token_locs[init_node.firstToken()].start;
1393 const init_inst = try astgen.expr(self, &gen_scope.base, init_result_loc, init_node);1338 const init_inst = try astgen.expr(self, &gen_scope.base, init_result_loc, init_node);
1394 if (self.comp.verbose_ir) {1339 if (std.builtin.mode == .Debug and self.comp.verbose_ir) {
1395 zir.dumpZir(self.gpa, "var_init", decl.name, gen_scope.instructions.items) catch {};1340 zir.dumpZir(self.gpa, "var_init", decl.name, gen_scope.instructions.items) catch {};
1396 }1341 }
13971342
...@@ -1435,7 +1380,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1435,7 +1380,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1435 .val = Value.initTag(.type_type),1380 .val = Value.initTag(.type_type),
1436 });1381 });
1437 const var_type = try astgen.expr(self, &type_scope.base, .{ .ty = type_type }, type_node);1382 const var_type = try astgen.expr(self, &type_scope.base, .{ .ty = type_type }, type_node);
1438 if (self.comp.verbose_ir) {1383 if (std.builtin.mode == .Debug and self.comp.verbose_ir) {
1439 zir.dumpZir(self.gpa, "var_type", decl.name, type_scope.instructions.items) catch {};1384 zir.dumpZir(self.gpa, "var_type", decl.name, type_scope.instructions.items) catch {};
1440 }1385 }
14411386
...@@ -1511,7 +1456,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1511,7 +1456,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1511 defer gen_scope.instructions.deinit(self.gpa);1456 defer gen_scope.instructions.deinit(self.gpa);
15121457
1513 _ = try astgen.comptimeExpr(self, &gen_scope.base, .none, comptime_decl.expr);1458 _ = try astgen.comptimeExpr(self, &gen_scope.base, .none, comptime_decl.expr);
1514 if (self.comp.verbose_ir) {1459 if (std.builtin.mode == .Debug and self.comp.verbose_ir) {
1515 zir.dumpZir(self.gpa, "comptime_block", decl.name, gen_scope.instructions.items) catch {};1460 zir.dumpZir(self.gpa, "comptime_block", decl.name, gen_scope.instructions.items) catch {};
1516 }1461 }
15171462
...@@ -1902,15 +1847,14 @@ pub fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void {...@@ -1902,15 +1847,14 @@ pub fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void {
1902 };1847 };
1903 defer inner_block.instructions.deinit(self.gpa);1848 defer inner_block.instructions.deinit(self.gpa);
19041849
1905 const fn_zir = func.data.zir;1850 func.state = .in_progress;
1906 defer fn_zir.arena.promote(self.gpa).deinit();
1907 func.setAnalysis(.in_progress);
1908 log.debug("set {s} to in_progress\n", .{decl.name});1851 log.debug("set {s} to in_progress\n", .{decl.name});
19091852
1910 try zir_sema.analyzeBody(self, &inner_block.base, fn_zir.body);1853 try zir_sema.analyzeBody(self, &inner_block.base, func.zir);
19111854
1912 const instructions = try arena.allocator.dupe(*Inst, inner_block.instructions.items);1855 const instructions = try arena.allocator.dupe(*Inst, inner_block.instructions.items);
1913 func.setAnalysis(.{ .success = .{ .instructions = instructions } });1856 func.state = .success;
1857 func.body = .{ .instructions = instructions };
1914 log.debug("set {s} to success\n", .{decl.name});1858 log.debug("set {s} to success\n", .{decl.name});
1915}1859}
19161860
...@@ -2407,7 +2351,7 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn...@@ -2407,7 +2351,7 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn
2407 self.ensureDeclAnalyzed(decl) catch |err| {2351 self.ensureDeclAnalyzed(decl) catch |err| {
2408 if (scope.cast(Scope.Block)) |block| {2352 if (scope.cast(Scope.Block)) |block| {
2409 if (block.func) |func| {2353 if (block.func) |func| {
2410 func.setAnalysis(.dependency_failure);2354 func.state = .dependency_failure;
2411 } else {2355 } else {
2412 block.decl.analysis = .dependency_failure;2356 block.decl.analysis = .dependency_failure;
2413 }2357 }
...@@ -3107,7 +3051,7 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Com...@@ -3107,7 +3051,7 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Com
3107 .block => {3051 .block => {
3108 const block = scope.cast(Scope.Block).?;3052 const block = scope.cast(Scope.Block).?;
3109 if (block.func) |func| {3053 if (block.func) |func| {
3110 func.setAnalysis(.sema_failure);3054 func.state = .sema_failure;
3111 } else {3055 } else {
3112 block.decl.analysis = .sema_failure;3056 block.decl.analysis = .sema_failure;
3113 block.decl.generation = self.generation;3057 block.decl.generation = self.generation;
src/codegen.zig+5-5
...@@ -532,7 +532,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -532,7 +532,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
532 self.code.items.len += 4;532 self.code.items.len += 4;
533533
534 try self.dbgSetPrologueEnd();534 try self.dbgSetPrologueEnd();
535 try self.genBody(self.mod_fn.data.body);535 try self.genBody(self.mod_fn.body);
536536
537 const stack_end = self.max_end_stack;537 const stack_end = self.max_end_stack;
538 if (stack_end > math.maxInt(i32))538 if (stack_end > math.maxInt(i32))
...@@ -576,7 +576,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -576,7 +576,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
576 });576 });
577 } else {577 } else {
578 try self.dbgSetPrologueEnd();578 try self.dbgSetPrologueEnd();
579 try self.genBody(self.mod_fn.data.body);579 try self.genBody(self.mod_fn.body);
580 try self.dbgSetEpilogueBegin();580 try self.dbgSetEpilogueBegin();
581 }581 }
582 },582 },
...@@ -593,7 +593,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -593,7 +593,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
593593
594 try self.dbgSetPrologueEnd();594 try self.dbgSetPrologueEnd();
595595
596 try self.genBody(self.mod_fn.data.body);596 try self.genBody(self.mod_fn.body);
597597
598 // Backpatch stack offset598 // Backpatch stack offset
599 const stack_end = self.max_end_stack;599 const stack_end = self.max_end_stack;
...@@ -638,13 +638,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -638,13 +638,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
638 writeInt(u32, try self.code.addManyAsArray(4), Instruction.pop(.al, .{ .fp, .pc }).toU32());638 writeInt(u32, try self.code.addManyAsArray(4), Instruction.pop(.al, .{ .fp, .pc }).toU32());
639 } else {639 } else {
640 try self.dbgSetPrologueEnd();640 try self.dbgSetPrologueEnd();
641 try self.genBody(self.mod_fn.data.body);641 try self.genBody(self.mod_fn.body);
642 try self.dbgSetEpilogueBegin();642 try self.dbgSetEpilogueBegin();
643 }643 }
644 },644 },
645 else => {645 else => {
646 try self.dbgSetPrologueEnd();646 try self.dbgSetPrologueEnd();
647 try self.genBody(self.mod_fn.data.body);647 try self.genBody(self.mod_fn.body);
648 try self.dbgSetEpilogueBegin();648 try self.dbgSetEpilogueBegin();
649 },649 },
650 }650 }
src/codegen/c.zig+1-1
...@@ -275,7 +275,7 @@ pub fn generate(file: *C, module: *Module, decl: *Decl) !void {...@@ -275,7 +275,7 @@ pub fn generate(file: *C, module: *Module, decl: *Decl) !void {
275 try writer.writeAll(" {");275 try writer.writeAll(" {");
276276
277 const func: *Module.Fn = func_payload.data;277 const func: *Module.Fn = func_payload.data;
278 const instructions = func.data.body.instructions;278 const instructions = func.body.instructions;
279 if (instructions.len > 0) {279 if (instructions.len > 0) {
280 try writer.writeAll("\n");280 try writer.writeAll("\n");
281 for (instructions) |inst| {281 for (instructions) |inst| {
src/codegen/wasm.zig+1-1
...@@ -63,7 +63,7 @@ pub fn genCode(buf: *ArrayList(u8), decl: *Decl) !void {...@@ -63,7 +63,7 @@ pub fn genCode(buf: *ArrayList(u8), decl: *Decl) !void {
63 // TODO: check for and handle death of instructions63 // TODO: check for and handle death of instructions
64 const tv = decl.typed_value.most_recent.typed_value;64 const tv = decl.typed_value.most_recent.typed_value;
65 const mod_fn = tv.val.castTag(.function).?.data;65 const mod_fn = tv.val.castTag(.function).?.data;
66 for (mod_fn.data.body.instructions) |inst| try genInst(buf, decl, inst);66 for (mod_fn.body.instructions) |inst| try genInst(buf, decl, inst);
6767
68 // Write 'end' opcode68 // Write 'end' opcode
69 try writer.writeByte(0x0B);69 try writer.writeByte(0x0B);
src/llvm_backend.zig+1-1
...@@ -294,7 +294,7 @@ pub const LLVMIRModule = struct {...@@ -294,7 +294,7 @@ pub const LLVMIRModule = struct {
294 const entry_block = llvm_func.appendBasicBlock("Entry");294 const entry_block = llvm_func.appendBasicBlock("Entry");
295 self.builder.positionBuilderAtEnd(entry_block);295 self.builder.positionBuilderAtEnd(entry_block);
296296
297 const instructions = func.data.body.instructions;297 const instructions = func.body.instructions;
298 for (instructions) |inst| {298 for (instructions) |inst| {
299 switch (inst.tag) {299 switch (inst.tag) {
300 .breakpoint => try self.genBreakpoint(inst.castTag(.breakpoint).?),300 .breakpoint => try self.genBreakpoint(inst.castTag(.breakpoint).?),
src/zir.zig+10-7
...@@ -1864,13 +1864,15 @@ pub fn dumpFn(old_module: IrModule, module_fn: *IrModule.Fn) void {...@@ -1864,13 +1864,15 @@ pub fn dumpFn(old_module: IrModule, module_fn: *IrModule.Fn) void {
1864 defer ctx.const_table.deinit();1864 defer ctx.const_table.deinit();
1865 defer ctx.arena.deinit();1865 defer ctx.arena.deinit();
18661866
1867 switch (module_fn.analysis()) {1867 switch (module_fn.state) {
1868 .queued => std.debug.print("(queued)", .{}),1868 .queued => std.debug.print("(queued)", .{}),
1869 .inline_only => std.debug.print("(inline_only)", .{}),
1869 .in_progress => std.debug.print("(in_progress)", .{}),1870 .in_progress => std.debug.print("(in_progress)", .{}),
1870 .sema_failure => std.debug.print("(sema_failure)", .{}),1871 .sema_failure => std.debug.print("(sema_failure)", .{}),
1871 .dependency_failure => std.debug.print("(dependency_failure)", .{}),1872 .dependency_failure => std.debug.print("(dependency_failure)", .{}),
1872 .success => |body| {1873 .success => {
1873 ctx.dump(body, std.io.getStdErr().writer()) catch @panic("failed to dump TZIR");1874 const writer = std.io.getStdErr().writer();
1875 ctx.dump(module_fn.body, writer) catch @panic("failed to dump TZIR");
1874 },1876 },
1875 }1877 }
1876}1878}
...@@ -2289,11 +2291,12 @@ const EmitZIR = struct {...@@ -2289,11 +2291,12 @@ const EmitZIR = struct {
2289 var instructions = std.ArrayList(*Inst).init(self.allocator);2291 var instructions = std.ArrayList(*Inst).init(self.allocator);
2290 defer instructions.deinit();2292 defer instructions.deinit();
22912293
2292 switch (module_fn.analysis()) {2294 switch (module_fn.state) {
2293 .queued => unreachable,2295 .queued => unreachable,
2294 .in_progress => unreachable,2296 .in_progress => unreachable,
2295 .success => |body| {2297 .inline_only => unreachable,
2296 try self.emitBody(body, &inst_table, &instructions);2298 .success => {
2299 try self.emitBody(module_fn.body, &inst_table, &instructions);
2297 },2300 },
2298 .sema_failure => {2301 .sema_failure => {
2299 const err_msg = self.old_module.failed_decls.get(module_fn.owner_decl).?;2302 const err_msg = self.old_module.failed_decls.get(module_fn.owner_decl).?;
...@@ -2372,7 +2375,7 @@ const EmitZIR = struct {...@@ -2372,7 +2375,7 @@ const EmitZIR = struct {
2372 .body = .{ .instructions = arena_instrs },2375 .body = .{ .instructions = arena_instrs },
2373 },2376 },
2374 .kw_args = .{2377 .kw_args = .{
2375 .is_inline = module_fn.bits.is_inline,2378 .is_inline = module_fn.state == .inline_only,
2376 },2379 },
2377 };2380 };
2378 return self.emitUnnamedDecl(&fn_inst.base);2381 return self.emitUnnamedDecl(&fn_inst.base);
src/zir_sema.zig+5-94
...@@ -25,8 +25,6 @@ const trace = @import("tracy.zig").trace;...@@ -25,8 +25,6 @@ const trace = @import("tracy.zig").trace;
25const Scope = Module.Scope;25const Scope = Module.Scope;
26const InnerError = Module.InnerError;26const InnerError = Module.InnerError;
27const Decl = Module.Decl;27const Decl = Module.Decl;
28const astgen = @import("astgen.zig");
29const ast = std.zig.ast;
3028
31pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {29pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {
32 switch (old_inst.tag) {30 switch (old_inst.tag) {
...@@ -861,7 +859,7 @@ fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError...@@ -861,7 +859,7 @@ fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError
861 .function => func_val.castTag(.function).?.data,859 .function => func_val.castTag(.function).?.data,
862 else => break :blk false,860 else => break :blk false,
863 };861 };
864 break :blk module_fn.bits.is_inline;862 break :blk module_fn.state == .inline_only;
865 }863 }
866 break :blk false;864 break :blk false;
867 };865 };
...@@ -874,76 +872,6 @@ fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError...@@ -874,76 +872,6 @@ fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError
874 }),872 }),
875 else => unreachable,873 else => unreachable,
876 };874 };
877 const callee_decl = module_fn.owner_decl;
878 // TODO: De-duplicate this with the code in Module.zig that generates
879 // ZIR for the same function and re-use the same ZIR for runtime function
880 // generation and for inline/comptime calls.
881 const callee_file_scope = callee_decl.getFileScope();
882 const tree = mod.getAstTree(callee_file_scope) catch |err| switch (err) {
883 error.OutOfMemory => return error.OutOfMemory,
884 error.AnalysisFail => return error.AnalysisFail,
885 // TODO: make sure this gets retried and not cached
886 else => return mod.fail(scope, inst.base.src, "failed to load {s}: {s}", .{
887 callee_file_scope.sub_file_path, @errorName(err),
888 }),
889 };
890 const ast_node = tree.root_node.decls()[callee_decl.src_index];
891 const fn_proto = ast_node.castTag(.FnProto).?;
892
893 var call_arena = std.heap.ArenaAllocator.init(mod.gpa);
894 defer call_arena.deinit();
895
896 var gen_scope: Scope.GenZIR = .{
897 .decl = callee_decl,
898 .arena = &call_arena.allocator,
899 .parent = callee_decl.scope,
900 };
901 defer gen_scope.instructions.deinit(mod.gpa);
902
903 // We need an instruction for each parameter, and they must be first in the body.
904 try gen_scope.instructions.resize(mod.gpa, fn_proto.params_len);
905 var params_scope = &gen_scope.base;
906 for (fn_proto.params()) |param, i| {
907 const name_token = param.name_token.?;
908 const src = tree.token_locs[name_token].start;
909 const param_name = try mod.identifierTokenString(scope, name_token);
910 const arg = try call_arena.allocator.create(zir.Inst.Arg);
911 arg.* = .{
912 .base = .{
913 .tag = .arg,
914 .src = src,
915 },
916 .positionals = .{
917 .name = param_name,
918 },
919 .kw_args = .{},
920 };
921 gen_scope.instructions.items[i] = &arg.base;
922 const sub_scope = try call_arena.allocator.create(Scope.LocalVal);
923 sub_scope.* = .{
924 .parent = params_scope,
925 .gen_zir = &gen_scope,
926 .name = param_name,
927 .inst = &arg.base,
928 };
929 params_scope = &sub_scope.base;
930 }
931
932 const body_node = fn_proto.getBodyNode().?; // We handle extern functions above.
933 const body_block = body_node.cast(ast.Node.Block).?;
934
935 try astgen.blockExpr(mod, params_scope, body_block);
936
937 if (gen_scope.instructions.items.len == 0 or
938 !gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn())
939 {
940 const src = tree.token_locs[body_block.rbrace].start;
941 _ = try astgen.addZIRNoOp(mod, &gen_scope.base, src, .returnvoid);
942 }
943
944 if (mod.comp.verbose_ir) {
945 zir.dumpZir(mod.gpa, "fn_body_callee", callee_decl.name, gen_scope.instructions.items) catch {};
946 }
947875
948 // Analyze the ZIR. The same ZIR gets analyzed into a runtime function876 // Analyze the ZIR. The same ZIR gets analyzed into a runtime function
949 // or an inlined call depending on what union tag the `label` field is877 // or an inlined call depending on what union tag the `label` field is
...@@ -986,9 +914,7 @@ fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError...@@ -986,9 +914,7 @@ fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError
986914
987 // This will have return instructions analyzed as break instructions to915 // This will have return instructions analyzed as break instructions to
988 // the block_inst above.916 // the block_inst above.
989 try analyzeBody(mod, &child_block.base, .{917 try analyzeBody(mod, &child_block.base, module_fn.zir);
990 .instructions = gen_scope.instructions.items,
991 });
992918
993 return analyzeBlockBody(mod, scope, &child_block, merges);919 return analyzeBlockBody(mod, scope, &child_block, merges);
994 }920 }
...@@ -998,26 +924,11 @@ fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError...@@ -998,26 +924,11 @@ fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError
998924
999fn analyzeInstFn(mod: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError!*Inst {925fn analyzeInstFn(mod: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError!*Inst {
1000 const fn_type = try resolveType(mod, scope, fn_inst.positionals.fn_type);926 const fn_type = try resolveType(mod, scope, fn_inst.positionals.fn_type);
1001 const fn_zir = blk: {
1002 var fn_arena = std.heap.ArenaAllocator.init(mod.gpa);
1003 errdefer fn_arena.deinit();
1004
1005 const fn_zir = try scope.arena().create(Module.Fn.ZIR);
1006 fn_zir.* = .{
1007 .body = .{
1008 .instructions = fn_inst.positionals.body.instructions,
1009 },
1010 .arena = fn_arena.state,
1011 };
1012 break :blk fn_zir;
1013 };
1014 const new_func = try scope.arena().create(Module.Fn);927 const new_func = try scope.arena().create(Module.Fn);
1015 new_func.* = .{928 new_func.* = .{
1016 .bits = .{929 .state = if (fn_inst.kw_args.is_inline) .inline_only else .queued,
1017 .state = .queued,930 .zir = fn_inst.positionals.body,
1018 .is_inline = fn_inst.kw_args.is_inline,931 .body = undefined,
1019 },
1020 .data = .{ .zir = fn_zir },
1021 .owner_decl = scope.decl().?,932 .owner_decl = scope.decl().?,
1022 };933 };
1023 return mod.constInst(scope, fn_inst.base.src, .{934 return mod.constInst(scope, fn_inst.base.src, .{
test/stage2/test.zig+25
...@@ -342,6 +342,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -342,6 +342,7 @@ pub fn addCases(ctx: *TestContext) !void {
342 ,342 ,
343 "",343 "",
344 );344 );
345 // comptime function call
345 case.addCompareOutput(346 case.addCompareOutput(
346 \\export fn _start() noreturn {347 \\export fn _start() noreturn {
347 \\ exit();348 \\ exit();
...@@ -365,6 +366,30 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -365,6 +366,30 @@ pub fn addCases(ctx: *TestContext) !void {
365 ,366 ,
366 "",367 "",
367 );368 );
369 // Inline function call
370 case.addCompareOutput(
371 \\export fn _start() noreturn {
372 \\ var x: usize = 3;
373 \\ const y = add(1, 2, x);
374 \\ exit(y - 6);
375 \\}
376 \\
377 \\inline fn add(a: usize, b: usize, c: usize) usize {
378 \\ return a + b + c;
379 \\}
380 \\
381 \\fn exit(code: usize) noreturn {
382 \\ asm volatile ("syscall"
383 \\ :
384 \\ : [number] "{rax}" (231),
385 \\ [arg1] "{rdi}" (code)
386 \\ : "rcx", "r11", "memory"
387 \\ );
388 \\ unreachable;
389 \\}
390 ,
391 "",
392 );
368 }393 }
369394
370 {395 {