authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-03-24 11:23:28+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-03-28 16:50:42+00:00
logd28c5069b8421628fcb333d8e558a41d2a2d93d5
treef60314af000528f7d966606ffede99585144792c
parent500e6c7cfe7fe57db51b99a8e76e67a3441de7ac
signaturelock-open Commit is signed but in an unrecognized format.

llvm: rework handling of globals

The main goal here is to make incremental compilation work a bit better. I also slightly expanded some `std.zig.llvm.Builder` APIs so that we don't need to pointlessly create new `Global`s whenever e.g. a function turns into a variable or vice versa. Also, lean into aliases for exports! If we just use aliases for every export, everything becomes simpler. Besides, we can't just go around renaming the globals of `Nav`s: the export could disappear on a future update, in which case we'd have to somehow revert that change, which is easier said than done.

6 files changed, 699 insertions(+), 724 deletions(-)

lib/std/zig/llvm/Builder.zig+107-48
...@@ -2343,12 +2343,13 @@ pub const Global = struct {...@@ -2343,12 +2343,13 @@ pub const Global = struct {
2343 none = maxInt(u32),2343 none = maxInt(u32),
2344 _,2344 _,
23452345
2346 pub fn unwrap(self: Index, builder: *const Builder) Index {2346 pub fn unwrap(orig_index: Index, builder: *const Builder) Index {
2347 var cur = self;2347 var cur = orig_index;
2348 while (true) {2348 while (true) {
2349 const replacement = cur.getReplacement(builder);2349 switch (builder.globals.values()[@intFromEnum(cur)].kind) {
2350 if (replacement == .none) return cur;2350 .replaced => |replacement| cur = replacement,
2351 cur = replacement;2351 else => return cur,
2352 }
2352 }2353 }
2353 }2354 }
23542355
...@@ -2388,8 +2389,12 @@ pub const Global = struct {...@@ -2388,8 +2389,12 @@ pub const Global = struct {
2388 return self.ptrConst(builder).type;2389 return self.ptrConst(builder).type;
2389 }2390 }
23902391
2391 pub fn toConst(self: Index) Constant {2392 pub fn toConst(global: Index) Constant {
2392 return @enumFromInt(@intFromEnum(Constant.first_global) + @intFromEnum(self));2393 return @enumFromInt(@intFromEnum(Constant.first_global) + @intFromEnum(global));
2394 }
2395
2396 pub fn toValue(global: Index) Value {
2397 return global.toConst().toValue();
2393 }2398 }
23942399
2395 pub fn setLinkage(self: Index, linkage: Linkage, builder: *Builder) void {2400 pub fn setLinkage(self: Index, linkage: Linkage, builder: *Builder) void {
...@@ -2450,6 +2455,42 @@ pub const Global = struct {...@@ -2450,6 +2455,42 @@ pub const Global = struct {
2450 self.ptr(builder).kind = .{ .replaced = .none };2455 self.ptr(builder).kind = .{ .replaced = .none };
2451 }2456 }
24522457
2458 /// Replaces whatever this `Global` currently contains with a new `Function`. Similar to
2459 /// `Builder.addFunction`, but the same `Global` is reused.
2460 pub fn toNewFunction(global: Index, builder: *Builder) Allocator.Error!Function.Index {
2461 try builder.functions.ensureUnusedCapacity(builder.gpa, 1);
2462 errdefer comptime unreachable;
2463 const function: Function.Index = @enumFromInt(builder.functions.items.len);
2464 builder.functions.appendAssumeCapacity(.{
2465 .global = global,
2466 .strip = undefined,
2467 });
2468 global.ptr(builder).kind = .{ .function = function };
2469 return function;
2470 }
2471
2472 /// Replaces whatever this `Global` currently contains with a new `Variable`. Similar to
2473 /// `Builder.addVariable`, but the same `Global` is reused.
2474 pub fn toNewVariable(global: Index, builder: *Builder) Allocator.Error!Variable.Index {
2475 try builder.variables.ensureUnusedCapacity(builder.gpa, 1);
2476 errdefer comptime unreachable;
2477 const variable: Variable.Index = @enumFromInt(builder.variables.items.len);
2478 builder.variables.appendAssumeCapacity(.{ .global = global });
2479 global.ptr(builder).kind = .{ .variable = variable };
2480 return variable;
2481 }
2482
2483 /// Replaces whatever this `Global` currently contains with a new `Alias`. Similar to
2484 /// `Builder.addAlias`, but the same `Global` is reused.
2485 pub fn toNewAlias(global: Index, builder: *Builder) Allocator.Error!Alias.Index {
2486 try builder.aliases.ensureUnusedCapacity(builder.gpa, 1);
2487 errdefer comptime unreachable;
2488 const alias: Alias.Index = @enumFromInt(builder.aliases.items.len);
2489 builder.aliass.appendAssumeCapacity(.{ .global = global, .aliasee = .none });
2490 global.ptr(builder).kind = .{ .alias = alias };
2491 return alias;
2492 }
2493
2453 fn updateDsoLocal(self: Index, builder: *Builder) void {2494 fn updateDsoLocal(self: Index, builder: *Builder) void {
2454 const self_ptr = self.ptr(builder);2495 const self_ptr = self.ptr(builder);
2455 switch (self_ptr.linkage) {2496 switch (self_ptr.linkage) {
...@@ -2494,13 +2535,6 @@ pub const Global = struct {...@@ -2494,13 +2535,6 @@ pub const Global = struct {
2494 self.renameAssumeCapacity(builder.next_replaced_global, builder);2535 self.renameAssumeCapacity(builder.next_replaced_global, builder);
2495 self.ptr(builder).kind = .{ .replaced = other.unwrap(builder) };2536 self.ptr(builder).kind = .{ .replaced = other.unwrap(builder) };
2496 }2537 }
2497
2498 fn getReplacement(self: Index, builder: *const Builder) Index {
2499 return switch (builder.globals.values()[@intFromEnum(self)].kind) {
2500 .replaced => |replacement| replacement,
2501 else => .none,
2502 };
2503 }
2504 };2538 };
2505};2539};
25062540
...@@ -2593,22 +2627,6 @@ pub const Variable = struct {...@@ -2593,22 +2627,6 @@ pub const Variable = struct {
2593 return self.toConst(builder).toValue();2627 return self.toConst(builder).toValue();
2594 }2628 }
25952629
2596 pub fn setLinkage(self: Index, linkage: Linkage, builder: *Builder) void {
2597 return self.ptrConst(builder).global.setLinkage(linkage, builder);
2598 }
2599
2600 pub fn setVisibility(self: Index, visibility: Visibility, builder: *Builder) void {
2601 return self.ptrConst(builder).global.setVisibility(visibility, builder);
2602 }
2603
2604 pub fn setDllStorageClass(self: Index, class: DllStorageClass, builder: *Builder) void {
2605 return self.ptrConst(builder).global.setDllStorageClass(class, builder);
2606 }
2607
2608 pub fn setUnnamedAddr(self: Index, unnamed_addr: UnnamedAddr, builder: *Builder) void {
2609 return self.ptrConst(builder).global.setUnnamedAddr(unnamed_addr, builder);
2610 }
2611
2612 pub fn setThreadLocal(self: Index, thread_local: ThreadLocal, builder: *Builder) void {2630 pub fn setThreadLocal(self: Index, thread_local: ThreadLocal, builder: *Builder) void {
2613 self.ptr(builder).thread_local = thread_local;2631 self.ptr(builder).thread_local = thread_local;
2614 }2632 }
...@@ -9692,8 +9710,12 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void...@@ -9692,8 +9710,12 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
96929710
9693 if (self.variables.items.len > 0) {9711 if (self.variables.items.len > 0) {
9694 if (need_newline) try w.writeByte('\n') else need_newline = true;9712 if (need_newline) try w.writeByte('\n') else need_newline = true;
9695 for (self.variables.items) |variable| {9713 for (self.variables.items, 0..) |variable, variable_i| {
9696 if (variable.global.getReplacement(self) != .none) continue;9714 // Skip the variable if its global has been repurposed for something else.
9715 switch (variable.global.ptrConst(self).kind) {
9716 .variable => |v| if (@intFromEnum(v) != variable_i) continue,
9717 else => continue,
9718 }
9697 const global = variable.global.ptrConst(self);9719 const global = variable.global.ptrConst(self);
9698 metadata_formatter.need_comma = true;9720 metadata_formatter.need_comma = true;
9699 defer metadata_formatter.need_comma = undefined;9721 defer metadata_formatter.need_comma = undefined;
...@@ -9723,8 +9745,12 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void...@@ -9723,8 +9745,12 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
97239745
9724 if (self.aliases.items.len > 0) {9746 if (self.aliases.items.len > 0) {
9725 if (need_newline) try w.writeByte('\n') else need_newline = true;9747 if (need_newline) try w.writeByte('\n') else need_newline = true;
9726 for (self.aliases.items) |alias| {9748 for (self.aliases.items, 0..) |alias, alias_i| {
9727 if (alias.global.getReplacement(self) != .none) continue;9749 // Skip the alias if its global has been repurposed for something else.
9750 switch (alias.global.ptrConst(self).kind) {
9751 .alias => |a| if (@intFromEnum(a) != alias_i) continue,
9752 else => continue,
9753 }
9728 const global = alias.global.ptrConst(self);9754 const global = alias.global.ptrConst(self);
9729 metadata_formatter.need_comma = true;9755 metadata_formatter.need_comma = true;
9730 defer metadata_formatter.need_comma = undefined;9756 defer metadata_formatter.need_comma = undefined;
...@@ -9750,7 +9776,11 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void...@@ -9750,7 +9776,11 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
9750 defer attribute_groups.deinit(self.gpa);9776 defer attribute_groups.deinit(self.gpa);
97519777
9752 for (0.., self.functions.items) |function_i, function| {9778 for (0.., self.functions.items) |function_i, function| {
9753 if (function.global.getReplacement(self) != .none) continue;9779 // Skip the function if its global has been repurposed for something else.
9780 switch (function.global.ptrConst(self).kind) {
9781 .function => |f| if (@intFromEnum(f) != function_i) continue,
9782 else => continue,
9783 }
9754 if (need_newline) try w.writeByte('\n') else need_newline = true;9784 if (need_newline) try w.writeByte('\n') else need_newline = true;
9755 const function_index: Function.Index = @enumFromInt(function_i);9785 const function_index: Function.Index = @enumFromInt(function_i);
9756 const global = function.global.ptrConst(self);9786 const global = function.global.ptrConst(self);
...@@ -13687,20 +13717,32 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco...@@ -13687,20 +13717,32 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
13687 self.aliases.items.len,13717 self.aliases.items.len,
13688 );13718 );
1368913719
13690 for (self.variables.items) |variable| {13720 for (self.variables.items, 0..) |variable, variable_i| {
13691 if (variable.global.getReplacement(self) != .none) continue;13721 // Skip the variable if its global has been repurposed for something else.
13722 switch (variable.global.ptrConst(self).kind) {
13723 .variable => |v| if (@intFromEnum(v) != variable_i) continue,
13724 else => continue,
13725 }
1369213726
13693 globals.putAssumeCapacity(variable.global, {});13727 globals.putAssumeCapacity(variable.global, {});
13694 }13728 }
1369513729
13696 for (self.functions.items) |function| {13730 for (self.functions.items, 0..) |function, function_i| {
13697 if (function.global.getReplacement(self) != .none) continue;13731 // Skip the function if its global has been repurposed for something else.
13732 switch (function.global.ptrConst(self).kind) {
13733 .function => |f| if (@intFromEnum(f) != function_i) continue,
13734 else => continue,
13735 }
1369813736
13699 globals.putAssumeCapacity(function.global, {});13737 globals.putAssumeCapacity(function.global, {});
13700 }13738 }
1370113739
13702 for (self.aliases.items) |alias| {13740 for (self.aliases.items, 0..) |alias, alias_i| {
13703 if (alias.global.getReplacement(self) != .none) continue;13741 // Skip the alias if its global has been repurposed for something else.
13742 switch (alias.global.ptrConst(self).kind) {
13743 .alias => |a| if (@intFromEnum(a) != alias_i) continue,
13744 else => continue,
13745 }
1370413746
13705 globals.putAssumeCapacity(alias.global, {});13747 globals.putAssumeCapacity(alias.global, {});
13706 }13748 }
...@@ -13742,8 +13784,12 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco...@@ -13742,8 +13784,12 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
13742 defer section_map.deinit(self.gpa);13784 defer section_map.deinit(self.gpa);
13743 try section_map.ensureUnusedCapacity(self.gpa, globals.count());13785 try section_map.ensureUnusedCapacity(self.gpa, globals.count());
1374413786
13745 for (self.variables.items) |variable| {13787 for (self.variables.items, 0..) |variable, variable_i| {
13746 if (variable.global.getReplacement(self) != .none) continue;13788 // Skip the variable if its global has been repurposed for something else.
13789 switch (variable.global.ptrConst(self).kind) {
13790 .variable => |v| if (@intFromEnum(v) != variable_i) continue,
13791 else => continue,
13792 }
1374713793
13748 const section = blk: {13794 const section = blk: {
13749 if (variable.section == .none) break :blk 0;13795 if (variable.section == .none) break :blk 0;
...@@ -13789,8 +13835,12 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco...@@ -13789,8 +13835,12 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
13789 });13835 });
13790 }13836 }
1379113837
13792 for (self.functions.items) |func| {13838 for (self.functions.items, 0..) |func, func_i| {
13793 if (func.global.getReplacement(self) != .none) continue;13839 // Skip the function if its global has been repurposed for something else.
13840 switch (func.global.ptrConst(self).kind) {
13841 .function => |f| if (@intFromEnum(f) != func_i) continue,
13842 else => continue,
13843 }
1379413844
13795 const section = blk: {13845 const section = blk: {
13796 if (func.section == .none) break :blk 0;13846 if (func.section == .none) break :blk 0;
...@@ -13830,8 +13880,12 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco...@@ -13830,8 +13880,12 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
13830 });13880 });
13831 }13881 }
1383213882
13833 for (self.aliases.items) |alias| {13883 for (self.aliases.items, 0..) |alias, alias_i| {
13834 if (alias.global.getReplacement(self) != .none) continue;13884 // Skip the alias if its global has been repurposed for something else.
13885 switch (alias.global.ptrConst(self).kind) {
13886 .alias => |a| if (@intFromEnum(a) != alias_i) continue,
13887 else => continue,
13888 }
1383513889
13836 const strtab = alias.global.strtab(self);13890 const strtab = alias.global.strtab(self);
1383713891
...@@ -14635,8 +14689,13 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco...@@ -14635,8 +14689,13 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
14635 };14689 };
1463614690
14637 for (self.functions.items, 0..) |func, func_index| {14691 for (self.functions.items, 0..) |func, func_index| {
14692 // Skip the function if its global has been repurposed for something else.
14693 switch (func.global.ptrConst(self).kind) {
14694 .function => |f| if (@intFromEnum(f) != func_index) continue,
14695 else => continue,
14696 }
14697
14638 const FunctionBlock = ir.ModuleBlock.FunctionBlock;14698 const FunctionBlock = ir.ModuleBlock.FunctionBlock;
14639 if (func.global.getReplacement(self) != .none) continue;
1464014699
14641 if (func.instructions.len == 0) continue;14700 if (func.instructions.len == 0) continue;
1464214701
src/Sema.zig-1
...@@ -5751,7 +5751,6 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void...@@ -5751,7 +5751,6 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
5751 if (ptr_info.byte_offset != 0) {5751 if (ptr_info.byte_offset != 0) {
5752 return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{});5752 return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{});
5753 }5753 }
5754 if (zcu.llvm_object != null and options.linkage == .internal) return;
5755 try sema.exports.append(zcu.gpa, .{5754 try sema.exports.append(zcu.gpa, .{
5756 .opts = options,5755 .opts = options,
5757 .src = src,5756 .src = src,
src/Zcu.zig+3-1
...@@ -3731,7 +3731,9 @@ pub fn resetUnit(zcu: *Zcu, unit: AnalUnit) void {...@@ -3731,7 +3731,9 @@ pub fn resetUnit(zcu: *Zcu, unit: AnalUnit) void {
3731 };3731 };
3732 for (zcu.all_exports.items[base..][0..len], base..) |exp, exp_index_usize| {3732 for (zcu.all_exports.items[base..][0..len], base..) |exp, exp_index_usize| {
3733 const exp_index: Export.Index = @enumFromInt(exp_index_usize);3733 const exp_index: Export.Index = @enumFromInt(exp_index_usize);
3734 if (zcu.comp.bin_file) |lf| {3734 if (zcu.llvm_object) |llvm_object| {
3735 _ = llvm_object; // TODO: delete exports from LLVM
3736 } else if (zcu.comp.bin_file) |lf| {
3735 lf.deleteExport(exp.exported, exp.opts.name);3737 lf.deleteExport(exp.exported, exp.opts.name);
3736 }3738 }
3737 if (zcu.failed_exports.fetchSwapRemove(exp_index)) |failed_kv| {3739 if (zcu.failed_exports.fetchSwapRemove(exp_index)) |failed_kv| {
src/Zcu/PerThread.zig+1-8
...@@ -1910,14 +1910,7 @@ fn analyzeNavVal(...@@ -1910,14 +1910,7 @@ fn analyzeNavVal(
19101910
1911 try sema.flushExports();1911 try sema.flushExports();
19121912
1913 queue_codegen: {1913 if (queue_linker_work) {
1914 if (!queue_linker_work) break :queue_codegen;
1915
1916 if (!nav_ty.hasRuntimeBits(zcu)) {
1917 if (comp.config.use_llvm) break :queue_codegen;
1918 if (file.mod.?.strip) break :queue_codegen;
1919 }
1920
1921 comp.link_prog_node.increaseEstimatedTotalItems(1);1914 comp.link_prog_node.increaseEstimatedTotalItems(1);
1922 try comp.link_queue.enqueueZcu(comp, pt.tid, .{ .link_nav = nav_id });1915 try comp.link_queue.enqueueZcu(comp, pt.tid, .{ .link_nav = nav_id });
1923 }1916 }
src/codegen/llvm.zig+553-641
...@@ -550,17 +550,13 @@ pub const Object = struct {...@@ -550,17 +550,13 @@ pub const Object = struct {
550 debug_anyerror_fwd_ref: Builder.Metadata.Optional,550 debug_anyerror_fwd_ref: Builder.Metadata.Optional,
551551
552 zcu: *Zcu,552 zcu: *Zcu,
553 /// Ideally we would use `llvm_module.getNamedFunction` to go from *Decl to LLVM function,553 /// Maps a `Nav` to the corresponding LLVM global.
554 /// but that has some downsides:
555 /// * we have to compute the fully qualified name every time we want to do the lookup
556 /// * for externally linked functions, the name is not fully qualified, but when
557 /// a Decl goes from exported to not exported and vice-versa, we would use the wrong
558 /// version of the name and incorrectly get function not found in the llvm module.
559 /// * it works for functions not all globals.
560 /// Therefore, this table keeps track of the mapping.
561 nav_map: std.AutoHashMapUnmanaged(InternPool.Nav.Index, Builder.Global.Index),554 nav_map: std.AutoHashMapUnmanaged(InternPool.Nav.Index, Builder.Global.Index),
562 /// Same deal as `decl_map` but for anonymous declarations, which are always global constants.555 /// Same as `nav_map` but for UAVs (which are always global constants).
563 uav_map: std.AutoHashMapUnmanaged(InternPool.Index, Builder.Global.Index),556 uav_map: std.AutoHashMapUnmanaged(struct {
557 val: InternPool.Index,
558 @"addrspace": std.builtin.AddressSpace,
559 }, Builder.Variable.Index),
564 /// Maps enum types to their corresponding LLVM functions for implementing the `tag_name` instruction.560 /// Maps enum types to their corresponding LLVM functions for implementing the `tag_name` instruction.
565 enum_tag_name_map: std.AutoHashMapUnmanaged(InternPool.Index, Builder.Function.Index),561 enum_tag_name_map: std.AutoHashMapUnmanaged(InternPool.Index, Builder.Function.Index),
566 /// Serves the same purpose as `enum_tag_name_map` but for the `is_named_enum_value` instruction.562 /// Serves the same purpose as `enum_tag_name_map` but for the `is_named_enum_value` instruction.
...@@ -717,13 +713,13 @@ pub const Object = struct {...@@ -717,13 +713,13 @@ pub const Object = struct {
717 for (llvm_errors[1..], error_name_list) |*llvm_error, name| {713 for (llvm_errors[1..], error_name_list) |*llvm_error, name| {
718 const name_string = try o.builder.stringNull(name.toSlice(ip));714 const name_string = try o.builder.stringNull(name.toSlice(ip));
719 const name_init = try o.builder.stringConst(name_string);715 const name_init = try o.builder.stringConst(name_string);
720 const name_variable_index =716 const name_variable_index = try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default);
721 try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default);
722 try name_variable_index.setInitializer(name_init, &o.builder);717 try name_variable_index.setInitializer(name_init, &o.builder);
723 name_variable_index.setLinkage(.private, &o.builder);
724 name_variable_index.setMutability(.constant, &o.builder);718 name_variable_index.setMutability(.constant, &o.builder);
725 name_variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
726 name_variable_index.setAlignment(comptime .fromByteUnits(1), &o.builder);719 name_variable_index.setAlignment(comptime .fromByteUnits(1), &o.builder);
720 const global_index = name_variable_index.ptrConst(&o.builder).global;
721 global_index.setLinkage(.private, &o.builder);
722 global_index.setUnnamedAddr(.unnamed_addr, &o.builder);
727723
728 llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{724 llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{
729 name_variable_index.toConst(&o.builder),725 name_variable_index.toConst(&o.builder),
...@@ -790,9 +786,9 @@ pub const Object = struct {...@@ -790,9 +786,9 @@ pub const Object = struct {
790 array_llvm_ty,786 array_llvm_ty,
791 .default,787 .default,
792 );788 );
793 compiler_used_variable.setLinkage(.appending, &o.builder);
794 compiler_used_variable.setSection(try o.builder.string("llvm.metadata"), &o.builder);
795 try compiler_used_variable.setInitializer(init_val, &o.builder);789 try compiler_used_variable.setInitializer(init_val, &o.builder);
790 compiler_used_variable.setSection(try o.builder.string("llvm.metadata"), &o.builder);
791 compiler_used_variable.ptrConst(&o.builder).global.setLinkage(.appending, &o.builder);
796 }792 }
797793
798 if (!o.builder.strip) {794 if (!o.builder.strip) {
...@@ -1140,6 +1136,7 @@ pub const Object = struct {...@@ -1140,6 +1136,7 @@ pub const Object = struct {
1140 ) Zcu.CodegenFailError!void {1136 ) Zcu.CodegenFailError!void {
1141 const zcu = o.zcu;1137 const zcu = o.zcu;
1142 const comp = zcu.comp;1138 const comp = zcu.comp;
1139 const gpa = comp.gpa;
1143 const ip = &zcu.intern_pool;1140 const ip = &zcu.intern_pool;
1144 const func = zcu.funcInfo(func_index);1141 const func = zcu.funcInfo(func_index);
1145 const nav = ip.getNav(func.owner_nav);1142 const nav = ip.getNav(func.owner_nav);
...@@ -1149,9 +1146,42 @@ pub const Object = struct {...@@ -1149,9 +1146,42 @@ pub const Object = struct {
1149 const fn_info = zcu.typeToFunc(fn_ty).?;1146 const fn_info = zcu.typeToFunc(fn_ty).?;
1150 const target = &owner_mod.resolved_target.result;1147 const target = &owner_mod.resolved_target.result;
11511148
1152 const function_index = try o.resolveLlvmFunction(func.owner_nav);1149 const gop = try o.nav_map.getOrPut(gpa, func.owner_nav);
1150 if (!gop.found_existing) {
1151 errdefer assert(o.nav_map.remove(func.owner_nav));
1152 // First time lowering this NAV! Create a fresh global.
1153 const llvm_name = try o.builder.strtabString(nav.fqn.toSlice(ip));
1154 gop.value_ptr.* = try o.builder.addGlobal(llvm_name, .{
1155 .type = .void, // placeholder; populated below
1156 .kind = .{ .alias = .none }, // placeholder; populated below
1157 });
1158 }
1159 const llvm_global = gop.value_ptr.*;
1160
1161 const llvm_function: Builder.Function.Index = switch (llvm_global.ptrConst(&o.builder).kind) {
1162 .function => |function| function, // re-use existing `Builder.Function`
1163 .replaced, .alias, .variable => try llvm_global.toNewFunction(&o.builder),
1164 };
1165 {
1166 const global = llvm_function.ptrConst(&o.builder).global.ptr(&o.builder);
1167 global.type = try o.lowerType(fn_ty);
1168 global.addr_space = toLlvmAddressSpace(nav.resolved.?.@"addrspace", target);
1169 global.linkage = if (o.builder.strip) .private else .internal;
1170 global.visibility = .default;
1171 global.dll_storage_class = .default;
1172 global.unnamed_addr = .unnamed_addr;
1173 }
1174 llvm_function.setAlignment(switch (nav.resolved.?.@"align") {
1175 .none => fn_ty.abiAlignment(zcu).toLlvm(),
1176 else => |a| a.toLlvm(),
1177 }, &o.builder);
1178 llvm_function.setSection(s: {
1179 const section = nav.resolved.?.@"linksection".toSlice(ip) orelse break :s .none;
1180 break :s try o.builder.string(section);
1181 }, &o.builder);
1182 try o.addLlvmFunctionAttributes(pt, func.owner_nav, llvm_function);
11531183
1154 var attributes = try function_index.ptrConst(&o.builder).attributes.toWip(&o.builder);1184 var attributes = try llvm_function.ptrConst(&o.builder).attributes.toWip(&o.builder);
1155 defer attributes.deinit(&o.builder);1185 defer attributes.deinit(&o.builder);
11561186
1157 const func_analysis = func.analysisUnordered(ip);1187 const func_analysis = func.analysisUnordered(ip);
...@@ -1221,47 +1251,41 @@ pub const Object = struct {...@@ -1221,47 +1251,41 @@ pub const Object = struct {
1221 } }, &o.builder);1251 } }, &o.builder);
1222 }1252 }
12231253
1224 if (nav.resolved.?.@"linksection".toSlice(ip)) |section|
1225 function_index.setSection(try o.builder.string(section), &o.builder);
1226
1227 var deinit_wip = true;1254 var deinit_wip = true;
1228 var wip = try Builder.WipFunction.init(&o.builder, .{1255 var wip = try Builder.WipFunction.init(&o.builder, .{
1229 .function = function_index,1256 .function = llvm_function,
1230 .strip = owner_mod.strip,1257 .strip = owner_mod.strip,
1231 });1258 });
1232 defer if (deinit_wip) wip.deinit();1259 defer if (deinit_wip) wip.deinit();
1233 wip.cursor = .{ .block = try wip.block(0, "Entry") };1260 wip.cursor = .{ .block = try wip.block(0, "Entry") };
12341261
1235 var llvm_arg_i: u32 = 0;
1236
1237 const ret_ptr: Builder.Value = if (firstParamSRet(fn_info, zcu, target)) param: {
1238 const param = wip.arg(llvm_arg_i);
1239 llvm_arg_i += 1;
1240 break :param param;
1241 } else .none;
1242
1243 if (ccAbiPromoteInt(fn_info.cc, zcu, Type.fromInterned(fn_info.return_type))) |s| switch (s) {1262 if (ccAbiPromoteInt(fn_info.cc, zcu, Type.fromInterned(fn_info.return_type))) |s| switch (s) {
1244 .signed => try attributes.addRetAttr(.signext, &o.builder),1263 .signed => try attributes.addRetAttr(.signext, &o.builder),
1245 .unsigned => try attributes.addRetAttr(.zeroext, &o.builder),1264 .unsigned => try attributes.addRetAttr(.zeroext, &o.builder),
1246 };1265 };
12471266
1248 const err_return_tracing = fn_info.cc == .auto and comp.config.any_error_tracing;
1249
1250 const err_ret_trace: Builder.Value = if (err_return_tracing) param: {
1251 const param = wip.arg(llvm_arg_i);
1252 llvm_arg_i += 1;
1253 break :param param;
1254 } else .none;
1255
1256 // This is the list of args we will use that correspond directly to the AIR arg1267 // This is the list of args we will use that correspond directly to the AIR arg
1257 // instructions. Depending on the calling convention, this list is not necessarily1268 // instructions. Depending on the calling convention, this list is not necessarily
1258 // a bijection with the actual LLVM parameters of the function.1269 // a bijection with the actual LLVM parameters of the function.
1259 const gpa = o.gpa;
1260 var args: std.ArrayList(Builder.Value) = .empty;1270 var args: std.ArrayList(Builder.Value) = .empty;
1261 defer args.deinit(gpa);1271 defer args.deinit(gpa);
12621272
1263 {1273 const ret_ptr: Builder.Value, const err_ret_trace: Builder.Value = implicit_args: {
1264 var it = iterateParamTypes(o, fn_info);1274 var it = iterateParamTypes(o, fn_info);
1275
1276 const ret_ptr: Builder.Value = if (firstParamSRet(fn_info, zcu, target)) param: {
1277 const param = wip.arg(it.llvm_index);
1278 it.llvm_index += 1;
1279 break :param param;
1280 } else .none;
1281
1282 const err_return_tracing = fn_info.cc == .auto and comp.config.any_error_tracing;
1283 const err_ret_trace: Builder.Value = if (err_return_tracing) param: {
1284 const param = wip.arg(it.llvm_index);
1285 it.llvm_index += 1;
1286 break :param param;
1287 } else .none;
1288
1265 while (try it.next()) |lowering| {1289 while (try it.next()) |lowering| {
1266 try args.ensureUnusedCapacity(gpa, 1);1290 try args.ensureUnusedCapacity(gpa, 1);
12671291
...@@ -1271,7 +1295,7 @@ pub const Object = struct {...@@ -1271,7 +1295,7 @@ pub const Object = struct {
1271 assert(!it.byval_attr);1295 assert(!it.byval_attr);
1272 const param_index = it.zig_index - 1;1296 const param_index = it.zig_index - 1;
1273 const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[param_index]);1297 const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[param_index]);
1274 const param = wip.arg(llvm_arg_i);1298 const param = wip.arg(it.llvm_index - 1);
12751299
1276 if (isByRef(param_ty, zcu)) {1300 if (isByRef(param_ty, zcu)) {
1277 const alignment = param_ty.abiAlignment(zcu).toLlvm();1301 const alignment = param_ty.abiAlignment(zcu).toLlvm();
...@@ -1281,146 +1305,116 @@ pub const Object = struct {...@@ -1281,146 +1305,116 @@ pub const Object = struct {
1281 args.appendAssumeCapacity(arg_ptr);1305 args.appendAssumeCapacity(arg_ptr);
1282 } else {1306 } else {
1283 args.appendAssumeCapacity(param);1307 args.appendAssumeCapacity(param);
1284
1285 try o.addByValParamAttrs(pt, &attributes, param_ty, param_index, fn_info, llvm_arg_i);
1286 }1308 }
1287 llvm_arg_i += 1;
1288 },1309 },
1289 .byref => {1310 .byref => {
1290 const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);1311 const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
1291 const param_llvm_ty = try o.lowerType(param_ty);1312 const param = wip.arg(it.llvm_index - 1);
1292 const param = wip.arg(llvm_arg_i);
1293 const alignment = param_ty.abiAlignment(zcu).toLlvm();
1294
1295 try o.addByRefParamAttrs(&attributes, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty);
1296 llvm_arg_i += 1;
12971313
1298 if (isByRef(param_ty, zcu)) {1314 if (isByRef(param_ty, zcu)) {
1299 args.appendAssumeCapacity(param);1315 args.appendAssumeCapacity(param);
1300 } else {1316 } else {
1317 const param_llvm_ty = try o.lowerType(param_ty);
1318 const alignment = param_ty.abiAlignment(zcu).toLlvm();
1301 args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, ""));1319 args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, ""));
1302 }1320 }
1303 },1321 },
1304 .byref_mut => {1322 .byref_mut => {
1305 const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);1323 const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
1306 const param_llvm_ty = try o.lowerType(param_ty);1324 const param = wip.arg(it.llvm_index - 1);
1307 const param = wip.arg(llvm_arg_i);
1308 const alignment = param_ty.abiAlignment(zcu).toLlvm();
1309
1310 try attributes.addParamAttr(llvm_arg_i, .noundef, &o.builder);
1311 llvm_arg_i += 1;
13121325
1313 if (isByRef(param_ty, zcu)) {1326 if (isByRef(param_ty, zcu)) {
1314 args.appendAssumeCapacity(param);1327 args.appendAssumeCapacity(param);
1315 } else {1328 } else {
1329 const param_llvm_ty = try o.lowerType(param_ty);
1330 const alignment = param_ty.abiAlignment(zcu).toLlvm();
1316 args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, ""));1331 args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, ""));
1317 }1332 }
1318 },1333 },
1319 .abi_sized_int => {1334 .abi_sized_int => {
1320 assert(!it.byval_attr);1335 assert(!it.byval_attr);
1321 const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);1336 const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
1322 const param = wip.arg(llvm_arg_i);1337 const param = wip.arg(it.llvm_index - 1);
1323 llvm_arg_i += 1;
13241338
1325 const param_llvm_ty = try o.lowerType(param_ty);1339 const param_llvm_ty = try o.lowerType(param_ty);
1326 const alignment = param_ty.abiAlignment(zcu).toLlvm();1340 const alignment = param_ty.abiAlignment(zcu).toLlvm();
1327 const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, alignment, target);1341 const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, alignment, target);
1328 _ = try wip.store(.normal, param, arg_ptr, alignment);1342 _ = try wip.store(.normal, param, arg_ptr, alignment);
13291343
1330 args.appendAssumeCapacity(if (isByRef(param_ty, zcu))1344 if (isByRef(param_ty, zcu)) {
1331 arg_ptr1345 args.appendAssumeCapacity(arg_ptr);
1332 else1346 } else {
1333 try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));1347 args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));
1348 }
1334 },1349 },
1335 .slice => {1350 .slice => {
1336 assert(!it.byval_attr);1351 assert(!it.byval_attr);
1337 const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);1352 const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
1338 const ptr_info = param_ty.ptrInfo(zcu);1353 assert(!isByRef(param_ty, zcu));
13391354 const slice_val = try wip.buildAggregate(
1340 if (std.math.cast(u5, it.zig_index - 1)) |i| {1355 try o.lowerType(param_ty),
1341 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {1356 &.{ wip.arg(it.llvm_index - 2), wip.arg(it.llvm_index - 1) },
1342 try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);1357 "",
1343 }
1344 }
1345 if (param_ty.zigTypeTag(zcu) != .optional and
1346 !ptr_info.flags.is_allowzero and
1347 ptr_info.flags.address_space == .generic)
1348 {
1349 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
1350 }
1351 if (ptr_info.flags.is_const) {
1352 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
1353 }
1354 const elem_align: Builder.Alignment.Lazy = switch (ptr_info.flags.alignment) {
1355 else => |a| .wrap(a.toLlvm()),
1356 .none => try o.lazyAbiAlignment(pt, .fromInterned(ptr_info.child)),
1357 };
1358 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
1359 const ptr_param = wip.arg(llvm_arg_i);
1360 llvm_arg_i += 1;
1361 const len_param = wip.arg(llvm_arg_i);
1362 llvm_arg_i += 1;
1363
1364 const slice_llvm_ty = try o.lowerType(param_ty);
1365 args.appendAssumeCapacity(
1366 try wip.buildAggregate(slice_llvm_ty, &.{ ptr_param, len_param }, ""),
1367 );1358 );
1359 args.appendAssumeCapacity(slice_val);
1368 },1360 },
1369 .multiple_llvm_types => {1361 .multiple_llvm_types => {
1370 assert(!it.byval_attr);1362 assert(!it.byval_attr);
1371 const field_types = it.types_buffer[0..it.types_len];1363 const field_types = it.types_buffer[0..it.types_len];
1372 const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);1364 const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
1373 const param_llvm_ty = try o.lowerType(param_ty);1365 const param_llvm_ty = try o.lowerType(param_ty);
1374 const param_alignment = param_ty.abiAlignment(zcu).toLlvm();1366 const param_alignment = param_ty.abiAlignment(zcu).toLlvm();
1375 const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, param_alignment, target);1367 const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, param_alignment, target);
1376 const llvm_ty = try o.builder.structType(.normal, field_types);1368 const llvm_ty = try o.builder.structType(.normal, field_types);
1377 for (0..field_types.len) |field_i| {1369 const llvm_args_start = it.llvm_index - field_types.len;
1378 const param = wip.arg(llvm_arg_i);1370 for (0..field_types.len, llvm_args_start..) |field_i, llvm_arg_index| {
1379 llvm_arg_i += 1;1371 const param = wip.arg(@intCast(llvm_arg_index));
1380 const field_ptr = try wip.gepStruct(llvm_ty, arg_ptr, field_i, "");1372 const field_ptr = try wip.gepStruct(llvm_ty, arg_ptr, field_i, "");
1381 const alignment = Builder.Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));1373 const alignment: Builder.Alignment = .fromByteUnits(@divExact(target.ptrBitWidth(), 8));
1382 _ = try wip.store(.normal, param, field_ptr, alignment);1374 _ = try wip.store(.normal, param, field_ptr, alignment);
1383 }1375 }
13841376
1385 const is_by_ref = isByRef(param_ty, zcu);1377 if (isByRef(param_ty, zcu)) {
1386 args.appendAssumeCapacity(if (is_by_ref)1378 args.appendAssumeCapacity(arg_ptr);
1387 arg_ptr1379 } else {
1388 else1380 args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, arg_ptr, param_alignment, ""));
1389 try wip.load(.normal, param_llvm_ty, arg_ptr, param_alignment, ""));1381 }
1390 },1382 },
1391 .float_array => {1383 .float_array => {
1392 const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);1384 const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
1393 const param_llvm_ty = try o.lowerType(param_ty);1385 const param_llvm_ty = try o.lowerType(param_ty);
1394 const param = wip.arg(llvm_arg_i);1386 const param = wip.arg(it.llvm_index - 1);
1395 llvm_arg_i += 1;
13961387
1397 const alignment = param_ty.abiAlignment(zcu).toLlvm();1388 const alignment = param_ty.abiAlignment(zcu).toLlvm();
1398 const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, alignment, target);1389 const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, alignment, target);
1399 _ = try wip.store(.normal, param, arg_ptr, alignment);1390 _ = try wip.store(.normal, param, arg_ptr, alignment);
14001391
1401 args.appendAssumeCapacity(if (isByRef(param_ty, zcu))1392 if (isByRef(param_ty, zcu)) {
1402 arg_ptr1393 args.appendAssumeCapacity(arg_ptr);
1403 else1394 } else {
1404 try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));1395 args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));
1396 }
1405 },1397 },
1406 .i32_array, .i64_array => {1398 .i32_array, .i64_array => {
1407 const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);1399 const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
1408 const param_llvm_ty = try o.lowerType(param_ty);1400 const param_llvm_ty = try o.lowerType(param_ty);
1409 const param = wip.arg(llvm_arg_i);1401 const param = wip.arg(it.llvm_index - 1);
1410 llvm_arg_i += 1;
14111402
1412 const alignment = param_ty.abiAlignment(zcu).toLlvm();1403 const alignment = param_ty.abiAlignment(zcu).toLlvm();
1413 const arg_ptr = try buildAllocaInner(&wip, param.typeOfWip(&wip), alignment, target);1404 const arg_ptr = try buildAllocaInner(&wip, param.typeOfWip(&wip), alignment, target);
1414 _ = try wip.store(.normal, param, arg_ptr, alignment);1405 _ = try wip.store(.normal, param, arg_ptr, alignment);
14151406
1416 args.appendAssumeCapacity(if (isByRef(param_ty, zcu))1407 if (isByRef(param_ty, zcu)) {
1417 arg_ptr1408 args.appendAssumeCapacity(arg_ptr);
1418 else1409 } else {
1419 try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));1410 args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));
1411 }
1420 },1412 },
1421 }1413 }
1422 }1414 }
1423 }1415
1416 break :implicit_args .{ ret_ptr, err_ret_trace };
1417 };
14241418
1425 const file, const subprogram = if (!wip.strip) debug_info: {1419 const file, const subprogram = if (!wip.strip) debug_info: {
1426 const file = try o.getDebugFile(file_scope);1420 const file = try o.getDebugFile(file_scope);
...@@ -1432,7 +1426,7 @@ pub const Object = struct {...@@ -1432,7 +1426,7 @@ pub const Object = struct {
1432 const subprogram = try o.builder.debugSubprogram(1426 const subprogram = try o.builder.debugSubprogram(
1433 file,1427 file,
1434 try o.builder.metadataString(nav.name.toSlice(ip)),1428 try o.builder.metadataString(nav.name.toSlice(ip)),
1435 try o.builder.metadataStringFromStrtabString(function_index.name(&o.builder)),1429 try o.builder.metadataString(nav.fqn.toSlice(ip)),
1436 line_number,1430 line_number,
1437 line_number + func.lbrace_line,1431 line_number + func.lbrace_line,
1438 debug_decl_type,1432 debug_decl_type,
...@@ -1449,7 +1443,7 @@ pub const Object = struct {...@@ -1449,7 +1443,7 @@ pub const Object = struct {
1449 },1443 },
1450 o.debug_compile_unit.unwrap().?,1444 o.debug_compile_unit.unwrap().?,
1451 );1445 );
1452 function_index.setSubprogram(subprogram, &o.builder);1446 llvm_function.setSubprogram(subprogram, &o.builder);
1453 break :debug_info .{ file, subprogram };1447 break :debug_info .{ file, subprogram };
1454 } else .{undefined} ** 2;1448 } else .{undefined} ** 2;
14551449
...@@ -1466,7 +1460,7 @@ pub const Object = struct {...@@ -1466,7 +1460,7 @@ pub const Object = struct {
1466 const anon_name = try o.builder.strtabStringFmt("__sancov_gen_.{d}", .{o.used.items.len});1460 const anon_name = try o.builder.strtabStringFmt("__sancov_gen_.{d}", .{o.used.items.len});
1467 const counters_variable = try o.builder.addVariable(anon_name, .void, .default);1461 const counters_variable = try o.builder.addVariable(anon_name, .void, .default);
1468 try o.used.append(gpa, counters_variable.toConst(&o.builder));1462 try o.used.append(gpa, counters_variable.toConst(&o.builder));
1469 counters_variable.setLinkage(.private, &o.builder);1463 counters_variable.ptrConst(&o.builder).global.setLinkage(.private, &o.builder);
1470 counters_variable.setAlignment(comptime Builder.Alignment.fromByteUnits(1), &o.builder);1464 counters_variable.setAlignment(comptime Builder.Alignment.fromByteUnits(1), &o.builder);
14711465
1472 if (target.ofmt == .macho) {1466 if (target.ofmt == .macho) {
...@@ -1524,7 +1518,7 @@ pub const Object = struct {...@@ -1524,7 +1518,7 @@ pub const Object = struct {
1524 _ = try attributes.removeFnAttr(.null_pointer_is_valid);1518 _ = try attributes.removeFnAttr(.null_pointer_is_valid);
1525 }1519 }
15261520
1527 function_index.setAttributes(try attributes.finish(&o.builder), &o.builder);1521 llvm_function.setAttributes(try attributes.finish(&o.builder), &o.builder);
15281522
1529 if (fg.fuzz) |*f| {1523 if (fg.fuzz) |*f| {
1530 {1524 {
...@@ -1539,158 +1533,162 @@ pub const Object = struct {...@@ -1539,158 +1533,162 @@ pub const Object = struct {
1539 // Due to error "members of llvm.compiler.used must be named", this global needs a name.1533 // Due to error "members of llvm.compiler.used must be named", this global needs a name.
1540 const anon_name = try o.builder.strtabStringFmt("__sancov_gen_.{d}", .{o.used.items.len});1534 const anon_name = try o.builder.strtabStringFmt("__sancov_gen_.{d}", .{o.used.items.len});
1541 const pcs_variable = try o.builder.addVariable(anon_name, array_llvm_ty, .default);1535 const pcs_variable = try o.builder.addVariable(anon_name, array_llvm_ty, .default);
1542 try o.used.append(gpa, pcs_variable.toConst(&o.builder));1536 try pcs_variable.setInitializer(init_val, &o.builder);
1543 pcs_variable.setLinkage(.private, &o.builder);
1544 pcs_variable.setMutability(.constant, &o.builder);1537 pcs_variable.setMutability(.constant, &o.builder);
1538 pcs_variable.setSection(switch (target.ofmt) {
1539 .macho => try o.builder.string("__DATA,__sancov_pcs1"),
1540 else => try o.builder.string("__sancov_pcs1"),
1541 }, &o.builder);
1545 pcs_variable.setAlignment(Type.usize.abiAlignment(zcu).toLlvm(), &o.builder);1542 pcs_variable.setAlignment(Type.usize.abiAlignment(zcu).toLlvm(), &o.builder);
1546 if (target.ofmt == .macho) {1543 const pcs_global = pcs_variable.ptrConst(&o.builder).global;
1547 pcs_variable.setSection(try o.builder.string("__DATA,__sancov_pcs1"), &o.builder);1544 pcs_global.setLinkage(.private, &o.builder);
1548 } else {1545 try o.used.append(gpa, pcs_global.toConst());
1549 pcs_variable.setSection(try o.builder.string("__sancov_pcs1"), &o.builder);
1550 }
1551 try pcs_variable.setInitializer(init_val, &o.builder);
1552 }1546 }
15531547
1554 try fg.wip.finish();1548 try fg.wip.finish();
1555 try o.flushTypePool(pt);1549 try o.flushTypePool(pt);
1556 }1550 }
15571551
1558 pub fn updateNav(o: *Object, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {1552 pub fn updateNav(o: *Object, pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) !void {
1559 const zcu = o.zcu;1553 const zcu = o.zcu;
1560 const ip = &zcu.intern_pool;1554 const ip = &zcu.intern_pool;
1555 const comp = zcu.comp;
1556 const gpa = comp.gpa;
15611557
1562 const nav = ip.getNav(nav_index);1558 const nav = ip.getNav(nav_id);
1563 const resolved = nav.resolved.?;1559 const resolved = nav.resolved.?;
15641560
1565 const lib_name, const linkage, const visibility: Builder.Visibility, const is_dll_import, const init_val, const owner_nav = switch (ip.indexToKey(resolved.value)) {1561 const opt_extern: ?InternPool.Key.Extern = switch (ip.indexToKey(resolved.value)) {
1566 else => .{ .none, .internal, .default, false, resolved.value, nav_index },1562 .@"extern" => |@"extern"| @"extern",
1567 .@"extern" => |e| .{ e.lib_name, e.linkage, .fromSymbolVisibility(e.visibility), e.is_dll_import, .none, e.owner_nav },1563 else => null,
1564 };
1565 const nav_ty: Type = .fromInterned(resolved.type);
1566 const llvm_ty: Builder.Type = if (opt_extern != null) ty: {
1567 // We *must* lower this declaration no matter what. If it has a type we can't actually
1568 // represent (because it doesn't have runtime bits), we instead lower as the zero-size
1569 // type `[0 x i8]`. I don't think the type on an extern declaration actually does much
1570 // anyway.
1571 if (nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) break :ty try o.lowerType(nav_ty);
1572 break :ty try o.builder.arrayType(0, .i8);
1573 } else if (nav_ty.hasRuntimeBits(zcu)) ty: {
1574 break :ty try o.lowerType(nav_ty);
1575 } else {
1576 // This is a non-extern zero-bit `Nav`---we're not interested in it.
1577 // TODO: we might need to rethink this a little under incremental compilation. If a
1578 // declaration becomes zero-bit, we can't just leave its old value there, because it
1579 // might now be ill-formed.
1580 return;
1568 };1581 };
1569 const ty: Type = .fromInterned(nav.resolved.?.type);
15701582
1571 if (linkage != .internal and ip.isFunctionType(ty.toIntern())) {1583 const gop = try o.nav_map.getOrPut(gpa, nav_id);
1572 const function_index = try o.resolveLlvmFunction(owner_nav);1584 if (!gop.found_existing) {
1573 // Add parameter attributes which weren't set by `resolveLlvmFunction`1585 errdefer assert(o.nav_map.remove(nav_id));
1574 const fn_info = zcu.typeToFunc(ty).?;1586 // First time lowering this NAV! Create a fresh global.
1575 var attributes = try function_index.ptrConst(&o.builder).attributes.toWip(&o.builder);1587 const llvm_name = try o.builder.strtabString(nav.fqn.toSlice(ip));
1576 defer attributes.deinit(&o.builder);1588 gop.value_ptr.* = try o.builder.addGlobal(llvm_name, .{
1577 var it = iterateParamTypes(o, fn_info);1589 .type = .void, // placeholder; populated below
1578 if (firstParamSRet(fn_info, zcu, zcu.getTarget())) it.llvm_index += 1;1590 .kind = .{ .alias = .none }, // placeholder; populated below
1579 if (fn_info.cc == .auto and zcu.comp.config.any_error_tracing) it.llvm_index += 1;1591 });
1580 while (try it.next()) |lowering| switch (lowering) {1592 }
1581 .byval => {1593 const llvm_global = gop.value_ptr.*;
1582 const param_index = it.zig_index - 1;1594
1583 const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[param_index]);1595 llvm_global.ptr(&o.builder).type = llvm_ty;
1584 if (!isByRef(param_ty, zcu)) {1596 llvm_global.ptr(&o.builder).addr_space = toLlvmAddressSpace(resolved.@"addrspace", zcu.getTarget());
1585 try o.addByValParamAttrs(pt, &attributes, param_ty, param_index, fn_info, it.llvm_index - 1);1597
1598 if (opt_extern) |@"extern"| {
1599 const name = name: {
1600 const name_slice = nav.name.toSlice(ip);
1601 if (zcu.getTarget().cpu.arch.isWasm() and nav_ty.zigTypeTag(zcu) == .@"fn") {
1602 if (@"extern".lib_name.toSlice(ip)) |lib_name_slice| {
1603 if (!std.mem.eql(u8, lib_name_slice, "c")) {
1604 break :name try o.builder.strtabStringFmt("{s}|{s}", .{ name_slice, lib_name_slice });
1605 }
1586 }1606 }
1587 },1607 }
1588 .byref => {1608 break :name try o.builder.strtabString(name_slice);
1589 const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);1609 };
1590 const param_llvm_ty = try o.lowerType(param_ty);1610 if (o.builder.getGlobal(name)) |other_global| {
1591 const alignment = param_ty.abiAlignment(zcu);1611 if (other_global != llvm_global) {
1592 try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment.toLlvm(), it.byval_attr, param_llvm_ty);1612 // Another global already has this name; just use it in place of this global.
1593 },1613 try llvm_global.replace(other_global, &o.builder);
1594 .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),1614 return;
1595 // No attributes needed for these.1615 }
1596 .no_bits,1616 }
1597 .abi_sized_int,1617 try llvm_global.rename(name, &o.builder);
1598 .multiple_llvm_types,1618 llvm_global.ptr(&o.builder).unnamed_addr = .default;
1599 .float_array,1619 llvm_global.ptr(&o.builder).dll_storage_class = switch (@"extern".is_dll_import) {
1600 .i32_array,1620 true => .dllimport,
1601 .i64_array,1621 false => .default,
1602 => continue,1622 };
16031623 llvm_global.ptr(&o.builder).linkage = switch (@"extern".linkage) {
1604 .slice => unreachable, // extern functions do not support slice types.1624 .internal => if (o.builder.strip) .private else .internal,
1625 .strong => .external,
1626 .weak => .extern_weak,
1627 .link_once => unreachable,
1605 };1628 };
1606 function_index.setAttributes(try attributes.finish(&o.builder), &o.builder);1629 llvm_global.ptr(&o.builder).visibility = .fromSymbolVisibility(@"extern".visibility);
1607 } else {1630 } else {
1608 const variable_index = try o.resolveGlobalNav(nav_index);1631 llvm_global.ptr(&o.builder).linkage = if (o.builder.strip) .private else .internal;
1609 variable_index.setAlignment(zcu.navAlignment(nav_index).toLlvm(), &o.builder);1632 llvm_global.ptr(&o.builder).visibility = .default;
1610 if (resolved.@"linksection".toSlice(ip)) |section|1633 llvm_global.ptr(&o.builder).dll_storage_class = .default;
1611 variable_index.setSection(try o.builder.string(section), &o.builder);1634 llvm_global.ptr(&o.builder).unnamed_addr = .unnamed_addr;
1612 if (resolved.@"const") variable_index.setMutability(.constant, &o.builder);1635 }
1613 try variable_index.setInitializer(switch (init_val) {1636
1614 .none => .no_init,1637 const llvm_align = switch (resolved.@"align") {
1615 else => try o.lowerValue(init_val),1638 .none => nav_ty.abiAlignment(zcu).toLlvm(),
1616 }, &o.builder);1639 else => |a| a.toLlvm(),
1617 variable_index.setVisibility(visibility, &o.builder);1640 };
1641 const llvm_section: Builder.String = if (resolved.@"linksection".toSlice(ip)) |section| s: {
1642 break :s try o.builder.string(section);
1643 } else .none;
16181644
1619 const file_scope = zcu.navFileScopeIndex(nav_index);1645 // Actual function bodies with AIR go through `updateFunc` instead, so the only functions we
1646 // can see are extern functions or other comptime function body values (e.g. undefined). Of
1647 // these, only extern functions need to be lowered to LLVM functions.
1648 if (opt_extern != null and nav_ty.zigTypeTag(zcu) == .@"fn" and nav_ty.fnHasRuntimeBits(zcu)) {
1649 const llvm_function: Builder.Function.Index = switch (llvm_global.ptrConst(&o.builder).kind) {
1650 .function => |function| function, // re-use existing `Builder.Function`
1651 .replaced, .alias, .variable => try llvm_global.toNewFunction(&o.builder),
1652 };
1653 llvm_function.setAlignment(llvm_align, &o.builder);
1654 llvm_function.setSection(llvm_section, &o.builder);
1655 try o.addLlvmFunctionAttributes(pt, nav_id, llvm_function);
1656 } else {
1657 const file_scope = nav.srcInst(ip).resolveFile(ip);
1620 const mod = zcu.fileByIndex(file_scope).mod.?;1658 const mod = zcu.fileByIndex(file_scope).mod.?;
1621 if (resolved.@"threadlocal" and !mod.single_threaded)
1622 variable_index.setThreadLocal(.generaldynamic, &o.builder);
16231659
1624 const line_number = zcu.navSrcLine(nav_index) + 1;1660 const llvm_variable: Builder.Variable.Index = switch (llvm_global.ptrConst(&o.builder).kind) {
1661 .variable => |variable| variable, // re-use existing `Builder.Variable`
1662 .replaced, .alias, .function => try llvm_global.toNewVariable(&o.builder),
1663 };
1664 llvm_variable.setAlignment(llvm_align, &o.builder);
1665 llvm_variable.setSection(llvm_section, &o.builder);
1666 llvm_variable.setMutability(if (resolved.@"const") .constant else .global, &o.builder);
1667 try llvm_variable.setInitializer(if (opt_extern != null) .no_init else try o.lowerValue(resolved.value), &o.builder);
1668 llvm_variable.setThreadLocal(tl: {
1669 if (resolved.@"threadlocal" and !mod.single_threaded) break :tl .generaldynamic;
1670 break :tl .default;
1671 }, &o.builder);
16251672
1626 if (!mod.strip) {1673 if (!mod.strip) {
1627 const debug_file = try o.getDebugFile(file_scope);1674 const debug_file = try o.getDebugFile(file_scope);
16281675 const debug_global_var_expr = try o.builder.debugGlobalVarExpression(
1629 const debug_global_var = try o.builder.debugGlobalVar(1676 try o.builder.debugGlobalVar(
1630 try o.builder.metadataString(nav.name.toSlice(ip)), // Name1677 try o.builder.metadataString(nav.name.toSlice(ip)), // Name
1631 try o.builder.metadataStringFromStrtabString(variable_index.name(&o.builder)), // Linkage name1678 try o.builder.metadataString(nav.fqn.toSlice(ip)), // Linkage name
1632 debug_file, // File1679 debug_file, // File
1633 debug_file, // Scope1680 debug_file, // Scope
1634 line_number,1681 zcu.navSrcLine(nav_id) + 1,
1635 try o.getDebugType(pt, ty),1682 try o.getDebugType(pt, nav_ty),
1636 variable_index,1683 llvm_variable,
1637 .{ .local = linkage == .internal },1684 .{ .local = llvm_global.ptrConst(&o.builder).linkage == .internal },
1638 );1685 ),
16391686 try o.builder.debugExpression(&.{}),
1640 const debug_expression = try o.builder.debugExpression(&.{});
1641
1642 const debug_global_var_expression = try o.builder.debugGlobalVarExpression(
1643 debug_global_var,
1644 debug_expression,
1645 );1687 );
16461688 llvm_variable.setGlobalVariableExpression(debug_global_var_expr, &o.builder);
1647 variable_index.setGlobalVariableExpression(debug_global_var_expression, &o.builder);1689 try o.debug_globals.append(o.gpa, debug_global_var_expr);
1648 try o.debug_globals.append(o.gpa, debug_global_var_expression);
1649 }1690 }
1650 }1691 }
1651
1652 switch (linkage) {
1653 .internal => {},
1654 .strong, .weak => {
1655 const global_index = o.nav_map.get(nav_index).?;
1656
1657 const decl_name = decl_name: {
1658 if (zcu.getTarget().cpu.arch.isWasm() and ty.zigTypeTag(zcu) == .@"fn") {
1659 if (lib_name.toSlice(ip)) |lib_name_slice| {
1660 if (!std.mem.eql(u8, lib_name_slice, "c")) {
1661 break :decl_name try o.builder.strtabStringFmt("{f}|{s}", .{ nav.name.fmt(ip), lib_name_slice });
1662 }
1663 }
1664 }
1665 break :decl_name try o.builder.strtabString(nav.name.toSlice(ip));
1666 };
1667
1668 if (o.builder.getGlobal(decl_name)) |other_global| {
1669 if (other_global != global_index) {
1670 // Another global already has this name; just use it in place of this global.
1671 try global_index.replace(other_global, &o.builder);
1672 return;
1673 }
1674 }
1675
1676 try global_index.rename(decl_name, &o.builder);
1677 global_index.setUnnamedAddr(.default, &o.builder);
1678 if (is_dll_import) {
1679 global_index.setDllStorageClass(.dllimport, &o.builder);
1680 } else if (zcu.comp.config.dll_export_fns) {
1681 global_index.setDllStorageClass(.default, &o.builder);
1682 }
1683
1684 global_index.setLinkage(switch (linkage) {
1685 .internal => unreachable,
1686 .strong => .external,
1687 .weak => .extern_weak,
1688 .link_once => unreachable,
1689 }, &o.builder);
1690 global_index.setVisibility(visibility, &o.builder);
1691 },
1692 .link_once => unreachable,
1693 }
1694 }1692 }
16951693
1696 fn flushTypePool(o: *Object, pt: Zcu.PerThread) Allocator.Error!void {1694 fn flushTypePool(o: *Object, pt: Zcu.PerThread) Allocator.Error!void {
...@@ -1698,18 +1696,43 @@ pub const Object = struct {...@@ -1698,18 +1696,43 @@ pub const Object = struct {
1698 }1696 }
16991697
1700 pub fn updateExports(1698 pub fn updateExports(
1701 self: *Object,1699 o: *Object,
1702 exported: Zcu.Exported,1700 exported: Zcu.Exported,
1703 export_indices: []const Zcu.Export.Index,1701 export_indices: []const Zcu.Export.Index,
1704 ) link.File.UpdateExportsError!void {1702 ) link.File.UpdateExportsError!void {
1705 const zcu = self.zcu;1703 const zcu = o.zcu;
1706 const nav_index = switch (exported) {
1707 .nav => |nav| nav,
1708 .uav => |uav| return updateExportedValue(self, uav, export_indices),
1709 };
1710 const ip = &zcu.intern_pool;1704 const ip = &zcu.intern_pool;
1711 const global_index = self.nav_map.get(nav_index).?;1705 const ty: Type, const llvm_ptr: Builder.Constant = switch (exported) {
1706 .nav => |nav| exp: {
1707 const nav_ty: Type = .fromInterned(ip.getNav(nav).resolved.?.type);
1708 const nav_ref = try o.lowerNavRef(nav);
1709 break :exp .{ nav_ty, nav_ref };
1710 },
1711 .uav => |uav| exp: {
1712 const uav_ty = Value.fromInterned(uav).typeOf(zcu);
1713 const uav_ref = try o.lowerUavRef(
1714 uav,
1715 uav_ty.abiAlignment(zcu),
1716 target_util.defaultAddressSpace(zcu.getTarget(), .global_constant),
1717 );
1718 break :exp .{ uav_ty, uav_ref };
1719 },
1720 };
1721 switch (llvm_ptr.unwrap()) {
1722 .global => |global| return o.updateExportedGlobal(global, ty, export_indices),
1723 .constant => @panic("LLVM TODO: export zero-bit value"),
1724 }
1725 }
1726
1727 fn updateExportedGlobal(
1728 o: *Object,
1729 global_index: Builder.Global.Index,
1730 ty: Type,
1731 export_indices: []const Zcu.Export.Index,
1732 ) link.File.UpdateExportsError!void {
1733 const zcu = o.zcu;
1712 const comp = zcu.comp;1734 const comp = zcu.comp;
1735 const ip = &zcu.intern_pool;
17131736
1714 // If we're on COFF and linking with LLD, the linker cares about our exports to determine the subsystem in use.1737 // If we're on COFF and linking with LLD, the linker cares about our exports to determine the subsystem in use.
1715 coff_export_flags: {1738 coff_export_flags: {
...@@ -1719,7 +1742,7 @@ pub const Object = struct {...@@ -1719,7 +1742,7 @@ pub const Object = struct {
1719 .elf, .wasm => break :coff_export_flags,1742 .elf, .wasm => break :coff_export_flags,
1720 .coff => |*coff| coff,1743 .coff => |*coff| coff,
1721 };1744 };
1722 if (!ip.isFunctionType(ip.getNav(nav_index).resolved.?.type)) break :coff_export_flags;1745 if (ty.zigTypeTag(zcu) != .@"fn") break :coff_export_flags;
1723 const flags = &coff.lld_export_flags;1746 const flags = &coff.lld_export_flags;
1724 for (export_indices) |export_index| {1747 for (export_indices) |export_index| {
1725 const name = export_index.ptr(zcu).opts.name;1748 const name = export_index.ptr(zcu).opts.name;
...@@ -1732,152 +1755,88 @@ pub const Object = struct {...@@ -1732,152 +1755,88 @@ pub const Object = struct {
1732 }1755 }
1733 }1756 }
17341757
1735 if (export_indices.len != 0) {1758 // If the first export specifies a linksection, set the exported variable's section to that
1736 return updateExportedGlobal(self, zcu, global_index, export_indices);1759 // one. This is kind of a hack because `std.builtin.ExportOptions.section` doesn't actually
1737 } else {1760 // make much sense: the linksection should be associated with the declaration itself rather
1738 const fqn = try self.builder.strtabString(ip.getNav(nav_index).fqn.toSlice(ip));1761 // than some particular symbol it is exported as!
1739 try global_index.rename(fqn, &self.builder);1762 if (export_indices[0].ptr(zcu).opts.section.toSlice(ip)) |section_slice| {
1740 global_index.setLinkage(if (self.builder.strip) .private else .internal, &self.builder);1763 const variable = &global_index.ptrConst(&o.builder).kind.variable;
1741 if (comp.config.dll_export_fns)1764 variable.setSection(try o.builder.string(section_slice), &o.builder);
1742 global_index.setDllStorageClass(.default, &self.builder);
1743 global_index.setUnnamedAddr(.unnamed_addr, &self.builder);
1744 }1765 }
1745 }
17461766
1747 fn updateExportedValue(1767 const llvm_global_ty = global_index.typeOf(&o.builder);
1748 o: *Object,
1749 exported_value: InternPool.Index,
1750 export_indices: []const Zcu.Export.Index,
1751 ) link.File.UpdateExportsError!void {
1752 const zcu = o.zcu;
1753 const gpa = zcu.gpa;
1754 const ip = &zcu.intern_pool;
1755 const main_exp_name = try o.builder.strtabString(export_indices[0].ptr(zcu).opts.name.toSlice(ip));
1756 const global_index = i: {
1757 const gop = try o.uav_map.getOrPut(gpa, exported_value);
1758 if (gop.found_existing) {
1759 const global_index = gop.value_ptr.*;
1760 try global_index.rename(main_exp_name, &o.builder);
1761 break :i global_index;
1762 }
1763 const llvm_addr_space = toLlvmAddressSpace(.generic, zcu.getTarget());
1764 const variable_index = try o.builder.addVariable(
1765 main_exp_name,
1766 try o.lowerType(.fromInterned(ip.typeOf(exported_value))),
1767 llvm_addr_space,
1768 );
1769 const global_index = variable_index.ptrConst(&o.builder).global;
1770 gop.value_ptr.* = global_index;
1771 // This line invalidates `gop`.
1772 const init_val = try o.lowerValue(exported_value);
1773 try variable_index.setInitializer(init_val, &o.builder);
1774 break :i global_index;
1775 };
1776 return updateExportedGlobal(o, zcu, global_index, export_indices);
1777 }
17781768
1779 fn updateExportedGlobal(1769 // All exports are represented as aliases to the original global.
1780 o: *Object,
1781 zcu: *Zcu,
1782 global_index: Builder.Global.Index,
1783 export_indices: []const Zcu.Export.Index,
1784 ) link.File.UpdateExportsError!void {
1785 const comp = zcu.comp;
1786 const ip = &zcu.intern_pool;
1787 const first_export = export_indices[0].ptr(zcu);
1788
1789 // We will rename this global to have a name matching `first_export`.
1790 // Successive exports become aliases.
1791 // If the first export name already exists, then there is a corresponding
1792 // extern global - we replace it with this global.
1793 const first_exp_name = try o.builder.strtabString(first_export.opts.name.toSlice(ip));
1794 if (o.builder.getGlobal(first_exp_name)) |other_global| replace: {
1795 if (other_global.toConst().getBase(&o.builder) == global_index.toConst().getBase(&o.builder)) {
1796 break :replace; // this global already has the name we want
1797 }
1798 try global_index.takeName(other_global, &o.builder);
1799 try other_global.replace(global_index, &o.builder);
1800 // Problem: now we need to replace in the decl_map that
1801 // the extern decl index points to this new global. However we don't
1802 // know the decl index.
1803 // Even if we did, a future incremental update to the extern would then
1804 // treat the LLVM global as an extern rather than an export, so it would
1805 // need a way to check that.
1806 // This is a TODO that needs to be solved when making
1807 // the LLVM backend support incremental compilation.
1808 } else {
1809 try global_index.rename(first_exp_name, &o.builder);
1810 }
18111770
1812 global_index.setUnnamedAddr(.default, &o.builder);1771 // TODO: we currently do not delete old exports. To do that we'll need to track which
1813 if (comp.config.dll_export_fns and first_export.opts.visibility != .hidden)1772 // globals actually *are* exports.
1814 global_index.setDllStorageClass(.dllexport, &o.builder);
1815 global_index.setLinkage(switch (first_export.opts.linkage) {
1816 .internal => unreachable,
1817 .strong => .external,
1818 .weak => .weak_odr,
1819 .link_once => .linkonce_odr,
1820 }, &o.builder);
1821 global_index.setVisibility(switch (first_export.opts.visibility) {
1822 .default => .default,
1823 .hidden => .hidden,
1824 .protected => .protected,
1825 }, &o.builder);
1826 if (first_export.opts.section.toSlice(ip)) |section|
1827 switch (global_index.ptrConst(&o.builder).kind) {
1828 .variable => |impl_index| impl_index.setSection(
1829 try o.builder.string(section),
1830 &o.builder,
1831 ),
1832 .function => unreachable,
1833 .alias => unreachable,
1834 .replaced => unreachable,
1835 };
18361773
1837 // If a Decl is exported more than one time (which is rare),1774 for (export_indices) |export_idx| {
1838 // we add aliases for all but the first export.
1839 // TODO LLVM C API does not support deleting aliases.
1840 // The planned solution to this is https://github.com/ziglang/zig/issues/13265
1841 // Until then we iterate over existing aliases and make them point
1842 // to the correct decl, or otherwise add a new alias. Old aliases are leaked.
1843 for (export_indices[1..]) |export_idx| {
1844 const exp = export_idx.ptr(zcu);1775 const exp = export_idx.ptr(zcu);
1845 const exp_name = try o.builder.strtabString(exp.opts.name.toSlice(ip));1776 const exp_name = try o.builder.strtabString(exp.opts.name.toSlice(ip));
1846 if (o.builder.getGlobal(exp_name)) |global| {1777
1847 switch (global.ptrConst(&o.builder).kind) {1778 // Our goal is to make an alias with the name `exp_name`, but if that name is already
1779 // taken by some existing global, we need to figure out what to do with that existing
1780 // global.
1781 //
1782 // The name, aliasee, and type will be set within this block. Other properties of the
1783 // alias will be set below.
1784 const alias_global: Builder.Global.Index = global: {
1785 const existing_global = o.builder.getGlobal(exp_name) orelse {
1786 // There is no existing global with this name, so make a new alias.
1787 const alias = try o.builder.addAlias(
1788 exp_name,
1789 llvm_global_ty,
1790 .default,
1791 global_index.toConst(),
1792 );
1793 break :global alias.ptrConst(&o.builder).global;
1794 };
1795 // There is an existing global with this name, so we can't just create an alias. We
1796 // need to figure out what to do with the existing global instead.
1797 switch (existing_global.ptrConst(&o.builder).kind) {
1848 .alias => |alias| {1798 .alias => |alias| {
1799 // We can just repurpose the existing alias.
1849 alias.setAliasee(global_index.toConst(), &o.builder);1800 alias.setAliasee(global_index.toConst(), &o.builder);
1850 continue;1801 alias.ptrConst(&o.builder).global.ptr(&o.builder).type = global_index.typeOf(&o.builder);
1802 break :global existing_global;
1851 },1803 },
1852 .variable, .function => {1804 .variable, .function => {
1853 // This existing global is an `extern` corresponding to this export.1805 // This must be an extern, which is no good to us---we need an alias. The
1854 // Replace it with the global being exported.1806 // extern should refer to the value we're exporting, so replace it with the
1855 // This existing global must be replaced with the alias.1807 // exported value. That will free up the name for us to create a new alias.
1856 try global.rename(.empty, &o.builder);1808 // We need to make a new global which is an alias. Replace this existing one
1857 try global.replace(global_index, &o.builder);1809 // with the target global, making the name available and fixing references
1810 // to this global to point to the target.
1811 try existing_global.replace(global_index, &o.builder);
1812 // The name is now free, so create an alias.
1813 const alias = try o.builder.addAlias(
1814 exp_name,
1815 llvm_global_ty,
1816 .default,
1817 global_index.toConst(),
1818 );
1819 break :global alias.ptrConst(&o.builder).global;
1858 },1820 },
1859 .replaced => unreachable,1821 .replaced => unreachable, // a replaced global would have lost the name `exp_name`
1860 }1822 }
1861 }1823 };
1862 const alias_index = try o.builder.addAlias(1824
1863 .empty,1825 // Now for a bit of setup which
1864 global_index.typeOf(&o.builder),1826
1865 .default,1827 // We need the alias to *not* be `unnamed_addr` to ensure that the alias address equals
1866 global_index.toConst(),1828 // the address of the original global.
1867 );1829 alias_global.setUnnamedAddr(.default, &o.builder);
1868 try alias_index.rename(exp_name, &o.builder);1830
18691831 if (comp.config.dll_export_fns and exp.opts.visibility != .hidden)
1870 const alias_global_index = alias_index.ptrConst(&o.builder).global;1832 alias_global.setDllStorageClass(.dllexport, &o.builder);
1871 alias_global_index.setUnnamedAddr(.default, &o.builder);1833 alias_global.setLinkage(switch (exp.opts.linkage) {
1872 if (comp.config.dll_export_fns and first_export.opts.visibility != .hidden)1834 .internal => if (o.builder.strip) .private else .internal, // we still did useful work in replacing an existing symbol if there was one
1873 alias_global_index.setDllStorageClass(.dllexport, &o.builder);
1874 alias_global_index.setLinkage(switch (first_export.opts.linkage) {
1875 .internal => unreachable,
1876 .strong => .external,1835 .strong => .external,
1877 .weak => .weak_odr,1836 .weak => .weak_odr,
1878 .link_once => .linkonce_odr,1837 .link_once => .linkonce_odr,
1879 }, &o.builder);1838 }, &o.builder);
1880 alias_global_index.setVisibility(switch (first_export.opts.visibility) {1839 alias_global.setVisibility(switch (exp.opts.visibility) {
1881 .default => .default,1840 .default => .default,
1882 .hidden => .hidden,1841 .hidden => .hidden,
1883 .protected => .protected,1842 .protected => .protected,
...@@ -1940,7 +1899,12 @@ pub const Object = struct {...@@ -1940,7 +1899,12 @@ pub const Object = struct {
1940 assert(val != .anyerror_type);1899 assert(val != .anyerror_type);
1941 const fwd_ref = o.debug_types.items[@intFromEnum(index)];1900 const fwd_ref = o.debug_types.items[@intFromEnum(index)];
1942 const name_str = try o.builder.metadataStringFmt("{f}", .{ty.fmt(pt)});1901 const name_str = try o.builder.metadataStringFmt("{f}", .{ty.fmt(pt)});
1943 const debug_incomplete_type = try o.builder.debugSignedType(name_str, 0);1902 // If `ty` is a function, use a dummy *function* type to prevent existing debug
1903 // subprograms from becoming ill-formed.
1904 const debug_incomplete_type = switch (ty.zigTypeTag(zcu)) {
1905 .@"fn" => try o.builder.debugSubroutineType(null),
1906 else => try o.builder.debugSignedType(name_str, 0),
1907 };
1944 o.builder.resolveDebugForwardReference(fwd_ref, debug_incomplete_type);1908 o.builder.resolveDebugForwardReference(fwd_ref, debug_incomplete_type);
1945 }1909 }
1946 }1910 }
...@@ -2269,7 +2233,9 @@ pub const Object = struct {...@@ -2269,7 +2233,9 @@ pub const Object = struct {
2269 },2233 },
2270 .@"fn" => {2234 .@"fn" => {
2271 if (!ty.fnHasRuntimeBits(zcu)) {2235 if (!ty.fnHasRuntimeBits(zcu)) {
2272 return o.builder.debugSignedType(name, 0);2236 // Use a dummy *function* type to prevent existing debug subprograms from
2237 // becoming ill-formed.
2238 return o.builder.debugSubroutineType(null);
2273 }2239 }
22742240
2275 const fn_info = zcu.typeToFunc(ty).?;2241 const fn_info = zcu.typeToFunc(ty).?;
...@@ -2716,75 +2682,38 @@ pub const Object = struct {...@@ -2716,75 +2682,38 @@ pub const Object = struct {
2716 return o.getDebugType(pt, .fromInterned(namespace.owner_type));2682 return o.getDebugType(pt, .fromInterned(namespace.owner_type));
2717 }2683 }
27182684
2719 /// If the llvm function does not exist, create it.2685 /// Sets the attributes and callconv of the given `Builder.Function`, which corresponds to the
2720 /// Note that this can be called before the function's semantic analysis has2686 /// given `Nav` (which is a function).
2721 /// completed, so if any attributes rely on that, they must be done in updateFunc, not here.2687 fn addLlvmFunctionAttributes(
2722 pub fn resolveLlvmFunction(
2723 o: *Object,2688 o: *Object,
2724 nav_index: InternPool.Nav.Index,2689 pt: Zcu.PerThread,
2725 ) Allocator.Error!Builder.Function.Index {2690 nav_id: InternPool.Nav.Index,
2691 function_index: Builder.Function.Index,
2692 ) Allocator.Error!void {
2726 const zcu = o.zcu;2693 const zcu = o.zcu;
2727 const ip = &zcu.intern_pool;2694 const ip = &zcu.intern_pool;
2728 const gpa = o.gpa;2695 const nav = ip.getNav(nav_id);
2729 const nav = ip.getNav(nav_index);2696 const owner_mod = zcu.navFileScope(nav_id).mod.?;
2730 const owner_mod = zcu.navFileScope(nav_index).mod.?;
2731 const ty: Type = .fromInterned(nav.resolved.?.type);2697 const ty: Type = .fromInterned(nav.resolved.?.type);
2732 const gop = try o.nav_map.getOrPut(gpa, nav_index);
2733 if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.function;
27342698
2735 const fn_info = zcu.typeToFunc(ty).?;2699 const fn_info = zcu.typeToFunc(ty).?;
2736 const target = &owner_mod.resolved_target.result;2700 const target = &owner_mod.resolved_target.result;
27372701
2738 const is_extern, const lib_name = if (nav.getExtern(ip)) |@"extern"|
2739 .{ true, @"extern".lib_name }
2740 else
2741 .{ false, .none };
2742 const function_index = try o.builder.addFunction(
2743 try o.lowerType(ty),
2744 try o.builder.strtabString((if (is_extern) nav.name else nav.fqn).toSlice(ip)),
2745 toLlvmAddressSpace(nav.resolved.?.@"addrspace", target),
2746 );
2747 gop.value_ptr.* = function_index.ptrConst(&o.builder).global;
2748
2749 var attributes: Builder.FunctionAttributes.Wip = .{};2702 var attributes: Builder.FunctionAttributes.Wip = .{};
2750 defer attributes.deinit(&o.builder);2703 defer attributes.deinit(&o.builder);
27512704
2752 if (!is_extern) {2705 if (target.cpu.arch.isWasm()) if (nav.getExtern(ip)) |@"extern"| {
2753 function_index.setLinkage(if (o.builder.strip) .private else .internal, &o.builder);2706 try attributes.addFnAttr(.{ .string = .{
2754 function_index.setUnnamedAddr(.unnamed_addr, &o.builder);2707 .kind = try o.builder.string("wasm-import-name"),
2755 } else {2708 .value = try o.builder.string(nav.name.toSlice(ip)),
2756 if (target.cpu.arch.isWasm()) {2709 } }, &o.builder);
2757 try attributes.addFnAttr(.{ .string = .{2710 if (@"extern".lib_name.toSlice(ip)) |lib_name_slice| {
2758 .kind = try o.builder.string("wasm-import-name"),2711 if (!std.mem.eql(u8, lib_name_slice, "c")) try attributes.addFnAttr(.{ .string = .{
2759 .value = try o.builder.string(nav.name.toSlice(ip)),2712 .kind = try o.builder.string("wasm-import-module"),
2713 .value = try o.builder.string(lib_name_slice),
2760 } }, &o.builder);2714 } }, &o.builder);
2761 if (lib_name.toSlice(ip)) |lib_name_slice| {
2762 if (!std.mem.eql(u8, lib_name_slice, "c")) try attributes.addFnAttr(.{ .string = .{
2763 .kind = try o.builder.string("wasm-import-module"),
2764 .value = try o.builder.string(lib_name_slice),
2765 } }, &o.builder);
2766 }
2767 }2715 }
2768 }2716 };
2769
2770 var llvm_arg_i: u32 = 0;
2771 if (firstParamSRet(fn_info, zcu, target)) {
2772 // Sret pointers must not be address 0
2773 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
2774 try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
2775
2776 const raw_llvm_ret_ty = try o.lowerType(.fromInterned(fn_info.return_type));
2777 try attributes.addParamAttr(llvm_arg_i, .{ .sret = raw_llvm_ret_ty }, &o.builder);
2778
2779 llvm_arg_i += 1;
2780 }
2781
2782 const err_return_tracing = fn_info.cc == .auto and zcu.comp.config.any_error_tracing;
2783
2784 if (err_return_tracing) {
2785 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
2786 llvm_arg_i += 1;
2787 }
27882717
2789 if (fn_info.cc == .async) {2718 if (fn_info.cc == .async) {
2790 @panic("TODO: LLVM backend lower async function");2719 @panic("TODO: LLVM backend lower async function");
...@@ -2859,9 +2788,6 @@ pub const Object = struct {...@@ -2859,9 +2788,6 @@ pub const Object = struct {
2859 }2788 }
2860 }2789 }
28612790
2862 if (nav.resolved.?.@"align" != .none)
2863 function_index.setAlignment(nav.resolved.?.@"align".toLlvm(), &o.builder);
2864
2865 // Function attributes that are independent of analysis results of the function body.2791 // Function attributes that are independent of analysis results of the function body.
2866 try o.addCommonFnAttributes(2792 try o.addCommonFnAttributes(
2867 &attributes,2793 &attributes,
...@@ -2877,8 +2803,71 @@ pub const Object = struct {...@@ -2877,8 +2803,71 @@ pub const Object = struct {
28772803
2878 if (fn_info.return_type == .noreturn_type) try attributes.addFnAttr(.noreturn, &o.builder);2804 if (fn_info.return_type == .noreturn_type) try attributes.addFnAttr(.noreturn, &o.builder);
28792805
2806 var it = iterateParamTypes(o, fn_info);
2807 if (firstParamSRet(fn_info, zcu, target)) {
2808 // Sret pointers must not be address 0
2809 try attributes.addParamAttr(it.llvm_index, .nonnull, &o.builder);
2810 try attributes.addParamAttr(it.llvm_index, .@"noalias", &o.builder);
2811
2812 const raw_llvm_ret_ty = try o.lowerType(.fromInterned(fn_info.return_type));
2813 try attributes.addParamAttr(it.llvm_index, .{ .sret = raw_llvm_ret_ty }, &o.builder);
2814 it.llvm_index += 1;
2815 }
2816 const err_return_tracing = fn_info.cc == .auto and zcu.comp.config.any_error_tracing;
2817 if (err_return_tracing) {
2818 try attributes.addParamAttr(it.llvm_index, .nonnull, &o.builder);
2819 it.llvm_index += 1;
2820 }
2821 while (try it.next()) |lowering| switch (lowering) {
2822 .byval => {
2823 const param_index = it.zig_index - 1;
2824 const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[param_index]);
2825 if (!isByRef(param_ty, zcu)) {
2826 try o.addByValParamAttrs(pt, &attributes, param_ty, param_index, fn_info, it.llvm_index - 1);
2827 }
2828 },
2829 .byref => {
2830 const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
2831 const param_llvm_ty = try o.lowerType(param_ty);
2832 const alignment = param_ty.abiAlignment(zcu);
2833 try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment.toLlvm(), it.byval_attr, param_llvm_ty);
2834 },
2835 .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),
2836 .slice => {
2837 const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
2838 const ptr_info = param_ty.ptrInfo(zcu);
2839 const llvm_ptr_index = it.llvm_index - 2;
2840 if (std.math.cast(u5, it.zig_index - 1)) |i| {
2841 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
2842 try attributes.addParamAttr(llvm_ptr_index, .@"noalias", &o.builder);
2843 }
2844 }
2845 if (param_ty.zigTypeTag(zcu) != .optional and
2846 !ptr_info.flags.is_allowzero and
2847 ptr_info.flags.address_space == .generic)
2848 {
2849 try attributes.addParamAttr(llvm_ptr_index, .nonnull, &o.builder);
2850 }
2851 if (ptr_info.flags.is_const) {
2852 try attributes.addParamAttr(llvm_ptr_index, .readonly, &o.builder);
2853 }
2854 const elem_align: Builder.Alignment.Lazy = switch (ptr_info.flags.alignment) {
2855 else => |a| .wrap(a.toLlvm()),
2856 .none => try o.lazyAbiAlignment(pt, .fromInterned(ptr_info.child)),
2857 };
2858 try attributes.addParamAttr(llvm_ptr_index, .{ .@"align" = elem_align }, &o.builder);
2859 },
2860 // No attributes needed for these.
2861 .no_bits,
2862 .abi_sized_int,
2863 .multiple_llvm_types,
2864 .float_array,
2865 .i32_array,
2866 .i64_array,
2867 => continue,
2868 };
2869
2880 function_index.setAttributes(try attributes.finish(&o.builder), &o.builder);2870 function_index.setAttributes(try attributes.finish(&o.builder), &o.builder);
2881 return function_index;
2882 }2871 }
28832872
2884 fn addCommonFnAttributes(2873 fn addCommonFnAttributes(
...@@ -2951,97 +2940,6 @@ pub const Object = struct {...@@ -2951,97 +2940,6 @@ pub const Object = struct {
2951 }2940 }
2952 }2941 }
29532942
2954 fn resolveGlobalUav(
2955 o: *Object,
2956 uav: InternPool.Index,
2957 llvm_addr_space: Builder.AddrSpace,
2958 alignment: InternPool.Alignment,
2959 ) Allocator.Error!Builder.Variable.Index {
2960 assert(alignment != .none);
2961 // TODO: Add address space to the anon_decl_map
2962 const gop = try o.uav_map.getOrPut(o.gpa, uav);
2963 if (gop.found_existing) {
2964 // Keep the greater of the two alignments.
2965 const variable_index = gop.value_ptr.ptr(&o.builder).kind.variable;
2966 const old_alignment = InternPool.Alignment.fromLlvm(variable_index.getAlignment(&o.builder));
2967 const max_alignment = old_alignment.maxStrict(alignment);
2968 variable_index.setAlignment(max_alignment.toLlvm(), &o.builder);
2969 return variable_index;
2970 }
2971 errdefer assert(o.uav_map.remove(uav));
2972
2973 const zcu = o.zcu;
2974 const decl_ty = zcu.intern_pool.typeOf(uav);
2975
2976 const variable_index = try o.builder.addVariable(
2977 try o.builder.strtabStringFmt("__anon_{d}", .{@intFromEnum(uav)}),
2978 try o.lowerType(.fromInterned(decl_ty)),
2979 llvm_addr_space,
2980 );
2981 gop.value_ptr.* = variable_index.ptrConst(&o.builder).global;
2982
2983 try variable_index.setInitializer(try o.lowerValue(uav), &o.builder);
2984 variable_index.setLinkage(if (o.builder.strip) .private else .internal, &o.builder);
2985 variable_index.setMutability(.constant, &o.builder);
2986 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
2987 variable_index.setAlignment(alignment.toLlvm(), &o.builder);
2988 return variable_index;
2989 }
2990
2991 fn resolveGlobalNav(
2992 o: *Object,
2993 nav_index: InternPool.Nav.Index,
2994 ) Allocator.Error!Builder.Variable.Index {
2995 const gop = try o.nav_map.getOrPut(o.gpa, nav_index);
2996 if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.variable;
2997 errdefer assert(o.nav_map.remove(nav_index));
2998
2999 const zcu = o.zcu;
3000 const ip = &zcu.intern_pool;
3001 const nav = ip.getNav(nav_index);
3002 const linkage: std.builtin.GlobalLinkage, const visibility: Builder.Visibility, const is_dll_import: bool = switch (nav.resolved.?.value) {
3003 .none => .{ .internal, .default, false }, // this is a source declaration which is *not* marked `extern`
3004 else => |val| switch (ip.indexToKey(val)) {
3005 else => .{ .internal, .default, false },
3006 .@"extern" => |e| .{ e.linkage, .fromSymbolVisibility(e.visibility), e.is_dll_import },
3007 },
3008 };
3009
3010 const variable_index = try o.builder.addVariable(
3011 try o.builder.strtabString(switch (linkage) {
3012 .internal => nav.fqn,
3013 .strong, .weak => nav.name,
3014 .link_once => unreachable,
3015 }.toSlice(ip)),
3016 try o.lowerType(.fromInterned(nav.resolved.?.type)),
3017 toLlvmGlobalAddressSpace(nav.resolved.?.@"addrspace", zcu.getTarget()),
3018 );
3019 gop.value_ptr.* = variable_index.ptrConst(&o.builder).global;
3020
3021 // This is needed for declarations created by `@extern`.
3022 switch (linkage) {
3023 .internal => {
3024 variable_index.setLinkage(if (o.builder.strip) .private else .internal, &o.builder);
3025 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
3026 },
3027 .strong, .weak => {
3028 variable_index.setLinkage(switch (linkage) {
3029 .internal => unreachable,
3030 .strong => .external,
3031 .weak => .extern_weak,
3032 .link_once => unreachable,
3033 }, &o.builder);
3034 variable_index.setUnnamedAddr(.default, &o.builder);
3035 if (nav.resolved.?.@"threadlocal" and !zcu.navFileScope(nav_index).mod.?.single_threaded)
3036 variable_index.setThreadLocal(.generaldynamic, &o.builder);
3037 if (is_dll_import) variable_index.setDllStorageClass(.dllimport, &o.builder);
3038 },
3039 .link_once => unreachable,
3040 }
3041 variable_index.setVisibility(visibility, &o.builder);
3042 return variable_index;
3043 }
3044
3045 pub fn errorIntType(o: *Object) Allocator.Error!Builder.Type {2943 pub fn errorIntType(o: *Object) Allocator.Error!Builder.Type {
3046 return o.builder.intType(o.zcu.errorSetBits());2944 return o.builder.intType(o.zcu.errorSetBits());
3047 }2945 }
...@@ -3051,7 +2949,7 @@ pub const Object = struct {...@@ -3051,7 +2949,7 @@ pub const Object = struct {
3051 const target = zcu.getTarget();2949 const target = zcu.getTarget();
3052 const ip = &zcu.intern_pool;2950 const ip = &zcu.intern_pool;
3053 return switch (t.toIntern()) {2951 return switch (t.toIntern()) {
3054 .u0_type, .i0_type => unreachable,2952 .u0_type, .i0_type => unreachable, // no runtime bits
3055 inline .u1_type,2953 inline .u1_type,
3056 .u8_type,2954 .u8_type,
3057 .i8_type,2955 .i8_type,
...@@ -3100,18 +2998,18 @@ pub const Object = struct {...@@ -3100,18 +2998,18 @@ pub const Object = struct {
3100 return .i8;2998 return .i8;
3101 },2999 },
3102 .bool_type => .i1,3000 .bool_type => .i1,
3103 .void_type => .void,
3104 .type_type => unreachable,
3105 .anyerror_type => try o.errorIntType(),3001 .anyerror_type => try o.errorIntType(),
3106 .comptime_int_type,3002 .void_type => unreachable, // no runtime bits
3107 .comptime_float_type,3003 .type_type => unreachable, // no runtime bits
3108 .noreturn_type,3004 .comptime_int_type => unreachable, // no runtime bits
3109 => unreachable,3005 .comptime_float_type => unreachable, // no runtime bits
3006 .noreturn_type => unreachable, // no runtime bits
3007 .null_type => unreachable, // no runtime bits
3008 .undefined_type => unreachable, // no runtime bits
3009 .enum_literal_type => unreachable, // no runtime bits
3010 .optional_noreturn_type => unreachable, // no runtime bits
3011 .empty_tuple_type => unreachable, // no runtime bits
3110 .anyframe_type => @panic("TODO implement lowerType for AnyFrame types"),3012 .anyframe_type => @panic("TODO implement lowerType for AnyFrame types"),
3111 .null_type,
3112 .undefined_type,
3113 .enum_literal_type,
3114 => unreachable,
3115 .ptr_usize_type,3013 .ptr_usize_type,
3116 .ptr_const_comptime_int_type,3014 .ptr_const_comptime_int_type,
3117 .manyptr_u8_type,3015 .manyptr_u8_type,
...@@ -3121,13 +3019,10 @@ pub const Object = struct {...@@ -3121,13 +3019,10 @@ pub const Object = struct {
3121 .slice_const_u8_type,3019 .slice_const_u8_type,
3122 .slice_const_u8_sentinel_0_type,3020 .slice_const_u8_sentinel_0_type,
3123 => try o.builder.structType(.normal, &.{ .ptr, try o.lowerType(.usize) }),3021 => try o.builder.structType(.normal, &.{ .ptr, try o.lowerType(.usize) }),
3124 .optional_noreturn_type => unreachable,
3125 .anyerror_void_error_union_type,3022 .anyerror_void_error_union_type,
3126 .adhoc_inferred_error_set_type,3023 .adhoc_inferred_error_set_type,
3127 => try o.errorIntType(),3024 => try o.errorIntType(),
3128 .generic_poison_type,3025 .generic_poison_type => unreachable,
3129 .empty_tuple_type,
3130 => unreachable,
3131 // values, not types3026 // values, not types
3132 .undef,3027 .undef,
3133 .undef_bool,3028 .undef_bool,
...@@ -3176,7 +3071,11 @@ pub const Object = struct {...@@ -3176,7 +3071,11 @@ pub const Object = struct {
3176 ),3071 ),
3177 .opt_type => |child_ty| {3072 .opt_type => |child_ty| {
3178 // Must stay in sync with `opt_payload` logic in `lowerPtr`.3073 // Must stay in sync with `opt_payload` logic in `lowerPtr`.
3179 if (!Type.fromInterned(child_ty).hasRuntimeBits(zcu)) return .i8;3074 switch (Type.fromInterned(child_ty).classify(zcu)) {
3075 .no_possible_value, .fully_comptime => unreachable,
3076 .one_possible_value => return .i8,
3077 .runtime, .partially_comptime => {},
3078 }
31803079
3181 const payload_ty = try o.lowerType(.fromInterned(child_ty));3080 const payload_ty = try o.lowerType(.fromInterned(child_ty));
3182 if (t.optionalReprIsPayload(zcu)) return payload_ty;3081 if (t.optionalReprIsPayload(zcu)) return payload_ty;
...@@ -3198,8 +3097,13 @@ pub const Object = struct {...@@ -3198,8 +3097,13 @@ pub const Object = struct {
3198 // Must stay in sync with `codegen.errUnionPayloadOffset`.3097 // Must stay in sync with `codegen.errUnionPayloadOffset`.
3199 // See logic in `lowerPtr`.3098 // See logic in `lowerPtr`.
3200 const error_type = try o.errorIntType();3099 const error_type = try o.errorIntType();
3201 if (!Type.fromInterned(error_union_type.payload_type).hasRuntimeBits(zcu))3100
3202 return error_type;3101 switch (Type.fromInterned(error_union_type.payload_type).classify(zcu)) {
3102 .fully_comptime => unreachable,
3103 .no_possible_value, .one_possible_value => return error_type,
3104 .runtime, .partially_comptime => {},
3105 }
3106
3203 const payload_type = try o.lowerType(.fromInterned(error_union_type.payload_type));3107 const payload_type = try o.lowerType(.fromInterned(error_union_type.payload_type));
32043108
3205 const payload_align = Type.fromInterned(error_union_type.payload_type).abiAlignment(zcu);3109 const payload_align = Type.fromInterned(error_union_type.payload_type).abiAlignment(zcu);
...@@ -3245,6 +3149,8 @@ pub const Object = struct {...@@ -3245,6 +3149,8 @@ pub const Object = struct {
3245 return int_ty;3149 return int_ty;
3246 }3150 }
32473151
3152 assert(struct_type.size > 0);
3153
3248 var llvm_field_types: std.ArrayList(Builder.Type) = .empty;3154 var llvm_field_types: std.ArrayList(Builder.Type) = .empty;
3249 defer llvm_field_types.deinit(o.gpa);3155 defer llvm_field_types.deinit(o.gpa);
3250 // Although we can estimate how much capacity to add, these cannot be3156 // Although we can estimate how much capacity to add, these cannot be
...@@ -3311,7 +3217,7 @@ pub const Object = struct {...@@ -3311,7 +3217,7 @@ pub const Object = struct {
33113217
3312 comptime assert(struct_layout_version == 2);3218 comptime assert(struct_layout_version == 2);
3313 var offset: u64 = 0;3219 var offset: u64 = 0;
3314 var big_align: InternPool.Alignment = .none;3220 var big_align: InternPool.Alignment = .@"1";
33153221
3316 for (3222 for (
3317 tuple_type.types.get(ip),3223 tuple_type.types.get(ip),
...@@ -3345,6 +3251,7 @@ pub const Object = struct {...@@ -3345,6 +3251,7 @@ pub const Object = struct {
3345 try o.builder.arrayType(padding_len, .i8),3251 try o.builder.arrayType(padding_len, .i8),
3346 );3252 );
3347 }3253 }
3254 assert(offset > 0);
3348 return o.builder.structType(.normal, llvm_field_types.items);3255 return o.builder.structType(.normal, llvm_field_types.items);
3349 },3256 },
3350 .union_type => {3257 .union_type => {
...@@ -3358,6 +3265,8 @@ pub const Object = struct {...@@ -3358,6 +3265,8 @@ pub const Object = struct {
3358 return int_ty;3265 return int_ty;
3359 }3266 }
33603267
3268 assert(union_obj.size > 0);
3269
3361 const layout = Type.getUnionLayout(union_obj, zcu);3270 const layout = Type.getUnionLayout(union_obj, zcu);
33623271
3363 if (layout.payload_size == 0) {3272 if (layout.payload_size == 0) {
...@@ -3421,15 +3330,9 @@ pub const Object = struct {...@@ -3421,15 +3330,9 @@ pub const Object = struct {
3421 );3330 );
3422 return ty;3331 return ty;
3423 },3332 },
3424 .opaque_type => {3333 .opaque_type => unreachable, // no runtime bits
3425 const gop = try o.type_map.getOrPut(o.gpa, t.toIntern());
3426 if (!gop.found_existing) {
3427 gop.value_ptr.* = try o.builder.opaqueType(try o.builder.string(t.containerTypeName(ip).toSlice(ip)));
3428 }
3429 return gop.value_ptr.*;
3430 },
3431 .enum_type => try o.lowerType(t.intTagType(zcu)),3334 .enum_type => try o.lowerType(t.intTagType(zcu)),
3432 .func_type => |func_type| try o.lowerFnType(func_type),3335 .func_type => |func_type| try o.lowerFnType(t, func_type),
3433 .error_set_type, .inferred_error_set_type => try o.errorIntType(),3336 .error_set_type, .inferred_error_set_type => try o.errorIntType(),
3434 // values, not types3337 // values, not types
3435 .undef,3338 .undef,
...@@ -3455,10 +3358,13 @@ pub const Object = struct {...@@ -3455,10 +3358,13 @@ pub const Object = struct {
3455 };3358 };
3456 }3359 }
34573360
3458 fn lowerFnType(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type {3361 fn lowerFnType(o: *Object, fn_ty: Type, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type {
3459 const zcu = o.zcu;3362 const zcu = o.zcu;
3460 const ip = &zcu.intern_pool;3363 const ip = &zcu.intern_pool;
3461 const target = zcu.getTarget();3364 const target = zcu.getTarget();
3365
3366 assert(fn_ty.fnHasRuntimeBits(zcu));
3367
3462 const ret_ty = try lowerFnRetTy(o, fn_info);3368 const ret_ty = try lowerFnRetTy(o, fn_info);
34633369
3464 var llvm_params: std.ArrayList(Builder.Type) = .empty;3370 var llvm_params: std.ArrayList(Builder.Type) = .empty;
...@@ -3526,15 +3432,12 @@ pub const Object = struct {...@@ -3526,15 +3432,12 @@ pub const Object = struct {
3526 const ip = &zcu.intern_pool;3432 const ip = &zcu.intern_pool;
3527 const target = zcu.getTarget();3433 const target = zcu.getTarget();
35283434
3529 const val = Value.fromInterned(arg_val);3435 const val: Value = .fromInterned(arg_val);
3530 const val_key = ip.indexToKey(val.toIntern());3436 const val_key = ip.indexToKey(val.toIntern());
35313437
3532 if (val.isUndef(zcu)) {
3533 return o.builder.undefConst(try o.lowerType(.fromInterned(val_key.typeOf())));
3534 }
3535
3536 const ty: Type = .fromInterned(val_key.typeOf());3438 const ty: Type = .fromInterned(val_key.typeOf());
3537 ty.assertHasLayout(zcu);3439 ty.assertHasLayout(zcu);
3440 assert(ty.hasRuntimeBits(zcu));
35383441
3539 return switch (val_key) {3442 return switch (val_key) {
3540 .int_type,3443 .int_type,
...@@ -3555,7 +3458,7 @@ pub const Object = struct {...@@ -3555,7 +3458,7 @@ pub const Object = struct {
3555 .inferred_error_set_type,3458 .inferred_error_set_type,
3556 => unreachable, // types, not values3459 => unreachable, // types, not values
35573460
3558 .undef => unreachable, // handled above3461 .undef => return o.builder.undefConst(try o.lowerType(ty)),
3559 .simple_value => |simple_value| switch (simple_value) {3462 .simple_value => |simple_value| switch (simple_value) {
3560 .void => unreachable, // non-runtime value3463 .void => unreachable, // non-runtime value
3561 .null => unreachable, // non-runtime value3464 .null => unreachable, // non-runtime value
...@@ -3565,14 +3468,8 @@ pub const Object = struct {...@@ -3565,14 +3468,8 @@ pub const Object = struct {
3565 .true => .true,3468 .true => .true,
3566 },3469 },
3567 .enum_literal => unreachable, // non-runtime value3470 .enum_literal => unreachable, // non-runtime value
3568 .@"extern" => |@"extern"| {3471 .@"extern" => unreachable, // non-runtime value
3569 const function_index = try o.resolveLlvmFunction(@"extern".owner_nav);3472 .func => unreachable, // non-runtime value
3570 return function_index.ptrConst(&o.builder).global.toConst();
3571 },
3572 .func => |func| {
3573 const function_index = try o.resolveLlvmFunction(func.owner_nav);
3574 return function_index.ptrConst(&o.builder).global.toConst();
3575 },
3576 .int => {3473 .int => {
3577 var bigint_space: Value.BigIntSpace = undefined;3474 var bigint_space: Value.BigIntSpace = undefined;
3578 const bigint = val.toBigInt(&bigint_space, zcu);3475 const bigint = val.toBigInt(&bigint_space, zcu);
...@@ -3815,7 +3712,7 @@ pub const Object = struct {...@@ -3815,7 +3712,7 @@ pub const Object = struct {
3815 comptime assert(struct_layout_version == 2);3712 comptime assert(struct_layout_version == 2);
3816 var llvm_index: usize = 0;3713 var llvm_index: usize = 0;
3817 var offset: u64 = 0;3714 var offset: u64 = 0;
3818 var big_align: InternPool.Alignment = .none;3715 var big_align: InternPool.Alignment = .@"1";
3819 var need_unnamed = false;3716 var need_unnamed = false;
3820 for (3717 for (
3821 tuple.types.get(ip),3718 tuple.types.get(ip),
...@@ -4033,7 +3930,7 @@ pub const Object = struct {...@@ -4033,7 +3930,7 @@ pub const Object = struct {
4033 const offset: u64 = prev_offset + ptr.byte_offset;3930 const offset: u64 = prev_offset + ptr.byte_offset;
4034 return switch (ptr.base_addr) {3931 return switch (ptr.base_addr) {
4035 .nav => |nav| {3932 .nav => |nav| {
4036 const base_ptr = try o.lowerNavRefValue(nav);3933 const base_ptr = try o.lowerNavRef(nav);
4037 return o.builder.gepConst(.inbounds, .i8, base_ptr, null, &.{3934 return o.builder.gepConst(.inbounds, .i8, base_ptr, null, &.{
4038 try o.builder.intConst(.i64, offset),3935 try o.builder.intConst(.i64, offset),
4039 });3936 });
...@@ -4092,8 +3989,19 @@ pub const Object = struct {...@@ -4092,8 +3989,19 @@ pub const Object = struct {
4092 };3989 };
4093 }3990 }
40943991
4095 /// This logic is very similar to `lowerNavRefValue` but for anonymous declarations.3992 pub fn lowerPtrToVoid(
4096 /// Maybe the logic could be unified.3993 o: *Object,
3994 /// Must not be `.none`.
3995 @"align": InternPool.Alignment,
3996 @"addrspace": std.builtin.AddressSpace,
3997 ) Allocator.Error!Builder.Constant {
3998 const addr: u64 = @"align".toByteUnits().?;
3999 const llvm_usize = try o.lowerType(.usize);
4000 const llvm_addr = try o.builder.intConst(llvm_usize, addr);
4001 const llvm_ptr_ty = try o.builder.ptrType(toLlvmAddressSpace(@"addrspace", o.zcu.getTarget()));
4002 return o.builder.castConst(.inttoptr, llvm_addr, llvm_ptr_ty);
4003 }
4004
4097 pub fn lowerUavRef(4005 pub fn lowerUavRef(
4098 o: *Object,4006 o: *Object,
4099 uav_val: InternPool.Index,4007 uav_val: InternPool.Index,
...@@ -4105,6 +4013,8 @@ pub const Object = struct {...@@ -4105,6 +4013,8 @@ pub const Object = struct {
41054013
4106 const zcu = o.zcu;4014 const zcu = o.zcu;
4107 const ip = &zcu.intern_pool;4015 const ip = &zcu.intern_pool;
4016 const gpa = zcu.comp.gpa;
4017
4108 const uav_ty: Type = .fromInterned(ip.typeOf(uav_val));4018 const uav_ty: Type = .fromInterned(ip.typeOf(uav_val));
41094019
4110 switch (ip.indexToKey(uav_val)) {4020 switch (ip.indexToKey(uav_val)) {
...@@ -4118,63 +4028,63 @@ pub const Object = struct {...@@ -4118,63 +4028,63 @@ pub const Object = struct {
4118 }4028 }
41194029
4120 const llvm_addrspace = toLlvmAddressSpace(@"addrspace", zcu.getTarget());4030 const llvm_addrspace = toLlvmAddressSpace(@"addrspace", zcu.getTarget());
4121 const llvm_global = (try o.resolveGlobalUav(uav_val, llvm_addrspace, @"align")).ptrConst(&o.builder).global;
41224031
4123 return o.builder.convConst(4032 const gop = try o.uav_map.getOrPut(gpa, .{ .val = uav_val, .@"addrspace" = @"addrspace" });
4124 llvm_global.toConst(),4033 if (gop.found_existing) {
4125 try o.builder.ptrType(llvm_addrspace),4034 // Keep the greater of the two alignments.
4126 );4035 const llvm_variable = gop.value_ptr.*;
4036 const old_align: InternPool.Alignment = .fromLlvm(llvm_variable.getAlignment(&o.builder));
4037 llvm_variable.setAlignment(old_align.maxStrict(@"align").toLlvm(), &o.builder);
4038 return llvm_variable.ptrConst(&o.builder).global.toConst();
4039 }
4040 errdefer assert(o.uav_map.remove(.{ .val = uav_val, .@"addrspace" = @"addrspace" }));
4041
4042 const llvm_ty = try o.lowerType(uav_ty);
4043 const llvm_name = try o.builder.strtabStringFmt("__anon_{d}", .{@intFromEnum(uav_val)});
4044 const llvm_variable = try o.builder.addVariable(llvm_name, llvm_ty, llvm_addrspace);
4045 gop.value_ptr.* = llvm_variable;
4046 try llvm_variable.setInitializer(try o.lowerValue(uav_val), &o.builder);
4047 llvm_variable.setMutability(.constant, &o.builder);
4048 llvm_variable.setAlignment(@"align".toLlvm(), &o.builder);
4049 const llvm_global = llvm_variable.ptrConst(&o.builder).global;
4050 llvm_global.setLinkage(if (o.builder.strip) .private else .internal, &o.builder);
4051 llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder);
4052 return llvm_global.toConst();
4127 }4053 }
41284054
4129 pub fn lowerNavRefValue(o: *Object, nav_index: InternPool.Nav.Index) Allocator.Error!Builder.Constant {4055 pub fn lowerNavRef(o: *Object, nav_id: InternPool.Nav.Index) Allocator.Error!Builder.Constant {
4130 const zcu = o.zcu;4056 const zcu = o.zcu;
4131 const ip = &zcu.intern_pool;4057 const ip = &zcu.intern_pool;
4058 const gpa = zcu.comp.gpa;
41324059
4133 const nav = ip.getNav(nav_index);4060 const nav = ip.getNav(nav_id);
4134
4135 const nav_ty: Type = .fromInterned(nav.resolved.?.type);4061 const nav_ty: Type = .fromInterned(nav.resolved.?.type);
41364062 if (!nav_ty.isRuntimeFnOrHasRuntimeBits(zcu) and nav.getExtern(ip) == null) {
4137 if (nav.getExtern(ip) == null and !nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) {4063 const nav_align = switch (nav.resolved.?.@"align") {
4138 return o.lowerPtrToVoid(nav.resolved.?.@"align", nav.resolved.?.@"addrspace");4064 .none => nav_ty.abiAlignment(zcu),
4065 else => |a| a,
4066 };
4067 return o.lowerPtrToVoid(nav_align, nav.resolved.?.@"addrspace");
4139 }4068 }
41404069
4141 const llvm_global = if (nav_ty.zigTypeTag(zcu) == .@"fn")4070 const gop = try o.nav_map.getOrPut(gpa, nav_id);
4142 (try o.resolveLlvmFunction(nav_index)).ptrConst(&o.builder).global4071 if (!gop.found_existing) {
4143 else4072 errdefer assert(o.nav_map.remove(nav_id));
4144 (try o.resolveGlobalNav(nav_index)).ptrConst(&o.builder).global;4073 // The NAV hasn't been lowered yet, so generate a placeholder global whose details will
4074 // be filled in later.
4075 const llvm_name = try o.builder.strtabString(nav.fqn.toSlice(ip));
4076 gop.value_ptr.* = try o.builder.addGlobal(llvm_name, .{
4077 .type = .void, // placeholder; populated by `updateNav`/`updateFunc`
4078 .kind = .{ .alias = .none }, // placeholder; populated by `updateNav`/`updateFunc`
4079 });
4080 }
4081 const llvm_global = gop.value_ptr.*;
41454082
4146 return try o.builder.convConst(4083 // We need to make sure the global's address space is up to date, because that affects the
4147 llvm_global.toConst(),4084 // type of a pointer to this global. But everything else about the global will be populated
4148 try o.builder.ptrType(toLlvmAddressSpace(nav.resolved.?.@"addrspace", zcu.getTarget())),4085 // by `updateNav` or `updateFunc`.
4149 );4086 llvm_global.ptr(&o.builder).addr_space = toLlvmAddressSpace(nav.resolved.?.@"addrspace", zcu.getTarget());
4150 }4087 return llvm_global.toConst();
4151
4152 pub fn lowerPtrToVoid(
4153 o: *Object,
4154 @"align": InternPool.Alignment,
4155 @"addrspace": std.builtin.AddressSpace,
4156 ) Allocator.Error!Builder.Constant {
4157 const target = o.zcu.getTarget();
4158 // Even though we are pointing at something which has zero bits (e.g. `void`),
4159 // Pointers are defined to have bits. So we must return something here.
4160 // The value cannot be undefined, because we use the `nonnull` annotation
4161 // for non-optional pointers. We also need to respect the alignment, even though
4162 // the address will never be dereferenced.
4163 const int: u64 = @"align".toByteUnits() orelse
4164 // Note that these 0xaa values are appropriate even in release-optimized builds
4165 // because we need a well-defined value that is not null, and LLVM does not
4166 // have an "undef_but_not_null" attribute. As an example, if this `alloc` AIR
4167 // instruction is followed by a `wrap_optional`, it will return this value
4168 // verbatim, and the result should test as non-null.
4169 switch (target.ptrBitWidth()) {
4170 16 => 0xaaaa,
4171 32 => 0xaaaaaaaa,
4172 64 => 0xaaaaaaaa_aaaaaaaa,
4173 else => unreachable,
4174 };
4175 const llvm_usize = try o.lowerType(.usize);
4176 const llvm_ptr_ty = try o.builder.ptrType(toLlvmAddressSpace(@"addrspace", target));
4177 return o.builder.castConst(.inttoptr, try o.builder.intConst(llvm_usize, int), llvm_ptr_ty);
4178 }4088 }
41794089
4180 pub fn addByValParamAttrs(4090 pub fn addByValParamAttrs(
...@@ -4243,13 +4153,14 @@ pub const Object = struct {...@@ -4243,13 +4153,14 @@ pub const Object = struct {
4243 const name = try o.builder.strtabString("__zig_error_name_table");4153 const name = try o.builder.strtabString("__zig_error_name_table");
4244 // TODO: Address space4154 // TODO: Address space
4245 const variable_index = try o.builder.addVariable(name, .ptr, .default);4155 const variable_index = try o.builder.addVariable(name, .ptr, .default);
4246 variable_index.setLinkage(.private, &o.builder);
4247 variable_index.setMutability(.constant, &o.builder);4156 variable_index.setMutability(.constant, &o.builder);
4248 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
4249 variable_index.setAlignment(4157 variable_index.setAlignment(
4250 Type.slice_const_u8_sentinel_0.abiAlignment(o.zcu).toLlvm(),4158 Type.slice_const_u8_sentinel_0.abiAlignment(o.zcu).toLlvm(),
4251 &o.builder,4159 &o.builder,
4252 );4160 );
4161 const global_index = variable_index.ptrConst(&o.builder).global;
4162 global_index.setLinkage(.private, &o.builder);
4163 global_index.setUnnamedAddr(.unnamed_addr, &o.builder);
42534164
4254 o.error_name_table = variable_index;4165 o.error_name_table = variable_index;
4255 return variable_index;4166 return variable_index;
...@@ -4261,10 +4172,11 @@ pub const Object = struct {...@@ -4261,10 +4172,11 @@ pub const Object = struct {
4261 const llvm_err_int_ty = try o.errorIntType();4172 const llvm_err_int_ty = try o.errorIntType();
4262 const name = try builder.strtabString("__zig_errors_len");4173 const name = try builder.strtabString("__zig_errors_len");
4263 const variable_index = try builder.addVariable(name, llvm_err_int_ty, .default);4174 const variable_index = try builder.addVariable(name, llvm_err_int_ty, .default);
4264 variable_index.setLinkage(.private, builder);
4265 variable_index.setMutability(.constant, builder);4175 variable_index.setMutability(.constant, builder);
4266 variable_index.setUnnamedAddr(.unnamed_addr, builder);
4267 variable_index.setAlignment(Type.errorAbiAlignment(o.zcu).toLlvm(), builder);4176 variable_index.setAlignment(Type.errorAbiAlignment(o.zcu).toLlvm(), builder);
4177 const global_index = variable_index.ptrConst(&o.builder).global;
4178 global_index.setLinkage(.private, builder);
4179 global_index.setUnnamedAddr(.unnamed_addr, builder);
4268 o.errors_len_variable = variable_index;4180 o.errors_len_variable = variable_index;
4269 }4181 }
4270 return o.errors_len_variable;4182 return o.errors_len_variable;
...@@ -4332,16 +4244,16 @@ pub const Object = struct {...@@ -4332,16 +4244,16 @@ pub const Object = struct {
4332 for (0..loaded_enum.field_names.len) |field_index| {4244 for (0..loaded_enum.field_names.len) |field_index| {
4333 const name = try o.builder.stringNull(loaded_enum.field_names.get(ip)[field_index].toSlice(ip));4245 const name = try o.builder.stringNull(loaded_enum.field_names.get(ip)[field_index].toSlice(ip));
4334 const name_init = try o.builder.stringConst(name);4246 const name_init = try o.builder.stringConst(name);
4335 const name_variable_index =4247 const name_variable_index = try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default);
4336 try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default);
4337 try name_variable_index.setInitializer(name_init, &o.builder);4248 try name_variable_index.setInitializer(name_init, &o.builder);
4338 name_variable_index.setLinkage(.private, &o.builder);
4339 name_variable_index.setMutability(.constant, &o.builder);4249 name_variable_index.setMutability(.constant, &o.builder);
4340 name_variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
4341 name_variable_index.setAlignment(comptime Builder.Alignment.fromByteUnits(1), &o.builder);4250 name_variable_index.setAlignment(comptime Builder.Alignment.fromByteUnits(1), &o.builder);
4251 const name_global_index = name_variable_index.ptrConst(&o.builder).global;
4252 name_global_index.setLinkage(.private, &o.builder);
4253 name_global_index.setUnnamedAddr(.unnamed_addr, &o.builder);
43424254
4343 const name_val = try o.builder.structValue(llvm_ret_ty, &.{4255 const name_val = try o.builder.structValue(llvm_ret_ty, &.{
4344 name_variable_index.toConst(&o.builder),4256 name_global_index.toConst(),
4345 try o.builder.intConst(llvm_usize_ty, name.slice(&o.builder).?.len - 1),4257 try o.builder.intConst(llvm_usize_ty, name.slice(&o.builder).?.len - 1),
4346 });4258 });
43474259
src/codegen/llvm/FuncGen.zig+35-25
...@@ -581,8 +581,17 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif...@@ -581,8 +581,17 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
581 else => unreachable,581 else => unreachable,
582 };582 };
583 const fn_info = zcu.typeToFunc(zig_fn_ty).?;583 const fn_info = zcu.typeToFunc(zig_fn_ty).?;
584 const return_type = Type.fromInterned(fn_info.return_type);584 const return_type: Type = .fromInterned(fn_info.return_type);
585 const llvm_fn = try self.resolveInst(air_call.callee);585 const llvm_fn = llvm_fn: {
586 // If the callee is a function *body*, we need to use a pointer to the global.
587 if (air_call.callee.toInterned()) |ip_index| switch (ip.indexToKey(ip_index)) {
588 .@"extern" => |e| break :llvm_fn (try o.lowerNavRef(e.owner_nav)).toValue(),
589 .func => |f| break :llvm_fn (try o.lowerNavRef(f.owner_nav)).toValue(),
590 else => {},
591 };
592 // Otherwise, the operand is already a function pointer (possibly runtime-known).
593 break :llvm_fn try self.resolveInst(air_call.callee);
594 };
586 const target = zcu.getTarget();595 const target = zcu.getTarget();
587 const sret = firstParamSRet(fn_info, zcu, target);596 const sret = firstParamSRet(fn_info, zcu, target);
588597
...@@ -875,7 +884,9 @@ fn buildSimplePanic(fg: *FuncGen, panic_id: Zcu.SimplePanicId) Allocator.Error!v...@@ -875,7 +884,9 @@ fn buildSimplePanic(fg: *FuncGen, panic_id: Zcu.SimplePanicId) Allocator.Error!v
875 const target = zcu.getTarget();884 const target = zcu.getTarget();
876 const panic_func = zcu.funcInfo(zcu.builtin_decl_values.get(panic_id.toBuiltin()));885 const panic_func = zcu.funcInfo(zcu.builtin_decl_values.get(panic_id.toBuiltin()));
877 const fn_info = zcu.typeToFunc(.fromInterned(panic_func.ty)).?;886 const fn_info = zcu.typeToFunc(.fromInterned(panic_func.ty)).?;
878 const panic_global = try o.resolveLlvmFunction(panic_func.owner_nav);887 const llvm_panic_fn_ty = try o.lowerType(.fromInterned(panic_func.ty));
888
889 const llvm_panic_fn_ref = try o.lowerNavRef(panic_func.owner_nav);
879890
880 const has_err_trace = zcu.comp.config.any_error_tracing and fn_info.cc == .auto;891 const has_err_trace = zcu.comp.config.any_error_tracing and fn_info.cc == .auto;
881 if (has_err_trace) assert(fg.err_ret_trace != .none);892 if (has_err_trace) assert(fg.err_ret_trace != .none);
...@@ -884,8 +895,8 @@ fn buildSimplePanic(fg: *FuncGen, panic_id: Zcu.SimplePanicId) Allocator.Error!v...@@ -884,8 +895,8 @@ fn buildSimplePanic(fg: *FuncGen, panic_id: Zcu.SimplePanicId) Allocator.Error!v
884 .normal,895 .normal,
885 llvm.toLlvmCallConvTag(fn_info.cc, target).?,896 llvm.toLlvmCallConvTag(fn_info.cc, target).?,
886 .none,897 .none,
887 panic_global.typeOf(&o.builder),898 llvm_panic_fn_ty,
888 panic_global.toValue(&o.builder),899 llvm_panic_fn_ref.toValue(),
889 if (has_err_trace) &.{fg.err_ret_trace} else &.{},900 if (has_err_trace) &.{fg.err_ret_trace} else &.{},
890 "",901 "",
891 );902 );
...@@ -1745,8 +1756,9 @@ fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Tod...@@ -1745,8 +1756,9 @@ fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Tod
1745 .default,1756 .default,
1746 );1757 );
1747 try table_variable.setInitializer(table_val, &o.builder);1758 try table_variable.setInitializer(table_val, &o.builder);
1748 table_variable.setLinkage(if (o.builder.strip) .private else .internal, &o.builder);1759 const table_global = table_variable.ptrConst(&o.builder).global;
1749 table_variable.setUnnamedAddr(.unnamed_addr, &o.builder);1760 table_global.setLinkage(if (o.builder.strip) .private else .internal, &o.builder);
1761 table_global.setUnnamedAddr(.unnamed_addr, &o.builder);
17501762
1751 const table_includes_else = item_count != table_len;1763 const table_includes_else = item_count != table_len;
17521764
...@@ -1759,7 +1771,7 @@ fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Tod...@@ -1759,7 +1771,7 @@ fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Tod
1759 .likely => .likely,1771 .likely => .likely,
1760 .unlikely => .unlikely,1772 .unlikely => .unlikely,
1761 },1773 },
1762 .table = table_variable.toConst(&o.builder),1774 .table = table_global.toConst(),
1763 .table_includes_else = table_includes_else,1775 .table_includes_else = table_includes_else,
1764 };1776 };
1765 };1777 };
...@@ -3255,8 +3267,8 @@ fn airWasmMemoryGrow(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Build...@@ -3255,8 +3267,8 @@ fn airWasmMemoryGrow(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Build
3255fn airRuntimeNavPtr(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {3267fn airRuntimeNavPtr(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {
3256 const o = fg.object;3268 const o = fg.object;
3257 const ty_nav = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;3269 const ty_nav = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
3258 const llvm_ptr_const = try o.lowerNavRefValue(ty_nav.nav);3270 const llvm_ptr = try o.lowerNavRef(ty_nav.nav);
3259 return llvm_ptr_const.toValue();3271 return llvm_ptr.toValue();
3260}3272}
32613273
3262fn airMin(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {3274fn airMin(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {
...@@ -4636,29 +4648,27 @@ fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value...@@ -4636,29 +4648,27 @@ fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value
4636 const o = self.object;4648 const o = self.object;
4637 const zcu = o.zcu;4649 const zcu = o.zcu;
4638 const ptr_ty = self.typeOfIndex(inst);4650 const ptr_ty = self.typeOfIndex(inst);
4639 const pointee_type = ptr_ty.childType(zcu);4651 const ptr_align = ptr_ty.ptrAlignment(zcu);
4640 if (!pointee_type.hasRuntimeBits(zcu)) {4652 const elem_ty = ptr_ty.childType(zcu);
4641 const ptr_info = ptr_ty.ptrInfo(zcu);4653 if (!elem_ty.hasRuntimeBits(zcu)) {
4642 return (try o.lowerPtrToVoid(ptr_info.flags.alignment, ptr_info.flags.address_space)).toValue();4654 return (try o.lowerPtrToVoid(ptr_align, ptr_ty.ptrAddressSpace(zcu))).toValue();
4643 }4655 }
4644 const pointee_llvm_ty = try o.lowerType(pointee_type);4656 const llvm_elem_ty = try o.lowerType(elem_ty);
4645 const alignment = ptr_ty.ptrAlignment(zcu).toLlvm();4657 return self.buildAlloca(llvm_elem_ty, ptr_align.toLlvm());
4646 return self.buildAlloca(pointee_llvm_ty, alignment);
4647}4658}
46484659
4649fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {4660fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {
4661 if (self.ret_ptr != .none) return self.ret_ptr;
4650 const o = self.object;4662 const o = self.object;
4651 const zcu = o.zcu;4663 const zcu = o.zcu;
4652 const ptr_ty = self.typeOfIndex(inst);4664 const ptr_ty = self.typeOfIndex(inst);
4653 const ret_ty = ptr_ty.childType(zcu);4665 const ptr_align = ptr_ty.ptrAlignment(zcu);
4654 if (!ret_ty.hasRuntimeBits(zcu)) {4666 const elem_ty = ptr_ty.childType(zcu);
4655 const ptr_info = ptr_ty.ptrInfo(zcu);4667 if (!elem_ty.hasRuntimeBits(zcu)) {
4656 return (try o.lowerPtrToVoid(ptr_info.flags.alignment, ptr_info.flags.address_space)).toValue();4668 return (try o.lowerPtrToVoid(ptr_align, ptr_ty.ptrAddressSpace(zcu))).toValue();
4657 }4669 }
4658 if (self.ret_ptr != .none) return self.ret_ptr;4670 const llvm_elem_ty = try o.lowerType(elem_ty);
4659 const ret_llvm_ty = try o.lowerType(ret_ty);4671 return self.buildAlloca(llvm_elem_ty, ptr_align.toLlvm());
4660 const alignment = ptr_ty.ptrAlignment(zcu).toLlvm();
4661 return self.buildAlloca(ret_llvm_ty, alignment);
4662}4672}
46634673
4664/// Use this instead of builder.buildAlloca, because this function makes sure to4674/// Use this instead of builder.buildAlloca, because this function makes sure to