From 180dae419630114b56f2ccd3a80d72c38bd8cad8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 24 Mar 2021 15:24:18 -0700 Subject: stage2: further cleanups regarding zir.Inst.Ref * Introduce helper functions on Module.WipZirCode and zir.Code * Move some logic around * re-introduce ref_start_index * prefer usize for local variables + `@intCast` at the end. Empirically this is easier to optimize. * Avoid using mem.{bytesAsSlice,sliceAsBytes} because it incurs an unnecessary multiplication/division which may cause problems for the optimizer. * Use a regular enum, not packed, for `Ref`. Memory layout is guaranteed for enums which specify their tag type. Packed enums have ABI alignment of 1 byte which is too small. --- src/Module.zig | 65 +++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 21 deletions(-) (limited to 'src/Module.zig') diff --git a/src/Module.zig b/src/Module.zig index 9fdc1c2c9a..8791452d99 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -1013,7 +1013,7 @@ pub const Scope = struct { .cc = args.cc, .param_types_len = @intCast(u32, args.param_types.len), }); - gz.zir_code.extra.appendSliceAssumeCapacity(mem.bytesAsSlice(u32, mem.sliceAsBytes(args.param_types))); + gz.zir_code.appendRefsAssumeCapacity(args.param_types); const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len); gz.zir_code.instructions.appendAssumeCapacity(.{ @@ -1024,7 +1024,7 @@ pub const Scope = struct { } }, }); gz.instructions.appendAssumeCapacity(new_index); - return zir.Inst.Ref.fromIndex(new_index, gz.zir_code.param_count); + return gz.zir_code.indexToRef(new_index); } pub fn addFnType( @@ -1043,7 +1043,7 @@ pub const Scope = struct { const payload_index = gz.zir_code.addExtraAssumeCapacity(zir.Inst.FnType{ .param_types_len = @intCast(u32, param_types.len), }); - gz.zir_code.extra.appendSliceAssumeCapacity(mem.bytesAsSlice(u32, mem.sliceAsBytes(param_types))); + gz.zir_code.appendRefsAssumeCapacity(param_types); const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len); gz.zir_code.instructions.appendAssumeCapacity(.{ @@ -1054,7 +1054,7 @@ pub const Scope = struct { } }, }); gz.instructions.appendAssumeCapacity(new_index); - return zir.Inst.Ref.fromIndex(new_index, gz.zir_code.param_count); + return gz.zir_code.indexToRef(new_index); } pub fn addCall( @@ -1077,7 +1077,7 @@ pub const Scope = struct { .callee = callee, .args_len = @intCast(u32, args.len), }); - gz.zir_code.extra.appendSliceAssumeCapacity(mem.bytesAsSlice(u32, mem.sliceAsBytes(args))); + gz.zir_code.appendRefsAssumeCapacity(args); const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len); gz.zir_code.instructions.appendAssumeCapacity(.{ @@ -1088,7 +1088,7 @@ pub const Scope = struct { } }, }); gz.instructions.appendAssumeCapacity(new_index); - return zir.Inst.Ref.fromIndex(new_index, gz.zir_code.param_count); + return gz.zir_code.indexToRef(new_index); } /// Note that this returns a `zir.Inst.Index` not a ref. @@ -1160,7 +1160,7 @@ pub const Scope = struct { } }, }); gz.instructions.appendAssumeCapacity(new_index); - return zir.Inst.Ref.fromIndex(new_index, gz.zir_code.param_count); + return gz.zir_code.indexToRef(new_index); } pub fn addArrayTypeSentinel( @@ -1186,7 +1186,7 @@ pub const Scope = struct { } }, }); gz.instructions.appendAssumeCapacity(new_index); - return zir.Inst.Ref.fromIndex(new_index, gz.zir_code.param_count); + return gz.zir_code.indexToRef(new_index); } pub fn addUnTok( @@ -1317,7 +1317,7 @@ pub const Scope = struct { const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len); gz.zir_code.instructions.appendAssumeCapacity(inst); gz.instructions.appendAssumeCapacity(new_index); - return zir.Inst.Ref.fromIndex(new_index, gz.zir_code.param_count); + return gz.zir_code.indexToRef(new_index); } }; @@ -1366,9 +1366,9 @@ pub const WipZirCode = struct { instructions: std.MultiArrayList(zir.Inst) = .{}, string_bytes: std.ArrayListUnmanaged(u8) = .{}, extra: std.ArrayListUnmanaged(u32) = .{}, - /// We need to keep track of this count in order to convert between - /// `zir.Inst.Ref` and `zir.Inst.Index` types. - param_count: u32 = 0, + /// The end of special indexes. `zir.Inst.Ref` subtracts against this number to convert + /// to `zir.Inst.Index`. The default here is correct if there are 0 parameters. + ref_start_index: u32 = zir.Inst.Ref.typed_value_map.len, decl: *Decl, gpa: *Allocator, arena: *Allocator, @@ -1386,20 +1386,43 @@ pub const WipZirCode = struct { wzc.extra.appendAssumeCapacity(switch (field.field_type) { u32 => @field(extra, field.name), zir.Inst.Ref => @enumToInt(@field(extra, field.name)), - else => unreachable, + else => @compileError("bad field type"), }); } return result; } - pub fn refIsNoReturn(wzc: WipZirCode, zir_inst_ref: zir.Inst.Ref) bool { - if (zir_inst_ref == .unreachable_value) return true; - if (zir_inst_ref.toIndex(wzc.param_count)) |zir_inst| { - return wzc.instructions.items(.tag)[zir_inst].isNoReturn(); + pub fn appendRefs(wzc: *WipZirCode, refs: []const zir.Inst.Ref) !void { + const coerced = @bitCast([]const u32, refs); + return wzc.extra.appendSlice(wzc.gpa, coerced); + } + + pub fn appendRefsAssumeCapacity(wzc: *WipZirCode, refs: []const zir.Inst.Ref) void { + const coerced = @bitCast([]const u32, refs); + wzc.extra.appendSliceAssumeCapacity(coerced); + } + + pub fn refIsNoReturn(wzc: WipZirCode, inst_ref: zir.Inst.Ref) bool { + if (inst_ref == .unreachable_value) return true; + if (wzc.refToIndex(inst_ref)) |inst_index| { + return wzc.instructions.items(.tag)[inst_index].isNoReturn(); } return false; } + pub fn indexToRef(wzc: WipZirCode, inst: zir.Inst.Index) zir.Inst.Ref { + return @intToEnum(zir.Inst.Ref, wzc.ref_start_index + inst); + } + + pub fn refToIndex(wzc: WipZirCode, inst: zir.Inst.Ref) ?zir.Inst.Index { + const ref_int = @enumToInt(inst); + if (ref_int >= wzc.ref_start_index) { + return ref_int - wzc.ref_start_index; + } else { + return null; + } + } + pub fn deinit(wzc: *WipZirCode) void { wzc.instructions.deinit(wzc.gpa); wzc.extra.deinit(wzc.gpa); @@ -2075,7 +2098,7 @@ fn astgenAndSemaFn( // The AST params array does not contain anytype and ... parameters. // We must iterate to count how many param types to allocate. const param_count = blk: { - var count: u32 = 0; + var count: usize = 0; var it = fn_proto.iterate(tree); while (it.next()) |param| { if (param.anytype_ellipsis3) |some| if (token_tags[some] == .ellipsis3) break; @@ -2297,7 +2320,7 @@ fn astgenAndSemaFn( .decl = decl, .arena = &decl_arena.allocator, .gpa = mod.gpa, - .param_count = param_count, + .ref_start_index = @intCast(u32, zir.Inst.Ref.typed_value_map.len + param_count), }; defer wip_zir_code.deinit(); @@ -2314,7 +2337,7 @@ fn astgenAndSemaFn( try wip_zir_code.extra.ensureCapacity(mod.gpa, param_count); var params_scope = &gen_scope.base; - var i: u32 = 0; + var i: usize = 0; var it = fn_proto.iterate(tree); while (it.next()) |param| : (i += 1) { const name_token = param.name_token.?; @@ -2325,7 +2348,7 @@ fn astgenAndSemaFn( .gen_zir = &gen_scope, .name = param_name, // Implicit const list first, then implicit arg list. - .inst = zir.Inst.Ref.fromParam(i), + .inst = @intToEnum(zir.Inst.Ref, @intCast(u32, zir.Inst.Ref.typed_value_map.len + i)), .src = decl.tokSrcLoc(name_token), }; params_scope = &sub_scope.base; -- cgit v1.2.3