cbe: fix for export changes

This commit is contained in:
Jacob Young 2024-06-30 00:11:51 -04:00 committed by mlugg
parent 0e5335aaf5
commit 00da182e68
No known key found for this signature in database
GPG key ID: 3F5B7DCCBF4AF02E
6 changed files with 286 additions and 276 deletions

View file

@ -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)

View file

@ -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);

View file

@ -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 {

View file

@ -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,
}
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 }),
switch (name) {
.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("{ }", .{
if (decl.getExternDecl(zcu).unwrap()) |extern_decl_index| try writer.print("{ }", .{
fmtIdent(zcu.declPtr(extern_decl_index).name.toSlice(ip)),
});
} else {
}) 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 ");
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");
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);
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), {}),

View file

@ -679,7 +679,6 @@ pub const File = struct {
if (build_options.only_c) @compileError("unreachable");
switch (base.tag) {
.plan9,
.c,
.spirv,
.nvptx,
=> {},

View file

@ -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),
}
}