| author | |
| committer | |
| log | 006e7f68056af62ae7713d7ef228841d11874735 |
| tree | 0d64585b1d78040506a898140ddc619e002b2147 |
| parent | 9362f382ab7023592cc1d71044217b847b122406 |
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); |
| 1480 | 1481 | ||
| 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 by | 286 | /// 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`. |
| 288 | pub const Fn = struct { | 288 | pub 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, |
| 305 | 290 | /// 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 | }; |
| 324 | 311 | ||
| 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 | }, .{}); |
| 1126 | 1080 | ||
| 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 | } |
| 1130 | 1084 | ||
| ... | @@ -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); |
| 1177 | 1131 | ||
| 1178 | const fn_zir = blk: { | 1132 | const fn_zir: zir.Module.Body = blk: { |
| 1179 | // This scope's arena memory is discarded after the ZIR generation | 1133 | // 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 | } |
| 1229 | 1180 | ||
| 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 | } |
| 1233 | 1184 | ||
| 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 | }; |
| 1243 | 1189 | ||
| 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)]; | ||
| 1252 | 1199 | ||
| 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 | } |
| 1277 | 1222 | ||
| 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 { |
| 1391 | 1336 | ||
| 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 | } |
| 1397 | 1342 | ||
| ... | @@ -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 | } |
| 1441 | 1386 | ||
| ... | @@ -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); |
| 1512 | 1457 | ||
| 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 | } |
| 1517 | 1462 | ||
| ... | @@ -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); |
| 1904 | 1849 | ||
| 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}); |
| 1909 | 1852 | ||
| 1910 | try zir_sema.analyzeBody(self, &inner_block.base, fn_zir.body); | 1853 | try zir_sema.analyzeBody(self, &inner_block.base, func.zir); |
| 1911 | 1854 | ||
| 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 | } |
| 1916 | 1860 | ||
| ... | @@ -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; |
| 533 | 533 | ||
| 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); |
| 536 | 536 | ||
| 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 { |
| 593 | 593 | ||
| 594 | try self.dbgSetPrologueEnd(); | 594 | try self.dbgSetPrologueEnd(); |
| 595 | 595 | ||
| 596 | try self.genBody(self.mod_fn.data.body); | 596 | try self.genBody(self.mod_fn.body); |
| 597 | 597 | ||
| 598 | // Backpatch stack offset | 598 | // 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(" {"); |
| 276 | 276 | ||
| 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 instructions | 63 | // 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); |
| 67 | 67 | ||
| 68 | // Write 'end' opcode | 68 | // 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); |
| 296 | 296 | ||
| 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(); |
| 1866 | 1866 | ||
| 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(); |
| 2291 | 2293 | ||
| 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; |
| 25 | const Scope = Module.Scope; | 25 | const Scope = Module.Scope; |
| 26 | const InnerError = Module.InnerError; | 26 | const InnerError = Module.InnerError; |
| 27 | const Decl = Module.Decl; | 27 | const Decl = Module.Decl; |
| 28 | const astgen = @import("astgen.zig"); | ||
| 29 | const ast = std.zig.ast; | ||
| 30 | 28 | ||
| 31 | pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst { | 29 | pub 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 | } | ||
| 947 | 875 | ||
| 948 | // Analyze the ZIR. The same ZIR gets analyzed into a runtime function | 876 | // 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 is | 877 | // 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 |
| 986 | 914 | ||
| 987 | // This will have return instructions analyzed as break instructions to | 915 | // 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 | }); | ||
| 992 | 918 | ||
| 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 |
| 998 | 924 | ||
| 999 | fn analyzeInstFn(mod: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError!*Inst { | 925 | fn 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 | } |
| 369 | 394 | ||
| 370 | { | 395 | { |