diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2022-04-19 21:51:08 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2022-04-20 17:37:35 -0700 |
| commit | f7596ae9423e9de8276629803147e1a243f2177b (patch) | |
| tree | b97f2a8e8fdb84a118f587bcbfd76918710587dd /src/codegen/c.zig | |
| parent | 4f527e5d36f66a83ff6a263a03f16e2c4d049f1e (diff) | |
| download | zig-f7596ae9423e9de8276629803147e1a243f2177b.tar.gz zig-f7596ae9423e9de8276629803147e1a243f2177b.zip | |
stage2: use indexes for Decl objects
Rather than allocating Decl objects with an Allocator, we instead allocate
them with a SegmentedList. This provides four advantages:
* Stable memory so that one thread can access a Decl object while another
thread allocates additional Decl objects from this list.
* It allows us to use u32 indexes to reference Decl objects rather than
pointers, saving memory in Type, Value, and dependency sets.
* Using integers to reference Decl objects rather than pointers makes
serialization trivial.
* It provides a unique integer to be used for anonymous symbol names,
avoiding multi-threaded contention on an atomic counter.
Diffstat (limited to 'src/codegen/c.zig')
| -rw-r--r-- | src/codegen/c.zig | 87 |
1 files changed, 43 insertions, 44 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 54f8285291..a0b1bc30b9 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -32,8 +32,8 @@ pub const CValue = union(enum) { /// Index into the parameters arg: usize, /// By-value - decl: *Decl, - decl_ref: *Decl, + decl: Decl.Index, + decl_ref: Decl.Index, /// An undefined (void *) pointer (cannot be dereferenced) undefined_ptr: void, /// Render the slice as an identifier (using fmtIdent) @@ -58,7 +58,7 @@ pub const TypedefMap = std.ArrayHashMap( const FormatTypeAsCIdentContext = struct { ty: Type, - target: std.Target, + mod: *Module, }; /// TODO make this not cut off at 128 bytes @@ -71,14 +71,14 @@ fn formatTypeAsCIdentifier( _ = fmt; _ = options; var buffer = [1]u8{0} ** 128; - var buf = std.fmt.bufPrint(&buffer, "{}", .{data.ty.fmt(data.target)}) catch &buffer; + var buf = std.fmt.bufPrint(&buffer, "{}", .{data.ty.fmt(data.mod)}) catch &buffer; return formatIdent(buf, "", .{}, writer); } -pub fn typeToCIdentifier(ty: Type, target: std.Target) std.fmt.Formatter(formatTypeAsCIdentifier) { +pub fn typeToCIdentifier(ty: Type, mod: *Module) std.fmt.Formatter(formatTypeAsCIdentifier) { return .{ .data = .{ .ty = ty, - .target = target, + .mod = mod, } }; } @@ -349,6 +349,7 @@ pub const DeclGen = struct { gpa: std.mem.Allocator, module: *Module, decl: *Decl, + decl_index: Decl.Index, fwd_decl: std.ArrayList(u8), error_msg: ?*Module.ErrorMsg, /// The key of this map is Type which has references to typedefs_arena. @@ -376,10 +377,8 @@ pub const DeclGen = struct { writer: anytype, ty: Type, val: Value, - decl: *Decl, + decl_index: Decl.Index, ) error{ OutOfMemory, AnalysisFail }!void { - const target = dg.module.getTarget(); - if (ty.isSlice()) { try writer.writeByte('('); try dg.renderTypecast(writer, ty); @@ -387,11 +386,12 @@ pub const DeclGen = struct { var buf: Type.SlicePtrFieldTypeBuffer = undefined; try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val.slicePtr()); try writer.writeAll(", "); - try writer.print("{d}", .{val.sliceLen(target)}); + try writer.print("{d}", .{val.sliceLen(dg.module)}); try writer.writeAll("}"); return; } + const decl = dg.module.declPtr(decl_index); assert(decl.has_tv); // We shouldn't cast C function pointers as this is UB (when you call // them). The analysis until now should ensure that the C function @@ -399,21 +399,21 @@ pub const DeclGen = struct { // somewhere and we should let the C compiler tell us about it. if (ty.castPtrToFn() == null) { // Determine if we must pointer cast. - if (ty.eql(decl.ty, target)) { + if (ty.eql(decl.ty, dg.module)) { try writer.writeByte('&'); - try dg.renderDeclName(writer, decl); + try dg.renderDeclName(writer, decl_index); return; } try writer.writeAll("(("); try dg.renderTypecast(writer, ty); try writer.writeAll(")&"); - try dg.renderDeclName(writer, decl); + try dg.renderDeclName(writer, decl_index); try writer.writeByte(')'); return; } - try dg.renderDeclName(writer, decl); + try dg.renderDeclName(writer, decl_index); } fn renderInt128( @@ -471,13 +471,13 @@ pub const DeclGen = struct { try writer.writeByte(')'); switch (ptr_val.tag()) { .decl_ref_mut, .decl_ref, .variable => { - const decl = switch (ptr_val.tag()) { + const decl_index = switch (ptr_val.tag()) { .decl_ref => ptr_val.castTag(.decl_ref).?.data, - .decl_ref_mut => ptr_val.castTag(.decl_ref_mut).?.data.decl, + .decl_ref_mut => ptr_val.castTag(.decl_ref_mut).?.data.decl_index, .variable => ptr_val.castTag(.variable).?.data.owner_decl, else => unreachable, }; - try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl); + try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index); }, .field_ptr => { const field_ptr = ptr_val.castTag(.field_ptr).?.data; @@ -685,7 +685,7 @@ pub const DeclGen = struct { var index: usize = 0; while (index < ai.len) : (index += 1) { if (index != 0) try writer.writeAll(","); - const elem_val = try val.elemValue(arena_allocator, index); + const elem_val = try val.elemValue(dg.module, arena_allocator, index); try dg.renderValue(writer, ai.elem_type, elem_val); } if (ai.sentinel) |s| { @@ -837,7 +837,7 @@ pub const DeclGen = struct { try writer.writeAll(".payload = {"); } - const index = union_ty.tag_ty.enumTagFieldIndex(union_obj.tag, target).?; + const index = union_ty.tag_ty.enumTagFieldIndex(union_obj.tag, dg.module).?; const field_ty = ty.unionFields().values()[index].ty; const field_name = ty.unionFields().keys()[index]; if (field_ty.hasRuntimeBits()) { @@ -889,7 +889,7 @@ pub const DeclGen = struct { try w.writeAll("void"); } try w.writeAll(" "); - try dg.renderDeclName(w, dg.decl); + try dg.renderDeclName(w, dg.decl_index); try w.writeAll("("); const param_len = dg.decl.ty.fnParamLen(); @@ -927,8 +927,7 @@ pub const DeclGen = struct { try bw.writeAll(" (*"); const name_start = buffer.items.len; - const target = dg.module.getTarget(); - try bw.print("zig_F_{s})(", .{typeToCIdentifier(t, target)}); + try bw.print("zig_F_{s})(", .{typeToCIdentifier(t, dg.module)}); const name_end = buffer.items.len - 2; const param_len = fn_info.param_types.len; @@ -982,11 +981,10 @@ pub const DeclGen = struct { try bw.writeAll("; size_t len; } "); const name_index = buffer.items.len; - const target = dg.module.getTarget(); if (t.isConstPtr()) { - try bw.print("zig_L_{s}", .{typeToCIdentifier(child_type, target)}); + try bw.print("zig_L_{s}", .{typeToCIdentifier(child_type, dg.module)}); } else { - try bw.print("zig_M_{s}", .{typeToCIdentifier(child_type, target)}); + try bw.print("zig_M_{s}", .{typeToCIdentifier(child_type, dg.module)}); } if (ptr_sentinel) |s| { try bw.writeAll("_s_"); @@ -1009,7 +1007,7 @@ pub const DeclGen = struct { fn renderStructTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { const struct_obj = t.castTag(.@"struct").?.data; // Handle 0 bit types elsewhere. - const fqn = try struct_obj.getFullyQualifiedName(dg.typedefs.allocator); + const fqn = try struct_obj.getFullyQualifiedName(dg.module); defer dg.typedefs.allocator.free(fqn); var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); @@ -1072,8 +1070,7 @@ pub const DeclGen = struct { try buffer.appendSlice("} "); const name_start = buffer.items.len; - const target = dg.module.getTarget(); - try writer.print("zig_T_{};\n", .{typeToCIdentifier(t, target)}); + try writer.print("zig_T_{};\n", .{typeToCIdentifier(t, dg.module)}); const rendered = buffer.toOwnedSlice(); errdefer dg.typedefs.allocator.free(rendered); @@ -1090,7 +1087,7 @@ pub const DeclGen = struct { fn renderUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { const union_ty = t.cast(Type.Payload.Union).?.data; - const fqn = try union_ty.getFullyQualifiedName(dg.typedefs.allocator); + const fqn = try union_ty.getFullyQualifiedName(dg.module); defer dg.typedefs.allocator.free(fqn); const target = dg.module.getTarget(); @@ -1157,7 +1154,6 @@ pub const DeclGen = struct { try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, 0); try bw.writeAll("; uint16_t error; } "); const name_index = buffer.items.len; - const target = dg.module.getTarget(); if (err_set_type.castTag(.error_set_inferred)) |inf_err_set_payload| { const func = inf_err_set_payload.data.func; try bw.writeAll("zig_E_"); @@ -1165,7 +1161,7 @@ pub const DeclGen = struct { try bw.writeAll(";\n"); } else { try bw.print("zig_E_{s}_{s};\n", .{ - typeToCIdentifier(err_set_type, target), typeToCIdentifier(child_type, target), + typeToCIdentifier(err_set_type, dg.module), typeToCIdentifier(child_type, dg.module), }); } @@ -1195,8 +1191,7 @@ pub const DeclGen = struct { try dg.renderType(bw, elem_type); const name_start = buffer.items.len + 1; - const target = dg.module.getTarget(); - try bw.print(" zig_A_{s}_{d}", .{ typeToCIdentifier(elem_type, target), c_len }); + try bw.print(" zig_A_{s}_{d}", .{ typeToCIdentifier(elem_type, dg.module), c_len }); const name_end = buffer.items.len; try bw.print("[{d}];\n", .{c_len}); @@ -1224,8 +1219,7 @@ pub const DeclGen = struct { try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, 0); try bw.writeAll("; bool is_null; } "); const name_index = buffer.items.len; - const target = dg.module.getTarget(); - try bw.print("zig_Q_{s};\n", .{typeToCIdentifier(child_type, target)}); + try bw.print("zig_Q_{s};\n", .{typeToCIdentifier(child_type, dg.module)}); const rendered = buffer.toOwnedSlice(); errdefer dg.typedefs.allocator.free(rendered); @@ -1535,16 +1529,17 @@ pub const DeclGen = struct { } } - fn renderDeclName(dg: DeclGen, writer: anytype, decl: *Decl) !void { - decl.markAlive(); + fn renderDeclName(dg: DeclGen, writer: anytype, decl_index: Decl.Index) !void { + const decl = dg.module.declPtr(decl_index); + dg.module.markDeclAlive(decl); - if (dg.module.decl_exports.get(decl)) |exports| { + if (dg.module.decl_exports.get(decl_index)) |exports| { return writer.writeAll(exports[0].options.name); } else if (decl.val.tag() == .extern_fn) { return writer.writeAll(mem.sliceTo(decl.name, 0)); } else { const gpa = dg.module.gpa; - const name = try decl.getFullyQualifiedName(gpa); + const name = try decl.getFullyQualifiedName(dg.module); defer gpa.free(name); return writer.print("{ }", .{fmtIdent(name)}); } @@ -1616,7 +1611,11 @@ pub fn genDecl(o: *Object) !void { try fwd_decl_writer.writeAll("zig_threadlocal "); } - const decl_c_value: CValue = if (is_global) .{ .bytes = mem.span(o.dg.decl.name) } else .{ .decl = o.dg.decl }; + const decl_c_value: CValue = if (is_global) .{ + .bytes = mem.span(o.dg.decl.name), + } else .{ + .decl = o.dg.decl_index, + }; try o.dg.renderTypeAndName(fwd_decl_writer, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align"); try fwd_decl_writer.writeAll(";\n"); @@ -1641,7 +1640,7 @@ pub fn genDecl(o: *Object) !void { // TODO ask the Decl if it is const // https://github.com/ziglang/zig/issues/7582 - const decl_c_value: CValue = .{ .decl = o.dg.decl }; + const decl_c_value: CValue = .{ .decl = o.dg.decl_index }; try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut, o.dg.decl.@"align"); try writer.writeAll(" = "); @@ -2234,13 +2233,12 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { if (src_val_is_undefined) return try airStoreUndefined(f, dest_ptr); - const target = f.object.dg.module.getTarget(); const writer = f.object.writer(); if (lhs_child_type.zigTypeTag() == .Array) { // For this memcpy to safely work we need the rhs to have the same // underlying type as the lhs (i.e. they must both be arrays of the same underlying type). const rhs_type = f.air.typeOf(bin_op.rhs); - assert(rhs_type.eql(lhs_child_type, target)); + assert(rhs_type.eql(lhs_child_type, f.object.dg.module)); // If the source is a constant, writeCValue will emit a brace initialization // so work around this by initializing into new local. @@ -2780,7 +2778,8 @@ fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue { const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; const writer = f.object.writer(); const function = f.air.values[ty_pl.payload].castTag(.function).?.data; - try writer.print("/* dbg func:{s} */\n", .{function.owner_decl.name}); + const mod = f.object.dg.module; + try writer.print("/* dbg func:{s} */\n", .{mod.declPtr(function.owner_decl).name}); return CValue.none; } |
