Commit 00da182e68
lib/zig.h
@@ -207,16 +207,16 @@ typedef char bool;
__asm(zig_mangle_c(name) " = " zig_mangle_c(symbol))
#endif
+#define zig_mangled_tentative zig_mangled
+#define zig_mangled_final zig_mangled
#if _MSC_VER
-#define zig_mangled_tentative(mangled, unmangled)
-#define zig_mangled_final(mangled, unmangled) ; \
+#define zig_mangled(mangled, unmangled) ; \
zig_export(#mangled, unmangled)
#define zig_mangled_export(mangled, unmangled, symbol) \
zig_export(unmangled, #mangled) \
zig_export(symbol, unmangled)
#else /* _MSC_VER */
-#define zig_mangled_tentative(mangled, unmangled) __asm(zig_mangle_c(unmangled))
-#define zig_mangled_final(mangled, unmangled) zig_mangled_tentative(mangled, unmangled)
+#define zig_mangled(mangled, unmangled) __asm(zig_mangle_c(unmangled))
#define zig_mangled_export(mangled, unmangled, symbol) \
zig_mangled_final(mangled, unmangled) \
zig_export(symbol, unmangled)
src/codegen/c.zig
@@ -731,8 +731,6 @@ pub const DeclGen = struct {
if (decl.val.getExternFunc(zcu)) |extern_func| if (extern_func.decl != decl_index)
return dg.renderDeclValue(writer, extern_func.decl, location);
- if (decl.val.getVariable(zcu)) |variable| try dg.renderFwdDecl(decl_index, variable, .tentative);
-
// 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
// pointers are compatible. If they are not, then there is a bug
@@ -748,7 +746,7 @@ pub const DeclGen = struct {
try writer.writeByte(')');
}
try writer.writeByte('&');
- try dg.renderDeclName(writer, decl_index, 0);
+ try dg.renderDeclName(writer, decl_index);
if (need_cast) try writer.writeByte(')');
}
@@ -1765,19 +1763,22 @@ pub const DeclGen = struct {
fn renderFunctionSignature(
dg: *DeclGen,
w: anytype,
- fn_decl_index: InternPool.DeclIndex,
+ fn_val: Value,
+ fn_align: InternPool.Alignment,
kind: CType.Kind,
name: union(enum) {
- export_index: u32,
- ident: []const u8,
+ decl: InternPool.DeclIndex,
fmt_ctype_pool_string: std.fmt.Formatter(formatCTypePoolString),
+ @"export": struct {
+ main_name: InternPool.NullTerminatedString,
+ extern_name: InternPool.NullTerminatedString,
+ },
},
) !void {
const zcu = dg.zcu;
const ip = &zcu.intern_pool;
- const fn_decl = zcu.declPtr(fn_decl_index);
- const fn_ty = fn_decl.typeOf(zcu);
+ const fn_ty = fn_val.typeOf(zcu);
const fn_ctype = try dg.ctypeFromType(fn_ty, kind);
const fn_info = zcu.typeToFunc(fn_ty).?;
@@ -1788,7 +1789,7 @@ pub const DeclGen = struct {
else => unreachable,
}
}
- if (fn_decl.val.getFunction(zcu)) |func| if (func.analysis(ip).is_cold)
+ if (fn_val.getFunction(zcu)) |func| if (func.analysis(ip).is_cold)
try w.writeAll("zig_cold ");
if (fn_info.return_type == .noreturn_type) try w.writeAll("zig_noreturn ");
@@ -1799,22 +1800,11 @@ pub const DeclGen = struct {
trailing = .maybe_space;
}
- switch (kind) {
- .forward => {},
- .complete => if (fn_decl.alignment.toByteUnits()) |a| {
- try w.print("{}zig_align_fn({})", .{ trailing, a });
- trailing = .maybe_space;
- },
- else => unreachable,
- }
-
+ try w.print("{}", .{trailing});
switch (name) {
- .export_index => |export_index| {
- try w.print("{}", .{trailing});
- try dg.renderDeclName(w, fn_decl_index, export_index);
- },
- .ident => |ident| try w.print("{}{ }", .{ trailing, fmtIdent(ident) }),
- .fmt_ctype_pool_string => |fmt| try w.print("{}{ }", .{ trailing, fmt }),
+ .decl => |decl_index| try dg.renderDeclName(w, decl_index),
+ .fmt_ctype_pool_string => |fmt| try w.print("{ }", .{fmt}),
+ .@"export" => |@"export"| try w.print("{ }", .{fmtIdent(@"export".extern_name.toSlice(ip))}),
}
try renderTypeSuffix(
@@ -1833,44 +1823,30 @@ pub const DeclGen = struct {
switch (kind) {
.forward => {
- if (fn_decl.alignment.toByteUnits()) |a| {
- try w.print(" zig_align_fn({})", .{a});
- }
+ if (fn_align.toByteUnits()) |a| try w.print(" zig_align_fn({})", .{a});
switch (name) {
- .export_index => |export_index| mangled: {
- const maybe_exports = zcu.decl_exports.get(fn_decl_index);
- const external_name = (if (maybe_exports) |exports|
- exports.items[export_index].opts.name
- else if (fn_decl.isExtern(zcu))
- fn_decl.name
- else
- break :mangled).toSlice(ip);
- const is_mangled = isMangledIdent(external_name, true);
- const is_export = export_index > 0;
+ .decl, .fmt_ctype_pool_string => {},
+ .@"export" => |@"export"| {
+ const extern_name = @"export".extern_name.toSlice(ip);
+ const is_mangled = isMangledIdent(extern_name, true);
+ const is_export = @"export".extern_name != @"export".main_name;
if (is_mangled and is_export) {
try w.print(" zig_mangled_export({ }, {s}, {s})", .{
- fmtIdent(external_name),
- fmtStringLiteral(external_name, null),
- fmtStringLiteral(
- maybe_exports.?.items[0].opts.name.toSlice(ip),
- null,
- ),
+ fmtIdent(extern_name),
+ fmtStringLiteral(extern_name, null),
+ fmtStringLiteral(@"export".main_name.toSlice(ip), null),
});
} else if (is_mangled) {
- try w.print(" zig_mangled_final({ }, {s})", .{
- fmtIdent(external_name), fmtStringLiteral(external_name, null),
+ try w.print(" zig_mangled({ }, {s})", .{
+ fmtIdent(extern_name), fmtStringLiteral(extern_name, null),
});
} else if (is_export) {
try w.print(" zig_export({s}, {s})", .{
- fmtStringLiteral(
- maybe_exports.?.items[0].opts.name.toSlice(ip),
- null,
- ),
- fmtStringLiteral(external_name, null),
+ fmtStringLiteral(@"export".main_name.toSlice(ip), null),
+ fmtStringLiteral(extern_name, null),
});
}
},
- .ident, .fmt_ctype_pool_string => {},
}
},
.complete => {},
@@ -2085,21 +2061,11 @@ pub const DeclGen = struct {
try renderTypeSuffix(dg.pass, &dg.ctype_pool, dg.zcu, w, ctype, .suffix, .{});
}
- fn declIsGlobal(dg: *DeclGen, val: Value) bool {
- const zcu = dg.zcu;
- return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
- .variable => |variable| zcu.decl_exports.contains(variable.decl),
- .extern_func => true,
- .func => |func| zcu.decl_exports.contains(func.owner_decl),
- else => unreachable,
- };
- }
-
fn writeName(dg: *DeclGen, w: anytype, c_value: CValue) !void {
switch (c_value) {
.new_local, .local => |i| try w.print("t{d}", .{i}),
.constant => |val| try renderAnonDeclName(w, val),
- .decl => |decl| try dg.renderDeclName(w, decl, 0),
+ .decl => |decl| try dg.renderDeclName(w, decl),
.identifier => |ident| try w.print("{ }", .{fmtIdent(ident)}),
else => unreachable,
}
@@ -2111,10 +2077,10 @@ pub const DeclGen = struct {
.constant => |val| try renderAnonDeclName(w, val),
.arg, .arg_array => unreachable,
.field => |i| try w.print("f{d}", .{i}),
- .decl => |decl| try dg.renderDeclName(w, decl, 0),
+ .decl => |decl| try dg.renderDeclName(w, decl),
.decl_ref => |decl| {
try w.writeByte('&');
- try dg.renderDeclName(w, decl, 0);
+ try dg.renderDeclName(w, decl);
},
.undef => |ty| try dg.renderUndefValue(w, ty, .Other),
.identifier => |ident| try w.print("{ }", .{fmtIdent(ident)}),
@@ -2142,10 +2108,10 @@ pub const DeclGen = struct {
.field => |i| try w.print("f{d}", .{i}),
.decl => |decl| {
try w.writeAll("(*");
- try dg.renderDeclName(w, decl, 0);
+ try dg.renderDeclName(w, decl);
try w.writeByte(')');
},
- .decl_ref => |decl| try dg.renderDeclName(w, decl, 0),
+ .decl_ref => |decl| try dg.renderDeclName(w, decl),
.undef => unreachable,
.identifier => |ident| try w.print("(*{ })", .{fmtIdent(ident)}),
.payload_identifier => |ident| try w.print("(*{ }.{ })", .{
@@ -2195,19 +2161,12 @@ pub const DeclGen = struct {
dg: *DeclGen,
decl_index: InternPool.DeclIndex,
variable: InternPool.Key.Variable,
- fwd_kind: enum { tentative, final },
) !void {
const zcu = dg.zcu;
const decl = zcu.declPtr(decl_index);
const fwd = dg.fwdDeclWriter();
- const is_global = variable.is_extern or dg.declIsGlobal(decl.val);
- try fwd.writeAll(if (is_global) "zig_extern " else "static ");
- const maybe_exports = zcu.decl_exports.get(decl_index);
- const export_weak_linkage = if (maybe_exports) |exports|
- exports.items[0].opts.linkage == .weak
- else
- false;
- if (variable.is_weak_linkage or export_weak_linkage) try fwd.writeAll("zig_weak_linkage ");
+ try fwd.writeAll(if (variable.is_extern) "zig_extern " else "static ");
+ if (variable.is_weak_linkage) try fwd.writeAll("zig_weak_linkage ");
if (variable.is_threadlocal and !dg.mod.single_threaded) try fwd.writeAll("zig_threadlocal ");
try dg.renderTypeAndName(
fwd,
@@ -2217,38 +2176,17 @@ pub const DeclGen = struct {
decl.alignment,
.complete,
);
- mangled: {
- const external_name = (if (maybe_exports) |exports|
- exports.items[0].opts.name
- else if (variable.is_extern)
- decl.name
- else
- break :mangled).toSlice(&zcu.intern_pool);
- if (isMangledIdent(external_name, true)) {
- try fwd.print(" zig_mangled_{s}({ }, {s})", .{
- @tagName(fwd_kind),
- fmtIdent(external_name),
- fmtStringLiteral(external_name, null),
- });
- }
- }
try fwd.writeAll(";\n");
}
- fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: InternPool.DeclIndex, export_index: u32) !void {
+ fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: InternPool.DeclIndex) !void {
const zcu = dg.zcu;
const ip = &zcu.intern_pool;
const decl = zcu.declPtr(decl_index);
- if (zcu.decl_exports.get(decl_index)) |exports| {
- try writer.print("{ }", .{
- fmtIdent(exports.items[export_index].opts.name.toSlice(ip)),
- });
- } else if (decl.getExternDecl(zcu).unwrap()) |extern_decl_index| {
- try writer.print("{ }", .{
- fmtIdent(zcu.declPtr(extern_decl_index).name.toSlice(ip)),
- });
- } else {
+ if (decl.getExternDecl(zcu).unwrap()) |extern_decl_index| try writer.print("{ }", .{
+ fmtIdent(zcu.declPtr(extern_decl_index).name.toSlice(ip)),
+ }) else {
// MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case),
// expand to 3x the length of its input, but let's cut it off at a much shorter limit.
var name: [100]u8 = undefined;
@@ -2761,69 +2699,6 @@ pub fn genErrDecls(o: *Object) !void {
try writer.writeAll("};\n");
}
-fn genExports(o: *Object) !void {
- const tracy = trace(@src());
- defer tracy.end();
-
- const zcu = o.dg.zcu;
- const ip = &zcu.intern_pool;
- const decl_index = switch (o.dg.pass) {
- .decl => |decl| decl,
- .anon, .flush => return,
- };
- const decl = zcu.declPtr(decl_index);
- const fwd = o.dg.fwdDeclWriter();
-
- const exports = zcu.decl_exports.get(decl_index) orelse return;
- if (exports.items.len < 2) return;
-
- const is_variable_const = switch (ip.indexToKey(decl.val.toIntern())) {
- .func => return for (exports.items[1..], 1..) |@"export", i| {
- try fwd.writeAll("zig_extern ");
- if (@"export".opts.linkage == .weak) try fwd.writeAll("zig_weak_linkage_fn ");
- try o.dg.renderFunctionSignature(
- fwd,
- decl_index,
- .forward,
- .{ .export_index = @intCast(i) },
- );
- try fwd.writeAll(";\n");
- },
- .extern_func => {
- // TODO: when sema allows re-exporting extern decls
- unreachable;
- },
- .variable => |variable| variable.is_const,
- else => true,
- };
- for (exports.items[1..]) |@"export"| {
- try fwd.writeAll("zig_extern ");
- if (@"export".opts.linkage == .weak) try fwd.writeAll("zig_weak_linkage ");
- const export_name = @"export".opts.name.toSlice(ip);
- try o.dg.renderTypeAndName(
- fwd,
- decl.typeOf(zcu),
- .{ .identifier = export_name },
- CQualifiers.init(.{ .@"const" = is_variable_const }),
- decl.alignment,
- .complete,
- );
- if (isMangledIdent(export_name, true)) {
- try fwd.print(" zig_mangled_export({ }, {s}, {s})", .{
- fmtIdent(export_name),
- fmtStringLiteral(export_name, null),
- fmtStringLiteral(exports.items[0].opts.name.toSlice(ip), null),
- });
- } else {
- try fwd.print(" zig_export({s}, {s})", .{
- fmtStringLiteral(exports.items[0].opts.name.toSlice(ip), null),
- fmtStringLiteral(export_name, null),
- });
- }
- try fwd.writeAll(";\n");
- }
-}
-
pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFnMap.Entry) !void {
const zcu = o.dg.zcu;
const ip = &zcu.intern_pool;
@@ -2885,19 +2760,19 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn
const fn_info = fn_ctype.info(ctype_pool).function;
const fn_name = fmtCTypePoolString(val.fn_name, lazy_ctype_pool);
- const fwd_decl_writer = o.dg.fwdDeclWriter();
- try fwd_decl_writer.print("static zig_{s} ", .{@tagName(key)});
- try o.dg.renderFunctionSignature(fwd_decl_writer, fn_decl_index, .forward, .{
+ const fwd = o.dg.fwdDeclWriter();
+ try fwd.print("static zig_{s} ", .{@tagName(key)});
+ try o.dg.renderFunctionSignature(fwd, fn_decl.val, fn_decl.alignment, .forward, .{
.fmt_ctype_pool_string = fn_name,
});
- try fwd_decl_writer.writeAll(";\n");
+ try fwd.writeAll(";\n");
- try w.print("static zig_{s} ", .{@tagName(key)});
- try o.dg.renderFunctionSignature(w, fn_decl_index, .complete, .{
+ try w.print("zig_{s} ", .{@tagName(key)});
+ try o.dg.renderFunctionSignature(w, fn_decl.val, .none, .complete, .{
.fmt_ctype_pool_string = fn_name,
});
try w.writeAll(" {\n return ");
- try o.dg.renderDeclName(w, fn_decl_index, 0);
+ try o.dg.renderDeclName(w, fn_decl_index);
try w.writeByte('(');
for (0..fn_info.param_ctypes.len) |arg| {
if (arg > 0) try w.writeAll(", ");
@@ -2921,21 +2796,26 @@ pub fn genFunc(f: *Function) !void {
o.code_header = std.ArrayList(u8).init(gpa);
defer o.code_header.deinit();
- const is_global = o.dg.declIsGlobal(decl.val);
- const fwd_decl_writer = o.dg.fwdDeclWriter();
- try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
-
- if (zcu.decl_exports.get(decl_index)) |exports|
- if (exports.items[0].opts.linkage == .weak) try fwd_decl_writer.writeAll("zig_weak_linkage_fn ");
- try o.dg.renderFunctionSignature(fwd_decl_writer, decl_index, .forward, .{ .export_index = 0 });
- try fwd_decl_writer.writeAll(";\n");
- try genExports(o);
+ const fwd = o.dg.fwdDeclWriter();
+ try fwd.writeAll("static ");
+ try o.dg.renderFunctionSignature(
+ fwd,
+ decl.val,
+ decl.alignment,
+ .forward,
+ .{ .decl = decl_index },
+ );
+ try fwd.writeAll(";\n");
- try o.indent_writer.insertNewline();
- if (!is_global) try o.writer().writeAll("static ");
if (decl.@"linksection".toSlice(&zcu.intern_pool)) |s|
try o.writer().print("zig_linksection_fn({s}) ", .{fmtStringLiteral(s, null)});
- try o.dg.renderFunctionSignature(o.writer(), decl_index, .complete, .{ .export_index = 0 });
+ try o.dg.renderFunctionSignature(
+ o.writer(),
+ decl.val,
+ .none,
+ .complete,
+ .{ .decl = decl_index },
+ );
try o.writer().writeByte(' ');
// In case we need to use the header, populate it with a copy of the function
@@ -2949,7 +2829,6 @@ pub fn genFunc(f: *Function) !void {
const main_body = f.air.getMainBody();
try genBodyResolveState(f, undefined, &.{}, main_body, false);
-
try o.indent_writer.insertNewline();
// Take advantage of the free_locals map to bucket locals per type. All
@@ -3007,20 +2886,25 @@ pub fn genDecl(o: *Object) !void {
if (!decl_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return;
if (decl.val.getExternFunc(zcu)) |_| {
- const fwd_decl_writer = o.dg.fwdDeclWriter();
- try fwd_decl_writer.writeAll("zig_extern ");
- try o.dg.renderFunctionSignature(fwd_decl_writer, decl_index, .forward, .{ .export_index = 0 });
- try fwd_decl_writer.writeAll(";\n");
- try genExports(o);
+ const fwd = o.dg.fwdDeclWriter();
+ try fwd.writeAll("zig_extern ");
+ try o.dg.renderFunctionSignature(
+ fwd,
+ decl.val,
+ decl.alignment,
+ .forward,
+ .{ .@"export" = .{
+ .main_name = decl.name,
+ .extern_name = decl.name,
+ } },
+ );
+ try fwd.writeAll(";\n");
} else if (decl.val.getVariable(zcu)) |variable| {
- try o.dg.renderFwdDecl(decl_index, variable, .final);
- try genExports(o);
+ try o.dg.renderFwdDecl(decl_index, variable);
if (variable.is_extern) return;
- const is_global = variable.is_extern or o.dg.declIsGlobal(decl.val);
const w = o.writer();
- if (!is_global) try w.writeAll("static ");
if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage ");
if (variable.is_threadlocal and !o.dg.mod.single_threaded) try w.writeAll("zig_threadlocal ");
if (decl.@"linksection".toSlice(&zcu.intern_pool)) |s|
@@ -3032,46 +2916,27 @@ pub fn genDecl(o: *Object) !void {
try w.writeByte(';');
try o.indent_writer.insertNewline();
} else {
- const is_global = o.dg.zcu.decl_exports.contains(decl_index);
const decl_c_value = .{ .decl = decl_index };
- try genDeclValue(o, decl.val, is_global, decl_c_value, decl.alignment, decl.@"linksection");
+ try genDeclValue(o, decl.val, decl_c_value, decl.alignment, decl.@"linksection");
}
}
pub fn genDeclValue(
o: *Object,
val: Value,
- is_global: bool,
decl_c_value: CValue,
alignment: Alignment,
@"linksection": InternPool.OptionalNullTerminatedString,
) !void {
const zcu = o.dg.zcu;
- const fwd_decl_writer = o.dg.fwdDeclWriter();
-
const ty = val.typeOf(zcu);
- try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
- try o.dg.renderTypeAndName(fwd_decl_writer, ty, decl_c_value, Const, alignment, .complete);
- switch (o.dg.pass) {
- .decl => |decl_index| {
- if (zcu.decl_exports.get(decl_index)) |exports| {
- const export_name = exports.items[0].opts.name.toSlice(&zcu.intern_pool);
- if (isMangledIdent(export_name, true)) {
- try fwd_decl_writer.print(" zig_mangled_final({ }, {s})", .{
- fmtIdent(export_name), fmtStringLiteral(export_name, null),
- });
- }
- }
- },
- .anon => {},
- .flush => unreachable,
- }
- try fwd_decl_writer.writeAll(";\n");
- try genExports(o);
+ const fwd = o.dg.fwdDeclWriter();
+ try fwd.writeAll("static ");
+ try o.dg.renderTypeAndName(fwd, ty, decl_c_value, Const, alignment, .complete);
+ try fwd.writeAll(";\n");
const w = o.writer();
- if (!is_global) try w.writeAll("static ");
if (@"linksection".toSlice(&zcu.intern_pool)) |s|
try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)});
try o.dg.renderTypeAndName(w, ty, decl_c_value, Const, alignment, .complete);
@@ -3080,24 +2945,73 @@ pub fn genDeclValue(
try w.writeAll(";\n");
}
-pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
- if (true) @panic("TODO jacobly");
-
- const tracy = trace(@src());
- defer tracy.end();
-
+pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const u32) !void {
const zcu = dg.zcu;
- const decl_index = dg.pass.decl;
- const decl = zcu.declPtr(decl_index);
- const writer = dg.fwdDeclWriter();
+ const ip = &zcu.intern_pool;
+ const fwd = dg.fwdDeclWriter();
- switch (decl.typeOf(zcu).zigTypeTag(zcu)) {
- .Fn => if (dg.declIsGlobal(decl.val)) {
- try writer.writeAll("zig_extern ");
- try dg.renderFunctionSignature(writer, dg.pass.decl, .complete, .{ .export_index = 0 });
- try dg.fwd_decl.appendSlice(";\n");
+ const main_name = zcu.all_exports.items[export_indices[0]].opts.name;
+ try fwd.writeAll("#define ");
+ switch (exported) {
+ .decl_index => |decl_index| try dg.renderDeclName(fwd, decl_index),
+ .value => |value| try DeclGen.renderAnonDeclName(fwd, Value.fromInterned(value)),
+ }
+ try fwd.writeByte(' ');
+ try fwd.print("{ }", .{fmtIdent(main_name.toSlice(ip))});
+ try fwd.writeByte('\n');
+
+ const is_const = switch (ip.indexToKey(exported.getValue(zcu).toIntern())) {
+ .func, .extern_func => return for (export_indices) |export_index| {
+ const @"export" = &zcu.all_exports.items[export_index];
+ try fwd.writeAll("zig_extern ");
+ if (@"export".opts.linkage == .weak) try fwd.writeAll("zig_weak_linkage_fn ");
+ try dg.renderFunctionSignature(
+ fwd,
+ exported.getValue(zcu),
+ exported.getAlign(zcu),
+ .forward,
+ .{ .@"export" = .{
+ .main_name = main_name,
+ .extern_name = @"export".opts.name,
+ } },
+ );
+ try fwd.writeAll(";\n");
},
- else => {},
+ .variable => |variable| variable.is_const,
+ else => true,
+ };
+ for (export_indices) |export_index| {
+ const @"export" = &zcu.all_exports.items[export_index];
+ try fwd.writeAll("zig_extern ");
+ if (@"export".opts.linkage == .weak) try fwd.writeAll("zig_weak_linkage ");
+ const extern_name = @"export".opts.name.toSlice(ip);
+ const is_mangled = isMangledIdent(extern_name, true);
+ const is_export = @"export".opts.name != main_name;
+ try dg.renderTypeAndName(
+ fwd,
+ exported.getValue(zcu).typeOf(zcu),
+ .{ .identifier = extern_name },
+ CQualifiers.init(.{ .@"const" = is_const }),
+ exported.getAlign(zcu),
+ .complete,
+ );
+ if (is_mangled and is_export) {
+ try fwd.print(" zig_mangled_export({ }, {s}, {s})", .{
+ fmtIdent(extern_name),
+ fmtStringLiteral(extern_name, null),
+ fmtStringLiteral(main_name.toSlice(ip), null),
+ });
+ } else if (is_mangled) {
+ try fwd.print(" zig_mangled({ }, {s})", .{
+ fmtIdent(extern_name), fmtStringLiteral(extern_name, null),
+ });
+ } else if (is_export) {
+ try fwd.print(" zig_export({s}, {s})", .{
+ fmtStringLiteral(main_name.toSlice(ip), null),
+ fmtStringLiteral(extern_name, null),
+ });
+ }
+ try fwd.writeAll(";\n");
}
}
@@ -4554,7 +4468,7 @@ fn airCall(
};
};
switch (modifier) {
- .auto, .always_tail => try f.object.dg.renderDeclName(writer, fn_decl, 0),
+ .auto, .always_tail => try f.object.dg.renderDeclName(writer, fn_decl),
inline .never_tail, .never_inline => |m| try writer.writeAll(try f.getLazyFnName(
@unionInit(LazyFnKey, @tagName(m), fn_decl),
@unionInit(LazyFnValue.Data, @tagName(m), {}),
src/link/C.zig
@@ -39,6 +39,9 @@ anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, DeclBlock) = .{},
/// the keys of `anon_decls`.
aligned_anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment) = .{},
+exported_decls: std.AutoArrayHashMapUnmanaged(InternPool.DeclIndex, ExportedBlock) = .{},
+exported_values: std.AutoArrayHashMapUnmanaged(InternPool.Index, ExportedBlock) = .{},
+
/// Optimization, `updateDecl` reuses this buffer rather than creating a new
/// one with every call.
fwd_decl_buf: std.ArrayListUnmanaged(u8) = .{},
@@ -80,6 +83,11 @@ pub const DeclBlock = struct {
}
};
+/// Per-exported-symbol data.
+pub const ExportedBlock = struct {
+ fwd_decl: String = String.empty,
+};
+
pub fn getString(this: C, s: String) []const u8 {
return this.string_bytes.items[s.start..][0..s.len];
}
@@ -183,8 +191,6 @@ pub fn updateFunc(
air: Air,
liveness: Liveness,
) !void {
- if (true) @panic("TODO jacobly");
-
const gpa = self.base.comp.gpa;
const func = zcu.funcInfo(func_index);
@@ -240,9 +246,13 @@ pub fn updateFunc(
function.deinit();
}
+ try zcu.failed_analysis.ensureUnusedCapacity(gpa, 1);
codegen.genFunc(&function) catch |err| switch (err) {
error.AnalysisFail => {
- try zcu.failed_decls.put(gpa, decl_index, function.object.dg.error_msg.?);
+ zcu.failed_analysis.putAssumeCapacityNoClobber(
+ InternPool.AnalUnit.wrap(.{ .decl = decl_index }),
+ function.object.dg.error_msg.?,
+ );
return;
},
else => |e| return e,
@@ -252,8 +262,6 @@ pub fn updateFunc(
}
fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {
- if (true) @panic("TODO jacobly");
-
const gpa = self.base.comp.gpa;
const anon_decl = self.anon_decls.keys()[i];
@@ -292,7 +300,7 @@ fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {
const c_value: codegen.CValue = .{ .constant = Value.fromInterned(anon_decl) };
const alignment: Alignment = self.aligned_anon_decls.get(anon_decl) orelse .none;
- codegen.genDeclValue(&object, c_value.constant, false, c_value, alignment, .none) catch |err| switch (err) {
+ codegen.genDeclValue(&object, c_value.constant, c_value, alignment, .none) catch |err| switch (err) {
error.AnalysisFail => {
@panic("TODO: C backend AnalysisFail on anonymous decl");
//try zcu.failed_decls.put(gpa, decl_index, object.dg.error_msg.?);
@@ -310,8 +318,6 @@ fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {
}
pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {
- if (true) @panic("TODO jacobly");
-
const tracy = trace(@src());
defer tracy.end();
@@ -357,9 +363,13 @@ pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {
code.* = object.code.moveToUnmanaged();
}
+ try zcu.failed_analysis.ensureUnusedCapacity(gpa, 1);
codegen.genDecl(&object) catch |err| switch (err) {
error.AnalysisFail => {
- try zcu.failed_decls.put(gpa, decl_index, object.dg.error_msg.?);
+ zcu.failed_analysis.putAssumeCapacityNoClobber(
+ InternPool.AnalUnit.wrap(.{ .decl = decl_index }),
+ object.dg.error_msg.?,
+ );
return;
},
else => |e| return e,
@@ -396,8 +406,6 @@ fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) {
}
pub fn flushModule(self: *C, arena: Allocator, prog_node: std.Progress.Node) !void {
- if (true) @panic("TODO jacobly");
-
_ = arena; // Has the same lifetime as the call to Compilation.update.
const tracy = trace(@src());
@@ -460,26 +468,39 @@ pub fn flushModule(self: *C, arena: Allocator, prog_node: std.Progress.Node) !vo
var export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
defer export_names.deinit(gpa);
try export_names.ensureTotalCapacity(gpa, @intCast(zcu.single_exports.count()));
- for (zcu.single_exports.values()) |export_idx| {
- export_names.putAssumeCapacity(gpa, zcu.all_exports.items[export_idx].opts.name, {});
+ for (zcu.single_exports.values()) |export_index| {
+ export_names.putAssumeCapacity(zcu.all_exports.items[export_index].opts.name, {});
}
for (zcu.multi_exports.values()) |info| {
- try export_names.ensureUnusedCapacity(info.len);
- for (zcu.all_exports.items[info.index..][0..info.len]) |export_idx| {
- export_names.putAssumeCapacity(gpa, zcu.all_exports.items[export_idx].opts.name, {});
+ try export_names.ensureUnusedCapacity(gpa, info.len);
+ for (zcu.all_exports.items[info.index..][0..info.len]) |@"export"| {
+ export_names.putAssumeCapacity(@"export".opts.name, {});
}
}
- for (self.anon_decls.values()) |*decl_block| {
- try self.flushDeclBlock(zcu, zcu.root_mod, &f, decl_block, export_names, .none);
- }
+ for (self.anon_decls.keys(), self.anon_decls.values()) |value, *decl_block| try self.flushDeclBlock(
+ zcu,
+ zcu.root_mod,
+ &f,
+ decl_block,
+ self.exported_values.getPtr(value),
+ export_names,
+ .none,
+ );
for (self.decl_table.keys(), self.decl_table.values()) |decl_index, *decl_block| {
const decl = zcu.declPtr(decl_index);
- assert(decl.has_tv);
- const extern_symbol_name = if (decl.isExtern(zcu)) decl.name.toOptional() else .none;
+ const extern_name = if (decl.isExtern(zcu)) decl.name.toOptional() else .none;
const mod = zcu.namespacePtr(decl.src_namespace).file_scope.mod;
- try self.flushDeclBlock(zcu, mod, &f, decl_block, export_names, extern_symbol_name);
+ try self.flushDeclBlock(
+ zcu,
+ mod,
+ &f,
+ decl_block,
+ self.exported_decls.getPtr(decl_index),
+ export_names,
+ extern_name,
+ );
}
}
@@ -512,12 +533,16 @@ pub fn flushModule(self: *C, arena: Allocator, prog_node: std.Progress.Node) !vo
f.file_size += lazy_fwd_decl_len;
// Now the code.
- const anon_decl_values = self.anon_decls.values();
- const decl_values = self.decl_table.values();
- try f.all_buffers.ensureUnusedCapacity(gpa, 1 + anon_decl_values.len + decl_values.len);
+ try f.all_buffers.ensureUnusedCapacity(gpa, 1 + (self.anon_decls.count() + self.decl_table.count()) * 2);
f.appendBufAssumeCapacity(self.lazy_code_buf.items);
- for (anon_decl_values) |db| f.appendBufAssumeCapacity(self.getString(db.code));
- for (decl_values) |db| f.appendBufAssumeCapacity(self.getString(db.code));
+ for (self.anon_decls.keys(), self.anon_decls.values()) |anon_decl, decl_block| f.appendCodeAssumeCapacity(
+ self.exported_values.contains(anon_decl),
+ self.getString(decl_block.code),
+ );
+ for (self.decl_table.keys(), self.decl_table.values()) |decl_index, decl_block| f.appendCodeAssumeCapacity(
+ self.exported_decls.contains(decl_index),
+ self.getString(decl_block.code),
+ );
const file = self.base.file.?;
try file.setEndPos(f.file_size);
@@ -547,6 +572,12 @@ const Flush = struct {
f.file_size += buf.len;
}
+ fn appendCodeAssumeCapacity(f: *Flush, is_extern: bool, code: []const u8) void {
+ if (code.len == 0) return;
+ f.appendBufAssumeCapacity(if (is_extern) "\nzig_extern " else "\nstatic ");
+ f.appendBufAssumeCapacity(code);
+ }
+
fn deinit(f: *Flush, gpa: Allocator) void {
f.all_buffers.deinit(gpa);
f.asm_buf.deinit(gpa);
@@ -734,19 +765,20 @@ fn flushDeclBlock(
zcu: *Zcu,
mod: *Module,
f: *Flush,
- decl_block: *DeclBlock,
+ decl_block: *const DeclBlock,
+ exported_block: ?*const ExportedBlock,
export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void),
- extern_symbol_name: InternPool.OptionalNullTerminatedString,
+ extern_name: InternPool.OptionalNullTerminatedString,
) FlushDeclError!void {
const gpa = self.base.comp.gpa;
try self.flushLazyFns(zcu, mod, f, &decl_block.ctype_pool, decl_block.lazy_fns);
try f.all_buffers.ensureUnusedCapacity(gpa, 1);
- fwd_decl: {
- if (extern_symbol_name.unwrap()) |name| {
- if (export_names.contains(name)) break :fwd_decl;
- }
- f.appendBufAssumeCapacity(self.getString(decl_block.fwd_decl));
- }
+ // avoid emitting extern decls that are already exported
+ if (extern_name.unwrap()) |name| if (export_names.contains(name)) return;
+ f.appendBufAssumeCapacity(self.getString(if (exported_block) |exported|
+ exported.fwd_decl
+ else
+ decl_block.fwd_decl));
}
pub fn flushEmitH(zcu: *Zcu) !void {
@@ -798,8 +830,56 @@ pub fn updateExports(
exported: Zcu.Exported,
export_indices: []const u32,
) !void {
- _ = self;
- _ = zcu;
- _ = exported;
- _ = export_indices;
+ const gpa = self.base.comp.gpa;
+ const mod, const pass: codegen.DeclGen.Pass, const decl_block, const exported_block = switch (exported) {
+ .decl_index => |decl_index| .{
+ zcu.namespacePtr(zcu.declPtr(decl_index).src_namespace).file_scope.mod,
+ .{ .decl = decl_index },
+ self.decl_table.getPtr(decl_index).?,
+ (try self.exported_decls.getOrPut(gpa, decl_index)).value_ptr,
+ },
+ .value => |value| .{
+ zcu.root_mod,
+ .{ .anon = value },
+ self.anon_decls.getPtr(value).?,
+ (try self.exported_values.getOrPut(gpa, value)).value_ptr,
+ },
+ };
+ const ctype_pool = &decl_block.ctype_pool;
+ const fwd_decl = &self.fwd_decl_buf;
+ fwd_decl.clearRetainingCapacity();
+ var dg: codegen.DeclGen = .{
+ .gpa = gpa,
+ .zcu = zcu,
+ .mod = mod,
+ .error_msg = null,
+ .pass = pass,
+ .is_naked_fn = false,
+ .fwd_decl = fwd_decl.toManaged(gpa),
+ .ctype_pool = decl_block.ctype_pool,
+ .scratch = .{},
+ .anon_decl_deps = .{},
+ .aligned_anon_decls = .{},
+ };
+ defer {
+ assert(dg.anon_decl_deps.count() == 0);
+ assert(dg.aligned_anon_decls.count() == 0);
+ fwd_decl.* = dg.fwd_decl.moveToUnmanaged();
+ ctype_pool.* = dg.ctype_pool.move();
+ ctype_pool.freeUnusedCapacity(gpa);
+ dg.scratch.deinit(gpa);
+ }
+ try codegen.genExports(&dg, exported, export_indices);
+ exported_block.* = .{ .fwd_decl = try self.addString(dg.fwd_decl.items) };
+}
+
+pub fn deleteExport(
+ self: *C,
+ exported: Zcu.Exported,
+ _: InternPool.NullTerminatedString,
+) void {
+ switch (exported) {
+ .decl_index => |decl_index| _ = self.exported_decls.swapRemove(decl_index),
+ .value => |value| _ = self.exported_values.swapRemove(value),
+ }
}
src/Compilation.zig
@@ -3466,6 +3466,9 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: std.Progress.Node) !vo
};
},
.emit_h_decl => |decl_index| {
+ if (true) @panic("regressed compiler feature: emit-h should hook into updateExports, " ++
+ "not decl analysis, which is too early to know about @export calls");
+
const module = comp.module.?;
const decl = module.declPtr(decl_index);
src/link.zig
@@ -679,7 +679,6 @@ pub const File = struct {
if (build_options.only_c) @compileError("unreachable");
switch (base.tag) {
.plan9,
- .c,
.spirv,
.nvptx,
=> {},
src/Zcu.zig
@@ -268,6 +268,20 @@ pub const Exported = union(enum) {
decl_index: Decl.Index,
/// Constant value being exported.
value: InternPool.Index,
+
+ pub fn getValue(exported: Exported, zcu: *Zcu) Value {
+ return switch (exported) {
+ .decl_index => |decl_index| zcu.declPtr(decl_index).val,
+ .value => |value| Value.fromInterned(value),
+ };
+ }
+
+ pub fn getAlign(exported: Exported, zcu: *Zcu) Alignment {
+ return switch (exported) {
+ .decl_index => |decl_index| zcu.declPtr(decl_index).alignment,
+ .value => .none,
+ };
+ }
};
pub const Export = struct {