diff options
Diffstat (limited to 'src/codegen')
| -rw-r--r-- | src/codegen/c.zig | 380 | ||||
| -rw-r--r-- | src/codegen/c/Type.zig | 2 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 276 | ||||
| -rw-r--r-- | src/codegen/spirv.zig | 8 |
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); |
