Commit cf7200e8f9
Changed files (4)
src
src/codegen/c/type.zig
@@ -290,11 +290,11 @@ pub const CType = extern union {
}
};
- const Promoted = struct {
+ pub const Promoted = struct {
arena: std.heap.ArenaAllocator,
set: Set,
- fn gpa(self: *Promoted) Allocator {
+ pub fn gpa(self: *Promoted) Allocator {
return self.arena.child_allocator;
}
@@ -345,11 +345,11 @@ pub const CType = extern union {
}
};
- fn promote(self: Store, gpa: Allocator) Promoted {
+ pub fn promote(self: Store, gpa: Allocator) Promoted {
return .{ .arena = self.arena.promote(gpa), .set = self.set };
}
- fn demote(self: *Store, promoted: Promoted) void {
+ pub fn demote(self: *Store, promoted: Promoted) void {
self.arena = promoted.arena.state;
self.set = promoted.set;
}
@@ -382,17 +382,17 @@ pub const CType = extern union {
_ = promoted.arena.reset(.retain_capacity);
}
- pub fn shrinkToFit(self: *Store, gpa: Allocator) void {
- self.map.shrinkAndFree(gpa, self.map.entries.len);
- }
-
- pub fn shrinkAndFree(self: *Store, gpa: Allocator) void {
+ pub fn clearAndFree(self: *Store, gpa: Allocator) void {
var promoted = self.promote(gpa);
defer self.demote(promoted);
promoted.set.map.clearAndFree(gpa);
_ = promoted.arena.reset(.free_all);
}
+ pub fn shrinkToFit(self: *Store, gpa: Allocator) void {
+ self.set.map.shrinkAndFree(gpa, self.set.map.count());
+ }
+
pub fn move(self: *Store) Store {
const moved = self.*;
self.* = .{};
@@ -1252,8 +1252,8 @@ pub const CType = extern union {
pub const HashContext64 = struct {
store: *const Store.Set,
- pub fn hash(_: @This(), cty: CType) u64 {
- return cty.hash();
+ pub fn hash(self: @This(), cty: CType) u64 {
+ return cty.hash(self.store.*);
}
pub fn eql(_: @This(), lhs: CType, rhs: CType) bool {
return lhs.eql(rhs);
src/codegen/c.zig
@@ -23,7 +23,7 @@ const libcFloatSuffix = target_util.libcFloatSuffix;
const compilerRtFloatAbbrev = target_util.compilerRtFloatAbbrev;
const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev;
-const Mutability = enum { Const, ConstArgument, Mut };
+const Mutability = enum { @"const", mut };
const BigIntLimb = std.math.big.Limb;
const BigInt = std.math.big.int;
@@ -63,12 +63,17 @@ const TypedefKind = enum {
};
pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue);
-pub const TypedefMap = std.ArrayHashMap(
- Type,
- struct { name: []const u8, rendered: []u8 },
- Type.HashContext32,
- true,
-);
+
+pub const LazyFnKey = union(enum) {
+ tag_name: Decl.Index,
+};
+pub const LazyFnValue = struct {
+ fn_name: []const u8,
+ data: union {
+ tag_name: Type,
+ },
+};
+pub const LazyFnMap = std.AutoArrayHashMapUnmanaged(LazyFnKey, LazyFnValue);
const LoopDepth = u16;
const Local = struct {
@@ -83,11 +88,6 @@ const LocalsList = std.ArrayListUnmanaged(LocalIndex);
const LocalsMap = std.ArrayHashMapUnmanaged(Type, LocalsList, Type.HashContext32, true);
const LocalsStack = std.ArrayListUnmanaged(LocalsMap);
-const FormatTypeAsCIdentContext = struct {
- ty: Type,
- mod: *Module,
-};
-
const ValueRenderLocation = enum {
FunctionArgument,
Initializer,
@@ -108,26 +108,6 @@ const BuiltinInfo = enum {
Bits,
};
-fn formatTypeAsCIdentifier(
- data: FormatTypeAsCIdentContext,
- comptime fmt: []const u8,
- options: std.fmt.FormatOptions,
- writer: anytype,
-) !void {
- var stack = std.heap.stackFallback(128, data.mod.gpa);
- const allocator = stack.get();
- const str = std.fmt.allocPrint(allocator, "{}", .{data.ty.fmt(data.mod)}) catch "";
- defer allocator.free(str);
- return formatIdent(str, fmt, options, writer);
-}
-
-pub fn typeToCIdentifier(ty: Type, mod: *Module) std.fmt.Formatter(formatTypeAsCIdentifier) {
- return .{ .data = .{
- .ty = ty,
- .mod = mod,
- } };
-}
-
const reserved_idents = std.ComptimeStringMap(void, .{
// C language
.{ "alignas", {
@@ -283,6 +263,7 @@ pub const Function = struct {
next_arg_index: usize = 0,
next_block_index: usize = 0,
object: Object,
+ lazy_fns: LazyFnMap,
func: *Module.Fn,
/// All the locals, to be emitted at the top of the function.
locals: std.ArrayListUnmanaged(Local) = .{},
@@ -319,7 +300,7 @@ pub const Function = struct {
const gpa = f.object.dg.gpa;
try f.allocs.put(gpa, decl_c_value.local, true);
try writer.writeAll("static ");
- try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, alignment, .Complete);
+ try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .@"const", alignment, .Complete);
try writer.writeAll(" = ");
try f.object.dg.renderValue(writer, ty, val, .StaticInitializer);
try writer.writeAll(";\n ");
@@ -353,7 +334,7 @@ pub const Function = struct {
}
fn allocLocal(f: *Function, inst: Air.Inst.Index, ty: Type) !CValue {
- const result = try f.allocAlignedLocal(ty, .Mut, 0);
+ const result = try f.allocAlignedLocal(ty, .mut, 0);
log.debug("%{d}: allocating t{d}", .{ inst, result.local });
return result;
}
@@ -448,6 +429,29 @@ pub const Function = struct {
return f.object.dg.fmtIntLiteral(ty, val);
}
+ fn getTagNameFn(f: *Function, enum_ty: Type) ![]const u8 {
+ const gpa = f.object.dg.gpa;
+ const owner_decl = enum_ty.getOwnerDecl();
+
+ const gop = try f.lazy_fns.getOrPut(gpa, .{ .tag_name = owner_decl });
+ if (!gop.found_existing) {
+ errdefer _ = f.lazy_fns.pop();
+
+ var promoted = f.object.dg.ctypes.promote(gpa);
+ defer f.object.dg.ctypes.demote(promoted);
+ const arena = promoted.arena.allocator();
+
+ gop.value_ptr.* = .{
+ .fn_name = try std.fmt.allocPrint(arena, "zig_tagName_{}__{d}", .{
+ fmtIdent(mem.span(f.object.dg.module.declPtr(owner_decl).name)),
+ @enumToInt(owner_decl),
+ }),
+ .data = .{ .tag_name = try enum_ty.copy(arena) },
+ };
+ }
+ return gop.value_ptr.fn_name;
+ }
+
pub fn deinit(f: *Function) void {
const gpa = f.object.dg.gpa;
f.allocs.deinit(gpa);
@@ -458,11 +462,8 @@ pub const Function = struct {
f.free_locals_stack.deinit(gpa);
f.blocks.deinit(gpa);
f.value_map.deinit();
+ f.lazy_fns.deinit(gpa);
f.object.code.deinit();
- for (f.object.dg.typedefs.values()) |typedef| {
- gpa.free(typedef.rendered);
- }
- f.object.dg.typedefs.deinit();
f.object.dg.ctypes.deinit(gpa);
f.object.dg.fwd_decl.deinit();
f.arena.deinit();
@@ -492,9 +493,6 @@ pub const DeclGen = struct {
fwd_decl: std.ArrayList(u8),
error_msg: ?*Module.ErrorMsg,
ctypes: CType.Store,
- /// The key of this map is Type which has references to typedefs_arena.
- typedefs: TypedefMap,
- typedefs_arena: std.mem.Allocator,
fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
@setCold(true);
@@ -504,14 +502,6 @@ pub const DeclGen = struct {
return error.AnalysisFail;
}
- fn getTypedefName(dg: *DeclGen, t: Type) ?[]const u8 {
- if (dg.typedefs.get(t)) |typedef| {
- return typedef.name;
- } else {
- return null;
- }
- }
-
fn renderDeclValue(
dg: *DeclGen,
writer: anytype,
@@ -1493,7 +1483,7 @@ pub const DeclGen = struct {
if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
if (index > 0) try w.writeAll(", ");
const name = CValue{ .arg = index };
- try dg.renderTypeAndName(w, param_type, name, .ConstArgument, 0, kind);
+ try dg.renderTypeAndName(w, param_type, name, .@"const", 0, kind);
index += 1;
}
@@ -1507,453 +1497,6 @@ pub const DeclGen = struct {
if (fn_info.alignment > 0 and kind == .Forward) try w.print(" zig_align_fn({})", .{fn_info.alignment});
}
- fn renderPtrToFnTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
- var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
- defer buffer.deinit();
- const bw = buffer.writer();
-
- const fn_info = t.fnInfo();
-
- const target = dg.module.getTarget();
- var ret_buf: LowerFnRetTyBuffer = undefined;
- const ret_ty = lowerFnRetTy(fn_info.return_type, &ret_buf, target);
-
- try bw.writeAll("typedef ");
- try dg.renderType(bw, ret_ty, .Forward);
- try bw.writeAll(" (*");
- const name_begin = buffer.items.len;
- try bw.print("zig_F_{}", .{typeToCIdentifier(t, dg.module)});
- const name_end = buffer.items.len;
- try bw.writeAll(")(");
-
- const param_len = fn_info.param_types.len;
-
- var params_written: usize = 0;
- var index: usize = 0;
- while (index < param_len) : (index += 1) {
- const param_ty = fn_info.param_types[index];
- if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue;
- if (params_written > 0) {
- try bw.writeAll(", ");
- }
- try dg.renderTypeAndName(bw, param_ty, .{ .bytes = "" }, .Mut, 0, .Forward);
- params_written += 1;
- }
-
- if (fn_info.is_var_args) {
- if (params_written != 0) try bw.writeAll(", ");
- try bw.writeAll("...");
- } else if (params_written == 0) {
- try dg.renderType(bw, Type.void, .Forward);
- }
- try bw.writeAll(");\n");
-
- const rendered = try buffer.toOwnedSlice();
- errdefer dg.typedefs.allocator.free(rendered);
- const name = rendered[name_begin..name_end];
-
- try dg.typedefs.ensureUnusedCapacity(1);
- dg.typedefs.putAssumeCapacityNoClobber(
- try t.copy(dg.typedefs_arena),
- .{ .name = name, .rendered = rendered },
- );
-
- return name;
- }
-
- fn renderSliceTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
- std.debug.assert(t.sentinel() == null); // expected canonical type
-
- var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
- defer buffer.deinit();
- const bw = buffer.writer();
-
- var ptr_ty_buf: Type.SlicePtrFieldTypeBuffer = undefined;
- const ptr_ty = t.slicePtrFieldType(&ptr_ty_buf);
- const ptr_name = CValue{ .identifier = "ptr" };
- const len_ty = Type.usize;
- const len_name = CValue{ .identifier = "len" };
-
- try bw.writeAll("typedef struct {\n ");
- try dg.renderTypeAndName(bw, ptr_ty, ptr_name, .Mut, 0, .Complete);
- try bw.writeAll(";\n ");
- try dg.renderTypeAndName(bw, len_ty, len_name, .Mut, 0, .Complete);
-
- try bw.writeAll(";\n} ");
- const name_begin = buffer.items.len;
- try bw.print("zig_{c}_{}", .{
- @as(u8, if (t.isConstPtr()) 'L' else 'M'),
- typeToCIdentifier(t.childType(), dg.module),
- });
- const name_end = buffer.items.len;
- try bw.writeAll(";\n");
-
- const rendered = try buffer.toOwnedSlice();
- errdefer dg.typedefs.allocator.free(rendered);
- const name = rendered[name_begin..name_end];
-
- try dg.typedefs.ensureUnusedCapacity(1);
- dg.typedefs.putAssumeCapacityNoClobber(
- try t.copy(dg.typedefs_arena),
- .{ .name = name, .rendered = rendered },
- );
-
- return name;
- }
-
- fn renderFwdTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
- // The forward declaration for T is stored with a key of *const T.
- const child_ty = t.childType();
-
- var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
- defer buffer.deinit();
- const bw = buffer.writer();
-
- const tag = switch (child_ty.zigTypeTag()) {
- .Struct, .ErrorUnion, .Optional => "struct",
- .Union => if (child_ty.unionTagTypeSafety()) |_| "struct" else "union",
- else => unreachable,
- };
- try bw.writeAll("typedef ");
- try bw.writeAll(tag);
- const name_begin = buffer.items.len + " ".len;
- try bw.writeAll(" zig_");
- switch (child_ty.zigTypeTag()) {
- .Struct, .Union => {
- var fqn_buf = std.ArrayList(u8).init(dg.typedefs.allocator);
- defer fqn_buf.deinit();
-
- const owner_decl_index = child_ty.getOwnerDecl();
- const owner_decl = dg.module.declPtr(owner_decl_index);
- try owner_decl.renderFullyQualifiedName(dg.module, fqn_buf.writer());
-
- try bw.print("S_{}__{d}", .{ fmtIdent(fqn_buf.items), @enumToInt(owner_decl_index) });
- },
- .ErrorUnion => {
- try bw.print("E_{}", .{typeToCIdentifier(child_ty.errorUnionPayload(), dg.module)});
- },
- .Optional => {
- var opt_buf: Type.Payload.ElemType = undefined;
- try bw.print("Q_{}", .{typeToCIdentifier(child_ty.optionalChild(&opt_buf), dg.module)});
- },
- else => unreachable,
- }
- const name_end = buffer.items.len;
- try buffer.ensureUnusedCapacity(" ".len + (name_end - name_begin) + ";\n".len);
- buffer.appendAssumeCapacity(' ');
- buffer.appendSliceAssumeCapacity(buffer.items[name_begin..name_end]);
- buffer.appendSliceAssumeCapacity(";\n");
-
- const rendered = try buffer.toOwnedSlice();
- errdefer dg.typedefs.allocator.free(rendered);
- const name = rendered[name_begin..name_end];
-
- try dg.typedefs.ensureUnusedCapacity(1);
- dg.typedefs.putAssumeCapacityNoClobber(
- try t.copy(dg.typedefs_arena),
- .{ .name = name, .rendered = rendered },
- );
-
- return name;
- }
-
- fn renderStructTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
- var ptr_pl = Type.Payload.ElemType{ .base = .{ .tag = .single_const_pointer }, .data = t };
- const ptr_ty = Type.initPayload(&ptr_pl.base);
- const name = dg.getTypedefName(ptr_ty) orelse
- try dg.renderFwdTypedef(ptr_ty);
-
- var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
- defer buffer.deinit();
-
- try buffer.appendSlice("struct ");
-
- var needs_pack_attr = false;
- {
- var it = t.structFields().iterator();
- while (it.next()) |field| {
- const field_ty = field.value_ptr.ty;
- if (!field_ty.hasRuntimeBits()) continue;
- const alignment = field.value_ptr.abi_align;
- if (alignment != 0 and alignment < field_ty.abiAlignment(dg.module.getTarget())) {
- needs_pack_attr = true;
- try buffer.appendSlice("zig_packed(");
- break;
- }
- }
- }
-
- try buffer.appendSlice(name);
- try buffer.appendSlice(" {\n");
- {
- var it = t.structFields().iterator();
- var empty = true;
- while (it.next()) |field| {
- const field_ty = field.value_ptr.ty;
- if (!field_ty.hasRuntimeBits()) continue;
-
- const alignment = field.value_ptr.alignment(dg.module.getTarget(), t.containerLayout());
- const field_name = CValue{ .identifier = field.key_ptr.* };
- try buffer.append(' ');
- try dg.renderTypeAndName(buffer.writer(), field_ty, field_name, .Mut, alignment, .Complete);
- try buffer.appendSlice(";\n");
-
- empty = false;
- }
- if (empty) try buffer.appendSlice(" char empty_struct;\n");
- }
- if (needs_pack_attr) try buffer.appendSlice("});\n") else try buffer.appendSlice("};\n");
-
- const rendered = try buffer.toOwnedSlice();
- errdefer dg.typedefs.allocator.free(rendered);
-
- try dg.typedefs.ensureUnusedCapacity(1);
- dg.typedefs.putAssumeCapacityNoClobber(
- try t.copy(dg.typedefs_arena),
- .{ .name = name, .rendered = rendered },
- );
-
- return name;
- }
-
- fn renderTupleTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
- var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
- defer buffer.deinit();
-
- try buffer.appendSlice("typedef struct {\n");
- {
- const fields = t.tupleFields();
- var field_id: usize = 0;
- for (fields.types, 0..) |field_ty, i| {
- if (!field_ty.hasRuntimeBits() or fields.values[i].tag() != .unreachable_value) continue;
-
- try buffer.append(' ');
- try dg.renderTypeAndName(buffer.writer(), field_ty, .{ .field = field_id }, .Mut, 0, .Complete);
- try buffer.appendSlice(";\n");
-
- field_id += 1;
- }
- if (field_id == 0) try buffer.appendSlice(" char empty_tuple;\n");
- }
- const name_begin = buffer.items.len + "} ".len;
- try buffer.writer().print("}} zig_T_{}_{d};\n", .{ typeToCIdentifier(t, dg.module), @truncate(u16, t.hash(dg.module)) });
- const name_end = buffer.items.len - ";\n".len;
-
- const rendered = try buffer.toOwnedSlice();
- errdefer dg.typedefs.allocator.free(rendered);
- const name = rendered[name_begin..name_end];
-
- try dg.typedefs.ensureUnusedCapacity(1);
- dg.typedefs.putAssumeCapacityNoClobber(
- try t.copy(dg.typedefs_arena),
- .{ .name = name, .rendered = rendered },
- );
-
- return name;
- }
-
- fn renderUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
- var ptr_pl = Type.Payload.ElemType{ .base = .{ .tag = .single_const_pointer }, .data = t };
- const ptr_ty = Type.initPayload(&ptr_pl.base);
- const name = dg.getTypedefName(ptr_ty) orelse
- try dg.renderFwdTypedef(ptr_ty);
-
- var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
- defer buffer.deinit();
-
- try buffer.appendSlice(if (t.unionTagTypeSafety()) |_| "struct " else "union ");
- try buffer.appendSlice(name);
- try buffer.appendSlice(" {\n");
-
- const indent = if (t.unionTagTypeSafety()) |tag_ty| indent: {
- const target = dg.module.getTarget();
- const layout = t.unionGetLayout(target);
- if (layout.tag_size != 0) {
- try buffer.append(' ');
- try dg.renderTypeAndName(buffer.writer(), tag_ty, .{ .identifier = "tag" }, .Mut, 0, .Complete);
- try buffer.appendSlice(";\n");
- }
- try buffer.appendSlice(" union {\n");
- break :indent " ";
- } else " ";
-
- {
- var it = t.unionFields().iterator();
- var empty = true;
- while (it.next()) |field| {
- const field_ty = field.value_ptr.ty;
- if (!field_ty.hasRuntimeBits()) continue;
-
- const alignment = field.value_ptr.abi_align;
- const field_name = CValue{ .identifier = field.key_ptr.* };
- try buffer.appendSlice(indent);
- try dg.renderTypeAndName(buffer.writer(), field_ty, field_name, .Mut, alignment, .Complete);
- try buffer.appendSlice(";\n");
-
- empty = false;
- }
- if (empty) {
- try buffer.appendSlice(indent);
- try buffer.appendSlice("char empty_union;\n");
- }
- }
-
- if (t.unionTagTypeSafety()) |_| try buffer.appendSlice(" } payload;\n");
- try buffer.appendSlice("};\n");
-
- const rendered = try buffer.toOwnedSlice();
- errdefer dg.typedefs.allocator.free(rendered);
-
- try dg.typedefs.ensureUnusedCapacity(1);
- dg.typedefs.putAssumeCapacityNoClobber(
- try t.copy(dg.typedefs_arena),
- .{ .name = name, .rendered = rendered },
- );
-
- return name;
- }
-
- fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
- assert(t.errorUnionSet().tag() == .anyerror);
-
- var ptr_pl = Type.Payload.ElemType{ .base = .{ .tag = .single_const_pointer }, .data = t };
- const ptr_ty = Type.initPayload(&ptr_pl.base);
- const name = dg.getTypedefName(ptr_ty) orelse
- try dg.renderFwdTypedef(ptr_ty);
-
- var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
- defer buffer.deinit();
- const bw = buffer.writer();
-
- const payload_ty = t.errorUnionPayload();
- const payload_name = CValue{ .identifier = "payload" };
- const error_ty = t.errorUnionSet();
- const error_name = CValue{ .identifier = "error" };
-
- const target = dg.module.getTarget();
- const payload_align = payload_ty.abiAlignment(target);
- const error_align = error_ty.abiAlignment(target);
- try bw.writeAll("struct ");
- try bw.writeAll(name);
- try bw.writeAll(" {\n ");
- if (error_align > payload_align) {
- try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0, .Complete);
- try bw.writeAll(";\n ");
- try dg.renderTypeAndName(bw, error_ty, error_name, .Mut, 0, .Complete);
- } else {
- try dg.renderTypeAndName(bw, error_ty, error_name, .Mut, 0, .Complete);
- try bw.writeAll(";\n ");
- try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0, .Complete);
- }
- try bw.writeAll(";\n};\n");
-
- const rendered = try buffer.toOwnedSlice();
- errdefer dg.typedefs.allocator.free(rendered);
-
- try dg.typedefs.ensureUnusedCapacity(1);
- dg.typedefs.putAssumeCapacityNoClobber(
- try t.copy(dg.typedefs_arena),
- .{ .name = name, .rendered = rendered },
- );
-
- return name;
- }
-
- fn renderArrayTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
- const info = t.arrayInfo();
- std.debug.assert(info.sentinel == null); // expected canonical type
-
- var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
- defer buffer.deinit();
- const bw = buffer.writer();
-
- try bw.writeAll("typedef ");
- try dg.renderType(bw, info.elem_type, .Complete);
-
- const name_begin = buffer.items.len + " ".len;
- try bw.print(" zig_A_{}_{d}", .{ typeToCIdentifier(info.elem_type, dg.module), info.len });
- const name_end = buffer.items.len;
-
- const c_len = if (info.len > 0) info.len else 1;
- var c_len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = c_len };
- const c_len_val = Value.initPayload(&c_len_pl.base);
- try bw.print("[{}];\n", .{try dg.fmtIntLiteral(Type.usize, c_len_val)});
-
- const rendered = try buffer.toOwnedSlice();
- errdefer dg.typedefs.allocator.free(rendered);
- const name = rendered[name_begin..name_end];
-
- try dg.typedefs.ensureUnusedCapacity(1);
- dg.typedefs.putAssumeCapacityNoClobber(
- try t.copy(dg.typedefs_arena),
- .{ .name = name, .rendered = rendered },
- );
-
- return name;
- }
-
- fn renderOptionalTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
- var ptr_pl = Type.Payload.ElemType{ .base = .{ .tag = .single_const_pointer }, .data = t };
- const ptr_ty = Type.initPayload(&ptr_pl.base);
- const name = dg.getTypedefName(ptr_ty) orelse
- try dg.renderFwdTypedef(ptr_ty);
-
- var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
- defer buffer.deinit();
- const bw = buffer.writer();
-
- var opt_buf: Type.Payload.ElemType = undefined;
- const child_ty = t.optionalChild(&opt_buf);
-
- try bw.writeAll("struct ");
- try bw.writeAll(name);
- try bw.writeAll(" {\n");
- try dg.renderTypeAndName(bw, child_ty, .{ .identifier = "payload" }, .Mut, 0, .Complete);
- try bw.writeAll(";\n ");
- try dg.renderTypeAndName(bw, Type.bool, .{ .identifier = "is_null" }, .Mut, 0, .Complete);
- try bw.writeAll(";\n};\n");
-
- const rendered = try buffer.toOwnedSlice();
- errdefer dg.typedefs.allocator.free(rendered);
-
- try dg.typedefs.ensureUnusedCapacity(1);
- dg.typedefs.putAssumeCapacityNoClobber(
- try t.copy(dg.typedefs_arena),
- .{ .name = name, .rendered = rendered },
- );
-
- return name;
- }
-
- fn renderOpaqueTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
- const opaque_ty = t.cast(Type.Payload.Opaque).?.data;
- const unqualified_name = dg.module.declPtr(opaque_ty.owner_decl).name;
- const fqn = try opaque_ty.getFullyQualifiedName(dg.module);
- defer dg.typedefs.allocator.free(fqn);
-
- var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
- defer buffer.deinit();
-
- try buffer.writer().print("typedef struct { } ", .{fmtIdent(std.mem.span(unqualified_name))});
-
- const name_begin = buffer.items.len;
- try buffer.writer().print("zig_O_{}", .{fmtIdent(fqn)});
- const name_end = buffer.items.len;
- try buffer.appendSlice(";\n");
-
- const rendered = try buffer.toOwnedSlice();
- errdefer dg.typedefs.allocator.free(rendered);
- const name = rendered[name_begin..name_end];
-
- try dg.typedefs.ensureUnusedCapacity(1);
- dg.typedefs.putAssumeCapacityNoClobber(
- try t.copy(dg.typedefs_arena),
- .{ .name = name, .rendered = rendered },
- );
-
- return name;
- }
-
fn indexToCType(dg: *DeclGen, idx: CType.Index) CType {
return dg.ctypes.indexToCType(idx);
}
@@ -2408,31 +1951,27 @@ pub const DeclGen = struct {
const idx = try dg.typeToIndex(ty);
try w.print("{}", .{try dg.renderTypePrefix(w, idx, .suffix, CQualifiers.init(.{
.@"const" = switch (mutability) {
- .Const, .ConstArgument => true,
- .Mut => false,
+ .mut => false,
+ .@"const" => true,
},
}))});
try dg.writeCValue(w, name);
try dg.renderTypeSuffix(w, idx, .suffix);
}
- fn renderTagNameFn(dg: *DeclGen, enum_ty: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
- var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
- defer buffer.deinit();
- const bw = buffer.writer();
-
+ fn renderTagNameFn(dg: *DeclGen, w: anytype, fn_name: []const u8, enum_ty: Type) !void {
const name_slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
- try buffer.appendSlice("static ");
- try dg.renderType(bw, name_slice_ty, .Complete);
- const name_begin = buffer.items.len + " ".len;
- try bw.print(" zig_tagName_{}_{d}(", .{ typeToCIdentifier(enum_ty, dg.module), @enumToInt(enum_ty.getOwnerDecl()) });
- const name_end = buffer.items.len - "(".len;
- try dg.renderTypeAndName(bw, enum_ty, .{ .identifier = "tag" }, .Const, 0, .Complete);
- try buffer.appendSlice(") {\n switch (tag) {\n");
+ try w.writeAll("static ");
+ try dg.renderType(w, name_slice_ty, .Complete);
+ try w.writeByte(' ');
+ try w.writeAll(fn_name);
+ try w.writeByte('(');
+ try dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, .@"const", 0, .Complete);
+ try w.writeAll(") {\n switch (tag) {\n");
for (enum_ty.enumFields().keys(), 0..) |name, index| {
- const name_z = try dg.typedefs.allocator.dupeZ(u8, name);
- defer dg.typedefs.allocator.free(name_z);
+ const name_z = try dg.gpa.dupeZ(u8, name);
+ defer dg.gpa.free(name_z);
const name_bytes = name_z[0 .. name_z.len + 1];
var tag_pl: Value.Payload.U32 = .{
@@ -2453,40 +1992,23 @@ pub const DeclGen = struct {
var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len };
const len_val = Value.initPayload(&len_pl.base);
- try bw.print(" case {}: {{\n static ", .{try dg.fmtIntLiteral(enum_ty, int_val)});
- try dg.renderTypeAndName(bw, name_ty, .{ .identifier = "name" }, .Const, 0, .Complete);
- try buffer.appendSlice(" = ");
- try dg.renderValue(bw, name_ty, name_val, .Initializer);
- try buffer.appendSlice(";\n return (");
- try dg.renderTypecast(bw, name_slice_ty);
- try bw.print("){{{}, {}}};\n", .{
+ try w.print(" case {}: {{\n static ", .{try dg.fmtIntLiteral(enum_ty, int_val)});
+ try dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, .@"const", 0, .Complete);
+ try w.writeAll(" = ");
+ try dg.renderValue(w, name_ty, name_val, .Initializer);
+ try w.writeAll(";\n return (");
+ try dg.renderTypecast(w, name_slice_ty);
+ try w.print("){{{}, {}}};\n", .{
fmtIdent("name"), try dg.fmtIntLiteral(Type.usize, len_val),
});
- try buffer.appendSlice(" }\n");
+ try w.writeAll(" }\n");
}
- try buffer.appendSlice(" }\n while (");
- try dg.renderValue(bw, Type.bool, Value.true, .Other);
- try buffer.appendSlice(") ");
- _ = try airBreakpoint(bw);
- try buffer.appendSlice("}\n");
-
- const rendered = try buffer.toOwnedSlice();
- errdefer dg.typedefs.allocator.free(rendered);
- const name = rendered[name_begin..name_end];
-
- try dg.typedefs.ensureUnusedCapacity(1);
- dg.typedefs.putAssumeCapacityNoClobber(
- try enum_ty.copy(dg.typedefs_arena),
- .{ .name = name, .rendered = rendered },
- );
-
- return name;
- }
-
- fn getTagNameFn(dg: *DeclGen, enum_ty: Type) ![]const u8 {
- return dg.getTypedefName(enum_ty) orelse
- try dg.renderTagNameFn(enum_ty);
+ try w.writeAll(" }\n while (");
+ try dg.renderValue(w, Type.bool, Value.true, .Other);
+ try w.writeAll(") ");
+ _ = try airBreakpoint(w);
+ try w.writeAll("}\n");
}
fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool {
@@ -2724,7 +2246,7 @@ pub fn genErrDecls(o: *Object) !void {
const name_val = Value.initPayload(&name_pl.base);
try writer.writeAll("static ");
- try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .Const, 0, .Complete);
+ try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .@"const", 0, .Complete);
try writer.writeAll(" = ");
try o.dg.renderValue(writer, name_ty, name_val, .StaticInitializer);
try writer.writeAll(";\n");
@@ -2737,7 +2259,7 @@ pub fn genErrDecls(o: *Object) !void {
const name_array_ty = Type.initPayload(&name_array_ty_pl.base);
try writer.writeAll("static ");
- try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = name_prefix }, .Const, 0, .Complete);
+ try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = name_prefix }, .@"const", 0, .Complete);
try writer.writeAll(" = {");
for (o.dg.module.error_name_list.items, 0..) |name, value| {
if (value != 0) try writer.writeByte(',');
@@ -2767,6 +2289,17 @@ fn genExports(o: *Object) !void {
};
}
+pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
+ const writer = o.writer();
+ switch (lazy_fn.key_ptr.*) {
+ .tag_name => _ = try o.dg.renderTagNameFn(
+ writer,
+ lazy_fn.value_ptr.fn_name,
+ lazy_fn.value_ptr.data.tag_name,
+ ),
+ }
+}
+
pub fn genFunc(f: *Function) !void {
const tracy = trace(@src());
defer tracy.end();
@@ -2845,7 +2378,7 @@ pub fn genFunc(f: *Function) !void {
w,
local.ty,
.{ .local = local_index },
- .Mut,
+ .mut,
local.alignment,
.Complete,
);
@@ -2886,7 +2419,7 @@ pub fn genDecl(o: *Object) !void {
try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
if (variable.is_threadlocal) try fwd_decl_writer.writeAll("zig_threadlocal ");
- try o.dg.renderTypeAndName(fwd_decl_writer, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete);
+ try o.dg.renderTypeAndName(fwd_decl_writer, o.dg.decl.ty, decl_c_value, .mut, o.dg.decl.@"align", .Complete);
try fwd_decl_writer.writeAll(";\n");
try genExports(o);
@@ -2896,7 +2429,7 @@ pub fn genDecl(o: *Object) !void {
if (!is_global) try w.writeAll("static ");
if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");
if (o.dg.decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});
- try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete);
+ try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .mut, o.dg.decl.@"align", .Complete);
if (o.dg.decl.@"linksection" != null) try w.writeAll(", read, write)");
try w.writeAll(" = ");
try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer);
@@ -2908,13 +2441,13 @@ pub fn genDecl(o: *Object) !void {
const decl_c_value: CValue = .{ .decl = o.dg.decl_index };
try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
- try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, .Const, o.dg.decl.@"align", .Complete);
+ try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, .@"const", o.dg.decl.@"align", .Complete);
try fwd_decl_writer.writeAll(";\n");
const w = o.writer();
if (!is_global) try w.writeAll("static ");
if (o.dg.decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});
- try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .Const, o.dg.decl.@"align", .Complete);
+ try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .@"const", o.dg.decl.@"align", .Complete);
if (o.dg.decl.@"linksection" != null) try w.writeAll(", read)");
try w.writeAll(" = ");
try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer);
@@ -3443,7 +2976,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
return CValue{ .undef = inst_ty };
}
- const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;
+ const mutability: Mutability = if (inst_ty.isConstPtr()) .@"const" else .mut;
const target = f.object.dg.module.getTarget();
const local = try f.allocAlignedLocal(elem_type, mutability, inst_ty.ptrAlignment(target));
log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.local });
@@ -3460,7 +2993,7 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
return CValue{ .undef = inst_ty };
}
- const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;
+ const mutability: Mutability = if (inst_ty.isConstPtr()) .@"const" else .mut;
const target = f.object.dg.module.getTarget();
const local = try f.allocAlignedLocal(elem_ty, mutability, inst_ty.ptrAlignment(target));
log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.local });
@@ -4937,7 +4470,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
writer,
output_ty,
local_value,
- .Mut,
+ .mut,
alignment,
.Complete,
);
@@ -4976,7 +4509,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
writer,
input_ty,
local_value,
- .Const,
+ .@"const",
alignment,
.Complete,
);
@@ -6474,7 +6007,7 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
try f.writeCValue(writer, local, .Other);
- try writer.print(" = {s}(", .{try f.object.dg.getTagNameFn(enum_ty)});
+ try writer.print(" = {s}(", .{try f.getTagNameFn(enum_ty)});
try f.writeCValue(writer, operand, .Other);
try writer.writeAll(");\n");
src/link/C.zig
@@ -22,26 +22,19 @@ base: link.File,
/// Instead, it tracks all declarations in this table, and iterates over it
/// in the flush function, stitching pre-rendered pieces of C code together.
decl_table: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclBlock) = .{},
-/// Stores Type/Value data for `typedefs` to reference.
-/// Accumulates allocations and then there is a periodic garbage collection after flush().
-arena: std.heap.ArenaAllocator,
/// Per-declaration data.
const DeclBlock = struct {
code: std.ArrayListUnmanaged(u8) = .{},
fwd_decl: std.ArrayListUnmanaged(u8) = .{},
+ /// Each `Decl` stores a set of used `CType`s. In `flush()`, we iterate
+ /// over each `Decl` and generate the definition for each used `CType` once.
ctypes: codegen.CType.Store = .{},
- /// Each Decl stores a mapping of Zig Types to corresponding C types, for every
- /// Zig Type used by the Decl. In flush(), we iterate over each Decl
- /// and emit the typedef code for all types, making sure to not emit the same thing twice.
- /// Any arena memory the Type points to lives in the `arena` field of `C`.
- typedefs: codegen.TypedefMap.Unmanaged = .{},
+ /// Key and Value storage use the ctype arena.
+ lazy_fns: codegen.LazyFnMap = .{},
fn deinit(db: *DeclBlock, gpa: Allocator) void {
- for (db.typedefs.values()) |typedef| {
- gpa.free(typedef.rendered);
- }
- db.typedefs.deinit(gpa);
+ db.lazy_fns.deinit(gpa);
db.ctypes.deinit(gpa);
db.fwd_decl.deinit(gpa);
db.code.deinit(gpa);
@@ -66,7 +59,6 @@ pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C
errdefer gpa.destroy(c_file);
c_file.* = C{
- .arena = std.heap.ArenaAllocator.init(gpa),
.base = .{
.tag = .c,
.options = options,
@@ -85,8 +77,6 @@ pub fn deinit(self: *C) void {
db.deinit(gpa);
}
self.decl_table.deinit(gpa);
-
- self.arena.deinit();
}
pub fn freeDecl(self: *C, decl_index: Module.Decl.Index) void {
@@ -101,44 +91,42 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes
const tracy = trace(@src());
defer tracy.end();
+ const gpa = self.base.allocator;
+
const decl_index = func.owner_decl;
- const gop = try self.decl_table.getOrPut(self.base.allocator, decl_index);
+ const gop = try self.decl_table.getOrPut(gpa, decl_index);
if (!gop.found_existing) {
gop.value_ptr.* = .{};
}
- const fwd_decl = &gop.value_ptr.fwd_decl;
const ctypes = &gop.value_ptr.ctypes;
- const typedefs = &gop.value_ptr.typedefs;
+ const lazy_fns = &gop.value_ptr.lazy_fns;
+ const fwd_decl = &gop.value_ptr.fwd_decl;
const code = &gop.value_ptr.code;
+ ctypes.clearRetainingCapacity(gpa);
+ lazy_fns.clearRetainingCapacity();
fwd_decl.shrinkRetainingCapacity(0);
- ctypes.clearRetainingCapacity(module.gpa);
- for (typedefs.values()) |typedef| {
- module.gpa.free(typedef.rendered);
- }
- typedefs.clearRetainingCapacity();
code.shrinkRetainingCapacity(0);
var function: codegen.Function = .{
- .value_map = codegen.CValueMap.init(module.gpa),
+ .value_map = codegen.CValueMap.init(gpa),
.air = air,
.liveness = liveness,
.func = func,
.object = .{
.dg = .{
- .gpa = module.gpa,
+ .gpa = gpa,
.module = module,
.error_msg = null,
.decl_index = decl_index,
.decl = module.declPtr(decl_index),
- .fwd_decl = fwd_decl.toManaged(module.gpa),
+ .fwd_decl = fwd_decl.toManaged(gpa),
.ctypes = ctypes.*,
- .typedefs = typedefs.promoteContext(module.gpa, .{ .mod = module }),
- .typedefs_arena = self.arena.allocator(),
},
- .code = code.toManaged(module.gpa),
+ .code = code.toManaged(gpa),
.indent_writer = undefined, // set later so we can get a pointer to object.code
},
- .arena = std.heap.ArenaAllocator.init(module.gpa),
+ .lazy_fns = lazy_fns.*,
+ .arena = std.heap.ArenaAllocator.init(gpa),
};
function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };
@@ -146,91 +134,79 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes
codegen.genFunc(&function) catch |err| switch (err) {
error.AnalysisFail => {
- try module.failed_decls.put(module.gpa, decl_index, function.object.dg.error_msg.?);
+ try module.failed_decls.put(gpa, decl_index, function.object.dg.error_msg.?);
return;
},
else => |e| return e,
};
- fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();
ctypes.* = function.object.dg.ctypes.move();
- typedefs.* = function.object.dg.typedefs.unmanaged;
- function.object.dg.typedefs.unmanaged = .{};
+ lazy_fns.* = function.lazy_fns.move();
+ fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();
code.* = function.object.code.moveToUnmanaged();
// Free excess allocated memory for this Decl.
- fwd_decl.shrinkAndFree(module.gpa, fwd_decl.items.len);
- code.shrinkAndFree(module.gpa, code.items.len);
- ctypes.shrinkAndFree(module.gpa);
+ ctypes.shrinkToFit(gpa);
+ lazy_fns.shrinkAndFree(gpa, lazy_fns.count());
+ fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len);
+ code.shrinkAndFree(gpa, code.items.len);
}
pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !void {
const tracy = trace(@src());
defer tracy.end();
- const gop = try self.decl_table.getOrPut(self.base.allocator, decl_index);
+ const gpa = self.base.allocator;
+
+ const gop = try self.decl_table.getOrPut(gpa, decl_index);
if (!gop.found_existing) {
gop.value_ptr.* = .{};
}
- const fwd_decl = &gop.value_ptr.fwd_decl;
const ctypes = &gop.value_ptr.ctypes;
- const typedefs = &gop.value_ptr.typedefs;
+ const fwd_decl = &gop.value_ptr.fwd_decl;
const code = &gop.value_ptr.code;
+ ctypes.clearRetainingCapacity(gpa);
fwd_decl.shrinkRetainingCapacity(0);
- ctypes.clearRetainingCapacity(module.gpa);
- for (typedefs.values()) |value| {
- module.gpa.free(value.rendered);
- }
- typedefs.clearRetainingCapacity();
code.shrinkRetainingCapacity(0);
const decl = module.declPtr(decl_index);
var object: codegen.Object = .{
.dg = .{
- .gpa = module.gpa,
+ .gpa = gpa,
.module = module,
.error_msg = null,
.decl_index = decl_index,
.decl = decl,
- .fwd_decl = fwd_decl.toManaged(module.gpa),
+ .fwd_decl = fwd_decl.toManaged(gpa),
.ctypes = ctypes.*,
- .typedefs = typedefs.promoteContext(module.gpa, .{ .mod = module }),
- .typedefs_arena = self.arena.allocator(),
},
- .code = code.toManaged(module.gpa),
+ .code = code.toManaged(gpa),
.indent_writer = undefined, // set later so we can get a pointer to object.code
};
object.indent_writer = .{ .underlying_writer = object.code.writer() };
defer {
object.code.deinit();
- for (object.dg.typedefs.values()) |typedef| {
- module.gpa.free(typedef.rendered);
- }
- object.dg.typedefs.deinit();
object.dg.ctypes.deinit(object.dg.gpa);
object.dg.fwd_decl.deinit();
}
codegen.genDecl(&object) catch |err| switch (err) {
error.AnalysisFail => {
- try module.failed_decls.put(module.gpa, decl_index, object.dg.error_msg.?);
+ try module.failed_decls.put(gpa, decl_index, object.dg.error_msg.?);
return;
},
else => |e| return e,
};
+ ctypes.* = object.dg.ctypes.move();
fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
- ctypes.* = object.dg.ctypes;
- object.dg.ctypes = .{};
- typedefs.* = object.dg.typedefs.unmanaged;
- object.dg.typedefs.unmanaged = .{};
code.* = object.code.moveToUnmanaged();
// Free excess allocated memory for this Decl.
- fwd_decl.shrinkAndFree(module.gpa, fwd_decl.items.len);
- code.shrinkAndFree(module.gpa, code.items.len);
- ctypes.shrinkAndFree(module.gpa);
+ ctypes.shrinkToFit(gpa);
+ fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len);
+ code.shrinkAndFree(gpa, code.items.len);
}
pub fn updateDeclLineNumber(self: *C, module: *Module, decl_index: Module.Decl.Index) !void {
@@ -260,7 +236,7 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
sub_prog_node.activate();
defer sub_prog_node.end();
- const gpa = comp.gpa;
+ const gpa = self.base.allocator;
const module = self.base.options.module.?;
// This code path happens exclusively with -ofmt=c. The flush logic for
@@ -271,19 +247,17 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
const abi_define = abiDefine(comp);
- // Covers defines, zig.h, typedef, and asm.
- var buf_count: usize = 2;
- if (abi_define != null) buf_count += 1;
- try f.all_buffers.ensureUnusedCapacity(gpa, buf_count);
+ // Covers defines, zig.h, ctypes, asm.
+ try f.all_buffers.ensureUnusedCapacity(gpa, 4);
if (abi_define) |buf| f.appendBufAssumeCapacity(buf);
f.appendBufAssumeCapacity(zig_h);
- const typedef_index = f.all_buffers.items.len;
+ const ctypes_index = f.all_buffers.items.len;
f.all_buffers.items.len += 1;
{
- var asm_buf = f.asm_buf.toManaged(module.gpa);
+ var asm_buf = f.asm_buf.toManaged(gpa);
defer asm_buf.deinit();
try codegen.genGlobalAsm(module, &asm_buf);
@@ -294,7 +268,7 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
try self.flushErrDecls(&f);
- // Typedefs, forward decls, and non-functions first.
+ // `CType`s, forward decls, and non-functions first.
// Unlike other backends, the .c code we are emitting is order-dependent. Therefore
// we must traverse the set of Decls that we are emitting according to their dependencies.
// Our strategy is to populate a set of remaining decls, pop Decls one by one,
@@ -321,11 +295,11 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
}
}
- f.all_buffers.items[typedef_index] = .{
- .iov_base = if (f.typedef_buf.items.len > 0) f.typedef_buf.items.ptr else "",
- .iov_len = f.typedef_buf.items.len,
+ f.all_buffers.items[ctypes_index] = .{
+ .iov_base = if (f.ctypes_buf.items.len > 0) f.ctypes_buf.items.ptr else "",
+ .iov_len = f.ctypes_buf.items.len,
};
- f.file_size += f.typedef_buf.items.len;
+ f.file_size += f.ctypes_buf.items.len;
// Now the code.
try f.all_buffers.ensureUnusedCapacity(gpa, decl_values.len);
@@ -338,31 +312,23 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
}
const Flush = struct {
- err_decls: DeclBlock = .{},
remaining_decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void) = .{},
- ctypes: CTypes = .{},
- typedefs: Typedefs = .{},
- typedef_buf: std.ArrayListUnmanaged(u8) = .{},
+ ctypes: codegen.CType.Store = .{},
+ ctypes_map: std.ArrayListUnmanaged(codegen.CType.Index) = .{},
+ ctypes_buf: std.ArrayListUnmanaged(u8) = .{},
+
+ err_decls: DeclBlock = .{},
+
+ lazy_fns: LazyFns = .{},
+
asm_buf: std.ArrayListUnmanaged(u8) = .{},
/// We collect a list of buffers to write, and write them all at once with pwritev ๐
all_buffers: std.ArrayListUnmanaged(std.os.iovec_const) = .{},
/// Keeps track of the total bytes of `all_buffers`.
file_size: u64 = 0,
- const CTypes = std.ArrayHashMapUnmanaged(
- codegen.CType,
- void,
- codegen.CType.HashContext32,
- true,
- );
-
- const Typedefs = std.HashMapUnmanaged(
- Type,
- void,
- Type.HashContext64,
- std.hash_map.default_max_load_percentage,
- );
+ const LazyFns = std.AutoHashMapUnmanaged(codegen.LazyFnKey, DeclBlock);
fn appendBufAssumeCapacity(f: *Flush, buf: []const u8) void {
if (buf.len == 0) return;
@@ -372,11 +338,14 @@ const Flush = struct {
fn deinit(f: *Flush, gpa: Allocator) void {
f.all_buffers.deinit(gpa);
- f.typedef_buf.deinit(gpa);
- f.typedefs.deinit(gpa);
+ var lazy_fns_it = f.lazy_fns.valueIterator();
+ while (lazy_fns_it.next()) |db| db.deinit(gpa);
+ f.lazy_fns.deinit(gpa);
+ f.err_decls.deinit(gpa);
+ f.ctypes_buf.deinit(gpa);
+ f.ctypes_map.deinit(gpa);
f.ctypes.deinit(gpa);
f.remaining_decls.deinit(gpa);
- f.err_decls.deinit(gpa);
}
};
@@ -384,56 +353,36 @@ const FlushDeclError = error{
OutOfMemory,
};
-fn flushTypedefs(self: *C, f: *Flush, typedefs: codegen.TypedefMap.Unmanaged) FlushDeclError!void {
- if (typedefs.count() == 0) return;
- const gpa = self.base.allocator;
- const module = self.base.options.module.?;
-
- try f.typedefs.ensureUnusedCapacityContext(gpa, @intCast(u32, typedefs.count()), .{
- .mod = module,
- });
- var it = typedefs.iterator();
- while (it.next()) |new| {
- const gop = f.typedefs.getOrPutAssumeCapacityContext(new.key_ptr.*, .{
- .mod = module,
- });
- if (!gop.found_existing) {
- try f.typedef_buf.appendSlice(gpa, new.value_ptr.rendered);
- }
- }
+fn flushCTypes(self: *C, f: *Flush, ctypes: codegen.CType.Store) FlushDeclError!void {
+ _ = self;
+ _ = f;
+ _ = ctypes;
}
fn flushErrDecls(self: *C, f: *Flush) FlushDeclError!void {
- const module = self.base.options.module.?;
+ const gpa = self.base.allocator;
const fwd_decl = &f.err_decls.fwd_decl;
const ctypes = &f.err_decls.ctypes;
- const typedefs = &f.err_decls.typedefs;
const code = &f.err_decls.code;
var object = codegen.Object{
.dg = .{
- .gpa = module.gpa,
- .module = module,
+ .gpa = gpa,
+ .module = self.base.options.module.?,
.error_msg = null,
.decl_index = undefined,
.decl = undefined,
- .fwd_decl = fwd_decl.toManaged(module.gpa),
+ .fwd_decl = fwd_decl.toManaged(gpa),
.ctypes = ctypes.*,
- .typedefs = typedefs.promoteContext(module.gpa, .{ .mod = module }),
- .typedefs_arena = self.arena.allocator(),
},
- .code = code.toManaged(module.gpa),
+ .code = code.toManaged(gpa),
.indent_writer = undefined, // set later so we can get a pointer to object.code
};
object.indent_writer = .{ .underlying_writer = object.code.writer() };
defer {
object.code.deinit();
- object.dg.ctypes.deinit(module.gpa);
- for (object.dg.typedefs.values()) |typedef| {
- module.gpa.free(typedef.rendered);
- }
- object.dg.typedefs.deinit();
+ object.dg.ctypes.deinit(gpa);
object.dg.fwd_decl.deinit();
}
@@ -443,16 +392,75 @@ fn flushErrDecls(self: *C, f: *Flush) FlushDeclError!void {
};
fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
- typedefs.* = object.dg.typedefs.unmanaged;
- object.dg.typedefs.unmanaged = .{};
+ ctypes.* = object.dg.ctypes.move();
+ code.* = object.code.moveToUnmanaged();
+
+ try self.flushCTypes(f, ctypes.*);
+ try f.all_buffers.ensureUnusedCapacity(gpa, 2);
+ f.appendBufAssumeCapacity(fwd_decl.items);
+ f.appendBufAssumeCapacity(code.items);
+}
+
+fn flushLazyFn(
+ self: *C,
+ f: *Flush,
+ db: *DeclBlock,
+ lazy_fn: codegen.LazyFnMap.Entry,
+) FlushDeclError!void {
+ const gpa = self.base.allocator;
+
+ const fwd_decl = &db.fwd_decl;
+ const ctypes = &db.ctypes;
+ const code = &db.code;
+
+ var object = codegen.Object{
+ .dg = .{
+ .gpa = gpa,
+ .module = self.base.options.module.?,
+ .error_msg = null,
+ .decl_index = undefined,
+ .decl = undefined,
+ .fwd_decl = fwd_decl.toManaged(gpa),
+ .ctypes = ctypes.*,
+ },
+ .code = code.toManaged(gpa),
+ .indent_writer = undefined, // set later so we can get a pointer to object.code
+ };
+ object.indent_writer = .{ .underlying_writer = object.code.writer() };
+ defer {
+ object.code.deinit();
+ object.dg.ctypes.deinit(gpa);
+ object.dg.fwd_decl.deinit();
+ }
+
+ codegen.genLazyFn(&object, lazy_fn) catch |err| switch (err) {
+ error.AnalysisFail => unreachable,
+ else => |e| return e,
+ };
+
+ fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
+ ctypes.* = object.dg.ctypes.move();
code.* = object.code.moveToUnmanaged();
- try self.flushTypedefs(f, typedefs.*);
- try f.all_buffers.ensureUnusedCapacity(self.base.allocator, 1);
+ try self.flushCTypes(f, ctypes.*);
+ try f.all_buffers.ensureUnusedCapacity(gpa, 2);
f.appendBufAssumeCapacity(fwd_decl.items);
f.appendBufAssumeCapacity(code.items);
}
+fn flushLazyFns(self: *C, f: *Flush, lazy_fns: codegen.LazyFnMap) FlushDeclError!void {
+ const gpa = self.base.allocator;
+ try f.lazy_fns.ensureUnusedCapacity(gpa, @intCast(Flush.LazyFns.Size, lazy_fns.count()));
+
+ var it = lazy_fns.iterator();
+ while (it.next()) |entry| {
+ const gop = f.lazy_fns.getOrPutAssumeCapacity(entry.key_ptr.*);
+ if (gop.found_existing) continue;
+ gop.value_ptr.* = .{};
+ try self.flushLazyFn(f, gop.value_ptr, entry);
+ }
+}
+
/// Assumes `decl` was in the `remaining_decls` set, and has already been removed.
fn flushDecl(
self: *C,
@@ -460,8 +468,8 @@ fn flushDecl(
decl_index: Module.Decl.Index,
export_names: std.StringHashMapUnmanaged(void),
) FlushDeclError!void {
- const module = self.base.options.module.?;
- const decl = module.declPtr(decl_index);
+ const gpa = self.base.allocator;
+ const decl = self.base.options.module.?.declPtr(decl_index);
// Before flushing any particular Decl we must ensure its
// dependencies are already flushed, so that the order in the .c
// file comes out correctly.
@@ -472,10 +480,10 @@ fn flushDecl(
}
const decl_block = self.decl_table.getPtr(decl_index).?;
- const gpa = self.base.allocator;
- try self.flushTypedefs(f, decl_block.typedefs);
- try f.all_buffers.ensureUnusedCapacity(gpa, 2);
+ try self.flushCTypes(f, decl_block.ctypes);
+ try self.flushLazyFns(f, decl_block.lazy_fns);
+ try f.all_buffers.ensureUnusedCapacity(gpa, 1);
if (!(decl.isExtern() and export_names.contains(mem.span(decl.name))))
f.appendBufAssumeCapacity(decl_block.fwd_decl.items);
}
src/Compilation.zig
@@ -3277,14 +3277,9 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
.decl = decl,
.fwd_decl = fwd_decl.toManaged(gpa),
.ctypes = .{},
- .typedefs = c_codegen.TypedefMap.initContext(gpa, .{ .mod = module }),
- .typedefs_arena = ctypes_arena.allocator(),
};
defer {
- for (dg.typedefs.values()) |typedef| {
- module.gpa.free(typedef.rendered);
- }
- dg.typedefs.deinit();
+ dg.ctypes.deinit(gpa);
dg.fwd_decl.deinit();
}