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
14591459 const module = self.bin_file.options.module.?;
14601460 if (decl.typed_value.most_recent.typed_value.val.castTag(.function)) |payload| {
14611461 const func = payload.data;
1462 switch (func.bits.state) {
1462 switch (func.state) {
14631463 .queued => module.analyzeFnBody(decl, func) catch |err| switch (err) {
14641464 error.AnalysisFail => {
1465 assert(func.bits.state != .in_progress);
1465 assert(func.state != .in_progress);
14661466 continue;
14671467 },
14681468 error.OutOfMemory => return error.OutOfMemory,
14691469 },
14701470 .in_progress => unreachable,
1471 .inline_only => unreachable, // don't queue work for this
14711472 .sema_failure, .dependency_failure => continue,
14721473 .success => {},
14731474 }
......@@ -1476,9 +1477,9 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
14761477 var decl_arena = decl.typed_value.most_recent.arena.?.promote(module.gpa);
14771478 defer decl.typed_value.most_recent.arena.?.* = decl_arena.state;
14781479 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) {
14821483 func.dump(module.*);
14831484 }
14841485 }
src/Module.zig+40-96
......@@ -286,75 +286,29 @@ pub const Decl = struct {
286286/// Extern functions do not have this data structure; they are represented by
287287/// the `Decl` only, with a `Value` tag of `extern_fn`.
288288pub 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 },
304289 owner_decl: *Decl,
305
306 pub const Analysis = union(Tag) {
307 queued: *ZIR,
290 /// Contains un-analyzed ZIR instructions generated from Zig source AST.
291 /// Even after we finish analysis, the ZIR is kept in memory, so that
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,
308303 in_progress,
304 /// There will be a corresponding ErrorMsg in Module.failed_decls
309305 sema_failure,
306 /// This Fn might be OK but it depends on another Decl which did not
307 /// successfully complete semantic analysis.
310308 dependency_failure,
311 success: Body,
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 };
309 success,
323310 };
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
358312 /// For debugging purposes.
359313 pub fn dump(self: *Fn, mod: Module) void {
360314 zir.dumpFn(mod, self);
......@@ -1124,7 +1078,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
11241078 .param_types = param_types,
11251079 }, .{});
11261080
1127 if (self.comp.verbose_ir) {
1081 if (std.builtin.mode == .Debug and self.comp.verbose_ir) {
11281082 zir.dumpZir(self.gpa, "fn_type", decl.name, fn_type_scope.instructions.items) catch {};
11291083 }
11301084
......@@ -1175,14 +1129,11 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
11751129 const new_func = try decl_arena.allocator.create(Fn);
11761130 const fn_payload = try decl_arena.allocator.create(Value.Payload.Function);
11771131
1178 const fn_zir = blk: {
1179 // This scope's arena memory is discarded after the ZIR generation
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();
1132 const fn_zir: zir.Module.Body = blk: {
1133 // We put the ZIR inside the Decl arena.
11831134 var gen_scope: Scope.GenZIR = .{
11841135 .decl = decl,
1185 .arena = &gen_scope_arena.allocator,
1136 .arena = &decl_arena.allocator,
11861137 .parent = decl.scope,
11871138 };
11881139 defer gen_scope.instructions.deinit(self.gpa);
......@@ -1194,7 +1145,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
11941145 const name_token = param.name_token.?;
11951146 const src = tree.token_locs[name_token].start;
11961147 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);
11981149 arg.* = .{
11991150 .base = .{
12001151 .tag = .arg,
......@@ -1206,7 +1157,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
12061157 .kw_args = .{},
12071158 };
12081159 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);
12101161 sub_scope.* = .{
12111162 .parent = params_scope,
12121163 .gen_zir = &gen_scope,
......@@ -1227,18 +1178,13 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
12271178 _ = try astgen.addZIRNoOp(self, &gen_scope.base, src, .returnvoid);
12281179 }
12291180
1230 if (self.comp.verbose_ir) {
1181 if (std.builtin.mode == .Debug and self.comp.verbose_ir) {
12311182 zir.dumpZir(self.gpa, "fn_body", decl.name, gen_scope.instructions.items) catch {};
12321183 }
12331184
1234 const fn_zir = try gen_scope_arena.allocator.create(Fn.ZIR);
1235 fn_zir.* = .{
1236 .body = .{
1237 .instructions = try gen_scope.arena.dupe(*zir.Inst, gen_scope.instructions.items),
1238 },
1239 .arena = gen_scope_arena.state,
1185 break :blk .{
1186 .instructions = try gen_scope.arena.dupe(*zir.Inst, gen_scope.instructions.items),
12401187 };
1241 break :blk fn_zir;
12421188 };
12431189
12441190 const is_inline = blk: {
......@@ -1249,13 +1195,12 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
12491195 }
12501196 break :blk false;
12511197 };
1198 const anal_state = ([2]Fn.Analysis{ .queued, .inline_only })[@boolToInt(is_inline)];
12521199
12531200 new_func.* = .{
1254 .bits = .{
1255 .state = .queued,
1256 .is_inline = is_inline,
1257 },
1258 .data = .{ .zir = fn_zir },
1201 .state = anal_state,
1202 .zir = fn_zir,
1203 .body = undefined,
12591204 .owner_decl = decl,
12601205 };
12611206 fn_payload.* = .{
......@@ -1272,7 +1217,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
12721217 type_changed = !tvm.typed_value.ty.eql(fn_type);
12731218 if (tvm.typed_value.val.castTag(.function)) |payload| {
12741219 const prev_func = payload.data;
1275 prev_is_inline = prev_func.bits.is_inline;
1220 prev_is_inline = prev_func.state == .inline_only;
12761221 }
12771222
12781223 tvm.deinit(self.gpa);
......@@ -1391,7 +1336,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
13911336
13921337 const src = tree.token_locs[init_node.firstToken()].start;
13931338 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) {
13951340 zir.dumpZir(self.gpa, "var_init", decl.name, gen_scope.instructions.items) catch {};
13961341 }
13971342
......@@ -1435,7 +1380,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
14351380 .val = Value.initTag(.type_type),
14361381 });
14371382 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) {
14391384 zir.dumpZir(self.gpa, "var_type", decl.name, type_scope.instructions.items) catch {};
14401385 }
14411386
......@@ -1511,7 +1456,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
15111456 defer gen_scope.instructions.deinit(self.gpa);
15121457
15131458 _ = 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) {
15151460 zir.dumpZir(self.gpa, "comptime_block", decl.name, gen_scope.instructions.items) catch {};
15161461 }
15171462
......@@ -1902,15 +1847,14 @@ pub fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void {
19021847 };
19031848 defer inner_block.instructions.deinit(self.gpa);
19041849
1905 const fn_zir = func.data.zir;
1906 defer fn_zir.arena.promote(self.gpa).deinit();
1907 func.setAnalysis(.in_progress);
1850 func.state = .in_progress;
19081851 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
19121855 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 };
19141858 log.debug("set {s} to success\n", .{decl.name});
19151859}
19161860
......@@ -2407,7 +2351,7 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn
24072351 self.ensureDeclAnalyzed(decl) catch |err| {
24082352 if (scope.cast(Scope.Block)) |block| {
24092353 if (block.func) |func| {
2410 func.setAnalysis(.dependency_failure);
2354 func.state = .dependency_failure;
24112355 } else {
24122356 block.decl.analysis = .dependency_failure;
24132357 }
......@@ -3107,7 +3051,7 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Com
31073051 .block => {
31083052 const block = scope.cast(Scope.Block).?;
31093053 if (block.func) |func| {
3110 func.setAnalysis(.sema_failure);
3054 func.state = .sema_failure;
31113055 } else {
31123056 block.decl.analysis = .sema_failure;
31133057 block.decl.generation = self.generation;
src/codegen.zig+5-5
......@@ -532,7 +532,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
532532 self.code.items.len += 4;
533533
534534 try self.dbgSetPrologueEnd();
535 try self.genBody(self.mod_fn.data.body);
535 try self.genBody(self.mod_fn.body);
536536
537537 const stack_end = self.max_end_stack;
538538 if (stack_end > math.maxInt(i32))
......@@ -576,7 +576,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
576576 });
577577 } else {
578578 try self.dbgSetPrologueEnd();
579 try self.genBody(self.mod_fn.data.body);
579 try self.genBody(self.mod_fn.body);
580580 try self.dbgSetEpilogueBegin();
581581 }
582582 },
......@@ -593,7 +593,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
593593
594594 try self.dbgSetPrologueEnd();
595595
596 try self.genBody(self.mod_fn.data.body);
596 try self.genBody(self.mod_fn.body);
597597
598598 // Backpatch stack offset
599599 const stack_end = self.max_end_stack;
......@@ -638,13 +638,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
638638 writeInt(u32, try self.code.addManyAsArray(4), Instruction.pop(.al, .{ .fp, .pc }).toU32());
639639 } else {
640640 try self.dbgSetPrologueEnd();
641 try self.genBody(self.mod_fn.data.body);
641 try self.genBody(self.mod_fn.body);
642642 try self.dbgSetEpilogueBegin();
643643 }
644644 },
645645 else => {
646646 try self.dbgSetPrologueEnd();
647 try self.genBody(self.mod_fn.data.body);
647 try self.genBody(self.mod_fn.body);
648648 try self.dbgSetEpilogueBegin();
649649 },
650650 }
src/codegen/c.zig+1-1
......@@ -275,7 +275,7 @@ pub fn generate(file: *C, module: *Module, decl: *Decl) !void {
275275 try writer.writeAll(" {");
276276
277277 const func: *Module.Fn = func_payload.data;
278 const instructions = func.data.body.instructions;
278 const instructions = func.body.instructions;
279279 if (instructions.len > 0) {
280280 try writer.writeAll("\n");
281281 for (instructions) |inst| {
src/codegen/wasm.zig+1-1
......@@ -63,7 +63,7 @@ pub fn genCode(buf: *ArrayList(u8), decl: *Decl) !void {
6363 // TODO: check for and handle death of instructions
6464 const tv = decl.typed_value.most_recent.typed_value;
6565 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
6868 // Write 'end' opcode
6969 try writer.writeByte(0x0B);
src/llvm_backend.zig+1-1
......@@ -294,7 +294,7 @@ pub const LLVMIRModule = struct {
294294 const entry_block = llvm_func.appendBasicBlock("Entry");
295295 self.builder.positionBuilderAtEnd(entry_block);
296296
297 const instructions = func.data.body.instructions;
297 const instructions = func.body.instructions;
298298 for (instructions) |inst| {
299299 switch (inst.tag) {
300300 .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 {
18641864 defer ctx.const_table.deinit();
18651865 defer ctx.arena.deinit();
18661866
1867 switch (module_fn.analysis()) {
1867 switch (module_fn.state) {
18681868 .queued => std.debug.print("(queued)", .{}),
1869 .inline_only => std.debug.print("(inline_only)", .{}),
18691870 .in_progress => std.debug.print("(in_progress)", .{}),
18701871 .sema_failure => std.debug.print("(sema_failure)", .{}),
18711872 .dependency_failure => std.debug.print("(dependency_failure)", .{}),
1872 .success => |body| {
1873 ctx.dump(body, std.io.getStdErr().writer()) catch @panic("failed to dump TZIR");
1873 .success => {
1874 const writer = std.io.getStdErr().writer();
1875 ctx.dump(module_fn.body, writer) catch @panic("failed to dump TZIR");
18741876 },
18751877 }
18761878}
......@@ -2289,11 +2291,12 @@ const EmitZIR = struct {
22892291 var instructions = std.ArrayList(*Inst).init(self.allocator);
22902292 defer instructions.deinit();
22912293
2292 switch (module_fn.analysis()) {
2294 switch (module_fn.state) {
22932295 .queued => unreachable,
22942296 .in_progress => unreachable,
2295 .success => |body| {
2296 try self.emitBody(body, &inst_table, &instructions);
2297 .inline_only => unreachable,
2298 .success => {
2299 try self.emitBody(module_fn.body, &inst_table, &instructions);
22972300 },
22982301 .sema_failure => {
22992302 const err_msg = self.old_module.failed_decls.get(module_fn.owner_decl).?;
......@@ -2372,7 +2375,7 @@ const EmitZIR = struct {
23722375 .body = .{ .instructions = arena_instrs },
23732376 },
23742377 .kw_args = .{
2375 .is_inline = module_fn.bits.is_inline,
2378 .is_inline = module_fn.state == .inline_only,
23762379 },
23772380 };
23782381 return self.emitUnnamedDecl(&fn_inst.base);
src/zir_sema.zig+5-94
......@@ -25,8 +25,6 @@ const trace = @import("tracy.zig").trace;
2525const Scope = Module.Scope;
2626const InnerError = Module.InnerError;
2727const Decl = Module.Decl;
28const astgen = @import("astgen.zig");
29const ast = std.zig.ast;
3028
3129pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {
3230 switch (old_inst.tag) {
......@@ -861,7 +859,7 @@ fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError
861859 .function => func_val.castTag(.function).?.data,
862860 else => break :blk false,
863861 };
864 break :blk module_fn.bits.is_inline;
862 break :blk module_fn.state == .inline_only;
865863 }
866864 break :blk false;
867865 };
......@@ -874,76 +872,6 @@ fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError
874872 }),
875873 else => unreachable,
876874 };
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
948876 // Analyze the ZIR. The same ZIR gets analyzed into a runtime function
949877 // 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
986914
987915 // This will have return instructions analyzed as break instructions to
988916 // the block_inst above.
989 try analyzeBody(mod, &child_block.base, .{
990 .instructions = gen_scope.instructions.items,
991 });
917 try analyzeBody(mod, &child_block.base, module_fn.zir);
992918
993919 return analyzeBlockBody(mod, scope, &child_block, merges);
994920 }
......@@ -998,26 +924,11 @@ fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError
998924
999925fn analyzeInstFn(mod: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError!*Inst {
1000926 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 };
1014927 const new_func = try scope.arena().create(Module.Fn);
1015928 new_func.* = .{
1016 .bits = .{
1017 .state = .queued,
1018 .is_inline = fn_inst.kw_args.is_inline,
1019 },
1020 .data = .{ .zir = fn_zir },
929 .state = if (fn_inst.kw_args.is_inline) .inline_only else .queued,
930 .zir = fn_inst.positionals.body,
931 .body = undefined,
1021932 .owner_decl = scope.decl().?,
1022933 };
1023934 return mod.constInst(scope, fn_inst.base.src, .{
test/stage2/test.zig+25
......@@ -342,6 +342,7 @@ pub fn addCases(ctx: *TestContext) !void {
342342 ,
343343 "",
344344 );
345 // comptime function call
345346 case.addCompareOutput(
346347 \\export fn _start() noreturn {
347348 \\ exit();
......@@ -365,6 +366,30 @@ pub fn addCases(ctx: *TestContext) !void {
365366 ,
366367 "",
367368 );
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 );
368393 }
369394
370395 {