authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-17 17:39:52-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-17 17:39:52-07:00
log67f5a28257b50e72750f51a03d6ce9ee27ad1439
treee2a205ff1e748ded4bfc848e0a841ac5cef3622a
parent5cacc446c4ff5591b7a9c506952f4eb9ae5efdd1

Sema: use a hash map for ZIR->AIR mapping

Previously, ZIR was per-function so we could simply allocate a slice for all ZIR instructions. However now ZIR is whole-file, so we need a sparse mapping of ZIR to AIR instructions in order to not waste memory.

3 files changed, 20 insertions(+), 21 deletions(-)

BRANCH_TODO-5
...@@ -1,8 +1,3 @@...@@ -1,8 +1,3 @@
1 * use a hash map for instructions because the array is too big
2 - no, actually modify the Zir.Inst.Ref strategy so that each decl gets
3 their indexes starting at 0 so that we can use an array to store Sema
4 results rather than a map.
5
6 * in SwitchProng resolve, make sure AST tree gets loaded.1 * in SwitchProng resolve, make sure AST tree gets loaded.
7 It will be unloaded if using cached ZIR.2 It will be unloaded if using cached ZIR.
8 3
src/Module.zig+5-9
...@@ -2904,14 +2904,13 @@ pub fn semaFile(mod: *Module, file: *Scope.File) InnerError!void {...@@ -2904,14 +2904,13 @@ pub fn semaFile(mod: *Module, file: *Scope.File) InnerError!void {
2904 .gpa = gpa,2904 .gpa = gpa,
2905 .arena = &sema_arena.allocator,2905 .arena = &sema_arena.allocator,
2906 .code = file.zir,2906 .code = file.zir,
2907 // TODO use a map because this array is too big
2908 .inst_map = try sema_arena.allocator.alloc(*ir.Inst, file.zir.instructions.len),
2909 .owner_decl = new_decl,2907 .owner_decl = new_decl,
2910 .namespace = &struct_obj.namespace,2908 .namespace = &struct_obj.namespace,
2911 .func = null,2909 .func = null,
2912 .owner_func = null,2910 .owner_func = null,
2913 .param_inst_list = &.{},2911 .param_inst_list = &.{},
2914 };2912 };
2913 defer sema.deinit();
2915 var block_scope: Scope.Block = .{2914 var block_scope: Scope.Block = .{
2916 .parent = null,2915 .parent = null,
2917 .sema = &sema,2916 .sema = &sema,
...@@ -2960,13 +2959,13 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -2960,13 +2959,13 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
2960 .gpa = gpa,2959 .gpa = gpa,
2961 .arena = &analysis_arena.allocator,2960 .arena = &analysis_arena.allocator,
2962 .code = zir,2961 .code = zir,
2963 .inst_map = try analysis_arena.allocator.alloc(*ir.Inst, zir.instructions.len),
2964 .owner_decl = decl,2962 .owner_decl = decl,
2965 .namespace = decl.namespace,2963 .namespace = decl.namespace,
2966 .func = null,2964 .func = null,
2967 .owner_func = null,2965 .owner_func = null,
2968 .param_inst_list = &.{},2966 .param_inst_list = &.{},
2969 };2967 };
2968 defer sema.deinit();
29702969
2971 if (decl.isRoot()) {2970 if (decl.isRoot()) {
2972 log.debug("semaDecl root {*} ({s})", .{ decl, decl.name });2971 log.debug("semaDecl root {*} ({s})", .{ decl, decl.name });
...@@ -3565,14 +3564,13 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !void {...@@ -3565,14 +3564,13 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !void {
3565 .gpa = mod.gpa,3564 .gpa = mod.gpa,
3566 .arena = &arena.allocator,3565 .arena = &arena.allocator,
3567 .code = zir,3566 .code = zir,
3568 .inst_map = try mod.gpa.alloc(*ir.Inst, zir.instructions.len),
3569 .owner_decl = decl,3567 .owner_decl = decl,
3570 .namespace = decl.namespace,3568 .namespace = decl.namespace,
3571 .func = func,3569 .func = func,
3572 .owner_func = func,3570 .owner_func = func,
3573 .param_inst_list = param_inst_list,3571 .param_inst_list = param_inst_list,
3574 };3572 };
3575 defer mod.gpa.free(sema.inst_map);3573 defer sema.deinit();
35763574
3577 var inner_block: Scope.Block = .{3575 var inner_block: Scope.Block = .{
3578 .parent = null,3576 .parent = null,
...@@ -4555,14 +4553,13 @@ pub fn analyzeStructFields(mod: *Module, struct_obj: *Struct) InnerError!void {...@@ -4555,14 +4553,13 @@ pub fn analyzeStructFields(mod: *Module, struct_obj: *Struct) InnerError!void {
4555 .gpa = gpa,4553 .gpa = gpa,
4556 .arena = &decl_arena.allocator,4554 .arena = &decl_arena.allocator,
4557 .code = zir,4555 .code = zir,
4558 .inst_map = try gpa.alloc(*ir.Inst, zir.instructions.len),
4559 .owner_decl = struct_obj.owner_decl,4556 .owner_decl = struct_obj.owner_decl,
4560 .namespace = &struct_obj.namespace,4557 .namespace = &struct_obj.namespace,
4561 .owner_func = null,4558 .owner_func = null,
4562 .func = null,4559 .func = null,
4563 .param_inst_list = &.{},4560 .param_inst_list = &.{},
4564 };4561 };
4565 defer gpa.free(sema.inst_map);4562 defer sema.deinit();
45664563
4567 var block: Scope.Block = .{4564 var block: Scope.Block = .{
4568 .parent = null,4565 .parent = null,
...@@ -4712,14 +4709,13 @@ pub fn analyzeUnionFields(mod: *Module, union_obj: *Union) InnerError!void {...@@ -4712,14 +4709,13 @@ pub fn analyzeUnionFields(mod: *Module, union_obj: *Union) InnerError!void {
4712 .gpa = gpa,4709 .gpa = gpa,
4713 .arena = &decl_arena.allocator,4710 .arena = &decl_arena.allocator,
4714 .code = zir,4711 .code = zir,
4715 .inst_map = try gpa.alloc(*ir.Inst, zir.instructions.len),
4716 .owner_decl = union_obj.owner_decl,4712 .owner_decl = union_obj.owner_decl,
4717 .namespace = &union_obj.namespace,4713 .namespace = &union_obj.namespace,
4718 .owner_func = null,4714 .owner_func = null,
4719 .func = null,4715 .func = null,
4720 .param_inst_list = &.{},4716 .param_inst_list = &.{},
4721 };4717 };
4722 defer gpa.free(sema.inst_map);4718 defer sema.deinit();
47234719
4724 var block: Scope.Block = .{4720 var block: Scope.Block = .{
4725 .parent = null,4721 .parent = null,
src/Sema.zig+15-7
...@@ -12,7 +12,7 @@ gpa: *Allocator,...@@ -12,7 +12,7 @@ gpa: *Allocator,
12arena: *Allocator,12arena: *Allocator,
13code: Zir,13code: Zir,
14/// Maps ZIR to AIR.14/// Maps ZIR to AIR.
15inst_map: []*Inst,15inst_map: InstMap = .{},
16/// When analyzing an inline function call, owner_decl is the Decl of the caller16/// When analyzing an inline function call, owner_decl is the Decl of the caller
17/// and `src_decl` of `Scope.Block` is the `Decl` of the callee.17/// and `src_decl` of `Scope.Block` is the `Decl` of the callee.
18/// This `Decl` owns the arena memory of this `Sema`.18/// This `Decl` owns the arena memory of this `Sema`.
...@@ -65,6 +65,13 @@ const LazySrcLoc = Module.LazySrcLoc;...@@ -65,6 +65,13 @@ const LazySrcLoc = Module.LazySrcLoc;
65const RangeSet = @import("RangeSet.zig");65const RangeSet = @import("RangeSet.zig");
66const target_util = @import("target.zig");66const target_util = @import("target.zig");
6767
68pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, *ir.Inst);
69
70pub fn deinit(sema: *Sema) void {
71 sema.inst_map.deinit(sema.gpa);
72 sema.* = undefined;
73}
74
68pub fn analyzeFnBody(75pub fn analyzeFnBody(
69 sema: *Sema,76 sema: *Sema,
70 block: *Scope.Block,77 block: *Scope.Block,
...@@ -129,7 +136,7 @@ pub fn analyzeBody(...@@ -129,7 +136,7 @@ pub fn analyzeBody(
129) InnerError!Zir.Inst.Index {136) InnerError!Zir.Inst.Index {
130 // No tracy calls here, to avoid interfering with the tail call mechanism.137 // No tracy calls here, to avoid interfering with the tail call mechanism.
131138
132 const map = block.sema.inst_map;139 const map = &block.sema.inst_map;
133 const tags = block.sema.code.instructions.items(.tag);140 const tags = block.sema.code.instructions.items(.tag);
134 const datas = block.sema.code.instructions.items(.data);141 const datas = block.sema.code.instructions.items(.data);
135142
...@@ -142,7 +149,7 @@ pub fn analyzeBody(...@@ -142,7 +149,7 @@ pub fn analyzeBody(
142 var i: usize = 0;149 var i: usize = 0;
143 while (true) : (i += 1) {150 while (true) : (i += 1) {
144 const inst = body[i];151 const inst = body[i];
145 map[inst] = switch (tags[inst]) {152 const air_inst = switch (tags[inst]) {
146 // zig fmt: off153 // zig fmt: off
147 .arg => try sema.zirArg(block, inst),154 .arg => try sema.zirArg(block, inst),
148 .alloc => try sema.zirAlloc(block, inst),155 .alloc => try sema.zirAlloc(block, inst),
...@@ -500,8 +507,9 @@ pub fn analyzeBody(...@@ -500,8 +507,9 @@ pub fn analyzeBody(
500 }507 }
501 },508 },
502 };509 };
503 if (map[inst].ty.isNoReturn())510 if (air_inst.ty.isNoReturn())
504 return always_noreturn;511 return always_noreturn;
512 try map.putNoClobber(sema.gpa, inst, air_inst);
505 }513 }
506}514}
507515
...@@ -556,7 +564,7 @@ pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) error{OutOfMemory}!*ir.In...@@ -556,7 +564,7 @@ pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) error{OutOfMemory}!*ir.In
556 i -= Zir.Inst.Ref.typed_value_map.len;564 i -= Zir.Inst.Ref.typed_value_map.len;
557565
558 // Finally, the last section of indexes refers to the map of ZIR=>AIR.566 // Finally, the last section of indexes refers to the map of ZIR=>AIR.
559 return sema.inst_map[i];567 return sema.inst_map.get(@intCast(u32, i)).?;
560}568}
561569
562fn resolveConstString(570fn resolveConstString(
...@@ -2244,9 +2252,9 @@ fn analyzeCall(...@@ -2244,9 +2252,9 @@ fn analyzeCall(
2244 defer sema.code = parent_zir;2252 defer sema.code = parent_zir;
22452253
2246 const parent_inst_map = sema.inst_map;2254 const parent_inst_map = sema.inst_map;
2247 sema.inst_map = try sema.gpa.alloc(*ir.Inst, sema.code.instructions.len);2255 sema.inst_map = .{};
2248 defer {2256 defer {
2249 sema.gpa.free(sema.inst_map);2257 sema.inst_map.deinit(sema.gpa);
2250 sema.inst_map = parent_inst_map;2258 sema.inst_map = parent_inst_map;
2251 }2259 }
22522260