aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/c.zig380
-rw-r--r--src/codegen/c/Type.zig2
-rw-r--r--src/codegen/llvm.zig276
-rw-r--r--src/codegen/spirv.zig8
4 files changed, 270 insertions, 396 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 94f8faa441..92e9edb433 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -9,7 +9,7 @@ const Zcu = @import("../Zcu.zig");
const Module = @import("../Package/Module.zig");
const Compilation = @import("../Compilation.zig");
const Value = @import("../Value.zig");
-const Type = @import("../type.zig").Type;
+const Type = @import("../Type.zig");
const C = link.File.C;
const Decl = Zcu.Decl;
const trace = @import("../tracy.zig").trace;
@@ -637,7 +637,7 @@ pub const DeclGen = struct {
const zcu = dg.zcu;
const decl_index = dg.pass.decl;
const decl = zcu.declPtr(decl_index);
- const src_loc = decl.navSrcLoc(zcu).upgrade(zcu);
+ const src_loc = decl.navSrcLoc(zcu);
dg.error_msg = try Zcu.ErrorMsg.create(dg.gpa, src_loc, format, args);
return error.AnalysisFail;
}
@@ -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,22 +2945,73 @@ pub fn genDeclValue(
try w.writeAll(";\n");
}
-pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
- 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");
}
}
@@ -4552,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), {}),
diff --git a/src/codegen/c/Type.zig b/src/codegen/c/Type.zig
index e316d7a154..0a0d84f061 100644
--- a/src/codegen/c/Type.zig
+++ b/src/codegen/c/Type.zig
@@ -2583,6 +2583,6 @@ const assert = std.debug.assert;
const CType = @This();
const Module = @import("../../Package/Module.zig");
const std = @import("std");
-const Type = @import("../../type.zig").Type;
+const Type = @import("../../Type.zig");
const Zcu = @import("../../Zcu.zig");
const DeclIndex = @import("../../InternPool.zig").DeclIndex;
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 00cfd4404a..02933929c8 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -22,7 +22,7 @@ const Package = @import("../Package.zig");
const Air = @import("../Air.zig");
const Liveness = @import("../Liveness.zig");
const Value = @import("../Value.zig");
-const Type = @import("../type.zig").Type;
+const Type = @import("../Type.zig");
const x86_64_abi = @import("../arch/x86_64/abi.zig");
const wasm_c_abi = @import("../arch/wasm/abi.zig");
const aarch64_c_abi = @import("../arch/aarch64/abi.zig");
@@ -848,10 +848,6 @@ pub const Object = struct {
/// Note that the values are not added until `emit`, when all errors in
/// the compilation are known.
error_name_table: Builder.Variable.Index,
- /// This map is usually very close to empty. It tracks only the cases when a
- /// second extern Decl could not be emitted with the correct name due to a
- /// name collision.
- extern_collisions: std.AutoArrayHashMapUnmanaged(InternPool.DeclIndex, void),
/// Memoizes a null `?usize` value.
null_opt_usize: Builder.Constant,
@@ -1011,7 +1007,6 @@ pub const Object = struct {
.named_enum_map = .{},
.type_map = .{},
.error_name_table = .none,
- .extern_collisions = .{},
.null_opt_usize = .no_init,
.struct_field_map = .{},
};
@@ -1029,7 +1024,6 @@ pub const Object = struct {
self.anon_decl_map.deinit(gpa);
self.named_enum_map.deinit(gpa);
self.type_map.deinit(gpa);
- self.extern_collisions.deinit(gpa);
self.builder.deinit();
self.struct_field_map.deinit(gpa);
self.* = undefined;
@@ -1121,61 +1115,6 @@ pub const Object = struct {
try object.builder.finishModuleAsm();
}
- fn resolveExportExternCollisions(object: *Object) !void {
- const mod = object.module;
-
- // This map has externs with incorrect symbol names.
- for (object.extern_collisions.keys()) |decl_index| {
- const global = object.decl_map.get(decl_index) orelse continue;
- // Same logic as below but for externs instead of exports.
- const decl_name = object.builder.strtabStringIfExists(mod.declPtr(decl_index).name.toSlice(&mod.intern_pool)) orelse continue;
- const other_global = object.builder.getGlobal(decl_name) orelse continue;
- if (other_global.toConst().getBase(&object.builder) ==
- global.toConst().getBase(&object.builder)) continue;
-
- try global.replace(other_global, &object.builder);
- }
- object.extern_collisions.clearRetainingCapacity();
-
- for (mod.decl_exports.keys(), mod.decl_exports.values()) |decl_index, export_list| {
- const global = object.decl_map.get(decl_index) orelse continue;
- try resolveGlobalCollisions(object, global, export_list.items);
- }
-
- for (mod.value_exports.keys(), mod.value_exports.values()) |val, export_list| {
- const global = object.anon_decl_map.get(val) orelse continue;
- try resolveGlobalCollisions(object, global, export_list.items);
- }
- }
-
- fn resolveGlobalCollisions(
- object: *Object,
- global: Builder.Global.Index,
- export_list: []const *Module.Export,
- ) !void {
- const mod = object.module;
- const global_base = global.toConst().getBase(&object.builder);
- for (export_list) |exp| {
- // Detect if the LLVM global has already been created as an extern. In such
- // case, we need to replace all uses of it with this exported global.
- const exp_name = object.builder.strtabStringIfExists(exp.opts.name.toSlice(&mod.intern_pool)) orelse continue;
-
- const other_global = object.builder.getGlobal(exp_name) orelse continue;
- if (other_global.toConst().getBase(&object.builder) == global_base) continue;
-
- try global.takeName(other_global, &object.builder);
- try other_global.replace(global, &object.builder);
- // Problem: now we need to replace in the decl_map that
- // the extern decl index points to this new global. However we don't
- // know the decl index.
- // Even if we did, a future incremental update to the extern would then
- // treat the LLVM global as an extern rather than an export, so it would
- // need a way to check that.
- // This is a TODO that needs to be solved when making
- // the LLVM backend support incremental compilation.
- }
- }
-
pub const EmitOptions = struct {
pre_ir_path: ?[]const u8,
pre_bc_path: ?[]const u8,
@@ -1193,7 +1132,6 @@ pub const Object = struct {
pub fn emit(self: *Object, options: EmitOptions) !void {
{
- try self.resolveExportExternCollisions();
try self.genErrorNameTable();
try self.genCmpLtErrorsLenFunction();
try self.genModuleLevelAssembly();
@@ -1698,8 +1636,7 @@ pub const Object = struct {
const file = try o.getDebugFile(namespace.file_scope);
const line_number = decl.navSrcLine(zcu) + 1;
- const is_internal_linkage = decl.val.getExternFunc(zcu) == null and
- !zcu.decl_exports.contains(decl_index);
+ const is_internal_linkage = decl.val.getExternFunc(zcu) == null;
const debug_decl_type = try o.lowerDebugType(decl.typeOf(zcu));
const subprogram = try o.builder.debugSubprogram(
@@ -1752,7 +1689,7 @@ pub const Object = struct {
fg.genBody(air.getMainBody()) catch |err| switch (err) {
error.CodegenFail => {
decl.analysis = .codegen_failure;
- try zcu.failed_decls.put(zcu.gpa, decl_index, dg.err_msg.?);
+ try zcu.failed_analysis.put(zcu.gpa, InternPool.AnalUnit.wrap(.{ .decl = decl_index }), dg.err_msg.?);
dg.err_msg = null;
return;
},
@@ -1760,8 +1697,6 @@ pub const Object = struct {
};
try fg.wip.finish();
-
- try o.updateExports(zcu, .{ .decl_index = decl_index }, zcu.getDeclExports(decl_index));
}
pub fn updateDecl(self: *Object, module: *Module, decl_index: InternPool.DeclIndex) !void {
@@ -1775,72 +1710,31 @@ pub const Object = struct {
dg.genDecl() catch |err| switch (err) {
error.CodegenFail => {
decl.analysis = .codegen_failure;
- try module.failed_decls.put(module.gpa, decl_index, dg.err_msg.?);
+ try module.failed_analysis.put(module.gpa, InternPool.AnalUnit.wrap(.{ .decl = decl_index }), dg.err_msg.?);
dg.err_msg = null;
return;
},
else => |e| return e,
};
- try self.updateExports(module, .{ .decl_index = decl_index }, module.getDeclExports(decl_index));
}
pub fn updateExports(
self: *Object,
mod: *Module,
exported: Module.Exported,
- exports: []const *Module.Export,
+ export_indices: []const u32,
) link.File.UpdateExportsError!void {
const decl_index = switch (exported) {
.decl_index => |i| i,
- .value => |val| return updateExportedValue(self, mod, val, exports),
+ .value => |val| return updateExportedValue(self, mod, val, export_indices),
};
- const gpa = mod.gpa;
const ip = &mod.intern_pool;
- // If the module does not already have the function, we ignore this function call
- // because we call `updateExports` at the end of `updateFunc` and `updateDecl`.
- const global_index = self.decl_map.get(decl_index) orelse return;
+ const global_index = self.decl_map.get(decl_index).?;
const decl = mod.declPtr(decl_index);
const comp = mod.comp;
- if (decl.isExtern(mod)) {
- const decl_name = decl_name: {
- if (mod.getTarget().isWasm() and decl.val.typeOf(mod).zigTypeTag(mod) == .Fn) {
- if (decl.getOwnedExternFunc(mod).?.lib_name.toSlice(ip)) |lib_name| {
- if (!std.mem.eql(u8, lib_name, "c")) {
- break :decl_name try self.builder.strtabStringFmt("{}|{s}", .{ decl.name.fmt(ip), lib_name });
- }
- }
- }
- break :decl_name try self.builder.strtabString(decl.name.toSlice(ip));
- };
- if (self.builder.getGlobal(decl_name)) |other_global| {
- if (other_global != global_index) {
- try self.extern_collisions.put(gpa, decl_index, {});
- }
- }
-
- try global_index.rename(decl_name, &self.builder);
- global_index.setLinkage(.external, &self.builder);
- global_index.setUnnamedAddr(.default, &self.builder);
- if (comp.config.dll_export_fns)
- global_index.setDllStorageClass(.default, &self.builder);
-
- if (decl.val.getVariable(mod)) |decl_var| {
- global_index.ptrConst(&self.builder).kind.variable.setThreadLocal(
- if (decl_var.is_threadlocal) .generaldynamic else .default,
- &self.builder,
- );
- if (decl_var.is_weak_linkage) global_index.setLinkage(.extern_weak, &self.builder);
- }
- } else if (exports.len != 0) {
- const main_exp_name = try self.builder.strtabString(exports[0].opts.name.toSlice(ip));
- try global_index.rename(main_exp_name, &self.builder);
-
- if (decl.val.getVariable(mod)) |decl_var| if (decl_var.is_threadlocal)
- global_index.ptrConst(&self.builder).kind
- .variable.setThreadLocal(.generaldynamic, &self.builder);
-
- return updateExportedGlobal(self, mod, global_index, exports);
+ if (export_indices.len != 0) {
+ return updateExportedGlobal(self, mod, global_index, export_indices);
} else {
const fqn = try self.builder.strtabString((try decl.fullyQualifiedName(mod)).toSlice(ip));
try global_index.rename(fqn, &self.builder);
@@ -1848,17 +1742,6 @@ pub const Object = struct {
if (comp.config.dll_export_fns)
global_index.setDllStorageClass(.default, &self.builder);
global_index.setUnnamedAddr(.unnamed_addr, &self.builder);
- if (decl.val.getVariable(mod)) |decl_var| {
- const decl_namespace = mod.namespacePtr(decl.src_namespace);
- const single_threaded = decl_namespace.file_scope.mod.single_threaded;
- global_index.ptrConst(&self.builder).kind.variable.setThreadLocal(
- if (decl_var.is_threadlocal and !single_threaded)
- .generaldynamic
- else
- .default,
- &self.builder,
- );
- }
}
}
@@ -1866,11 +1749,11 @@ pub const Object = struct {
o: *Object,
mod: *Module,
exported_value: InternPool.Index,
- exports: []const *Module.Export,
+ export_indices: []const u32,
) link.File.UpdateExportsError!void {
const gpa = mod.gpa;
const ip = &mod.intern_pool;
- const main_exp_name = try o.builder.strtabString(exports[0].opts.name.toSlice(ip));
+ const main_exp_name = try o.builder.strtabString(mod.all_exports.items[export_indices[0]].opts.name.toSlice(ip));
const global_index = i: {
const gop = try o.anon_decl_map.getOrPut(gpa, exported_value);
if (gop.found_existing) {
@@ -1894,32 +1777,57 @@ pub const Object = struct {
try variable_index.setInitializer(init_val, &o.builder);
break :i global_index;
};
- return updateExportedGlobal(o, mod, global_index, exports);
+ return updateExportedGlobal(o, mod, global_index, export_indices);
}
fn updateExportedGlobal(
o: *Object,
mod: *Module,
global_index: Builder.Global.Index,
- exports: []const *Module.Export,
+ export_indices: []const u32,
) link.File.UpdateExportsError!void {
const comp = mod.comp;
const ip = &mod.intern_pool;
+ const first_export = mod.all_exports.items[export_indices[0]];
+
+ // We will rename this global to have a name matching `first_export`.
+ // Successive exports become aliases.
+ // If the first export name already exists, then there is a corresponding
+ // extern global - we replace it with this global.
+ const first_exp_name = try o.builder.strtabString(first_export.opts.name.toSlice(ip));
+ if (o.builder.getGlobal(first_exp_name)) |other_global| replace: {
+ if (other_global.toConst().getBase(&o.builder) == global_index.toConst().getBase(&o.builder)) {
+ break :replace; // this global already has the name we want
+ }
+ try global_index.takeName(other_global, &o.builder);
+ try other_global.replace(global_index, &o.builder);
+ // Problem: now we need to replace in the decl_map that
+ // the extern decl index points to this new global. However we don't
+ // know the decl index.
+ // Even if we did, a future incremental update to the extern would then
+ // treat the LLVM global as an extern rather than an export, so it would
+ // need a way to check that.
+ // This is a TODO that needs to be solved when making
+ // the LLVM backend support incremental compilation.
+ } else {
+ try global_index.rename(first_exp_name, &o.builder);
+ }
+
global_index.setUnnamedAddr(.default, &o.builder);
if (comp.config.dll_export_fns)
global_index.setDllStorageClass(.dllexport, &o.builder);
- global_index.setLinkage(switch (exports[0].opts.linkage) {
+ global_index.setLinkage(switch (first_export.opts.linkage) {
.internal => unreachable,
.strong => .external,
.weak => .weak_odr,
.link_once => .linkonce_odr,
}, &o.builder);
- global_index.setVisibility(switch (exports[0].opts.visibility) {
+ global_index.setVisibility(switch (first_export.opts.visibility) {
.default => .default,
.hidden => .hidden,
.protected => .protected,
}, &o.builder);
- if (exports[0].opts.section.toSlice(ip)) |section|
+ if (first_export.opts.section.toSlice(ip)) |section|
switch (global_index.ptrConst(&o.builder).kind) {
.variable => |impl_index| impl_index.setSection(
try o.builder.string(section),
@@ -1936,7 +1844,8 @@ pub const Object = struct {
// The planned solution to this is https://github.com/ziglang/zig/issues/13265
// Until then we iterate over existing aliases and make them point
// to the correct decl, or otherwise add a new alias. Old aliases are leaked.
- for (exports[1..]) |exp| {
+ for (export_indices[1..]) |export_idx| {
+ const exp = mod.all_exports.items[export_idx];
const exp_name = try o.builder.strtabString(exp.opts.name.toSlice(ip));
if (o.builder.getGlobal(exp_name)) |global| {
switch (global.ptrConst(&o.builder).kind) {
@@ -1944,7 +1853,13 @@ pub const Object = struct {
alias.setAliasee(global_index.toConst(), &o.builder);
continue;
},
- .variable, .function => {},
+ .variable, .function => {
+ // This existing global is an `extern` corresponding to this export.
+ // Replace it with the global being exported.
+ // This existing global must be replaced with the alias.
+ try global.rename(.empty, &o.builder);
+ try global.replace(global_index, &o.builder);
+ },
.replaced => unreachable,
}
}
@@ -2688,7 +2603,10 @@ pub const Object = struct {
if (!Type.fromInterned(field_ty).hasRuntimeBitsIgnoreComptime(mod)) continue;
const field_size = Type.fromInterned(field_ty).abiSize(mod);
- const field_align = mod.unionFieldNormalAlignment(union_type, @intCast(field_index));
+ const field_align: InternPool.Alignment = switch (union_type.flagsPtr(ip).layout) {
+ .@"packed" => .none,
+ .auto, .@"extern" => mod.unionFieldNormalAlignment(union_type, @intCast(field_index)),
+ };
const field_name = tag_type.names.get(ip)[field_index];
fields.appendAssumeCapacity(try o.builder.debugMemberType(
@@ -4729,7 +4647,7 @@ pub const DeclGen = struct {
const o = dg.object;
const gpa = o.gpa;
const mod = o.module;
- const src_loc = dg.decl.navSrcLoc(mod).upgrade(mod);
+ const src_loc = dg.decl.navSrcLoc(mod);
dg.err_msg = try Module.ErrorMsg.create(gpa, src_loc, "TODO (LLVM): " ++ format, args);
return error.CodegenFail;
}
@@ -4762,36 +4680,77 @@ pub const DeclGen = struct {
else => try o.lowerValue(init_val),
}, &o.builder);
+ if (decl.val.getVariable(zcu)) |decl_var| {
+ const decl_namespace = zcu.namespacePtr(decl.src_namespace);
+ const single_threaded = decl_namespace.file_scope.mod.single_threaded;
+ variable_index.setThreadLocal(
+ if (decl_var.is_threadlocal and !single_threaded) .generaldynamic else .default,
+ &o.builder,
+ );
+ }
+
const line_number = decl.navSrcLine(zcu) + 1;
- const is_internal_linkage = !o.module.decl_exports.contains(decl_index);
const namespace = zcu.namespacePtr(decl.src_namespace);
const owner_mod = namespace.file_scope.mod;
- if (owner_mod.strip) return;
+ if (!owner_mod.strip) {
+ const debug_file = try o.getDebugFile(namespace.file_scope);
+
+ const debug_global_var = try o.builder.debugGlobalVar(
+ try o.builder.metadataString(decl.name.toSlice(ip)), // Name
+ try o.builder.metadataStringFromStrtabString(variable_index.name(&o.builder)), // Linkage name
+ debug_file, // File
+ debug_file, // Scope
+ line_number,
+ try o.lowerDebugType(decl.typeOf(zcu)),
+ variable_index,
+ .{ .local = !decl.isExtern(zcu) },
+ );
- const debug_file = try o.getDebugFile(namespace.file_scope);
+ const debug_expression = try o.builder.debugExpression(&.{});
- const debug_global_var = try o.builder.debugGlobalVar(
- try o.builder.metadataString(decl.name.toSlice(ip)), // Name
- try o.builder.metadataStringFromStrtabString(variable_index.name(&o.builder)), // Linkage name
- debug_file, // File
- debug_file, // Scope
- line_number,
- try o.lowerDebugType(decl.typeOf(zcu)),
- variable_index,
- .{ .local = is_internal_linkage },
- );
+ const debug_global_var_expression = try o.builder.debugGlobalVarExpression(
+ debug_global_var,
+ debug_expression,
+ );
- const debug_expression = try o.builder.debugExpression(&.{});
+ variable_index.setGlobalVariableExpression(debug_global_var_expression, &o.builder);
+ try o.debug_globals.append(o.gpa, debug_global_var_expression);
+ }
+ }
- const debug_global_var_expression = try o.builder.debugGlobalVarExpression(
- debug_global_var,
- debug_expression,
- );
+ if (decl.isExtern(zcu)) {
+ const global_index = o.decl_map.get(decl_index).?;
- variable_index.setGlobalVariableExpression(debug_global_var_expression, &o.builder);
- try o.debug_globals.append(o.gpa, debug_global_var_expression);
+ const decl_name = decl_name: {
+ if (zcu.getTarget().isWasm() and decl.typeOf(zcu).zigTypeTag(zcu) == .Fn) {
+ if (decl.getOwnedExternFunc(zcu).?.lib_name.toSlice(ip)) |lib_name| {
+ if (!std.mem.eql(u8, lib_name, "c")) {
+ break :decl_name try o.builder.strtabStringFmt("{}|{s}", .{ decl.name.fmt(ip), lib_name });
+ }
+ }
+ }
+ break :decl_name try o.builder.strtabString(decl.name.toSlice(ip));
+ };
+
+ if (o.builder.getGlobal(decl_name)) |other_global| {
+ if (other_global != global_index) {
+ // Another global already has this name; just use it in place of this global.
+ try global_index.replace(other_global, &o.builder);
+ return;
+ }
+ }
+
+ try global_index.rename(decl_name, &o.builder);
+ global_index.setLinkage(.external, &o.builder);
+ global_index.setUnnamedAddr(.default, &o.builder);
+ if (zcu.comp.config.dll_export_fns)
+ global_index.setDllStorageClass(.default, &o.builder);
+
+ if (decl.val.getVariable(zcu)) |decl_var| {
+ if (decl_var.is_weak_linkage) global_index.setLinkage(.extern_weak, &o.builder);
+ }
}
}
};
@@ -5193,7 +5152,6 @@ pub const FuncGen = struct {
const fqn = try decl.fullyQualifiedName(zcu);
- const is_internal_linkage = !zcu.decl_exports.contains(decl_index);
const fn_ty = try zcu.funcType(.{
.param_types = &.{},
.return_type = .void_type,
@@ -5211,7 +5169,7 @@ pub const FuncGen = struct {
.sp_flags = .{
.Optimized = owner_mod.optimize_mode != .Debug,
.Definition = true,
- .LocalToUnit = is_internal_linkage,
+ .LocalToUnit = true, // TODO: we can't know this at this point, since the function could be exported later!
},
},
o.debug_compile_unit,
diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig
index ee163c3154..c56a5a799e 100644
--- a/src/codegen/spirv.zig
+++ b/src/codegen/spirv.zig
@@ -9,7 +9,7 @@ const Zcu = @import("../Zcu.zig");
/// Deprecated.
const Module = Zcu;
const Decl = Module.Decl;
-const Type = @import("../type.zig").Type;
+const Type = @import("../Type.zig");
const Value = @import("../Value.zig");
const Air = @import("../Air.zig");
const Liveness = @import("../Liveness.zig");
@@ -218,7 +218,7 @@ pub const Object = struct {
decl_gen.genDecl() catch |err| switch (err) {
error.CodegenFail => {
- try mod.failed_decls.put(mod.gpa, decl_index, decl_gen.error_msg.?);
+ try mod.failed_analysis.put(mod.gpa, InternPool.AnalUnit.wrap(.{ .decl = decl_index }), decl_gen.error_msg.?);
},
else => |other| {
// There might be an error that happened *after* self.error_msg
@@ -415,7 +415,7 @@ const DeclGen = struct {
pub fn fail(self: *DeclGen, comptime format: []const u8, args: anytype) Error {
@setCold(true);
const mod = self.module;
- const src_loc = self.module.declPtr(self.decl_index).navSrcLoc(mod).upgrade(mod);
+ const src_loc = self.module.declPtr(self.decl_index).navSrcLoc(mod);
assert(self.error_msg == null);
self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, format, args);
return error.CodegenFail;
@@ -6439,7 +6439,7 @@ const DeclGen = struct {
// TODO: Translate proper error locations.
assert(as.errors.items.len != 0);
assert(self.error_msg == null);
- const src_loc = self.module.declPtr(self.decl_index).navSrcLoc(mod).upgrade(mod);
+ const src_loc = self.module.declPtr(self.decl_index).navSrcLoc(mod);
self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, "failed to assemble SPIR-V inline assembly", .{});
const notes = try self.module.gpa.alloc(Module.ErrorMsg, as.errors.items.len);