CBE: remove typedef data structures
Adds a new mechanism for `@tagName` function generation that doesn't piggyback on the removed typedef system.
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
274
src/link/C.zig
274
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.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 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.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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user