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 {
23432343 none = maxInt(u32),
23442344 _,
23452345
2346 pub fn unwrap(self: Index, builder: *const Builder) Index {
2347 var cur = self;
2346 pub fn unwrap(orig_index: Index, builder: *const Builder) Index {
2347 var cur = orig_index;
23482348 while (true) {
2349 const replacement = cur.getReplacement(builder);
2350 if (replacement == .none) return cur;
2351 cur = replacement;
2349 switch (builder.globals.values()[@intFromEnum(cur)].kind) {
2350 .replaced => |replacement| cur = replacement,
2351 else => return cur,
2352 }
23522353 }
23532354 }
23542355
......@@ -2388,8 +2389,12 @@ pub const Global = struct {
23882389 return self.ptrConst(builder).type;
23892390 }
23902391
2391 pub fn toConst(self: Index) Constant {
2392 return @enumFromInt(@intFromEnum(Constant.first_global) + @intFromEnum(self));
2392 pub fn toConst(global: Index) Constant {
2393 return @enumFromInt(@intFromEnum(Constant.first_global) + @intFromEnum(global));
2394 }
2395
2396 pub fn toValue(global: Index) Value {
2397 return global.toConst().toValue();
23932398 }
23942399
23952400 pub fn setLinkage(self: Index, linkage: Linkage, builder: *Builder) void {
......@@ -2450,6 +2455,42 @@ pub const Global = struct {
24502455 self.ptr(builder).kind = .{ .replaced = .none };
24512456 }
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
24532494 fn updateDsoLocal(self: Index, builder: *Builder) void {
24542495 const self_ptr = self.ptr(builder);
24552496 switch (self_ptr.linkage) {
......@@ -2494,13 +2535,6 @@ pub const Global = struct {
24942535 self.renameAssumeCapacity(builder.next_replaced_global, builder);
24952536 self.ptr(builder).kind = .{ .replaced = other.unwrap(builder) };
24962537 }
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 }
25042538 };
25052539};
25062540
......@@ -2593,22 +2627,6 @@ pub const Variable = struct {
25932627 return self.toConst(builder).toValue();
25942628 }
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
26122630 pub fn setThreadLocal(self: Index, thread_local: ThreadLocal, builder: *Builder) void {
26132631 self.ptr(builder).thread_local = thread_local;
26142632 }
......@@ -9692,8 +9710,12 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
96929710
96939711 if (self.variables.items.len > 0) {
96949712 if (need_newline) try w.writeByte('\n') else need_newline = true;
9695 for (self.variables.items) |variable| {
9696 if (variable.global.getReplacement(self) != .none) continue;
9713 for (self.variables.items, 0..) |variable, variable_i| {
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 }
96979719 const global = variable.global.ptrConst(self);
96989720 metadata_formatter.need_comma = true;
96999721 defer metadata_formatter.need_comma = undefined;
......@@ -9723,8 +9745,12 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
97239745
97249746 if (self.aliases.items.len > 0) {
97259747 if (need_newline) try w.writeByte('\n') else need_newline = true;
9726 for (self.aliases.items) |alias| {
9727 if (alias.global.getReplacement(self) != .none) continue;
9748 for (self.aliases.items, 0..) |alias, alias_i| {
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 }
97289754 const global = alias.global.ptrConst(self);
97299755 metadata_formatter.need_comma = true;
97309756 defer metadata_formatter.need_comma = undefined;
......@@ -9750,7 +9776,11 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
97509776 defer attribute_groups.deinit(self.gpa);
97519777
97529778 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 }
97549784 if (need_newline) try w.writeByte('\n') else need_newline = true;
97559785 const function_index: Function.Index = @enumFromInt(function_i);
97569786 const global = function.global.ptrConst(self);
......@@ -13687,20 +13717,32 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
1368713717 self.aliases.items.len,
1368813718 );
1368913719
13690 for (self.variables.items) |variable| {
13691 if (variable.global.getReplacement(self) != .none) continue;
13720 for (self.variables.items, 0..) |variable, variable_i| {
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
1369313727 globals.putAssumeCapacity(variable.global, {});
1369413728 }
1369513729
13696 for (self.functions.items) |function| {
13697 if (function.global.getReplacement(self) != .none) continue;
13730 for (self.functions.items, 0..) |function, function_i| {
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
1369913737 globals.putAssumeCapacity(function.global, {});
1370013738 }
1370113739
13702 for (self.aliases.items) |alias| {
13703 if (alias.global.getReplacement(self) != .none) continue;
13740 for (self.aliases.items, 0..) |alias, alias_i| {
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
1370513747 globals.putAssumeCapacity(alias.global, {});
1370613748 }
......@@ -13742,8 +13784,12 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
1374213784 defer section_map.deinit(self.gpa);
1374313785 try section_map.ensureUnusedCapacity(self.gpa, globals.count());
1374413786
13745 for (self.variables.items) |variable| {
13746 if (variable.global.getReplacement(self) != .none) continue;
13787 for (self.variables.items, 0..) |variable, variable_i| {
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
1374813794 const section = blk: {
1374913795 if (variable.section == .none) break :blk 0;
......@@ -13789,8 +13835,12 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
1378913835 });
1379013836 }
1379113837
13792 for (self.functions.items) |func| {
13793 if (func.global.getReplacement(self) != .none) continue;
13838 for (self.functions.items, 0..) |func, func_i| {
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
1379513845 const section = blk: {
1379613846 if (func.section == .none) break :blk 0;
......@@ -13830,8 +13880,12 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
1383013880 });
1383113881 }
1383213882
13833 for (self.aliases.items) |alias| {
13834 if (alias.global.getReplacement(self) != .none) continue;
13883 for (self.aliases.items, 0..) |alias, alias_i| {
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
1383613890 const strtab = alias.global.strtab(self);
1383713891
......@@ -14635,8 +14689,13 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
1463514689 };
1463614690
1463714691 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
1463814698 const FunctionBlock = ir.ModuleBlock.FunctionBlock;
14639 if (func.global.getReplacement(self) != .none) continue;
1464014699
1464114700 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
57515751 if (ptr_info.byte_offset != 0) {
57525752 return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{});
57535753 }
5754 if (zcu.llvm_object != null and options.linkage == .internal) return;
57555754 try sema.exports.append(zcu.gpa, .{
57565755 .opts = options,
57575756 .src = src,
src/Zcu.zig+3-1
......@@ -3731,7 +3731,9 @@ pub fn resetUnit(zcu: *Zcu, unit: AnalUnit) void {
37313731 };
37323732 for (zcu.all_exports.items[base..][0..len], base..) |exp, exp_index_usize| {
37333733 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| {
37353737 lf.deleteExport(exp.exported, exp.opts.name);
37363738 }
37373739 if (zcu.failed_exports.fetchSwapRemove(exp_index)) |failed_kv| {
src/Zcu/PerThread.zig+1-8
......@@ -1910,14 +1910,7 @@ fn analyzeNavVal(
19101910
19111911 try sema.flushExports();
19121912
1913 queue_codegen: {
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
1913 if (queue_linker_work) {
19211914 comp.link_prog_node.increaseEstimatedTotalItems(1);
19221915 try comp.link_queue.enqueueZcu(comp, pt.tid, .{ .link_nav = nav_id });
19231916 }
src/codegen/llvm.zig+553-641
......@@ -550,17 +550,13 @@ pub const Object = struct {
550550 debug_anyerror_fwd_ref: Builder.Metadata.Optional,
551551
552552 zcu: *Zcu,
553 /// Ideally we would use `llvm_module.getNamedFunction` to go from *Decl to LLVM function,
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.
553 /// Maps a `Nav` to the corresponding LLVM global.
561554 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.
563 uav_map: std.AutoHashMapUnmanaged(InternPool.Index, Builder.Global.Index),
555 /// Same as `nav_map` but for UAVs (which are always global constants).
556 uav_map: std.AutoHashMapUnmanaged(struct {
557 val: InternPool.Index,
558 @"addrspace": std.builtin.AddressSpace,
559 }, Builder.Variable.Index),
564560 /// Maps enum types to their corresponding LLVM functions for implementing the `tag_name` instruction.
565561 enum_tag_name_map: std.AutoHashMapUnmanaged(InternPool.Index, Builder.Function.Index),
566562 /// 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 {
717713 for (llvm_errors[1..], error_name_list) |*llvm_error, name| {
718714 const name_string = try o.builder.stringNull(name.toSlice(ip));
719715 const name_init = try o.builder.stringConst(name_string);
720 const name_variable_index =
721 try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default);
716 const name_variable_index = try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default);
722717 try name_variable_index.setInitializer(name_init, &o.builder);
723 name_variable_index.setLinkage(.private, &o.builder);
724718 name_variable_index.setMutability(.constant, &o.builder);
725 name_variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
726719 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
728724 llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{
729725 name_variable_index.toConst(&o.builder),
......@@ -790,9 +786,9 @@ pub const Object = struct {
790786 array_llvm_ty,
791787 .default,
792788 );
793 compiler_used_variable.setLinkage(.appending, &o.builder);
794 compiler_used_variable.setSection(try o.builder.string("llvm.metadata"), &o.builder);
795789 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);
796792 }
797793
798794 if (!o.builder.strip) {
......@@ -1140,6 +1136,7 @@ pub const Object = struct {
11401136 ) Zcu.CodegenFailError!void {
11411137 const zcu = o.zcu;
11421138 const comp = zcu.comp;
1139 const gpa = comp.gpa;
11431140 const ip = &zcu.intern_pool;
11441141 const func = zcu.funcInfo(func_index);
11451142 const nav = ip.getNav(func.owner_nav);
......@@ -1149,9 +1146,42 @@ pub const Object = struct {
11491146 const fn_info = zcu.typeToFunc(fn_ty).?;
11501147 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);
11551185 defer attributes.deinit(&o.builder);
11561186
11571187 const func_analysis = func.analysisUnordered(ip);
......@@ -1221,47 +1251,41 @@ pub const Object = struct {
12211251 } }, &o.builder);
12221252 }
12231253
1224 if (nav.resolved.?.@"linksection".toSlice(ip)) |section|
1225 function_index.setSection(try o.builder.string(section), &o.builder);
1226
12271254 var deinit_wip = true;
12281255 var wip = try Builder.WipFunction.init(&o.builder, .{
1229 .function = function_index,
1256 .function = llvm_function,
12301257 .strip = owner_mod.strip,
12311258 });
12321259 defer if (deinit_wip) wip.deinit();
12331260 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
12431262 if (ccAbiPromoteInt(fn_info.cc, zcu, Type.fromInterned(fn_info.return_type))) |s| switch (s) {
12441263 .signed => try attributes.addRetAttr(.signext, &o.builder),
12451264 .unsigned => try attributes.addRetAttr(.zeroext, &o.builder),
12461265 };
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
12561267 // This is the list of args we will use that correspond directly to the AIR arg
12571268 // instructions. Depending on the calling convention, this list is not necessarily
12581269 // a bijection with the actual LLVM parameters of the function.
1259 const gpa = o.gpa;
12601270 var args: std.ArrayList(Builder.Value) = .empty;
12611271 defer args.deinit(gpa);
12621272
1263 {
1273 const ret_ptr: Builder.Value, const err_ret_trace: Builder.Value = implicit_args: {
12641274 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
12651289 while (try it.next()) |lowering| {
12661290 try args.ensureUnusedCapacity(gpa, 1);
12671291
......@@ -1271,7 +1295,7 @@ pub const Object = struct {
12711295 assert(!it.byval_attr);
12721296 const param_index = it.zig_index - 1;
12731297 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
12761300 if (isByRef(param_ty, zcu)) {
12771301 const alignment = param_ty.abiAlignment(zcu).toLlvm();
......@@ -1281,146 +1305,116 @@ pub const Object = struct {
12811305 args.appendAssumeCapacity(arg_ptr);
12821306 } else {
12831307 args.appendAssumeCapacity(param);
1284
1285 try o.addByValParamAttrs(pt, &attributes, param_ty, param_index, fn_info, llvm_arg_i);
12861308 }
1287 llvm_arg_i += 1;
12881309 },
12891310 .byref => {
1290 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);
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;
1311 const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
1312 const param = wip.arg(it.llvm_index - 1);
12971313
12981314 if (isByRef(param_ty, zcu)) {
12991315 args.appendAssumeCapacity(param);
13001316 } else {
1317 const param_llvm_ty = try o.lowerType(param_ty);
1318 const alignment = param_ty.abiAlignment(zcu).toLlvm();
13011319 args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, ""));
13021320 }
13031321 },
13041322 .byref_mut => {
1305 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);
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;
1323 const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
1324 const param = wip.arg(it.llvm_index - 1);
13121325
13131326 if (isByRef(param_ty, zcu)) {
13141327 args.appendAssumeCapacity(param);
13151328 } else {
1329 const param_llvm_ty = try o.lowerType(param_ty);
1330 const alignment = param_ty.abiAlignment(zcu).toLlvm();
13161331 args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, ""));
13171332 }
13181333 },
13191334 .abi_sized_int => {
13201335 assert(!it.byval_attr);
1321 const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
1322 const param = wip.arg(llvm_arg_i);
1323 llvm_arg_i += 1;
1336 const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
1337 const param = wip.arg(it.llvm_index - 1);
13241338
13251339 const param_llvm_ty = try o.lowerType(param_ty);
13261340 const alignment = param_ty.abiAlignment(zcu).toLlvm();
13271341 const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, alignment, target);
13281342 _ = try wip.store(.normal, param, arg_ptr, alignment);
13291343
1330 args.appendAssumeCapacity(if (isByRef(param_ty, zcu))
1331 arg_ptr
1332 else
1333 try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));
1344 if (isByRef(param_ty, zcu)) {
1345 args.appendAssumeCapacity(arg_ptr);
1346 } else {
1347 args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));
1348 }
13341349 },
13351350 .slice => {
13361351 assert(!it.byval_attr);
1337 const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
1338 const ptr_info = param_ty.ptrInfo(zcu);
1339
1340 if (std.math.cast(u5, it.zig_index - 1)) |i| {
1341 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
1342 try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
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 }, ""),
1352 const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
1353 assert(!isByRef(param_ty, zcu));
1354 const slice_val = try wip.buildAggregate(
1355 try o.lowerType(param_ty),
1356 &.{ wip.arg(it.llvm_index - 2), wip.arg(it.llvm_index - 1) },
1357 "",
13671358 );
1359 args.appendAssumeCapacity(slice_val);
13681360 },
13691361 .multiple_llvm_types => {
13701362 assert(!it.byval_attr);
13711363 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]);
13731365 const param_llvm_ty = try o.lowerType(param_ty);
13741366 const param_alignment = param_ty.abiAlignment(zcu).toLlvm();
13751367 const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, param_alignment, target);
13761368 const llvm_ty = try o.builder.structType(.normal, field_types);
1377 for (0..field_types.len) |field_i| {
1378 const param = wip.arg(llvm_arg_i);
1379 llvm_arg_i += 1;
1369 const llvm_args_start = it.llvm_index - field_types.len;
1370 for (0..field_types.len, llvm_args_start..) |field_i, llvm_arg_index| {
1371 const param = wip.arg(@intCast(llvm_arg_index));
13801372 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));
13821374 _ = try wip.store(.normal, param, field_ptr, alignment);
13831375 }
13841376
1385 const is_by_ref = isByRef(param_ty, zcu);
1386 args.appendAssumeCapacity(if (is_by_ref)
1387 arg_ptr
1388 else
1389 try wip.load(.normal, param_llvm_ty, arg_ptr, param_alignment, ""));
1377 if (isByRef(param_ty, zcu)) {
1378 args.appendAssumeCapacity(arg_ptr);
1379 } else {
1380 args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, arg_ptr, param_alignment, ""));
1381 }
13901382 },
13911383 .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]);
13931385 const param_llvm_ty = try o.lowerType(param_ty);
1394 const param = wip.arg(llvm_arg_i);
1395 llvm_arg_i += 1;
1386 const param = wip.arg(it.llvm_index - 1);
13961387
13971388 const alignment = param_ty.abiAlignment(zcu).toLlvm();
13981389 const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, alignment, target);
13991390 _ = try wip.store(.normal, param, arg_ptr, alignment);
14001391
1401 args.appendAssumeCapacity(if (isByRef(param_ty, zcu))
1402 arg_ptr
1403 else
1404 try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));
1392 if (isByRef(param_ty, zcu)) {
1393 args.appendAssumeCapacity(arg_ptr);
1394 } else {
1395 args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));
1396 }
14051397 },
14061398 .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]);
14081400 const param_llvm_ty = try o.lowerType(param_ty);
1409 const param = wip.arg(llvm_arg_i);
1410 llvm_arg_i += 1;
1401 const param = wip.arg(it.llvm_index - 1);
14111402
14121403 const alignment = param_ty.abiAlignment(zcu).toLlvm();
14131404 const arg_ptr = try buildAllocaInner(&wip, param.typeOfWip(&wip), alignment, target);
14141405 _ = try wip.store(.normal, param, arg_ptr, alignment);
14151406
1416 args.appendAssumeCapacity(if (isByRef(param_ty, zcu))
1417 arg_ptr
1418 else
1419 try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));
1407 if (isByRef(param_ty, zcu)) {
1408 args.appendAssumeCapacity(arg_ptr);
1409 } else {
1410 args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));
1411 }
14201412 },
14211413 }
14221414 }
1423 }
1415
1416 break :implicit_args .{ ret_ptr, err_ret_trace };
1417 };
14241418
14251419 const file, const subprogram = if (!wip.strip) debug_info: {
14261420 const file = try o.getDebugFile(file_scope);
......@@ -1432,7 +1426,7 @@ pub const Object = struct {
14321426 const subprogram = try o.builder.debugSubprogram(
14331427 file,
14341428 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)),
14361430 line_number,
14371431 line_number + func.lbrace_line,
14381432 debug_decl_type,
......@@ -1449,7 +1443,7 @@ pub const Object = struct {
14491443 },
14501444 o.debug_compile_unit.unwrap().?,
14511445 );
1452 function_index.setSubprogram(subprogram, &o.builder);
1446 llvm_function.setSubprogram(subprogram, &o.builder);
14531447 break :debug_info .{ file, subprogram };
14541448 } else .{undefined} ** 2;
14551449
......@@ -1466,7 +1460,7 @@ pub const Object = struct {
14661460 const anon_name = try o.builder.strtabStringFmt("__sancov_gen_.{d}", .{o.used.items.len});
14671461 const counters_variable = try o.builder.addVariable(anon_name, .void, .default);
14681462 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);
14701464 counters_variable.setAlignment(comptime Builder.Alignment.fromByteUnits(1), &o.builder);
14711465
14721466 if (target.ofmt == .macho) {
......@@ -1524,7 +1518,7 @@ pub const Object = struct {
15241518 _ = try attributes.removeFnAttr(.null_pointer_is_valid);
15251519 }
15261520
1527 function_index.setAttributes(try attributes.finish(&o.builder), &o.builder);
1521 llvm_function.setAttributes(try attributes.finish(&o.builder), &o.builder);
15281522
15291523 if (fg.fuzz) |*f| {
15301524 {
......@@ -1539,158 +1533,162 @@ pub const Object = struct {
15391533 // Due to error "members of llvm.compiler.used must be named", this global needs a name.
15401534 const anon_name = try o.builder.strtabStringFmt("__sancov_gen_.{d}", .{o.used.items.len});
15411535 const pcs_variable = try o.builder.addVariable(anon_name, array_llvm_ty, .default);
1542 try o.used.append(gpa, pcs_variable.toConst(&o.builder));
1543 pcs_variable.setLinkage(.private, &o.builder);
1536 try pcs_variable.setInitializer(init_val, &o.builder);
15441537 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);
15451542 pcs_variable.setAlignment(Type.usize.abiAlignment(zcu).toLlvm(), &o.builder);
1546 if (target.ofmt == .macho) {
1547 pcs_variable.setSection(try o.builder.string("__DATA,__sancov_pcs1"), &o.builder);
1548 } else {
1549 pcs_variable.setSection(try o.builder.string("__sancov_pcs1"), &o.builder);
1550 }
1551 try pcs_variable.setInitializer(init_val, &o.builder);
1543 const pcs_global = pcs_variable.ptrConst(&o.builder).global;
1544 pcs_global.setLinkage(.private, &o.builder);
1545 try o.used.append(gpa, pcs_global.toConst());
15521546 }
15531547
15541548 try fg.wip.finish();
15551549 try o.flushTypePool(pt);
15561550 }
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 {
15591553 const zcu = o.zcu;
15601554 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);
15631559 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)) {
1566 else => .{ .none, .internal, .default, false, resolved.value, nav_index },
1567 .@"extern" => |e| .{ e.lib_name, e.linkage, .fromSymbolVisibility(e.visibility), e.is_dll_import, .none, e.owner_nav },
1561 const opt_extern: ?InternPool.Key.Extern = switch (ip.indexToKey(resolved.value)) {
1562 .@"extern" => |@"extern"| @"extern",
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;
15681581 };
1569 const ty: Type = .fromInterned(nav.resolved.?.type);
15701582
1571 if (linkage != .internal and ip.isFunctionType(ty.toIntern())) {
1572 const function_index = try o.resolveLlvmFunction(owner_nav);
1573 // Add parameter attributes which weren't set by `resolveLlvmFunction`
1574 const fn_info = zcu.typeToFunc(ty).?;
1575 var attributes = try function_index.ptrConst(&o.builder).attributes.toWip(&o.builder);
1576 defer attributes.deinit(&o.builder);
1577 var it = iterateParamTypes(o, fn_info);
1578 if (firstParamSRet(fn_info, zcu, zcu.getTarget())) it.llvm_index += 1;
1579 if (fn_info.cc == .auto and zcu.comp.config.any_error_tracing) it.llvm_index += 1;
1580 while (try it.next()) |lowering| switch (lowering) {
1581 .byval => {
1582 const param_index = it.zig_index - 1;
1583 const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[param_index]);
1584 if (!isByRef(param_ty, zcu)) {
1585 try o.addByValParamAttrs(pt, &attributes, param_ty, param_index, fn_info, it.llvm_index - 1);
1583 const gop = try o.nav_map.getOrPut(gpa, nav_id);
1584 if (!gop.found_existing) {
1585 errdefer assert(o.nav_map.remove(nav_id));
1586 // First time lowering this NAV! Create a fresh global.
1587 const llvm_name = try o.builder.strtabString(nav.fqn.toSlice(ip));
1588 gop.value_ptr.* = try o.builder.addGlobal(llvm_name, .{
1589 .type = .void, // placeholder; populated below
1590 .kind = .{ .alias = .none }, // placeholder; populated below
1591 });
1592 }
1593 const llvm_global = gop.value_ptr.*;
1594
1595 llvm_global.ptr(&o.builder).type = llvm_ty;
1596 llvm_global.ptr(&o.builder).addr_space = toLlvmAddressSpace(resolved.@"addrspace", zcu.getTarget());
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 }
15861606 }
1587 },
1588 .byref => {
1589 const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
1590 const param_llvm_ty = try o.lowerType(param_ty);
1591 const alignment = param_ty.abiAlignment(zcu);
1592 try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment.toLlvm(), it.byval_attr, param_llvm_ty);
1593 },
1594 .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),
1595 // No attributes needed for these.
1596 .no_bits,
1597 .abi_sized_int,
1598 .multiple_llvm_types,
1599 .float_array,
1600 .i32_array,
1601 .i64_array,
1602 => continue,
1603
1604 .slice => unreachable, // extern functions do not support slice types.
1607 }
1608 break :name try o.builder.strtabString(name_slice);
1609 };
1610 if (o.builder.getGlobal(name)) |other_global| {
1611 if (other_global != llvm_global) {
1612 // Another global already has this name; just use it in place of this global.
1613 try llvm_global.replace(other_global, &o.builder);
1614 return;
1615 }
1616 }
1617 try llvm_global.rename(name, &o.builder);
1618 llvm_global.ptr(&o.builder).unnamed_addr = .default;
1619 llvm_global.ptr(&o.builder).dll_storage_class = switch (@"extern".is_dll_import) {
1620 true => .dllimport,
1621 false => .default,
1622 };
1623 llvm_global.ptr(&o.builder).linkage = switch (@"extern".linkage) {
1624 .internal => if (o.builder.strip) .private else .internal,
1625 .strong => .external,
1626 .weak => .extern_weak,
1627 .link_once => unreachable,
16051628 };
1606 function_index.setAttributes(try attributes.finish(&o.builder), &o.builder);
1629 llvm_global.ptr(&o.builder).visibility = .fromSymbolVisibility(@"extern".visibility);
16071630 } else {
1608 const variable_index = try o.resolveGlobalNav(nav_index);
1609 variable_index.setAlignment(zcu.navAlignment(nav_index).toLlvm(), &o.builder);
1610 if (resolved.@"linksection".toSlice(ip)) |section|
1611 variable_index.setSection(try o.builder.string(section), &o.builder);
1612 if (resolved.@"const") variable_index.setMutability(.constant, &o.builder);
1613 try variable_index.setInitializer(switch (init_val) {
1614 .none => .no_init,
1615 else => try o.lowerValue(init_val),
1616 }, &o.builder);
1617 variable_index.setVisibility(visibility, &o.builder);
1631 llvm_global.ptr(&o.builder).linkage = if (o.builder.strip) .private else .internal;
1632 llvm_global.ptr(&o.builder).visibility = .default;
1633 llvm_global.ptr(&o.builder).dll_storage_class = .default;
1634 llvm_global.ptr(&o.builder).unnamed_addr = .unnamed_addr;
1635 }
1636
1637 const llvm_align = switch (resolved.@"align") {
1638 .none => nav_ty.abiAlignment(zcu).toLlvm(),
1639 else => |a| a.toLlvm(),
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);
16201658 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
16261673 if (!mod.strip) {
16271674 const debug_file = try o.getDebugFile(file_scope);
1628
1629 const debug_global_var = try o.builder.debugGlobalVar(
1630 try o.builder.metadataString(nav.name.toSlice(ip)), // Name
1631 try o.builder.metadataStringFromStrtabString(variable_index.name(&o.builder)), // Linkage name
1632 debug_file, // File
1633 debug_file, // Scope
1634 line_number,
1635 try o.getDebugType(pt, ty),
1636 variable_index,
1637 .{ .local = linkage == .internal },
1638 );
1639
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,
1675 const debug_global_var_expr = try o.builder.debugGlobalVarExpression(
1676 try o.builder.debugGlobalVar(
1677 try o.builder.metadataString(nav.name.toSlice(ip)), // Name
1678 try o.builder.metadataString(nav.fqn.toSlice(ip)), // Linkage name
1679 debug_file, // File
1680 debug_file, // Scope
1681 zcu.navSrcLine(nav_id) + 1,
1682 try o.getDebugType(pt, nav_ty),
1683 llvm_variable,
1684 .{ .local = llvm_global.ptrConst(&o.builder).linkage == .internal },
1685 ),
1686 try o.builder.debugExpression(&.{}),
16451687 );
1646
1647 variable_index.setGlobalVariableExpression(debug_global_var_expression, &o.builder);
1648 try o.debug_globals.append(o.gpa, debug_global_var_expression);
1688 llvm_variable.setGlobalVariableExpression(debug_global_var_expr, &o.builder);
1689 try o.debug_globals.append(o.gpa, debug_global_var_expr);
16491690 }
16501691 }
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 }
16941692 }
16951693
16961694 fn flushTypePool(o: *Object, pt: Zcu.PerThread) Allocator.Error!void {
......@@ -1698,18 +1696,43 @@ pub const Object = struct {
16981696 }
16991697
17001698 pub fn updateExports(
1701 self: *Object,
1699 o: *Object,
17021700 exported: Zcu.Exported,
17031701 export_indices: []const Zcu.Export.Index,
17041702 ) link.File.UpdateExportsError!void {
1705 const zcu = self.zcu;
1706 const nav_index = switch (exported) {
1707 .nav => |nav| nav,
1708 .uav => |uav| return updateExportedValue(self, uav, export_indices),
1709 };
1703 const zcu = o.zcu;
17101704 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;
17121734 const comp = zcu.comp;
1735 const ip = &zcu.intern_pool;
17131736
17141737 // If we're on COFF and linking with LLD, the linker cares about our exports to determine the subsystem in use.
17151738 coff_export_flags: {
......@@ -1719,7 +1742,7 @@ pub const Object = struct {
17191742 .elf, .wasm => break :coff_export_flags,
17201743 .coff => |*coff| coff,
17211744 };
1722 if (!ip.isFunctionType(ip.getNav(nav_index).resolved.?.type)) break :coff_export_flags;
1745 if (ty.zigTypeTag(zcu) != .@"fn") break :coff_export_flags;
17231746 const flags = &coff.lld_export_flags;
17241747 for (export_indices) |export_index| {
17251748 const name = export_index.ptr(zcu).opts.name;
......@@ -1732,152 +1755,88 @@ pub const Object = struct {
17321755 }
17331756 }
17341757
1735 if (export_indices.len != 0) {
1736 return updateExportedGlobal(self, zcu, global_index, export_indices);
1737 } else {
1738 const fqn = try self.builder.strtabString(ip.getNav(nav_index).fqn.toSlice(ip));
1739 try global_index.rename(fqn, &self.builder);
1740 global_index.setLinkage(if (self.builder.strip) .private else .internal, &self.builder);
1741 if (comp.config.dll_export_fns)
1742 global_index.setDllStorageClass(.default, &self.builder);
1743 global_index.setUnnamedAddr(.unnamed_addr, &self.builder);
1758 // If the first export specifies a linksection, set the exported variable's section to that
1759 // one. This is kind of a hack because `std.builtin.ExportOptions.section` doesn't actually
1760 // make much sense: the linksection should be associated with the declaration itself rather
1761 // than some particular symbol it is exported as!
1762 if (export_indices[0].ptr(zcu).opts.section.toSlice(ip)) |section_slice| {
1763 const variable = &global_index.ptrConst(&o.builder).kind.variable;
1764 variable.setSection(try o.builder.string(section_slice), &o.builder);
17441765 }
1745 }
17461766
1747 fn updateExportedValue(
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 }
1767 const llvm_global_ty = global_index.typeOf(&o.builder);
17781768
1779 fn updateExportedGlobal(
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 }
1769 // All exports are represented as aliases to the original global.
18111770
1812 global_index.setUnnamedAddr(.default, &o.builder);
1813 if (comp.config.dll_export_fns and first_export.opts.visibility != .hidden)
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 };
1771 // TODO: we currently do not delete old exports. To do that we'll need to track which
1772 // globals actually *are* exports.
18361773
1837 // If a Decl is exported more than one time (which is rare),
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| {
1774 for (export_indices) |export_idx| {
18441775 const exp = export_idx.ptr(zcu);
18451776 const exp_name = try o.builder.strtabString(exp.opts.name.toSlice(ip));
1846 if (o.builder.getGlobal(exp_name)) |global| {
1847 switch (global.ptrConst(&o.builder).kind) {
1777
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) {
18481798 .alias => |alias| {
1799 // We can just repurpose the existing alias.
18491800 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;
18511803 },
18521804 .variable, .function => {
1853 // This existing global is an `extern` corresponding to this export.
1854 // Replace it with the global being exported.
1855 // This existing global must be replaced with the alias.
1856 try global.rename(.empty, &o.builder);
1857 try global.replace(global_index, &o.builder);
1805 // This must be an extern, which is no good to us---we need an alias. The
1806 // extern should refer to the value we're exporting, so replace it with the
1807 // exported value. That will free up the name for us to create a new alias.
1808 // We need to make a new global which is an alias. Replace this existing one
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;
18581820 },
1859 .replaced => unreachable,
1821 .replaced => unreachable, // a replaced global would have lost the name `exp_name`
18601822 }
1861 }
1862 const alias_index = try o.builder.addAlias(
1863 .empty,
1864 global_index.typeOf(&o.builder),
1865 .default,
1866 global_index.toConst(),
1867 );
1868 try alias_index.rename(exp_name, &o.builder);
1869
1870 const alias_global_index = alias_index.ptrConst(&o.builder).global;
1871 alias_global_index.setUnnamedAddr(.default, &o.builder);
1872 if (comp.config.dll_export_fns and first_export.opts.visibility != .hidden)
1873 alias_global_index.setDllStorageClass(.dllexport, &o.builder);
1874 alias_global_index.setLinkage(switch (first_export.opts.linkage) {
1875 .internal => unreachable,
1823 };
1824
1825 // Now for a bit of setup which
1826
1827 // We need the alias to *not* be `unnamed_addr` to ensure that the alias address equals
1828 // the address of the original global.
1829 alias_global.setUnnamedAddr(.default, &o.builder);
1830
1831 if (comp.config.dll_export_fns and exp.opts.visibility != .hidden)
1832 alias_global.setDllStorageClass(.dllexport, &o.builder);
1833 alias_global.setLinkage(switch (exp.opts.linkage) {
1834 .internal => if (o.builder.strip) .private else .internal, // we still did useful work in replacing an existing symbol if there was one
18761835 .strong => .external,
18771836 .weak => .weak_odr,
18781837 .link_once => .linkonce_odr,
18791838 }, &o.builder);
1880 alias_global_index.setVisibility(switch (first_export.opts.visibility) {
1839 alias_global.setVisibility(switch (exp.opts.visibility) {
18811840 .default => .default,
18821841 .hidden => .hidden,
18831842 .protected => .protected,
......@@ -1940,7 +1899,12 @@ pub const Object = struct {
19401899 assert(val != .anyerror_type);
19411900 const fwd_ref = o.debug_types.items[@intFromEnum(index)];
19421901 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 };
19441908 o.builder.resolveDebugForwardReference(fwd_ref, debug_incomplete_type);
19451909 }
19461910 }
......@@ -2269,7 +2233,9 @@ pub const Object = struct {
22692233 },
22702234 .@"fn" => {
22712235 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);
22732239 }
22742240
22752241 const fn_info = zcu.typeToFunc(ty).?;
......@@ -2716,75 +2682,38 @@ pub const Object = struct {
27162682 return o.getDebugType(pt, .fromInterned(namespace.owner_type));
27172683 }
27182684
2719 /// If the llvm function does not exist, create it.
2720 /// Note that this can be called before the function's semantic analysis has
2721 /// completed, so if any attributes rely on that, they must be done in updateFunc, not here.
2722 pub fn resolveLlvmFunction(
2685 /// Sets the attributes and callconv of the given `Builder.Function`, which corresponds to the
2686 /// given `Nav` (which is a function).
2687 fn addLlvmFunctionAttributes(
27232688 o: *Object,
2724 nav_index: InternPool.Nav.Index,
2725 ) Allocator.Error!Builder.Function.Index {
2689 pt: Zcu.PerThread,
2690 nav_id: InternPool.Nav.Index,
2691 function_index: Builder.Function.Index,
2692 ) Allocator.Error!void {
27262693 const zcu = o.zcu;
27272694 const ip = &zcu.intern_pool;
2728 const gpa = o.gpa;
2729 const nav = ip.getNav(nav_index);
2730 const owner_mod = zcu.navFileScope(nav_index).mod.?;
2695 const nav = ip.getNav(nav_id);
2696 const owner_mod = zcu.navFileScope(nav_id).mod.?;
27312697 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
27352699 const fn_info = zcu.typeToFunc(ty).?;
27362700 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
27492702 var attributes: Builder.FunctionAttributes.Wip = .{};
27502703 defer attributes.deinit(&o.builder);
27512704
2752 if (!is_extern) {
2753 function_index.setLinkage(if (o.builder.strip) .private else .internal, &o.builder);
2754 function_index.setUnnamedAddr(.unnamed_addr, &o.builder);
2755 } else {
2756 if (target.cpu.arch.isWasm()) {
2757 try attributes.addFnAttr(.{ .string = .{
2758 .kind = try o.builder.string("wasm-import-name"),
2759 .value = try o.builder.string(nav.name.toSlice(ip)),
2705 if (target.cpu.arch.isWasm()) if (nav.getExtern(ip)) |@"extern"| {
2706 try attributes.addFnAttr(.{ .string = .{
2707 .kind = try o.builder.string("wasm-import-name"),
2708 .value = try o.builder.string(nav.name.toSlice(ip)),
2709 } }, &o.builder);
2710 if (@"extern".lib_name.toSlice(ip)) |lib_name_slice| {
2711 if (!std.mem.eql(u8, lib_name_slice, "c")) try attributes.addFnAttr(.{ .string = .{
2712 .kind = try o.builder.string("wasm-import-module"),
2713 .value = try o.builder.string(lib_name_slice),
27602714 } }, &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 }
27672715 }
2768 }
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 }
2716 };
27882717
27892718 if (fn_info.cc == .async) {
27902719 @panic("TODO: LLVM backend lower async function");
......@@ -2859,9 +2788,6 @@ pub const Object = struct {
28592788 }
28602789 }
28612790
2862 if (nav.resolved.?.@"align" != .none)
2863 function_index.setAlignment(nav.resolved.?.@"align".toLlvm(), &o.builder);
2864
28652791 // Function attributes that are independent of analysis results of the function body.
28662792 try o.addCommonFnAttributes(
28672793 &attributes,
......@@ -2877,8 +2803,71 @@ pub const Object = struct {
28772803
28782804 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
28802870 function_index.setAttributes(try attributes.finish(&o.builder), &o.builder);
2881 return function_index;
28822871 }
28832872
28842873 fn addCommonFnAttributes(
......@@ -2951,97 +2940,6 @@ pub const Object = struct {
29512940 }
29522941 }
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
30452943 pub fn errorIntType(o: *Object) Allocator.Error!Builder.Type {
30462944 return o.builder.intType(o.zcu.errorSetBits());
30472945 }
......@@ -3051,7 +2949,7 @@ pub const Object = struct {
30512949 const target = zcu.getTarget();
30522950 const ip = &zcu.intern_pool;
30532951 return switch (t.toIntern()) {
3054 .u0_type, .i0_type => unreachable,
2952 .u0_type, .i0_type => unreachable, // no runtime bits
30552953 inline .u1_type,
30562954 .u8_type,
30572955 .i8_type,
......@@ -3100,18 +2998,18 @@ pub const Object = struct {
31002998 return .i8;
31012999 },
31023000 .bool_type => .i1,
3103 .void_type => .void,
3104 .type_type => unreachable,
31053001 .anyerror_type => try o.errorIntType(),
3106 .comptime_int_type,
3107 .comptime_float_type,
3108 .noreturn_type,
3109 => unreachable,
3002 .void_type => unreachable, // no runtime bits
3003 .type_type => unreachable, // no runtime bits
3004 .comptime_int_type => unreachable, // no runtime bits
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
31103012 .anyframe_type => @panic("TODO implement lowerType for AnyFrame types"),
3111 .null_type,
3112 .undefined_type,
3113 .enum_literal_type,
3114 => unreachable,
31153013 .ptr_usize_type,
31163014 .ptr_const_comptime_int_type,
31173015 .manyptr_u8_type,
......@@ -3121,13 +3019,10 @@ pub const Object = struct {
31213019 .slice_const_u8_type,
31223020 .slice_const_u8_sentinel_0_type,
31233021 => try o.builder.structType(.normal, &.{ .ptr, try o.lowerType(.usize) }),
3124 .optional_noreturn_type => unreachable,
31253022 .anyerror_void_error_union_type,
31263023 .adhoc_inferred_error_set_type,
31273024 => try o.errorIntType(),
3128 .generic_poison_type,
3129 .empty_tuple_type,
3130 => unreachable,
3025 .generic_poison_type => unreachable,
31313026 // values, not types
31323027 .undef,
31333028 .undef_bool,
......@@ -3176,7 +3071,11 @@ pub const Object = struct {
31763071 ),
31773072 .opt_type => |child_ty| {
31783073 // 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
31813080 const payload_ty = try o.lowerType(.fromInterned(child_ty));
31823081 if (t.optionalReprIsPayload(zcu)) return payload_ty;
......@@ -3198,8 +3097,13 @@ pub const Object = struct {
31983097 // Must stay in sync with `codegen.errUnionPayloadOffset`.
31993098 // See logic in `lowerPtr`.
32003099 const error_type = try o.errorIntType();
3201 if (!Type.fromInterned(error_union_type.payload_type).hasRuntimeBits(zcu))
3202 return error_type;
3100
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
32033107 const payload_type = try o.lowerType(.fromInterned(error_union_type.payload_type));
32043108
32053109 const payload_align = Type.fromInterned(error_union_type.payload_type).abiAlignment(zcu);
......@@ -3245,6 +3149,8 @@ pub const Object = struct {
32453149 return int_ty;
32463150 }
32473151
3152 assert(struct_type.size > 0);
3153
32483154 var llvm_field_types: std.ArrayList(Builder.Type) = .empty;
32493155 defer llvm_field_types.deinit(o.gpa);
32503156 // Although we can estimate how much capacity to add, these cannot be
......@@ -3311,7 +3217,7 @@ pub const Object = struct {
33113217
33123218 comptime assert(struct_layout_version == 2);
33133219 var offset: u64 = 0;
3314 var big_align: InternPool.Alignment = .none;
3220 var big_align: InternPool.Alignment = .@"1";
33153221
33163222 for (
33173223 tuple_type.types.get(ip),
......@@ -3345,6 +3251,7 @@ pub const Object = struct {
33453251 try o.builder.arrayType(padding_len, .i8),
33463252 );
33473253 }
3254 assert(offset > 0);
33483255 return o.builder.structType(.normal, llvm_field_types.items);
33493256 },
33503257 .union_type => {
......@@ -3358,6 +3265,8 @@ pub const Object = struct {
33583265 return int_ty;
33593266 }
33603267
3268 assert(union_obj.size > 0);
3269
33613270 const layout = Type.getUnionLayout(union_obj, zcu);
33623271
33633272 if (layout.payload_size == 0) {
......@@ -3421,15 +3330,9 @@ pub const Object = struct {
34213330 );
34223331 return ty;
34233332 },
3424 .opaque_type => {
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 },
3333 .opaque_type => unreachable, // no runtime bits
34313334 .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),
34333336 .error_set_type, .inferred_error_set_type => try o.errorIntType(),
34343337 // values, not types
34353338 .undef,
......@@ -3455,10 +3358,13 @@ pub const Object = struct {
34553358 };
34563359 }
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 {
34593362 const zcu = o.zcu;
34603363 const ip = &zcu.intern_pool;
34613364 const target = zcu.getTarget();
3365
3366 assert(fn_ty.fnHasRuntimeBits(zcu));
3367
34623368 const ret_ty = try lowerFnRetTy(o, fn_info);
34633369
34643370 var llvm_params: std.ArrayList(Builder.Type) = .empty;
......@@ -3526,15 +3432,12 @@ pub const Object = struct {
35263432 const ip = &zcu.intern_pool;
35273433 const target = zcu.getTarget();
35283434
3529 const val = Value.fromInterned(arg_val);
3435 const val: Value = .fromInterned(arg_val);
35303436 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
35363438 const ty: Type = .fromInterned(val_key.typeOf());
35373439 ty.assertHasLayout(zcu);
3440 assert(ty.hasRuntimeBits(zcu));
35383441
35393442 return switch (val_key) {
35403443 .int_type,
......@@ -3555,7 +3458,7 @@ pub const Object = struct {
35553458 .inferred_error_set_type,
35563459 => unreachable, // types, not values
35573460
3558 .undef => unreachable, // handled above
3461 .undef => return o.builder.undefConst(try o.lowerType(ty)),
35593462 .simple_value => |simple_value| switch (simple_value) {
35603463 .void => unreachable, // non-runtime value
35613464 .null => unreachable, // non-runtime value
......@@ -3565,14 +3468,8 @@ pub const Object = struct {
35653468 .true => .true,
35663469 },
35673470 .enum_literal => unreachable, // non-runtime value
3568 .@"extern" => |@"extern"| {
3569 const function_index = try o.resolveLlvmFunction(@"extern".owner_nav);
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 },
3471 .@"extern" => unreachable, // non-runtime value
3472 .func => unreachable, // non-runtime value
35763473 .int => {
35773474 var bigint_space: Value.BigIntSpace = undefined;
35783475 const bigint = val.toBigInt(&bigint_space, zcu);
......@@ -3815,7 +3712,7 @@ pub const Object = struct {
38153712 comptime assert(struct_layout_version == 2);
38163713 var llvm_index: usize = 0;
38173714 var offset: u64 = 0;
3818 var big_align: InternPool.Alignment = .none;
3715 var big_align: InternPool.Alignment = .@"1";
38193716 var need_unnamed = false;
38203717 for (
38213718 tuple.types.get(ip),
......@@ -4033,7 +3930,7 @@ pub const Object = struct {
40333930 const offset: u64 = prev_offset + ptr.byte_offset;
40343931 return switch (ptr.base_addr) {
40353932 .nav => |nav| {
4036 const base_ptr = try o.lowerNavRefValue(nav);
3933 const base_ptr = try o.lowerNavRef(nav);
40373934 return o.builder.gepConst(.inbounds, .i8, base_ptr, null, &.{
40383935 try o.builder.intConst(.i64, offset),
40393936 });
......@@ -4092,8 +3989,19 @@ pub const Object = struct {
40923989 };
40933990 }
40943991
4095 /// This logic is very similar to `lowerNavRefValue` but for anonymous declarations.
4096 /// Maybe the logic could be unified.
3992 pub fn lowerPtrToVoid(
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
40974005 pub fn lowerUavRef(
40984006 o: *Object,
40994007 uav_val: InternPool.Index,
......@@ -4105,6 +4013,8 @@ pub const Object = struct {
41054013
41064014 const zcu = o.zcu;
41074015 const ip = &zcu.intern_pool;
4016 const gpa = zcu.comp.gpa;
4017
41084018 const uav_ty: Type = .fromInterned(ip.typeOf(uav_val));
41094019
41104020 switch (ip.indexToKey(uav_val)) {
......@@ -4118,63 +4028,63 @@ pub const Object = struct {
41184028 }
41194029
41204030 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(
4124 llvm_global.toConst(),
4125 try o.builder.ptrType(llvm_addrspace),
4126 );
4032 const gop = try o.uav_map.getOrPut(gpa, .{ .val = uav_val, .@"addrspace" = @"addrspace" });
4033 if (gop.found_existing) {
4034 // Keep the greater of the two alignments.
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();
41274053 }
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 {
41304056 const zcu = o.zcu;
41314057 const ip = &zcu.intern_pool;
4058 const gpa = zcu.comp.gpa;
41324059
4133 const nav = ip.getNav(nav_index);
4134
4060 const nav = ip.getNav(nav_id);
41354061 const nav_ty: Type = .fromInterned(nav.resolved.?.type);
4136
4137 if (nav.getExtern(ip) == null and !nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) {
4138 return o.lowerPtrToVoid(nav.resolved.?.@"align", nav.resolved.?.@"addrspace");
4062 if (!nav_ty.isRuntimeFnOrHasRuntimeBits(zcu) and nav.getExtern(ip) == null) {
4063 const nav_align = switch (nav.resolved.?.@"align") {
4064 .none => nav_ty.abiAlignment(zcu),
4065 else => |a| a,
4066 };
4067 return o.lowerPtrToVoid(nav_align, nav.resolved.?.@"addrspace");
41394068 }
41404069
4141 const llvm_global = if (nav_ty.zigTypeTag(zcu) == .@"fn")
4142 (try o.resolveLlvmFunction(nav_index)).ptrConst(&o.builder).global
4143 else
4144 (try o.resolveGlobalNav(nav_index)).ptrConst(&o.builder).global;
4070 const gop = try o.nav_map.getOrPut(gpa, nav_id);
4071 if (!gop.found_existing) {
4072 errdefer assert(o.nav_map.remove(nav_id));
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(
4147 llvm_global.toConst(),
4148 try o.builder.ptrType(toLlvmAddressSpace(nav.resolved.?.@"addrspace", zcu.getTarget())),
4149 );
4150 }
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);
4083 // We need to make sure the global's address space is up to date, because that affects the
4084 // type of a pointer to this global. But everything else about the global will be populated
4085 // by `updateNav` or `updateFunc`.
4086 llvm_global.ptr(&o.builder).addr_space = toLlvmAddressSpace(nav.resolved.?.@"addrspace", zcu.getTarget());
4087 return llvm_global.toConst();
41784088 }
41794089
41804090 pub fn addByValParamAttrs(
......@@ -4243,13 +4153,14 @@ pub const Object = struct {
42434153 const name = try o.builder.strtabString("__zig_error_name_table");
42444154 // TODO: Address space
42454155 const variable_index = try o.builder.addVariable(name, .ptr, .default);
4246 variable_index.setLinkage(.private, &o.builder);
42474156 variable_index.setMutability(.constant, &o.builder);
4248 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
42494157 variable_index.setAlignment(
42504158 Type.slice_const_u8_sentinel_0.abiAlignment(o.zcu).toLlvm(),
42514159 &o.builder,
42524160 );
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
42544165 o.error_name_table = variable_index;
42554166 return variable_index;
......@@ -4261,10 +4172,11 @@ pub const Object = struct {
42614172 const llvm_err_int_ty = try o.errorIntType();
42624173 const name = try builder.strtabString("__zig_errors_len");
42634174 const variable_index = try builder.addVariable(name, llvm_err_int_ty, .default);
4264 variable_index.setLinkage(.private, builder);
42654175 variable_index.setMutability(.constant, builder);
4266 variable_index.setUnnamedAddr(.unnamed_addr, builder);
42674176 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);
42684180 o.errors_len_variable = variable_index;
42694181 }
42704182 return o.errors_len_variable;
......@@ -4332,16 +4244,16 @@ pub const Object = struct {
43324244 for (0..loaded_enum.field_names.len) |field_index| {
43334245 const name = try o.builder.stringNull(loaded_enum.field_names.get(ip)[field_index].toSlice(ip));
43344246 const name_init = try o.builder.stringConst(name);
4335 const name_variable_index =
4336 try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default);
4247 const name_variable_index = try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default);
43374248 try name_variable_index.setInitializer(name_init, &o.builder);
4338 name_variable_index.setLinkage(.private, &o.builder);
43394249 name_variable_index.setMutability(.constant, &o.builder);
4340 name_variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
43414250 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
43434255 const name_val = try o.builder.structValue(llvm_ret_ty, &.{
4344 name_variable_index.toConst(&o.builder),
4256 name_global_index.toConst(),
43454257 try o.builder.intConst(llvm_usize_ty, name.slice(&o.builder).?.len - 1),
43464258 });
43474259
src/codegen/llvm/FuncGen.zig+35-25
......@@ -581,8 +581,17 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
581581 else => unreachable,
582582 };
583583 const fn_info = zcu.typeToFunc(zig_fn_ty).?;
584 const return_type = Type.fromInterned(fn_info.return_type);
585 const llvm_fn = try self.resolveInst(air_call.callee);
584 const return_type: Type = .fromInterned(fn_info.return_type);
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 };
586595 const target = zcu.getTarget();
587596 const sret = firstParamSRet(fn_info, zcu, target);
588597
......@@ -875,7 +884,9 @@ fn buildSimplePanic(fg: *FuncGen, panic_id: Zcu.SimplePanicId) Allocator.Error!v
875884 const target = zcu.getTarget();
876885 const panic_func = zcu.funcInfo(zcu.builtin_decl_values.get(panic_id.toBuiltin()));
877886 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
880891 const has_err_trace = zcu.comp.config.any_error_tracing and fn_info.cc == .auto;
881892 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
884895 .normal,
885896 llvm.toLlvmCallConvTag(fn_info.cc, target).?,
886897 .none,
887 panic_global.typeOf(&o.builder),
888 panic_global.toValue(&o.builder),
898 llvm_panic_fn_ty,
899 llvm_panic_fn_ref.toValue(),
889900 if (has_err_trace) &.{fg.err_ret_trace} else &.{},
890901 "",
891902 );
......@@ -1745,8 +1756,9 @@ fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Tod
17451756 .default,
17461757 );
17471758 try table_variable.setInitializer(table_val, &o.builder);
1748 table_variable.setLinkage(if (o.builder.strip) .private else .internal, &o.builder);
1749 table_variable.setUnnamedAddr(.unnamed_addr, &o.builder);
1759 const table_global = table_variable.ptrConst(&o.builder).global;
1760 table_global.setLinkage(if (o.builder.strip) .private else .internal, &o.builder);
1761 table_global.setUnnamedAddr(.unnamed_addr, &o.builder);
17501762
17511763 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
17591771 .likely => .likely,
17601772 .unlikely => .unlikely,
17611773 },
1762 .table = table_variable.toConst(&o.builder),
1774 .table = table_global.toConst(),
17631775 .table_includes_else = table_includes_else,
17641776 };
17651777 };
......@@ -3255,8 +3267,8 @@ fn airWasmMemoryGrow(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Build
32553267fn airRuntimeNavPtr(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {
32563268 const o = fg.object;
32573269 const ty_nav = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
3258 const llvm_ptr_const = try o.lowerNavRefValue(ty_nav.nav);
3259 return llvm_ptr_const.toValue();
3270 const llvm_ptr = try o.lowerNavRef(ty_nav.nav);
3271 return llvm_ptr.toValue();
32603272}
32613273
32623274fn 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
46364648 const o = self.object;
46374649 const zcu = o.zcu;
46384650 const ptr_ty = self.typeOfIndex(inst);
4639 const pointee_type = ptr_ty.childType(zcu);
4640 if (!pointee_type.hasRuntimeBits(zcu)) {
4641 const ptr_info = ptr_ty.ptrInfo(zcu);
4642 return (try o.lowerPtrToVoid(ptr_info.flags.alignment, ptr_info.flags.address_space)).toValue();
4651 const ptr_align = ptr_ty.ptrAlignment(zcu);
4652 const elem_ty = ptr_ty.childType(zcu);
4653 if (!elem_ty.hasRuntimeBits(zcu)) {
4654 return (try o.lowerPtrToVoid(ptr_align, ptr_ty.ptrAddressSpace(zcu))).toValue();
46434655 }
4644 const pointee_llvm_ty = try o.lowerType(pointee_type);
4645 const alignment = ptr_ty.ptrAlignment(zcu).toLlvm();
4646 return self.buildAlloca(pointee_llvm_ty, alignment);
4656 const llvm_elem_ty = try o.lowerType(elem_ty);
4657 return self.buildAlloca(llvm_elem_ty, ptr_align.toLlvm());
46474658}
46484659
46494660fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {
4661 if (self.ret_ptr != .none) return self.ret_ptr;
46504662 const o = self.object;
46514663 const zcu = o.zcu;
46524664 const ptr_ty = self.typeOfIndex(inst);
4653 const ret_ty = ptr_ty.childType(zcu);
4654 if (!ret_ty.hasRuntimeBits(zcu)) {
4655 const ptr_info = ptr_ty.ptrInfo(zcu);
4656 return (try o.lowerPtrToVoid(ptr_info.flags.alignment, ptr_info.flags.address_space)).toValue();
4665 const ptr_align = ptr_ty.ptrAlignment(zcu);
4666 const elem_ty = ptr_ty.childType(zcu);
4667 if (!elem_ty.hasRuntimeBits(zcu)) {
4668 return (try o.lowerPtrToVoid(ptr_align, ptr_ty.ptrAddressSpace(zcu))).toValue();
46574669 }
4658 if (self.ret_ptr != .none) return self.ret_ptr;
4659 const ret_llvm_ty = try o.lowerType(ret_ty);
4660 const alignment = ptr_ty.ptrAlignment(zcu).toLlvm();
4661 return self.buildAlloca(ret_llvm_ty, alignment);
4670 const llvm_elem_ty = try o.lowerType(elem_ty);
4671 return self.buildAlloca(llvm_elem_ty, ptr_align.toLlvm());
46624672}
46634673
46644674/// Use this instead of builder.buildAlloca, because this function makes sure to