1const std = @import("std");
2const Io = std.Io;
3const assert = std.debug.assert;
4const Allocator = std.mem.Allocator;
5const DW = std.dwarf;
6const Builder = std.zig.llvm.Builder;
7const builtin = @import("builtin");
8const build_options = @import("build_options");
9
10const Air = @import("../Air.zig");
11const codegen = @import("../codegen.zig");
12const Compilation = @import("../Compilation.zig");
13const InternPool = @import("../InternPool.zig");
14const link = @import("../link.zig");
15const Module = @import("../Module.zig");
16const target_util = @import("../target.zig");
17const Type = @import("../Type.zig");
18const Value = @import("../Value.zig");
19const Zcu = @import("../Zcu.zig");
20const aarch64_c_abi = @import("aarch64/abi.zig");
21const FuncGen = @import("llvm/FuncGen.zig");
22const isByRef = FuncGen.isByRef;
23const fnReturnStrat = FuncGen.fnReturnStrat;
24const iterateParamTypes = FuncGen.iterateParamTypes;
25const ccAbiPromoteInt = FuncGen.ccAbiPromoteInt;
26
27const log = std.log.scoped(.codegen);
28const bindings = if (build_options.have_llvm)
29 @import("llvm/bindings.zig")
30else
31 @compileError("LLVM unavailable");
32
33pub fn legalizeFeatures(target: *const std.Target) ?*const Air.Legalize.Features {
34 return switch (target.cpu.arch.endian()) {
35 inline else => |endian| comptime &.init(.{
36 .expand_int_from_float_safe = true,
37 .expand_int_from_float_optimized_safe = true,
38
39 .scalarize_bit_cast_array = true,
40 // LLVM's `bitcast` on vectors places element 0 in the least significant bits on
41 // little-endian targets, which matches our semantics; but it does the opposite on
42 // big-endian targets, so in that case we need to scalarize.
43 .scalarize_bit_cast_vector_non_elementwise = endian != .little,
44 }),
45 };
46}
47
48pub fn supportsTailCall(target: *const std.Target) bool {
49 return switch (target.cpu.arch) {
50 .wasm32, .wasm64 => target.cpu.has(.wasm, .tail_call),
51 // Although these ISAs support tail calls, LLVM does not support tail calls on them.
52 .mips, .mipsel, .mips64, .mips64el => false,
53 .powerpc, .powerpcle, .powerpc64, .powerpc64le => false,
54 else => true,
55 };
56}
57
58// Avoid depending on `bindings.CodeModel` in the bitcode-only case.
59const CodeModel = enum {
60 default,
61 tiny,
62 small,
63 kernel,
64 medium,
65 large,
66};
67
68fn codeModel(model: std.lang.CodeModel, target: *const std.Target) CodeModel {
69 // Roughly match Clang's mapping of GCC code models to LLVM code models.
70 return switch (model) {
71 .default => .default,
72 .extreme, .large => .large,
73 .kernel => .kernel,
74 .medany => if (target.cpu.arch.isRISCV()) .medium else .large,
75 .medium => .medium,
76 .medmid => .medium,
77 .normal, .medlow, .small => .small,
78 .tiny => .tiny,
79 };
80}
81
82pub const Object = struct {
83 gpa: Allocator,
84 builder: Builder,
85
86 /// The basename of the object file which will emitted by LLVM for the ZCU. Once it it emitted,
87 /// this object file is passed to the active linker implementation as an ordinary link input.
88 ///
89 /// For the full path, use `Compilation.resolveEmitPath` with `kind == .temp`.
90 out_bin_basename: []const u8,
91
92 /// This pool contains only types (and not `@as(type, undefined)`). It has two purposes:
93 ///
94 /// * Lazily tracking ABI alignment of types, so that `@"align"` attributes can be set to a
95 /// type's ABI alignment before that type is fully resolved. Each type in the pool has a
96 /// corresponding entry in `lazy_abi_aligns`.
97 ///
98 /// * If `!Object.builder.strip`, lazily tracking debug information types, so that debug
99 /// information can handle indirect self-reference (and so that debug information works
100 /// correctly across incremental updates). Each type has a corresponding entry in
101 /// `debug_types`, provided that `Object.builder.strip` is `false`.
102 type_pool: link.ConstPool,
103
104 /// Keyed on `link.ConstPool.Index`.
105 lazy_abi_aligns: std.ArrayList(Builder.Alignment.Lazy),
106
107 debug_compile_unit: Builder.Metadata.Optional,
108
109 debug_enums_fwd_ref: Builder.Metadata.Optional,
110 debug_globals_fwd_ref: Builder.Metadata.Optional,
111
112 debug_enums: std.ArrayList(Builder.Metadata),
113 debug_globals: std.ArrayList(Builder.Metadata),
114
115 debug_file_map: std.AutoHashMapUnmanaged(Zcu.File.Index, Builder.Metadata),
116
117 /// Keyed on `link.ConstPool.Index`.
118 debug_types: std.ArrayList(Builder.Metadata),
119 /// Initially `.none`, set if the type `anyerror` is lowered to a debug type. The type will not
120 /// actually be created until `emit`, which must resolve this reference with an appropriate enum
121 /// type from the global error set.
122 debug_anyerror_fwd_ref: Builder.Metadata.Optional,
123
124 zcu: *Zcu,
125 /// Maps a `Nav` to the corresponding LLVM global.
126 nav_map: std.AutoHashMapUnmanaged(InternPool.Nav.Index, Builder.Global.Index),
127 /// Same as `nav_map` but for UAVs (which are always global constants).
128 uav_map: std.AutoHashMapUnmanaged(struct {
129 val: InternPool.Index,
130 @"addrspace": std.lang.AddressSpace,
131 }, Builder.Variable.Index),
132 /// Same as `uav_map` but for llvm values not originating from the frontend.
133 const_map: std.AutoHashMapUnmanaged(Builder.Constant, Builder.Variable.Index),
134 /// Maps enum types to their corresponding LLVM functions for implementing the `tag_name` instruction.
135 enum_tag_name_map: std.AutoHashMapUnmanaged(InternPool.Index, Builder.Function.Index),
136 /// Serves the same purpose as `enum_tag_name_map` but for the `is_named_enum_value` instruction.
137 named_enum_map: std.AutoHashMapUnmanaged(InternPool.Index, Builder.Function.Index),
138 /// Maps Zig types to LLVM types. The table memory is backed by the GPA of
139 /// the compiler.
140 /// TODO when InternPool garbage collection is implemented, this map needs
141 /// to be garbage collected as well.
142 type_map: TypeMap,
143 /// The LLVM global table which holds the names corresponding to Zig errors.
144 /// Note that the values are not added until `emit`, when all errors in
145 /// the compilation are known.
146 error_name_table: Builder.Variable.Index,
147 /// Constant variable whose value is the number of errors in the Zcu.
148 ///
149 /// Initially `.none`---populated lazily by `getErrorsLen`.
150 ///
151 /// If this is not `.none`, the variable's initializer is set in `emit`.
152 errors_len_variable: Builder.Variable.Index,
153
154 /// Values for `@llvm.used`.
155 used: std.ArrayList(Builder.Constant),
156
157 pub const Ptr = if (@import("../dev.zig").env.supports(.llvm_backend)) *Object else noreturn;
158
159 const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, Builder.Type);
160
161 pub fn create(arena: Allocator, zcu: *Zcu) !Ptr {
162 const comp = zcu.comp;
163 const gpa = comp.gpa;
164 const target = zcu.getTarget();
165
166 var builder = try Builder.init(.{
167 .allocator = gpa,
168 .strip = comp.config.debug_format == .strip,
169 .name = comp.root_name,
170 .target = target,
171 });
172 errdefer builder.deinit();
173
174 const debug_compile_unit, const debug_enums_fwd_ref, const debug_globals_fwd_ref =
175 if (!builder.strip) debug_info: {
176 // We fully resolve all paths at this point to avoid lack of
177 // source line info in stack traces or lack of debugging
178 // information which, if relative paths were used, would be
179 // very location dependent.
180 // TODO: the only concern I have with this is WASI as either host or target, should
181 // we leave the paths as relative then?
182 // TODO: This is totally wrong. In dwarf, paths are encoded as relative to
183 // a particular directory, and then the directory path is specified elsewhere.
184 // In the compiler frontend we have it stored correctly in this
185 // way already, but here we throw all that sweet information
186 // into the garbage can by converting into absolute paths. What
187 // a terrible tragedy.
188 const compile_unit_dir = try zcu.main_mod.root.toAbsolute(&comp.dirs, arena);
189
190 const debug_file = try builder.debugFile(
191 try builder.metadataString(comp.root_name),
192 try builder.metadataString(compile_unit_dir),
193 );
194
195 const debug_enums_fwd_ref = try builder.debugForwardReference();
196 const debug_globals_fwd_ref = try builder.debugForwardReference();
197
198 const debug_compile_unit = try builder.debugCompileUnit(
199 debug_file,
200 // Don't use the version string here; LLVM misparses it when it
201 // includes the git revision.
202 try builder.metadataStringFmt("zig {d}.{d}.{d}", .{
203 build_options.semver.major,
204 build_options.semver.minor,
205 build_options.semver.patch,
206 }),
207 debug_enums_fwd_ref,
208 debug_globals_fwd_ref,
209 .{ .optimized = comp.root_mod.optimize_mode != .debug },
210 );
211
212 try builder.addNamedMetadata(try builder.string("llvm.dbg.cu"), &.{debug_compile_unit});
213 break :debug_info .{
214 debug_compile_unit.toOptional(),
215 debug_enums_fwd_ref.toOptional(),
216 debug_globals_fwd_ref.toOptional(),
217 };
218 } else .{
219 Builder.Metadata.Optional.none,
220 Builder.Metadata.Optional.none,
221 Builder.Metadata.Optional.none,
222 };
223
224 const obj = try arena.create(Object);
225 obj.* = .{
226 .gpa = gpa,
227 .builder = builder,
228 .out_bin_basename = try std.zig.binNameAlloc(arena, .{
229 .root_name = try std.fmt.allocPrint(arena, "{s}_zcu", .{comp.root_name}),
230 .cpu_arch = target.cpu.arch,
231 .os_tag = target.os.tag,
232 .ofmt = target.ofmt,
233 .abi = target.abi,
234 .output_mode = .Obj,
235 }),
236 .type_pool = .empty,
237 .lazy_abi_aligns = .empty,
238 .debug_compile_unit = debug_compile_unit,
239 .debug_enums_fwd_ref = debug_enums_fwd_ref,
240 .debug_globals_fwd_ref = debug_globals_fwd_ref,
241 .debug_enums = .empty,
242 .debug_globals = .empty,
243 .debug_file_map = .empty,
244 .debug_types = .empty,
245 .debug_anyerror_fwd_ref = .none,
246 .zcu = zcu,
247 .nav_map = .empty,
248 .uav_map = .empty,
249 .const_map = .empty,
250 .enum_tag_name_map = .empty,
251 .named_enum_map = .empty,
252 .type_map = .empty,
253 .error_name_table = .none,
254 .errors_len_variable = .none,
255 .used = .empty,
256 };
257 return obj;
258 }
259
260 pub fn deinit(o: *Object) void {
261 const gpa = o.gpa;
262 o.type_pool.deinit(gpa);
263 o.lazy_abi_aligns.deinit(gpa);
264 o.debug_enums.deinit(gpa);
265 o.debug_globals.deinit(gpa);
266 o.debug_file_map.deinit(gpa);
267 o.debug_types.deinit(gpa);
268 o.nav_map.deinit(gpa);
269 o.uav_map.deinit(gpa);
270 o.const_map.deinit(gpa);
271 o.enum_tag_name_map.deinit(gpa);
272 o.named_enum_map.deinit(gpa);
273 o.type_map.deinit(gpa);
274 o.builder.deinit();
275 o.* = undefined;
276 }
277
278 fn genErrorNameTable(o: *Object) Allocator.Error!void {
279 // If o.error_name_table is null, then it was not referenced by any instructions.
280 if (o.error_name_table == .none) return;
281
282 const zcu = o.zcu;
283 const ip = &zcu.intern_pool;
284
285 const error_name_list = ip.global_error_set.getNamesFromMainThread();
286 const llvm_errors = try zcu.gpa.alloc(Builder.Constant, 1 + error_name_list.len);
287 defer zcu.gpa.free(llvm_errors);
288
289 // TODO: Address space
290 const slice_ty = Type.slice_const_u8_sentinel_0;
291 const llvm_usize_ty = try o.lowerType(.usize, .in_memory);
292 const llvm_slice_ty = try o.lowerType(slice_ty, .in_memory);
293 const llvm_table_ty = try o.builder.arrayType(1 + error_name_list.len, llvm_slice_ty);
294
295 llvm_errors[0] = try o.builder.undefConst(llvm_slice_ty);
296 for (llvm_errors[1..], error_name_list) |*llvm_error, name| {
297 const name_string = try o.builder.stringNull(name.toSlice(ip));
298 const name_init = try o.builder.stringConst(name_string);
299 const name_llvm_variable = try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default);
300 try name_llvm_variable.setInitializer(name_init, &o.builder);
301 name_llvm_variable.setMutability(.constant, &o.builder);
302 name_llvm_variable.setAlignment(comptime .fromByteUnits(1), &o.builder);
303 const llvm_global = name_llvm_variable.ptrConst(&o.builder).global;
304 llvm_global.setLinkage(.private, &o.builder);
305 llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder);
306
307 llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{
308 name_llvm_variable.toConst(&o.builder),
309 try o.builder.intConst(llvm_usize_ty, name_string.slice(&o.builder).?.len - 1),
310 });
311 }
312
313 try o.error_name_table.setInitializer(
314 try o.builder.arrayConst(llvm_table_ty, llvm_errors),
315 &o.builder,
316 );
317 }
318
319 fn genModuleLevelAssembly(object: *Object) Allocator.Error!void {
320 const b = &object.builder;
321 const gpa = b.gpa;
322 b.module_asm.clearRetainingCapacity();
323 for (object.zcu.global_assembly.values()) |assembly| {
324 try b.module_asm.ensureUnusedCapacity(gpa, assembly.len + 1);
325 b.module_asm.appendSliceAssumeCapacity(assembly);
326 b.module_asm.appendAssumeCapacity('\n');
327 }
328 if (b.module_asm.last()) |last| {
329 if (last != '\n') try b.module_asm.append(gpa, '\n');
330 }
331 }
332
333 pub const EmitOptions = struct {
334 pre_ir_path: ?[]const u8,
335 pre_bc_path: ?[]const u8,
336 bin_path: ?[:0]const u8,
337 asm_path: ?[:0]const u8,
338 post_ir_path: ?[:0]const u8,
339 post_bc_path: ?[]const u8,
340
341 is_debug: bool,
342 is_small: bool,
343 time_report: ?*Compilation.TimeReport,
344 sanitize_thread: bool,
345 fuzz: bool,
346 lto: std.zig.LtoMode,
347 };
348
349 pub fn emit(o: *Object, pt: Zcu.PerThread, options: EmitOptions) link.Error!void {
350 const zcu = o.zcu;
351 const comp = zcu.comp;
352 const io = comp.io;
353 const diags = &comp.link_diags;
354
355 {
356 if (o.errors_len_variable != .none) {
357 const errors_len = zcu.intern_pool.global_error_set.getNamesFromMainThread().len;
358 const init_val = try o.builder.intConst(try o.errorIntType(.in_memory), errors_len);
359 try o.errors_len_variable.setInitializer(init_val, &o.builder);
360 }
361 try o.genErrorNameTable();
362 try o.genModuleLevelAssembly();
363
364 if (o.used.items.len > 0) {
365 const array_llvm_ty = try o.builder.arrayType(o.used.items.len, .ptr);
366 const init_val = try o.builder.arrayConst(array_llvm_ty, o.used.items);
367 const compiler_used_variable = try o.builder.addVariable(
368 try o.builder.strtabString("llvm.used"),
369 array_llvm_ty,
370 .default,
371 );
372 try compiler_used_variable.setInitializer(init_val, &o.builder);
373 compiler_used_variable.setSection(try o.builder.string("llvm.metadata"), &o.builder);
374 compiler_used_variable.ptrConst(&o.builder).global.setLinkage(.appending, &o.builder);
375 }
376
377 if (!o.builder.strip) {
378 if (o.debug_anyerror_fwd_ref.unwrap()) |fwd_ref| {
379 const debug_anyerror_type = try o.lowerDebugAnyerrorType();
380 o.builder.resolveDebugForwardReference(fwd_ref, debug_anyerror_type);
381 }
382
383 try o.flushTypePool(pt);
384
385 o.builder.resolveDebugForwardReference(
386 o.debug_enums_fwd_ref.unwrap().?,
387 try o.builder.metadataTuple(o.debug_enums.items),
388 );
389
390 o.builder.resolveDebugForwardReference(
391 o.debug_globals_fwd_ref.unwrap().?,
392 try o.builder.metadataTuple(o.debug_globals.items),
393 );
394 }
395 }
396
397 {
398 var module_flags = try std.array_list.Managed(Builder.Metadata).initCapacity(o.gpa, 11);
399 defer module_flags.deinit();
400
401 const behavior_error = try o.builder.metadataConstant(try o.builder.intConst(.i32, 1));
402 const behavior_warning = try o.builder.metadataConstant(try o.builder.intConst(.i32, 2));
403 const behavior_max = try o.builder.metadataConstant(try o.builder.intConst(.i32, 7));
404 const behavior_min = try o.builder.metadataConstant(try o.builder.intConst(.i32, 8));
405
406 if (target_util.llvmMachineAbi(&comp.root_mod.resolved_target.result)) |abi| {
407 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{
408 behavior_error,
409 (try o.builder.metadataString("target-abi")).toMetadata(),
410 (try o.builder.metadataString(abi)).toMetadata(),
411 }));
412 }
413
414 const pic_level = target_util.picLevel(&comp.root_mod.resolved_target.result);
415 if (comp.root_mod.pic) {
416 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{
417 behavior_min,
418 (try o.builder.metadataString("PIC Level")).toMetadata(),
419 try o.builder.metadataConstant(try o.builder.intConst(.i32, pic_level)),
420 }));
421 }
422
423 if (comp.config.pie) {
424 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{
425 behavior_max,
426 (try o.builder.metadataString("PIE Level")).toMetadata(),
427 try o.builder.metadataConstant(try o.builder.intConst(.i32, pic_level)),
428 }));
429 }
430
431 if (comp.root_mod.code_model != .default) {
432 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{
433 behavior_error,
434 (try o.builder.metadataString("Code Model")).toMetadata(),
435 try o.builder.metadataConstant(try o.builder.intConst(.i32, @as(
436 i32,
437 switch (codeModel(comp.root_mod.code_model, &comp.root_mod.resolved_target.result)) {
438 .default => unreachable,
439 .tiny => 0,
440 .small => 1,
441 .kernel => 2,
442 .medium => 3,
443 .large => 4,
444 },
445 ))),
446 }));
447 }
448
449 if (!o.builder.strip) {
450 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{
451 behavior_warning,
452 (try o.builder.metadataString("Debug Info Version")).toMetadata(),
453 try o.builder.metadataConstant(try o.builder.intConst(.i32, 3)),
454 }));
455
456 switch (comp.config.debug_format) {
457 .strip => unreachable,
458 .dwarf => |f| {
459 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{
460 behavior_max,
461 (try o.builder.metadataString("Dwarf Version")).toMetadata(),
462 try o.builder.metadataConstant(try o.builder.intConst(.i32, 4)),
463 }));
464
465 if (f == .@"64") {
466 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{
467 behavior_max,
468 (try o.builder.metadataString("DWARF64")).toMetadata(),
469 try o.builder.metadataConstant(.@"1"),
470 }));
471 }
472 },
473 .code_view => {
474 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{
475 behavior_warning,
476 (try o.builder.metadataString("CodeView")).toMetadata(),
477 try o.builder.metadataConstant(.@"1"),
478 }));
479 },
480 }
481 }
482
483 const target = &comp.root_mod.resolved_target.result;
484 if (target.os.tag == .windows and (target.cpu.arch == .x86_64 or target.cpu.arch == .x86)) {
485 // Add the "RegCallv4" flag so that any functions using `x86_regcallcc` use regcall
486 // v4, which is essentially a requirement on Windows. See corresponding logic in
487 // `toLlvmCallConvTag`.
488 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{
489 behavior_max,
490 (try o.builder.metadataString("RegCallv4")).toMetadata(),
491 try o.builder.metadataConstant(.@"1"),
492 }));
493 }
494
495 // The frontend should eventually offer options to control these.
496 if (target.cpu.arch.isAarch64() and target.os.tag == .openbsd) {
497 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{
498 behavior_min,
499 (try o.builder.metadataString("branch-target-enforcement")).toMetadata(),
500 try o.builder.metadataConstant(try o.builder.intConst(.i32, 2)),
501 }));
502 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{
503 behavior_min,
504 (try o.builder.metadataString("sign-return-address")).toMetadata(),
505 try o.builder.metadataConstant(try o.builder.intConst(.i32, 2)),
506 }));
507 }
508
509 try o.builder.addNamedMetadata(try o.builder.string("llvm.module.flags"), module_flags.items);
510 }
511
512 const target_triple_sentinel =
513 try o.gpa.dupeSentinel(u8, o.builder.target_triple.slice(&o.builder).?, 0);
514 defer o.gpa.free(target_triple_sentinel);
515
516 const emit_asm_msg = options.asm_path orelse "(none)";
517 const emit_bin_msg = options.bin_path orelse "(none)";
518 const post_llvm_ir_msg = options.post_ir_path orelse "(none)";
519 const post_llvm_bc_msg = options.post_bc_path orelse "(none)";
520 log.debug("emit LLVM object asm={s} bin={s} ir={s} bc={s}", .{
521 emit_asm_msg, emit_bin_msg, post_llvm_ir_msg, post_llvm_bc_msg,
522 });
523
524 const context, const module = emit: {
525 if (options.pre_ir_path) |path| {
526 if (std.mem.eql(u8, path, "-")) {
527 o.builder.dump(io);
528 } else {
529 o.builder.printToFilePath(io, Io.Dir.cwd(), path) catch |err| {
530 log.err("failed printing LLVM module to \"{s}\": {t}", .{ path, err });
531 };
532 }
533 }
534
535 const bitcode = try o.builder.toBitcode(o.gpa, .{
536 .name = "zig",
537 .version = build_options.semver,
538 });
539 defer o.gpa.free(bitcode);
540
541 if (options.pre_bc_path) |path| {
542 var file = Io.Dir.cwd().createFile(io, path, .{}) catch |err|
543 return diags.fail("failed to create '{s}': {t}", .{ path, err });
544 defer file.close(io);
545
546 const ptr: [*]const u8 = @ptrCast(bitcode.ptr);
547 file.writeStreamingAll(io, ptr[0..(bitcode.len * 4)]) catch |err|
548 return diags.fail("failed to write to '{s}': {t}", .{ path, err });
549 }
550
551 if (options.asm_path == null and options.bin_path == null and
552 options.post_ir_path == null and options.post_bc_path == null) return;
553
554 if (options.post_bc_path) |path| {
555 var file = Io.Dir.cwd().createFile(io, path, .{}) catch |err|
556 return diags.fail("failed to create '{s}': {t}", .{ path, err });
557 defer file.close(io);
558
559 const ptr: [*]const u8 = @ptrCast(bitcode.ptr);
560 file.writeStreamingAll(io, ptr[0..(bitcode.len * 4)]) catch |err|
561 return diags.fail("failed to write to '{s}': {t}", .{ path, err });
562 }
563
564 if (!build_options.have_llvm or !comp.config.use_lib_llvm) {
565 return diags.fail("emitting without libllvm not implemented", .{});
566 }
567
568 initializeLLVMTarget(io, comp.root_mod.resolved_target.result.cpu.arch);
569
570 const context: *bindings.Context = .create();
571 errdefer context.dispose();
572
573 const bitcode_memory_buffer = bindings.MemoryBuffer.createMemoryBufferWithMemoryRange(
574 @ptrCast(bitcode.ptr),
575 bitcode.len * 4,
576 "BitcodeBuffer",
577 bindings.Bool.False,
578 );
579 defer bitcode_memory_buffer.dispose();
580
581 context.enableBrokenDebugInfoCheck();
582
583 var module: *bindings.Module = undefined;
584 if (context.parseBitcodeInContext2(bitcode_memory_buffer, &module).toBool() or context.getBrokenDebugInfo()) {
585 return diags.fail("Failed to parse bitcode", .{});
586 }
587 break :emit .{ context, module };
588 };
589 defer context.dispose();
590
591 var target: *bindings.Target = undefined;
592 var error_message: [*:0]const u8 = undefined;
593 if (bindings.Target.getFromTriple(target_triple_sentinel, &target, &error_message).toBool()) {
594 defer bindings.disposeMessage(error_message);
595 return diags.fail("LLVM failed to parse '{s}': {s}", .{ target_triple_sentinel, error_message });
596 }
597
598 const optimize_mode = comp.root_mod.optimize_mode;
599
600 const opt_level: bindings.CodeGenOptLevel = if (optimize_mode == .debug)
601 .None
602 else
603 .Aggressive;
604
605 const reloc_mode: bindings.RelocMode = if (comp.root_mod.pic)
606 .PIC
607 else if (comp.config.link_mode == .dynamic)
608 bindings.RelocMode.DynamicNoPIC
609 else
610 .Static;
611
612 const code_model: bindings.CodeModel = switch (codeModel(comp.root_mod.code_model, &comp.root_mod.resolved_target.result)) {
613 .default => .Default,
614 .tiny => .Tiny,
615 .small => .Small,
616 .kernel => .Kernel,
617 .medium => .Medium,
618 .large => .Large,
619 };
620
621 const float_abi: bindings.TargetMachine.FloatABI = if (comp.root_mod.resolved_target.result.abi.float() == .hard)
622 .Hard
623 else
624 .Soft;
625
626 var target_machine = bindings.TargetMachine.create(
627 target,
628 target_triple_sentinel,
629 if (comp.root_mod.resolved_target.result.cpu.model.llvm_name) |s| s.ptr else null,
630 comp.root_mod.resolved_target.llvm_cpu_features.?,
631 opt_level,
632 reloc_mode,
633 code_model,
634 comp.function_sections,
635 comp.data_sections,
636 float_abi,
637 if (target_util.llvmMachineAbi(&comp.root_mod.resolved_target.result)) |s| s.ptr else null,
638 target_util.useEmulatedTls(&comp.root_mod.resolved_target.result),
639 );
640 errdefer target_machine.dispose();
641
642 if (comp.llvm_opt_bisect_limit >= 0) {
643 context.setOptBisectLimit(comp.llvm_opt_bisect_limit);
644 }
645
646 // Unfortunately, LLVM shits the bed when we ask for both binary and assembly.
647 // So we call the entire pipeline multiple times if this is requested.
648 // var error_message: [*:0]const u8 = undefined;
649 var lowered_options: bindings.TargetMachine.EmitOptions = .{
650 .is_debug = options.is_debug,
651 .is_small = options.is_small,
652 .time_report_out = null, // set below to make sure it's only set for a single `emitToFile`
653 .tsan = options.sanitize_thread,
654 .lto = switch (options.lto) {
655 .none => .None,
656 .thin => .ThinPreLink,
657 .full => .FullPreLink,
658 },
659 .allow_fast_isel = true,
660 // LLVM's RISC-V backend for some reason enables the machine outliner by default even
661 // though it's clearly not ready and produces multiple miscompilations in our std tests.
662 .allow_machine_outliner = !comp.root_mod.resolved_target.result.cpu.arch.isRISCV(),
663 .asm_filename = null,
664 .bin_filename = if (options.bin_path) |x| x.ptr else null,
665 .llvm_ir_filename = if (options.post_ir_path) |x| x.ptr else null,
666 .bitcode_filename = null,
667
668 // `.coverage` value is only used when `.sancov` is enabled.
669 .sancov = options.fuzz or comp.config.san_cov_trace_pc_guard,
670 .coverage = .{
671 .CoverageType = .Edge,
672 // Works in tandem with Inline8bitCounters or InlineBoolFlag.
673 // Zig does not yet implement its own version of this but it
674 // needs to for better fuzzing logic.
675 .IndirectCalls = false,
676 .TraceBB = false,
677 .TraceCmp = false,
678 .TraceDiv = false,
679 .TraceGep = false,
680 .Use8bitCounters = false,
681 .TracePC = false,
682 .TracePCGuard = comp.config.san_cov_trace_pc_guard,
683 // Zig emits its own inline 8-bit counters instrumentation.
684 .Inline8bitCounters = false,
685 .InlineBoolFlag = false,
686 // Zig emits its own PC table instrumentation.
687 .PCTable = false,
688 .NoPrune = false,
689 // Workaround for https://github.com/llvm/llvm-project/pull/106464
690 .StackDepth = true,
691 .TraceLoads = false,
692 .TraceStores = false,
693 .CollectControlFlow = false,
694 },
695 };
696 if (options.asm_path != null and options.bin_path != null) {
697 if (target_machine.emitToFile(module, &error_message, &lowered_options)) {
698 defer bindings.disposeMessage(error_message);
699 return diags.fail("LLVM failed to emit bin={s} ir={s}: {s}", .{
700 emit_bin_msg, post_llvm_ir_msg, error_message,
701 });
702 }
703 lowered_options.bin_filename = null;
704 lowered_options.llvm_ir_filename = null;
705 }
706
707 var time_report_c_str: [*:0]u8 = undefined;
708 if (options.time_report != null) {
709 lowered_options.time_report_out = &time_report_c_str;
710 }
711
712 lowered_options.asm_filename = if (options.asm_path) |x| x.ptr else null;
713 if (target_machine.emitToFile(module, &error_message, &lowered_options)) {
714 defer bindings.disposeMessage(error_message);
715 return diags.fail("LLVM failed to emit asm={s} bin={s} ir={s} bc={s}: {s}", .{
716 emit_asm_msg, emit_bin_msg, post_llvm_ir_msg, post_llvm_bc_msg, error_message,
717 });
718 }
719 if (options.time_report) |tr| {
720 defer std.c.free(time_report_c_str);
721 const time_report_data = std.mem.span(time_report_c_str);
722 assert(tr.llvm_pass_timings.len == 0);
723 tr.llvm_pass_timings = try comp.gpa.dupe(u8, time_report_data);
724 }
725 }
726
727 pub fn updateFunc(
728 o: *Object,
729 pt: Zcu.PerThread,
730 func_index: InternPool.Index,
731 air: *const Air,
732 liveness: *const ?Air.Liveness,
733 ) Zcu.CodegenFailError!void {
734 const zcu = o.zcu;
735 const comp = zcu.comp;
736 const gpa = comp.gpa;
737 const ip = &zcu.intern_pool;
738 const func = zcu.funcInfo(func_index);
739 const nav = ip.getNav(func.owner_nav);
740 const file_scope = zcu.navFileScopeIndex(func.owner_nav);
741 const owner_mod = zcu.fileByIndex(file_scope).mod.?;
742 const fn_ty = Type.fromInterned(func.ty);
743 const fn_info = zcu.typeToFunc(fn_ty).?;
744 const target = &owner_mod.resolved_target.result;
745
746 const gop = try o.nav_map.getOrPut(gpa, func.owner_nav);
747 if (!gop.found_existing) {
748 errdefer assert(o.nav_map.remove(func.owner_nav));
749 // First time lowering this NAV! Create a fresh global.
750 const llvm_name = try o.builder.strtabString(nav.fqn.toSlice(ip));
751 gop.value_ptr.* = try o.builder.addGlobal(llvm_name, .{
752 .type = .void, // placeholder; populated below
753 .kind = .{ .alias = .none }, // placeholder; populated below
754 });
755 }
756 const llvm_global = gop.value_ptr.*;
757
758 const llvm_function: Builder.Function.Index = switch (llvm_global.ptrConst(&o.builder).kind) {
759 .function => |function| function, // re-use existing `Builder.Function`
760 .replaced, .alias, .variable => try llvm_global.toNewFunction(&o.builder),
761 };
762 {
763 const global = llvm_function.ptrConst(&o.builder).global.ptr(&o.builder);
764 global.type = try o.lowerType(fn_ty, .in_memory);
765 global.addr_space = toLlvmAddressSpace(nav.resolved.?.@"addrspace", target);
766 global.linkage = if (o.builder.strip) .private else .internal;
767 global.visibility = .default;
768 global.dll_storage_class = .default;
769 global.unnamed_addr = .unnamed_addr;
770 }
771 llvm_function.setAlignment(nav.resolved.?.@"align".toLlvm(), &o.builder);
772 llvm_function.setSection(s: {
773 const section = nav.resolved.?.@"linksection".toSlice(ip) orelse break :s .none;
774 break :s try o.builder.string(section);
775 }, &o.builder);
776
777 var attributes: Builder.FunctionAttributes.Wip = .{};
778 defer attributes.deinit(&o.builder);
779
780 // Function attributes that are independent of analysis results of the function body.
781 try o.addCommonFnAttributes(
782 &attributes,
783 owner_mod,
784 // Some backends don't respect the `naked` attribute in `TargetFrameLowering::hasFP()`,
785 // so for these backends, LLVM will happily emit code that accesses the stack through
786 // the frame pointer. This is nonsensical since what the `naked` attribute does is
787 // suppress generation of the prologue and epilogue, and the prologue is where the
788 // frame pointer normally gets set up. At time of writing, this is the case for at
789 // least x86 and RISC-V.
790 owner_mod.omit_frame_pointer or fn_info.cc == .naked,
791 );
792
793 try o.addCallingConventionFnAttributes(pt, llvm_function, &attributes, if (nav.getExtern(ip)) |@"extern"| .{
794 .name = nav.name.toSlice(ip),
795 .lib_name = @"extern".lib_name.toSlice(ip),
796 } else null, .fromIntern(fn_info, ip));
797
798 const func_analysis = func.analysisUnordered(ip);
799 if (func_analysis.is_noinline) {
800 try attributes.addFnAttr(.@"noinline", &o.builder);
801 } else {
802 _ = try attributes.removeFnAttr(.@"noinline");
803 }
804
805 if (func_analysis.branch_hint == .cold) {
806 try attributes.addFnAttr(.cold, &o.builder);
807 } else {
808 _ = try attributes.removeFnAttr(.cold);
809 }
810
811 if (owner_mod.sanitize_thread and !func_analysis.disable_instrumentation) {
812 try attributes.addFnAttr(.sanitize_thread, &o.builder);
813 } else {
814 _ = try attributes.removeFnAttr(.sanitize_thread);
815 }
816 const is_naked = fn_info.cc == .naked;
817 if (!func_analysis.disable_instrumentation and !is_naked) {
818 if (owner_mod.fuzz) {
819 try attributes.addFnAttr(.optforfuzzing, &o.builder);
820 }
821 _ = try attributes.removeFnAttr(.skipprofile);
822 _ = try attributes.removeFnAttr(.nosanitize_coverage);
823 } else {
824 _ = try attributes.removeFnAttr(.optforfuzzing);
825 try attributes.addFnAttr(.skipprofile, &o.builder);
826 try attributes.addFnAttr(.nosanitize_coverage, &o.builder);
827 }
828
829 const disable_intrinsics = func_analysis.disable_intrinsics or owner_mod.no_builtin;
830 if (disable_intrinsics) {
831 // The intent here is for compiler-rt and libc functions to not generate
832 // infinite recursion. For example, if we are compiling the memcpy function,
833 // and llvm detects that the body is equivalent to memcpy, it may replace the
834 // body of memcpy with a call to memcpy, which would then cause a stack
835 // overflow instead of performing memcpy.
836 try attributes.addFnAttr(.{ .string = .{
837 .kind = try o.builder.string("no-builtins"),
838 .value = .empty,
839 } }, &o.builder);
840 }
841
842 // TODO: disable this if safety is off for the function scope
843 const ssp_buf_size = owner_mod.stack_protector;
844 if (ssp_buf_size != 0) {
845 try attributes.addFnAttr(.sspstrong, &o.builder);
846 try attributes.addFnAttr(.{ .string = .{
847 .kind = try o.builder.string("stack-protector-buffer-size"),
848 .value = try o.builder.fmt("{d}", .{ssp_buf_size}),
849 } }, &o.builder);
850 }
851
852 // TODO: disable this if safety is off for the function scope
853 if (owner_mod.stack_check) {
854 try attributes.addFnAttr(.{ .string = .{
855 .kind = try o.builder.string("probe-stack"),
856 .value = try o.builder.string("__zig_probe_stack"),
857 } }, &o.builder);
858 } else if (target.os.tag == .uefi) {
859 try attributes.addFnAttr(.{ .string = .{
860 .kind = try o.builder.string("no-stack-arg-probe"),
861 .value = .empty,
862 } }, &o.builder);
863 }
864
865 const file, const subprogram = if (!owner_mod.strip) debug_info: {
866 const file = try o.getDebugFile(file_scope);
867
868 const line_number = zcu.navSrcLine(func.owner_nav) + 1;
869 const is_internal_linkage = ip.indexToKey(nav.resolved.?.value) != .@"extern";
870 const debug_decl_type = try o.getDebugType(pt, fn_ty);
871
872 const subprogram = try o.builder.debugSubprogram(
873 file,
874 try o.builder.metadataString(nav.name.toSlice(ip)),
875 try o.builder.metadataString(nav.fqn.toSlice(ip)),
876 line_number,
877 line_number + func.lbrace_line,
878 debug_decl_type,
879 .{
880 .di_flags = .{
881 .StaticMember = true,
882 .NoReturn = fn_info.return_type == .noreturn_type,
883 },
884 .sp_flags = .{
885 .Optimized = owner_mod.optimize_mode != .debug,
886 .Definition = true,
887 .LocalToUnit = is_internal_linkage,
888 },
889 },
890 o.debug_compile_unit.unwrap().?,
891 );
892 llvm_function.setSubprogram(subprogram, &o.builder);
893 break :debug_info .{ file, subprogram };
894 } else .{ undefined, undefined };
895
896 const fuzz: ?FuncGen.Fuzz = f: {
897 if (!owner_mod.fuzz) break :f null;
898 if (func_analysis.disable_instrumentation) break :f null;
899 if (is_naked) break :f null;
900 if (comp.config.san_cov_trace_pc_guard) break :f null;
901
902 // The void type used here is a placeholder to be replaced with an
903 // array of the appropriate size after the POI count is known.
904
905 // Due to error "members of llvm.compiler.used must be named", this global needs a name.
906 const anon_name = try o.builder.strtabStringFmt("__sancov_gen_.{d}", .{o.used.items.len});
907 const counters_variable = try o.builder.addVariable(anon_name, .void, .default);
908 try o.used.append(gpa, counters_variable.toConst(&o.builder));
909 counters_variable.ptrConst(&o.builder).global.setLinkage(.private, &o.builder);
910 counters_variable.setAlignment(comptime .fromByteUnits(1), &o.builder);
911
912 if (target.ofmt == .macho) {
913 counters_variable.setSection(try o.builder.string("__DATA,__sancov_cntrs"), &o.builder);
914 } else {
915 counters_variable.setSection(try o.builder.string("__sancov_cntrs"), &o.builder);
916 }
917
918 break :f .{
919 .counters_variable = counters_variable,
920 .pcs = .empty,
921 };
922 };
923
924 var fg: FuncGen = .{
925 .object = o,
926 .nav_index = func.owner_nav,
927 .pt = pt,
928 .gpa = gpa,
929 .air = air.*,
930 .liveness = liveness.*.?,
931 .wip = try .init(&o.builder, .{
932 .function = llvm_function,
933 .strip = owner_mod.strip,
934 }),
935 .is_naked = fn_info.cc == .naked,
936 .fuzz = fuzz,
937 .arg_index = 0,
938 .arg_inline_index = 0,
939 .func_inst_table = .empty,
940 .blocks = .empty,
941 .loops = .empty,
942 .switch_dispatch_info = .empty,
943 .sync_scope = if (owner_mod.single_threaded) .singlethread else .system,
944 .file = file,
945 .scope = subprogram,
946 .inlined_at = .none,
947 .base_line = zcu.navSrcLine(func.owner_nav),
948 .prev_dbg_line = 0,
949 .prev_dbg_column = 0,
950 .disable_intrinsics = disable_intrinsics,
951 .allowzero_access = false,
952
953 .ret_ptr = undefined, // populated by `genMainBody`
954 .err_ret_trace = undefined, // populated by `genMainBody`
955 .args = undefined, // populated by `genMainBody`
956 };
957 defer fg.deinit();
958
959 fg.wip.cursor = .{ .block = try fg.wip.block(0, "Entry") };
960
961 try fg.genMainBody();
962
963 // If we saw any loads or stores involving `allowzero` pointers, we need to mark the whole
964 // function as considering null pointers valid so that LLVM's optimizers don't remove these
965 // operations on the assumption that they're undefined behavior.
966 if (fg.allowzero_access) {
967 try attributes.addFnAttr(.null_pointer_is_valid, &o.builder);
968 } else {
969 _ = try attributes.removeFnAttr(.null_pointer_is_valid);
970 }
971
972 llvm_function.setAttributes(try attributes.finish(&o.builder), &o.builder);
973
974 if (fg.fuzz) |*f| {
975 {
976 const array_llvm_ty = try o.builder.arrayType(f.pcs.items.len, .i8);
977 f.counters_variable.ptrConst(&o.builder).global.ptr(&o.builder).type = array_llvm_ty;
978 const zero_init = try o.builder.zeroInitConst(array_llvm_ty);
979 try f.counters_variable.setInitializer(zero_init, &o.builder);
980 }
981
982 const array_llvm_ty = try o.builder.arrayType(f.pcs.items.len, .ptr);
983 const init_val = try o.builder.arrayConst(array_llvm_ty, f.pcs.items);
984 // Due to error "members of llvm.compiler.used must be named", this global needs a name.
985 const anon_name = try o.builder.strtabStringFmt("__sancov_gen_.{d}", .{o.used.items.len});
986 const pcs_variable = try o.builder.addVariable(anon_name, array_llvm_ty, .default);
987 try pcs_variable.setInitializer(init_val, &o.builder);
988 pcs_variable.setMutability(.constant, &o.builder);
989 pcs_variable.setSection(switch (target.ofmt) {
990 .macho => try o.builder.string("__DATA,__sancov_pcs1"),
991 else => try o.builder.string("__sancov_pcs1"),
992 }, &o.builder);
993 pcs_variable.setAlignment(Type.usize.abiAlignment(zcu).toLlvm(), &o.builder);
994 const pcs_global = pcs_variable.ptrConst(&o.builder).global;
995 pcs_global.setLinkage(.private, &o.builder);
996 try o.used.append(gpa, pcs_global.toConst());
997 }
998
999 try fg.wip.finish();
1000 try o.flushTypePool(pt);
1001 }
1002
1003 fn workaroundPrivateSymbolBugs(target: *const std.Target, resolved: *const InternPool.Nav.Resolved) bool {
1004 // https://codeberg.org/ziglang/zig/issues/31865
1005 return target.cpu.arch.isAARCH64() and target.ofmt == .coff and resolved.@"threadlocal";
1006 }
1007
1008 pub fn updateNav(o: *Object, pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) !void {
1009 const zcu = o.zcu;
1010 const ip = &zcu.intern_pool;
1011 const comp = zcu.comp;
1012 const gpa = comp.gpa;
1013
1014 const nav = ip.getNav(nav_id);
1015 const resolved = nav.resolved.?;
1016
1017 const opt_extern: ?InternPool.Key.Extern = switch (ip.indexToKey(resolved.value)) {
1018 .@"extern" => |@"extern"| @"extern",
1019 else => null,
1020 };
1021 const nav_ty: Type = .fromInterned(resolved.type);
1022 const llvm_ty: Builder.Type = if (opt_extern != null) ty: {
1023 // We *must* lower this declaration no matter what. If it has a type we can't actually
1024 // represent (because it doesn't have runtime bits), we instead lower as the zero-size
1025 // type `[0 x i8]`. I don't think the type on an extern declaration actually does much
1026 // anyway.
1027 if (nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) break :ty try o.lowerType(nav_ty, .in_memory);
1028 break :ty try o.builder.arrayType(0, .i8);
1029 } else if (nav_ty.hasRuntimeBits(zcu)) ty: {
1030 break :ty try o.lowerType(nav_ty, .in_memory);
1031 } else {
1032 // This is a non-extern zero-bit `Nav`---we're not interested in it.
1033 // TODO: we might need to rethink this a little under incremental compilation. If a
1034 // declaration becomes zero-bit, we can't just leave its old value there, because it
1035 // might now be ill-formed.
1036 return;
1037 };
1038
1039 const gop = try o.nav_map.getOrPut(gpa, nav_id);
1040 if (!gop.found_existing) {
1041 errdefer assert(o.nav_map.remove(nav_id));
1042 // First time lowering this NAV! Create a fresh global.
1043 const llvm_name = try o.builder.strtabString(nav.fqn.toSlice(ip));
1044 gop.value_ptr.* = try o.builder.addGlobal(llvm_name, .{
1045 .type = .void, // placeholder; populated below
1046 .kind = .{ .alias = .none }, // placeholder; populated below
1047 });
1048 }
1049 const llvm_global = gop.value_ptr.*;
1050
1051 llvm_global.ptr(&o.builder).type = llvm_ty;
1052 llvm_global.ptr(&o.builder).addr_space = toLlvmAddressSpace(resolved.@"addrspace", zcu.getTarget());
1053
1054 if (opt_extern) |@"extern"| {
1055 const name = name: {
1056 const name_slice = nav.name.toSlice(ip);
1057 if (zcu.getTarget().cpu.arch.isWasm() and nav_ty.zigTypeTag(zcu) == .@"fn") {
1058 if (@"extern".lib_name.toSlice(ip)) |lib_name_slice| {
1059 if (!std.mem.eql(u8, lib_name_slice, "c")) {
1060 break :name try o.builder.strtabStringFmt("{s}|{s}", .{ name_slice, lib_name_slice });
1061 }
1062 }
1063 }
1064 break :name try o.builder.strtabString(name_slice);
1065 };
1066 if (o.builder.getGlobal(name)) |other_global| {
1067 if (other_global != llvm_global) {
1068 // Another global already has this name; just use it in place of this global.
1069 try llvm_global.replace(other_global, &o.builder);
1070 return;
1071 }
1072 }
1073 try llvm_global.rename(name, &o.builder);
1074 llvm_global.ptr(&o.builder).unnamed_addr = .default;
1075 llvm_global.ptr(&o.builder).dll_storage_class = switch (@"extern".is_dll_import) {
1076 true => .dllimport,
1077 false => .default,
1078 };
1079 llvm_global.ptr(&o.builder).linkage = switch (@"extern".linkage) {
1080 .internal => if (o.builder.strip and !workaroundPrivateSymbolBugs(zcu.getTarget(), &resolved)) .private else .internal,
1081 .strong => .external,
1082 .weak => .extern_weak,
1083 .link_once => unreachable,
1084 };
1085 llvm_global.ptr(&o.builder).visibility = .fromSymbolVisibility(@"extern".visibility);
1086 } else {
1087 llvm_global.ptr(&o.builder).linkage = if (o.builder.strip and !workaroundPrivateSymbolBugs(zcu.getTarget(), &resolved)) .private else .internal;
1088 llvm_global.ptr(&o.builder).visibility = .default;
1089 llvm_global.ptr(&o.builder).dll_storage_class = .default;
1090 llvm_global.ptr(&o.builder).unnamed_addr = .unnamed_addr;
1091 }
1092
1093 const llvm_section: Builder.String = if (resolved.@"linksection".toSlice(ip)) |section| s: {
1094 break :s try o.builder.string(section);
1095 } else .none;
1096
1097 // Actual function bodies with AIR go through `updateFunc` instead, so the only functions we
1098 // can see are extern functions or other comptime function body values (e.g. undefined). Of
1099 // these, only extern functions need to be lowered to LLVM functions.
1100 if (opt_extern != null and nav_ty.zigTypeTag(zcu) == .@"fn" and nav_ty.fnHasRuntimeBits(zcu)) {
1101 const fn_info = zcu.typeToFunc(nav_ty).?;
1102 const llvm_function: Builder.Function.Index = switch (llvm_global.ptrConst(&o.builder).kind) {
1103 .function => |function| function, // re-use existing `Builder.Function`
1104 .replaced, .alias, .variable => try llvm_global.toNewFunction(&o.builder),
1105 };
1106 llvm_function.setAlignment(resolved.@"align".toLlvm(), &o.builder);
1107 llvm_function.setSection(llvm_section, &o.builder);
1108 var attributes: Builder.FunctionAttributes.Wip = .{};
1109 defer attributes.deinit(&o.builder);
1110 try o.addCallingConventionFnAttributes(pt, llvm_function, &attributes, .{
1111 .name = nav.name.toSlice(ip),
1112 .lib_name = opt_extern.?.lib_name.toSlice(ip),
1113 }, .fromIntern(fn_info, ip));
1114 llvm_function.setAttributes(try attributes.finish(&o.builder), &o.builder);
1115 } else {
1116 const file_scope = nav.srcInst(ip).resolveFile(ip);
1117 const mod = zcu.fileByIndex(file_scope).mod.?;
1118
1119 const llvm_variable: Builder.Variable.Index = switch (llvm_global.ptrConst(&o.builder).kind) {
1120 .variable => |variable| variable, // re-use existing `Builder.Variable`
1121 .replaced, .alias, .function => try llvm_global.toNewVariable(&o.builder),
1122 };
1123 llvm_variable.setAlignment(switch (resolved.@"align") {
1124 .none => nav_ty.abiAlignment(zcu).toLlvm(),
1125 else => |a| a.toLlvm(),
1126 }, &o.builder);
1127 llvm_variable.setSection(llvm_section, &o.builder);
1128 llvm_variable.setMutability(if (resolved.@"const") .constant else .global, &o.builder);
1129 try llvm_variable.setInitializer(if (opt_extern != null) .no_init else try o.lowerValue(resolved.value, .in_memory), &o.builder);
1130 llvm_variable.setThreadLocal(tl: {
1131 if (resolved.@"threadlocal" and !mod.single_threaded) break :tl .generaldynamic;
1132 break :tl .default;
1133 }, &o.builder);
1134
1135 if (!mod.strip) {
1136 const debug_file = try o.getDebugFile(file_scope);
1137 const debug_global_var_expr = try o.builder.debugGlobalVarExpression(
1138 try o.builder.debugGlobalVar(
1139 try o.builder.metadataString(nav.name.toSlice(ip)), // Name
1140 try o.builder.metadataString(nav.fqn.toSlice(ip)), // Linkage name
1141 debug_file, // File
1142 debug_file, // Scope
1143 zcu.navSrcLine(nav_id) + 1,
1144 try o.getDebugType(pt, nav_ty),
1145 llvm_variable,
1146 .{ .local = llvm_global.ptrConst(&o.builder).linkage == .internal },
1147 ),
1148 try o.builder.debugExpression(&.{}),
1149 );
1150 llvm_variable.setGlobalVariableExpression(debug_global_var_expr, &o.builder);
1151 try o.debug_globals.append(o.gpa, debug_global_var_expr);
1152 }
1153 }
1154 }
1155
1156 fn flushTypePool(o: *Object, pt: Zcu.PerThread) link.Error!void {
1157 try o.type_pool.flushPending(pt, .{ .llvm = o });
1158 }
1159
1160 pub fn updateExports(
1161 o: *Object,
1162 export_indices: []const Zcu.Export.Index,
1163 ) link.Error!void {
1164 const zcu = o.zcu;
1165 const ip = &zcu.intern_pool;
1166 for (export_indices) |export_index| {
1167 const ty: Type, const llvm_ptr: Builder.Constant = switch (export_index.ptr(zcu).exported) {
1168 .nav => |nav| exp: {
1169 const nav_ty: Type = .fromInterned(ip.getNav(nav).resolved.?.type);
1170 const nav_ref = try o.lowerNavRef(nav);
1171 break :exp .{ nav_ty, nav_ref };
1172 },
1173 .uav => |uav| exp: {
1174 const uav_ty = Value.fromInterned(uav).typeOf(zcu);
1175 const uav_ref = try o.lowerUavRef(
1176 uav,
1177 uav_ty.abiAlignment(zcu).toLlvm(),
1178 target_util.defaultAddressSpace(zcu.getTarget(), .global_constant),
1179 );
1180 break :exp .{ uav_ty, uav_ref };
1181 },
1182 };
1183 switch (llvm_ptr.unwrap()) {
1184 .global => |global| try o.addGlobalExport(global, ty, export_index),
1185 .constant => @panic("LLVM TODO: export zero-bit value"),
1186 }
1187 }
1188 }
1189
1190 fn addGlobalExport(
1191 o: *Object,
1192 llvm_global: Builder.Global.Index,
1193 ty: Type,
1194 export_index: Zcu.Export.Index,
1195 ) link.Error!void {
1196 const zcu = o.zcu;
1197 const comp = zcu.comp;
1198 const ip = &zcu.intern_pool;
1199
1200 const exp = export_index.ptr(zcu);
1201
1202 // If we're on COFF and linking with LLD, the linker cares about our exports to determine the subsystem in use.
1203 coff_export_flags: {
1204 const lf = comp.bin_file orelse break :coff_export_flags;
1205 const lld = lf.cast(.lld) orelse break :coff_export_flags;
1206 const coff = switch (lld.ofmt) {
1207 .elf, .wasm => break :coff_export_flags,
1208 .coff => |*coff| coff,
1209 };
1210 if (ty.zigTypeTag(zcu) != .@"fn") break :coff_export_flags;
1211 const flags = &coff.lld_export_flags;
1212 if (exp.opts.name.eqlSlice("main", ip)) flags.c_main = true;
1213 if (exp.opts.name.eqlSlice("WinMain", ip)) flags.winmain = true;
1214 if (exp.opts.name.eqlSlice("wWinMain", ip)) flags.wwinmain = true;
1215 if (exp.opts.name.eqlSlice("WinMainCRTStartup", ip)) flags.winmain_crt_startup = true;
1216 if (exp.opts.name.eqlSlice("wWinMainCRTStartup", ip)) flags.wwinmain_crt_startup = true;
1217 if (exp.opts.name.eqlSlice("DllMainCRTStartup", ip)) flags.dllmain_crt_startup = true;
1218 if (exp.opts.name.eqlSlice("_DllMainCRTStartup", ip)) flags.dllmain_crt_startup = true;
1219 }
1220
1221 // If the export specifies a linksection, set the exported variable's section to that one.
1222 // This is kind of a hack because `std.lang.ExportOptions.section` doesn't actually make
1223 // much sense: the linksection should be associated with the declaration itself rather than
1224 // some particular symbol it is exported as!
1225 if (exp.opts.section.toSlice(ip)) |section_slice| {
1226 const variable = &llvm_global.ptrConst(&o.builder).kind.variable;
1227 variable.setSection(try o.builder.string(section_slice), &o.builder);
1228 }
1229
1230 const arch = comp.root_mod.resolved_target.result.cpu.arch;
1231 const workaround_alias_bugs = arch == .amdgcn or arch == .nvptx or arch == .nvptx64;
1232
1233 const llvm_global_ty = llvm_global.typeOf(&o.builder);
1234
1235 // All exports are represented as aliases to the original global.
1236
1237 // TODO: we currently do not delete old exports. To do that we'll need to track which
1238 // globals actually *are* exports.
1239
1240 const exp_name = try o.builder.strtabString(exp.opts.name.toSlice(ip));
1241
1242 // Our goal is to make an alias with the name `exp_name`, but if that name is already
1243 // taken by some existing global, we need to figure out what to do with that existing
1244 // global.
1245 //
1246 // The name, aliasee, and type will be set within this block. Other properties of the
1247 // alias will be set below.
1248 const alias_global: Builder.Global.Index = global: {
1249
1250 // WORKAROUND (see https://github.com/llvm/llvm-project/issues/213504, https://github.com/llvm/llvm-project/issues/214835)
1251 // For NVPTX, LLVM throws "NVPTX aliasee must be a non-kernel function definition" if we try to alias a kernel
1252 // On AMDGCN, LLVM does not generate an alias for the kernel descriptor symbol on associated functions
1253 // To solve these, we rename the global
1254 if (workaround_alias_bugs) {
1255 try llvm_global.rename(exp_name, &o.builder);
1256 break :global llvm_global;
1257 }
1258
1259 const existing_global = o.builder.getGlobal(exp_name) orelse {
1260 // There is no existing global with this name, so make a new alias.
1261 const alias = try o.builder.addAlias(
1262 exp_name,
1263 llvm_global_ty,
1264 llvm_global.ptrConst(&o.builder).addr_space,
1265 llvm_global.toConst(),
1266 );
1267 break :global alias.ptrConst(&o.builder).global;
1268 };
1269 // There is an existing global with this name, so we can't just create an alias. We
1270 // need to figure out what to do with the existing global instead.
1271 switch (existing_global.ptrConst(&o.builder).kind) {
1272 .alias => |alias| {
1273 // We can just repurpose the existing alias.
1274 alias.setAliasee(llvm_global.toConst(), &o.builder);
1275 alias.ptrConst(&o.builder).global.ptr(&o.builder).type = llvm_global.typeOf(&o.builder);
1276 alias.ptrConst(&o.builder).global.ptr(&o.builder).addr_space = llvm_global.ptrConst(&o.builder).addr_space;
1277 break :global existing_global;
1278 },
1279 .variable, .function => {
1280 // This must be an extern, which is no good to us---we need an alias. The
1281 // extern should refer to the value we're exporting, so replace it with the
1282 // exported value. That will free up the name for us to create a new alias.
1283 // We need to make a new global which is an alias. Replace this existing one
1284 // with the target global, making the name available and fixing references
1285 // to this global to point to the target.
1286 try existing_global.replace(llvm_global, &o.builder);
1287 // The name is now free, so create an alias.
1288 const alias = try o.builder.addAlias(
1289 exp_name,
1290 llvm_global_ty,
1291 llvm_global.ptrConst(&o.builder).addr_space,
1292 llvm_global.toConst(),
1293 );
1294 break :global alias.ptrConst(&o.builder).global;
1295 },
1296 .replaced => unreachable, // a replaced global would have lost the name `exp_name`
1297 }
1298 };
1299
1300 // We need the alias to *not* be `unnamed_addr` to ensure that the alias address equals
1301 // the address of the original global.
1302 alias_global.setUnnamedAddr(.default, &o.builder);
1303
1304 if (comp.config.dll_export_fns and exp.opts.visibility != .hidden)
1305 alias_global.setDllStorageClass(.dllexport, &o.builder);
1306 alias_global.setLinkage(switch (exp.opts.linkage) {
1307 .internal => if (o.builder.strip) .private else .internal, // we still did useful work in replacing an existing symbol if there was one
1308 .strong => .external,
1309 .weak => .weak_odr,
1310 .link_once => .linkonce_odr,
1311 }, &o.builder);
1312 alias_global.setVisibility(switch (exp.opts.visibility) {
1313 .default => .default,
1314 .hidden => .hidden,
1315 .protected => .protected,
1316 }, &o.builder);
1317 }
1318
1319 pub fn updateContainerType(o: *Object, pt: Zcu.PerThread, ty: InternPool.Index, success: bool) link.Error!void {
1320 _ = o.type_map.remove(ty);
1321 try o.type_pool.updateContainerType(pt, .{ .llvm = o }, ty, success);
1322 if (o.named_enum_map.get(ty)) |llvm_function| {
1323 try o.updateIsNamedEnumValueFunction(.fromInterned(ty), llvm_function);
1324 }
1325 if (o.enum_tag_name_map.get(ty)) |llvm_function| {
1326 try o.updateEnumTagNameFunction(.fromInterned(ty), llvm_function);
1327 }
1328 }
1329
1330 /// Should only be called by the `link.ConstPool` implementation.
1331 ///
1332 /// `val` is always a type because `o.type_pool` only contains types.
1333 pub fn addConst(o: *Object, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) Allocator.Error!void {
1334 _ = pt;
1335 const zcu = o.zcu;
1336 const gpa = zcu.comp.gpa;
1337 assert(zcu.intern_pool.typeOf(val) == .type_type);
1338
1339 {
1340 assert(@backingInt(index) == o.lazy_abi_aligns.items.len);
1341 try o.lazy_abi_aligns.ensureUnusedCapacity(gpa, 1);
1342 const fwd_ref = try o.builder.alignmentForwardReference();
1343 o.lazy_abi_aligns.appendAssumeCapacity(fwd_ref);
1344 }
1345
1346 if (!o.builder.strip) {
1347 assert(@backingInt(index) == o.debug_types.items.len);
1348 try o.debug_types.ensureUnusedCapacity(gpa, 1);
1349 const fwd_ref = try o.builder.debugForwardReference();
1350 o.debug_types.appendAssumeCapacity(fwd_ref);
1351 if (val == .anyerror_type) {
1352 assert(o.debug_anyerror_fwd_ref.is_none);
1353 o.debug_anyerror_fwd_ref = fwd_ref.toOptional();
1354 }
1355 }
1356 }
1357 /// Should only be called by the `link.ConstPool` implementation.
1358 ///
1359 /// `val` is always a type because `o.type_pool` only contains types.
1360 pub fn updateConstIncomplete(o: *Object, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) Allocator.Error!void {
1361 const zcu = o.zcu;
1362 assert(zcu.intern_pool.typeOf(val) == .type_type);
1363
1364 const ty: Type = .fromInterned(val);
1365
1366 {
1367 const fwd_ref = o.lazy_abi_aligns.items[@backingInt(index)];
1368 o.builder.resolveAlignmentForwardReference(fwd_ref, .fromByteUnits(1));
1369 }
1370
1371 if (!o.builder.strip) {
1372 assert(val != .anyerror_type);
1373 const fwd_ref = o.debug_types.items[@backingInt(index)];
1374 const name_str = try o.builder.metadataStringFmt("{f}", .{ty.fmt(pt)});
1375 // If `ty` is a function, use a dummy *function* type to prevent existing debug
1376 // subprograms from becoming ill-formed.
1377 const debug_incomplete_type = switch (ty.zigTypeTag(zcu)) {
1378 .@"fn" => try o.builder.debugSubroutineType(null),
1379 else => try o.builder.debugSignedType(name_str, 0),
1380 };
1381 o.builder.resolveDebugForwardReference(fwd_ref, debug_incomplete_type);
1382 }
1383 }
1384 /// Should only be called by the `link.ConstPool` implementation.
1385 ///
1386 /// `val` is always a type because `o.type_pool` only contains types.
1387 pub fn updateConst(o: *Object, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) Allocator.Error!void {
1388 const zcu = o.zcu;
1389 assert(zcu.intern_pool.typeOf(val) == .type_type);
1390
1391 const ty: Type = .fromInterned(val);
1392
1393 {
1394 const fwd_ref = o.lazy_abi_aligns.items[@backingInt(index)];
1395 o.builder.resolveAlignmentForwardReference(fwd_ref, ty.abiAlignment(zcu).toLlvm());
1396 }
1397
1398 if (!o.builder.strip) {
1399 const fwd_ref = o.debug_types.items[@backingInt(index)];
1400 if (val == .anyerror_type) {
1401 // Don't lower this now; it will be populated in `emit` instead.
1402 assert(o.debug_anyerror_fwd_ref == fwd_ref.toOptional());
1403 } else {
1404 const debug_type = try o.lowerDebugType(pt, ty, fwd_ref);
1405 o.builder.resolveDebugForwardReference(fwd_ref, debug_type);
1406 }
1407 }
1408 }
1409
1410 pub fn getDebugFile(o: *Object, file_index: Zcu.File.Index) Allocator.Error!Builder.Metadata {
1411 const gpa = o.gpa;
1412 const gop = try o.debug_file_map.getOrPut(gpa, file_index);
1413 errdefer assert(o.debug_file_map.remove(file_index));
1414 if (gop.found_existing) return gop.value_ptr.*;
1415
1416 const dirs = o.zcu.comp.dirs;
1417 const path = o.zcu.fileByIndex(file_index).path;
1418 const root_path: ?[]const u8 = switch (path.root) {
1419 .zig_lib => dirs.zig_lib.path,
1420 .global_cache => dirs.global_cache.path,
1421 .local_cache => dirs.local_cache.path,
1422 .build_root => dirs.build_root.path,
1423 .none => null,
1424 };
1425
1426 const file = if (root_path) |root|
1427 try o.builder.debugFile(
1428 try o.builder.metadataString(path.sub_path),
1429 try o.builder.metadataString(root),
1430 )
1431 else blk: {
1432 const relative = try std.fs.path.relative(gpa, dirs.cwd, null, dirs.cwd, path.sub_path);
1433 defer gpa.free(relative);
1434 break :blk try o.builder.debugFile(
1435 try o.builder.metadataString(relative),
1436 try o.builder.metadataString(dirs.cwd),
1437 );
1438 };
1439
1440 gop.value_ptr.* = file;
1441 return file;
1442 }
1443
1444 pub fn getDebugType(o: *Object, pt: Zcu.PerThread, ty: Type) Allocator.Error!Builder.Metadata {
1445 assert(!o.builder.strip);
1446 const index = o.type_pool.get(pt, .{ .llvm = o }, ty.toIntern()) catch |err| return @errorCast(err);
1447 return o.debug_types.items[@backingInt(index)];
1448 }
1449
1450 /// In codegen logic, instead of calling this directly, use `getDebugType` to get a forward
1451 /// reference which will be populated only when all necessary type resolution is complete.
1452 fn lowerDebugType(
1453 o: *Object,
1454 pt: Zcu.PerThread,
1455 ty: Type,
1456 ty_fwd_ref: Builder.Metadata,
1457 ) Allocator.Error!Builder.Metadata {
1458 assert(!o.builder.strip);
1459
1460 const gpa = o.gpa;
1461 const zcu = o.zcu;
1462 const target = zcu.getTarget();
1463 const ip = &zcu.intern_pool;
1464
1465 const name = try o.builder.metadataStringFmt("{f}", .{ty.fmt(pt)});
1466
1467 // lldb cannot handle non-byte-sized types, so in the logic below, bit sizes are padded up.
1468 // For instance, `bool` is considered to be 8 bits, and `u60` is considered to be 64 bits.
1469
1470 // I tried using variants (DW_TAG_variant_part + DW_TAG_variant) to encode error unions,
1471 // tagged unions, etc; this would have told debuggers which field was active, which could
1472 // improve UX significantly. GDB handles this perfectly fine, but unfortunately, LLDB has no
1473 // handling for variants at all, and will never print fields in them, so I opted not to use
1474 // them for now.
1475
1476 switch (ty.zigTypeTag(zcu)) {
1477 .void,
1478 .noreturn,
1479 .comptime_int,
1480 .comptime_float,
1481 .type,
1482 .undefined,
1483 .null,
1484 .enum_literal,
1485 => return o.builder.debugSignedType(name, 0),
1486
1487 .float => return o.builder.debugFloatType(name, ty.floatBits(target)),
1488
1489 .bool => return o.builder.debugBoolType(name, 8),
1490
1491 .int => {
1492 const info = ty.intInfo(zcu);
1493 const bits = ty.abiSize(zcu) * 8;
1494 return switch (info.signedness) {
1495 .signed => try o.builder.debugSignedType(name, bits),
1496 .unsigned => try o.builder.debugUnsignedType(name, bits),
1497 };
1498 },
1499
1500 .pointer => {
1501 const ptr_size = Type.ptrAbiSize(zcu.getTarget());
1502 const ptr_align = Type.ptrAbiAlignment(zcu.getTarget());
1503
1504 if (ty.isSlice(zcu)) {
1505 const debug_ptr_type = try o.builder.debugMemberType(
1506 try o.builder.metadataString("ptr"),
1507 null, // file
1508 ty_fwd_ref,
1509 0, // line
1510 try o.getDebugType(pt, ty.slicePtrFieldType(zcu)),
1511 ptr_size * 8,
1512 ptr_align.toByteUnits().? * 8,
1513 0, // offset
1514 );
1515
1516 const debug_len_type = try o.builder.debugMemberType(
1517 try o.builder.metadataString("len"),
1518 null, // file
1519 ty_fwd_ref,
1520 0, // line
1521 try o.getDebugType(pt, .usize),
1522 ptr_size * 8,
1523 ptr_align.toByteUnits().? * 8,
1524 ptr_size * 8,
1525 );
1526
1527 return o.builder.debugStructType(
1528 name,
1529 null, // file
1530 o.debug_compile_unit.unwrap().?, // scope
1531 0, // line
1532 null, // underlying type
1533 ptr_size * 2 * 8,
1534 ptr_align.toByteUnits().? * 8,
1535 try o.builder.metadataTuple(&.{
1536 debug_ptr_type,
1537 debug_len_type,
1538 }),
1539 );
1540 }
1541
1542 return o.builder.debugPointerType(
1543 name,
1544 null, // file
1545 o.debug_compile_unit.unwrap().?, // scope
1546 0, // line
1547 try o.getDebugType(pt, ty.childType(zcu)),
1548 ptr_size * 8,
1549 ptr_align.toByteUnits().? * 8,
1550 0, // offset
1551 );
1552 },
1553 .array => return o.builder.debugArrayType(
1554 name,
1555 null, // file
1556 o.debug_compile_unit.unwrap().?, // scope
1557 0, // line
1558 try o.getDebugType(pt, ty.childType(zcu)),
1559 ty.abiSize(zcu) * 8,
1560 ty.abiAlignment(zcu).toByteUnits().? * 8,
1561 try o.builder.metadataTuple(&.{
1562 try o.builder.debugSubrange(
1563 try o.builder.metadataConstant(try o.builder.intConst(.i64, 0)),
1564 try o.builder.metadataConstant(try o.builder.intConst(.i64, ty.arrayLen(zcu))),
1565 ),
1566 }),
1567 ),
1568 .vector => {
1569 const elem_ty = ty.childType(zcu);
1570 // Vector elements cannot be padded since that would make
1571 // @bitSizeOf(elem) * len > @bitSizOf(vec).
1572 // Neither gdb nor lldb seem to be able to display non-byte sized
1573 // vectors properly.
1574 const debug_elem_type = switch (elem_ty.zigTypeTag(zcu)) {
1575 .int => blk: {
1576 const info = elem_ty.intInfo(zcu);
1577 break :blk switch (info.signedness) {
1578 .signed => try o.builder.debugSignedType(name, info.bits),
1579 .unsigned => try o.builder.debugUnsignedType(name, info.bits),
1580 };
1581 },
1582 .bool => try o.builder.debugBoolType(try o.builder.metadataString("bool"), 1),
1583 // We don't pad pointers or floats, so we can lower those normally.
1584 .pointer, .optional, .float => try o.getDebugType(pt, elem_ty),
1585 else => unreachable,
1586 };
1587
1588 return o.builder.debugVectorType(
1589 name,
1590 null, // file
1591 o.debug_compile_unit.unwrap().?, // scope
1592 0, // line
1593 debug_elem_type,
1594 ty.abiSize(zcu) * 8,
1595 ty.abiAlignment(zcu).toByteUnits().? * 8,
1596 try o.builder.metadataTuple(&.{
1597 try o.builder.debugSubrange(
1598 try o.builder.metadataConstant(try o.builder.intConst(.i64, 0)),
1599 try o.builder.metadataConstant(try o.builder.intConst(.i64, ty.vectorLen(zcu))),
1600 ),
1601 }),
1602 );
1603 },
1604 .optional => {
1605 const payload_ty = ty.optionalChild(zcu);
1606 if (ty.optionalReprIsPayload(zcu)) {
1607 return o.builder.debugTypedefType(
1608 name,
1609 null, // file
1610 o.debug_compile_unit.unwrap().?, // scope
1611 0, // line
1612 try o.getDebugType(pt, payload_ty),
1613 ty.abiSize(zcu) * 8,
1614 ty.abiAlignment(zcu).toByteUnits().? * 8,
1615 0, // offset
1616 );
1617 }
1618
1619 const payload_size = payload_ty.abiSize(zcu);
1620
1621 const non_null_ty = Type.u8;
1622 const non_null_size = non_null_ty.abiSize(zcu);
1623 const non_null_align = non_null_ty.abiAlignment(zcu);
1624 const non_null_offset = non_null_align.forward(payload_size);
1625
1626 const debug_payload_type = try o.builder.debugMemberType(
1627 try o.builder.metadataString("payload"),
1628 null, // file
1629 ty_fwd_ref, // scope
1630 0, // line
1631 try o.getDebugType(pt, payload_ty),
1632 payload_size * 8,
1633 payload_ty.abiAlignment(zcu).toByteUnits().? * 8,
1634 0, // offset
1635 );
1636
1637 const debug_some_type = try o.builder.debugMemberType(
1638 try o.builder.metadataString("some"),
1639 null,
1640 ty_fwd_ref,
1641 0,
1642 try o.getDebugType(pt, non_null_ty),
1643 non_null_size * 8,
1644 non_null_align.toByteUnits().? * 8,
1645 non_null_offset * 8,
1646 );
1647
1648 return o.builder.debugStructType(
1649 name,
1650 null, // file
1651 o.debug_compile_unit.unwrap().?, // scope
1652 0, // line
1653 null, // underlying type
1654 ty.abiSize(zcu) * 8,
1655 ty.abiAlignment(zcu).toByteUnits().? * 8,
1656 try o.builder.metadataTuple(&.{
1657 debug_payload_type,
1658 debug_some_type,
1659 }),
1660 );
1661 },
1662 .error_union => {
1663 const error_ty = ty.errorUnionSet(zcu);
1664 const payload_ty = ty.errorUnionPayload(zcu);
1665
1666 const error_size = error_ty.abiSize(zcu);
1667 const error_align = error_ty.abiAlignment(zcu);
1668 const payload_size = payload_ty.abiSize(zcu);
1669 const payload_align = payload_ty.abiAlignment(zcu);
1670
1671 const error_offset: u64, const payload_offset: u64 = offsets: {
1672 if (error_align.compare(.gt, payload_align)) {
1673 break :offsets .{ 0, payload_align.forward(error_size) };
1674 } else {
1675 break :offsets .{ error_align.forward(payload_size), 0 };
1676 }
1677 };
1678
1679 const error_field = try o.builder.debugMemberType(
1680 try o.builder.metadataString("error"),
1681 null, // file
1682 ty_fwd_ref,
1683 0, // line
1684 try o.getDebugType(pt, error_ty),
1685 error_size * 8,
1686 error_align.toByteUnits().? * 8,
1687 error_offset * 8,
1688 );
1689 const payload_field = try o.builder.debugMemberType(
1690 try o.builder.metadataString("payload"),
1691 null, // file
1692 ty_fwd_ref, // scope
1693 0, // line
1694 try o.getDebugType(pt, payload_ty),
1695 payload_size * 8,
1696 payload_align.toByteUnits().? * 8,
1697 payload_offset * 8,
1698 );
1699
1700 return o.builder.debugStructType(
1701 name,
1702 null, // File
1703 o.debug_compile_unit.unwrap().?, // Scope
1704 0, // Line
1705 null, // Underlying type
1706 ty.abiSize(zcu) * 8,
1707 ty.abiAlignment(zcu).toByteUnits().? * 8,
1708 try o.builder.metadataTuple(&.{ error_field, payload_field }),
1709 );
1710 },
1711 .error_set => {
1712 assert(ty.toIntern() != .anyerror_type); // handled specially in `updateConst`; will be populated by `emit` instead
1713 // Error sets are just named wrappers around `anyerror`.
1714 return o.builder.debugTypedefType(
1715 name,
1716 null, // file
1717 o.debug_compile_unit.unwrap().?, // scope
1718 0, // line
1719 try o.getDebugType(pt, .anyerror),
1720 ty.abiSize(zcu) * 8,
1721 ty.abiAlignment(zcu).toByteUnits().? * 8,
1722 0, // offset
1723 );
1724 },
1725 .@"fn" => {
1726 if (!ty.fnHasRuntimeBits(zcu)) {
1727 // Use a dummy *function* type to prevent existing debug subprograms from
1728 // becoming ill-formed.
1729 return o.builder.debugSubroutineType(null);
1730 }
1731
1732 const fn_info = zcu.typeToFunc(ty).?;
1733
1734 var debug_param_types: std.ArrayList(Builder.Metadata) = try .initCapacity(gpa, 3 + fn_info.param_types.len);
1735 defer debug_param_types.deinit(gpa);
1736
1737 // Return type goes first.
1738 if (try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type)) == .sret) {
1739 // Actual return type is void, then first arg is the sret pointer.
1740 const ptr_ty = try pt.singleMutPtrType(.fromInterned(fn_info.return_type));
1741 debug_param_types.appendAssumeCapacity(try o.getDebugType(pt, .void));
1742 debug_param_types.appendAssumeCapacity(try o.getDebugType(pt, ptr_ty));
1743 } else {
1744 const ret_ty: Type = .fromInterned(fn_info.return_type);
1745 debug_param_types.appendAssumeCapacity(try o.getDebugType(pt, ret_ty));
1746 }
1747
1748 if (fn_info.cc == .auto and zcu.comp.config.any_error_tracing) {
1749 // Stack trace pointer.
1750 debug_param_types.appendAssumeCapacity(try o.getDebugType(pt, .ptr_usize));
1751 }
1752
1753 for (fn_info.param_types.get(ip)) |param_ty_ip| {
1754 const param_ty: Type = .fromInterned(param_ty_ip);
1755 if (!param_ty.hasRuntimeBits(zcu)) continue;
1756 if (isByRef(param_ty, zcu)) {
1757 const ptr_ty = try pt.singleConstPtrType(param_ty);
1758 debug_param_types.appendAssumeCapacity(try o.getDebugType(pt, ptr_ty));
1759 } else {
1760 debug_param_types.appendAssumeCapacity(try o.getDebugType(pt, param_ty));
1761 }
1762 }
1763
1764 return o.builder.debugSubroutineType(
1765 try o.builder.metadataTuple(debug_param_types.items),
1766 );
1767 },
1768 .@"struct" => {
1769 if (ty.isTuple(zcu)) {
1770 const tuple = ip.indexToKey(ty.toIntern()).tuple_type;
1771 var fields: std.ArrayList(Builder.Metadata) = .empty;
1772 defer fields.deinit(gpa);
1773
1774 try fields.ensureUnusedCapacity(gpa, tuple.types.len);
1775
1776 comptime assert(struct_layout_version == 2);
1777 var offset: u64 = 0;
1778
1779 for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty_ip, field_val, i| {
1780 const field_ty: Type = .fromInterned(field_ty_ip);
1781 if (field_val != .none or !field_ty.hasRuntimeBits(zcu)) continue;
1782
1783 const field_size = field_ty.abiSize(zcu);
1784 const field_align = field_ty.abiAlignment(zcu);
1785 const field_offset = field_align.forward(offset);
1786 offset = field_offset + field_size;
1787
1788 fields.appendAssumeCapacity(try o.builder.debugMemberType(
1789 try o.builder.metadataStringFmt("{d}", .{i}),
1790 null, // file
1791 ty_fwd_ref,
1792 0, // line
1793 try o.getDebugType(pt, field_ty),
1794 field_size * 8,
1795 field_align.toByteUnits().? * 8,
1796 field_offset * 8,
1797 ));
1798 }
1799
1800 return o.builder.debugStructType(
1801 name,
1802 null, // file
1803 o.debug_compile_unit.unwrap().?,
1804 0, // line
1805 null, // underlying type
1806 ty.abiSize(zcu) * 8,
1807 (ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
1808 try o.builder.metadataTuple(fields.items),
1809 );
1810 }
1811
1812 const struct_type = zcu.typeToStruct(ty).?;
1813
1814 const file = try o.getDebugFile(struct_type.zir_index.resolveFile(ip));
1815 const scope = if (ty.getParentNamespace(zcu).unwrap()) |parent_namespace|
1816 try o.namespaceToDebugScope(pt, parent_namespace)
1817 else
1818 file;
1819
1820 const line = ty.typeDeclSrcLine(zcu).? + 1;
1821
1822 var fields: std.ArrayList(Builder.Metadata) = .empty;
1823 defer fields.deinit(gpa);
1824
1825 switch (struct_type.layout) {
1826 .@"packed" => {
1827 try fields.ensureTotalCapacityPrecise(gpa, 1);
1828 fields.appendAssumeCapacity(try o.builder.debugMemberType(
1829 try o.builder.metadataString("bits"),
1830 null, // file
1831 ty_fwd_ref,
1832 0, // line
1833 try o.getDebugType(pt, .fromInterned(struct_type.packed_backing_int_type)),
1834 ty.abiSize(zcu) * 8,
1835 ty.abiAlignment(zcu).toByteUnits().? * 8,
1836 0, // offset
1837 ));
1838 },
1839 .auto, .@"extern" => {
1840 comptime assert(struct_layout_version == 2);
1841 try fields.ensureTotalCapacityPrecise(gpa, struct_type.field_types.len);
1842 var it = struct_type.iterateRuntimeOrder(ip);
1843 while (it.next()) |field_index| {
1844 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);
1845 if (!field_ty.hasRuntimeBits(zcu)) continue;
1846 const field_size = field_ty.abiSize(zcu);
1847 const field_align = switch (ty.explicitFieldAlignment(field_index, zcu)) {
1848 .none => field_ty.abiAlignment(zcu),
1849 else => |a| a,
1850 };
1851 const field_offset = struct_type.field_offsets.get(ip)[field_index];
1852 const field_name = struct_type.field_names.get(ip)[field_index];
1853 fields.appendAssumeCapacity(try o.builder.debugMemberType(
1854 try o.builder.metadataString(field_name.toSlice(ip)),
1855 null, // file
1856 ty_fwd_ref,
1857 0, // line
1858 try o.getDebugType(pt, field_ty),
1859 field_size * 8,
1860 field_align.toByteUnits().? * 8,
1861 field_offset * 8,
1862 ));
1863 }
1864 },
1865 }
1866
1867 return o.builder.debugStructType(
1868 name,
1869 file,
1870 scope,
1871 line,
1872 null, // underlying type
1873 ty.abiSize(zcu) * 8,
1874 ty.abiAlignment(zcu).toByteUnits().? * 8,
1875 try o.builder.metadataTuple(fields.items),
1876 );
1877 },
1878 .@"union" => {
1879 const union_type = ip.loadUnionType(ty.toIntern());
1880
1881 const file = try o.getDebugFile(union_type.zir_index.resolveFile(ip));
1882 const scope = if (ty.getParentNamespace(zcu).unwrap()) |parent_namespace|
1883 try o.namespaceToDebugScope(pt, parent_namespace)
1884 else
1885 file;
1886
1887 const line = ty.typeDeclSrcLine(zcu).? + 1;
1888
1889 const enum_tag_ty: Type = .fromInterned(union_type.enum_tag_type);
1890
1891 if (union_type.layout == .@"packed") {
1892 const bitpack_field = try o.builder.debugMemberType(
1893 try o.builder.metadataString("bits"),
1894 null, // file
1895 ty_fwd_ref,
1896 0, // line
1897 try o.getDebugType(pt, .fromInterned(union_type.packed_backing_int_type)),
1898 ty.abiSize(zcu) * 8,
1899 ty.abiAlignment(zcu).toByteUnits().? * 8,
1900 0, // offset
1901 );
1902 return o.builder.debugStructType(
1903 name,
1904 file,
1905 scope,
1906 line,
1907 null, // underlying type
1908 ty.abiSize(zcu) * 8,
1909 ty.abiAlignment(zcu).toByteUnits().? * 8,
1910 try o.builder.metadataTuple(&.{bitpack_field}),
1911 );
1912 }
1913
1914 const layout = Type.getUnionLayout(union_type, zcu);
1915
1916 if (layout.payload_size == 0) {
1917 const fields_tuple: ?Builder.Metadata = fields: {
1918 if (layout.tag_size == 0) break :fields null;
1919 break :fields try o.builder.metadataTuple(&.{
1920 try o.builder.debugMemberType(
1921 try o.builder.metadataString("tag"),
1922 null, // file
1923 ty_fwd_ref,
1924 0, // line
1925 try o.getDebugType(pt, enum_tag_ty),
1926 layout.tag_size * 8,
1927 layout.tag_align.toByteUnits().? * 8,
1928 0, // offset
1929 ),
1930 });
1931 };
1932 return o.builder.debugStructType(
1933 name,
1934 file,
1935 scope,
1936 line,
1937 null, // underlying type
1938 ty.abiSize(zcu) * 8,
1939 ty.abiAlignment(zcu).toByteUnits().? * 8,
1940 fields_tuple,
1941 );
1942 }
1943
1944 var fields: std.ArrayList(Builder.Metadata) = try .initCapacity(gpa, union_type.field_types.len);
1945 defer fields.deinit(gpa);
1946
1947 const payload_fwd_ref = if (layout.tag_size == 0)
1948 ty_fwd_ref
1949 else
1950 try o.builder.debugForwardReference();
1951
1952 for (0..union_type.field_types.len) |field_index| {
1953 const field_ty = union_type.field_types.get(ip)[field_index];
1954
1955 const field_size = Type.fromInterned(field_ty).abiSize(zcu);
1956 const field_align: InternPool.Alignment = ty.explicitFieldAlignment(field_index, zcu);
1957
1958 const field_name = enum_tag_ty.enumFieldName(field_index, zcu);
1959 fields.appendAssumeCapacity(try o.builder.debugMemberType(
1960 try o.builder.metadataString(field_name.toSlice(ip)),
1961 null, // file
1962 payload_fwd_ref,
1963 0, // line
1964 try o.getDebugType(pt, .fromInterned(field_ty)),
1965 field_size * 8,
1966 (field_align.toByteUnits() orelse 0) * 8,
1967 0, // offset
1968 ));
1969 }
1970
1971 const debug_payload_type = try o.builder.debugUnionType(
1972 payload_name: {
1973 if (layout.tag_size == 0) break :payload_name name;
1974 break :payload_name try o.builder.metadataStringFmt("{f}:Payload", .{ty.fmt(pt)});
1975 },
1976 file,
1977 scope,
1978 line,
1979 null, // underlying type
1980 layout.payload_size * 8,
1981 ty.abiAlignment(zcu).toByteUnits().? * 8,
1982 try o.builder.metadataTuple(fields.items),
1983 );
1984
1985 if (layout.tag_size == 0) {
1986 return debug_payload_type;
1987 }
1988
1989 o.builder.resolveDebugForwardReference(payload_fwd_ref, debug_payload_type);
1990
1991 const tag_offset: u64, const payload_offset: u64 = offsets: {
1992 if (layout.tag_align.compare(.gte, layout.payload_align)) {
1993 break :offsets .{ 0, layout.payload_align.forward(layout.tag_size) };
1994 } else {
1995 break :offsets .{ layout.tag_align.forward(layout.payload_size), 0 };
1996 }
1997 };
1998
1999 const tag_member_type = try o.builder.debugMemberType(
2000 try o.builder.metadataString("tag"),
2001 null, // file
2002 ty_fwd_ref,
2003 0, // line
2004 try o.getDebugType(pt, enum_tag_ty),
2005 layout.tag_size * 8,
2006 layout.tag_align.toByteUnits().? * 8,
2007 tag_offset * 8,
2008 );
2009
2010 const payload_member_type = try o.builder.debugMemberType(
2011 try o.builder.metadataString("payload"),
2012 null, // file
2013 ty_fwd_ref,
2014 0, // line
2015 debug_payload_type,
2016 layout.payload_size * 8,
2017 layout.payload_align.toByteUnits().? * 8,
2018 payload_offset * 8,
2019 );
2020
2021 const full_fields: [2]Builder.Metadata =
2022 if (layout.tag_align.compare(.gte, layout.payload_align))
2023 .{ tag_member_type, payload_member_type }
2024 else
2025 .{ payload_member_type, tag_member_type };
2026
2027 return o.builder.debugStructType(
2028 name,
2029 file,
2030 scope,
2031 line,
2032 null, // underlying type
2033 ty.abiSize(zcu) * 8,
2034 ty.abiAlignment(zcu).toByteUnits().? * 8,
2035 try o.builder.metadataTuple(&full_fields),
2036 );
2037 },
2038 .@"enum" => {
2039 const file = try o.getDebugFile(ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(ip));
2040 const scope = if (ty.getParentNamespace(zcu).unwrap()) |parent_namespace|
2041 try o.namespaceToDebugScope(pt, parent_namespace)
2042 else
2043 file;
2044
2045 const line = ty.typeDeclSrcLine(zcu).? + 1;
2046
2047 if (!ty.hasRuntimeBits(zcu)) {
2048 return o.builder.debugStructType(
2049 name,
2050 file,
2051 scope,
2052 line,
2053 null, // underlying type
2054 ty.abiSize(zcu) * 8,
2055 ty.abiAlignment(zcu).toByteUnits().? * 8,
2056 null, // fields
2057 );
2058 }
2059
2060 const enum_type = ip.loadEnumType(ty.toIntern());
2061 const enumerators = try gpa.alloc(Builder.Metadata, enum_type.field_names.len);
2062 defer gpa.free(enumerators);
2063
2064 const int_ty: Type = .fromInterned(enum_type.int_tag_type);
2065 const int_info = ty.intInfo(zcu);
2066 assert(int_info.bits != 0);
2067
2068 for (enumerators, enum_type.field_names.get(ip), 0..) |*out, field_name, field_index| {
2069 var space: Value.BigIntSpace = undefined;
2070 const field_val: std.math.big.int.Const = switch (enum_type.field_values.len) {
2071 0 => std.math.big.int.Mutable.init(&space.limbs, field_index).toConst(),
2072 else => Value.fromInterned(enum_type.field_values.get(ip)[field_index]).toBigInt(&space, zcu),
2073 };
2074 out.* = try o.builder.debugEnumerator(
2075 try o.builder.metadataString(field_name.toSlice(ip)),
2076 int_info.signedness == .unsigned,
2077 int_info.bits,
2078 field_val,
2079 );
2080 }
2081
2082 const debug_enum_type = try o.builder.debugEnumerationType(
2083 name,
2084 file,
2085 scope,
2086 line,
2087 try o.getDebugType(pt, int_ty),
2088 ty.abiSize(zcu) * 8,
2089 ty.abiAlignment(zcu).toByteUnits().? * 8,
2090 try o.builder.metadataTuple(enumerators),
2091 );
2092 try o.debug_enums.append(gpa, debug_enum_type);
2093 return debug_enum_type;
2094 },
2095 .@"opaque" => {
2096 if (ty.toIntern() == .anyopaque_type) {
2097 return o.builder.debugSignedType(name, 0);
2098 }
2099
2100 const file = try o.getDebugFile(ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(ip));
2101 const scope = if (ty.getParentNamespace(zcu).unwrap()) |parent_namespace|
2102 try o.namespaceToDebugScope(pt, parent_namespace)
2103 else
2104 file;
2105
2106 const line = ty.typeDeclSrcLine(zcu).? + 1;
2107
2108 return o.builder.debugStructType(
2109 name,
2110 file,
2111 scope,
2112 line,
2113 null, // underlying type
2114 0, // size
2115 ty.abiAlignment(zcu).toByteUnits().? * 8,
2116 null, // fields
2117 );
2118 },
2119 .frame => @panic("TODO implement lowerDebugType for Frame types"),
2120 .@"anyframe" => @panic("TODO implement lowerDebugType for AnyFrame types"),
2121 .spirv => unreachable,
2122 }
2123 }
2124
2125 /// Called in `emit` so that the global error set is fully populated.
2126 fn lowerDebugAnyerrorType(o: *Object) Allocator.Error!Builder.Metadata {
2127 const zcu = o.zcu;
2128 const ip = &zcu.intern_pool;
2129 const gpa = zcu.comp.gpa;
2130
2131 const error_set_bits = zcu.errorSetBits();
2132 const error_names = ip.global_error_set.getNamesFromMainThread();
2133
2134 const enumerators = try gpa.alloc(Builder.Metadata, error_names.len + 1);
2135 defer gpa.free(enumerators);
2136
2137 // The value 0 means "no error" in optionals and error unions.
2138 enumerators[0] = try o.builder.debugEnumerator(
2139 try o.builder.metadataString("null"),
2140 true, // unsigned,
2141 error_set_bits,
2142 .{ .limbs = &.{0}, .positive = true }, // zero
2143 );
2144
2145 for (enumerators[1..], error_names, 1..) |*out, error_name, error_value| {
2146 var space: Value.BigIntSpace = undefined;
2147 var bigint: std.math.big.int.Mutable = .init(&space.limbs, error_value);
2148 out.* = try o.builder.debugEnumerator(
2149 try o.builder.metadataStringFmt("error.{f}", .{error_name.fmtId(ip)}),
2150 true, // unsigned
2151 error_set_bits,
2152 bigint.toConst(),
2153 );
2154 }
2155
2156 const debug_enum_type = try o.builder.debugEnumerationType(
2157 try o.builder.metadataString("anyerror"),
2158 null, // file
2159 o.debug_compile_unit.unwrap().?, // scope
2160 0, // line
2161 try o.builder.debugUnsignedType(null, error_set_bits),
2162 Type.anyerror.abiSize(zcu) * 8,
2163 Type.anyerror.abiAlignment(zcu).toByteUnits().? * 8,
2164 try o.builder.metadataTuple(enumerators),
2165 );
2166 try o.debug_enums.append(gpa, debug_enum_type);
2167 return debug_enum_type;
2168 }
2169
2170 fn namespaceToDebugScope(o: *Object, pt: Zcu.PerThread, namespace_index: InternPool.NamespaceIndex) !Builder.Metadata {
2171 const zcu = o.zcu;
2172 const namespace = zcu.namespacePtr(namespace_index);
2173 if (namespace.parent == .none) return o.getDebugFile(namespace.file_scope);
2174 return o.getDebugType(pt, .fromInterned(namespace.owner_type));
2175 }
2176
2177 fn addCommonFnAttributes(
2178 o: *Object,
2179 attributes: *Builder.FunctionAttributes.Wip,
2180 owner_mod: *Module,
2181 omit_frame_pointer: bool,
2182 ) Allocator.Error!void {
2183 if (!owner_mod.red_zone) {
2184 try attributes.addFnAttr(.noredzone, &o.builder);
2185 }
2186 if (omit_frame_pointer) {
2187 try attributes.addFnAttr(.{ .string = .{
2188 .kind = try o.builder.string("frame-pointer"),
2189 .value = try o.builder.string("none"),
2190 } }, &o.builder);
2191 } else {
2192 try attributes.addFnAttr(.{ .string = .{
2193 .kind = try o.builder.string("frame-pointer"),
2194 .value = try o.builder.string("all"),
2195 } }, &o.builder);
2196 }
2197 try attributes.addFnAttr(.nounwind, &o.builder);
2198 if (owner_mod.unwind_tables != .none) {
2199 try attributes.addFnAttr(
2200 .{ .uwtable = if (owner_mod.unwind_tables == .async) .async else .sync },
2201 &o.builder,
2202 );
2203 }
2204 if (owner_mod.optimize_mode == .small) {
2205 try attributes.addFnAttr(.minsize, &o.builder);
2206 try attributes.addFnAttr(.optsize, &o.builder);
2207 }
2208 const target = &owner_mod.resolved_target.result;
2209 if (target.cpu.model.llvm_name) |s| {
2210 try attributes.addFnAttr(.{ .string = .{
2211 .kind = try o.builder.string("target-cpu"),
2212 .value = try o.builder.string(s),
2213 } }, &o.builder);
2214 }
2215 if (owner_mod.resolved_target.llvm_cpu_features) |s| {
2216 try attributes.addFnAttr(.{ .string = .{
2217 .kind = try o.builder.string("target-features"),
2218 .value = try o.builder.string(std.mem.span(s)),
2219 } }, &o.builder);
2220 }
2221 if (target.abi.float() == .soft) {
2222 // `use-soft-float` means "use software routines for floating point computations". In
2223 // other words, it configures how LLVM lowers basic float instructions like `fcmp`,
2224 // `fadd`, etc. The float calling convention is configured on `TargetMachine` and is
2225 // mostly an orthogonal concept, although obviously we do need hardware float operations
2226 // to actually be able to pass float values in float registers.
2227 //
2228 // Ideally, we would support something akin to the `-mfloat-abi=softfp` option that GCC
2229 // and Clang support for Arm32 and CSKY. We don't currently expose such an option in
2230 // Zig, and using CPU features as the source of truth for this makes for a miserable
2231 // user experience since people expect e.g. `arm-linux-gnueabi` to mean full soft float
2232 // unless the compiler has explicitly been told otherwise. (And note that our baseline
2233 // CPU models almost all include FPU features!)
2234 //
2235 // Revisit this at some point.
2236 try attributes.addFnAttr(.{ .string = .{
2237 .kind = try o.builder.string("use-soft-float"),
2238 .value = try o.builder.string("true"),
2239 } }, &o.builder);
2240
2241 // This prevents LLVM from using FPU/SIMD code for things like `memcpy`. As for the
2242 // above, this should be revisited if `softfp` support is added.
2243 try attributes.addFnAttr(.noimplicitfloat, &o.builder);
2244 }
2245
2246 // The frontend should eventually offer options to control these.
2247 if (target.cpu.arch.isAarch64() and target.os.tag == .openbsd) {
2248 try attributes.addFnAttr(.{ .string = .{
2249 .kind = try o.builder.string("branch-target-enforcement"),
2250 .value = try o.builder.string(""),
2251 } }, &o.builder);
2252 try attributes.addFnAttr(.{ .string = .{
2253 .kind = try o.builder.string("sign-return-address"),
2254 .value = try o.builder.string("non-leaf"),
2255 } }, &o.builder);
2256 try attributes.addFnAttr(.{ .string = .{
2257 .kind = try o.builder.string("sign-return-address-key"),
2258 .value = try o.builder.string("a_key"),
2259 } }, &o.builder);
2260 }
2261 }
2262
2263 pub fn addCallingConventionFnAttributes(
2264 o: *Object,
2265 pt: Zcu.PerThread,
2266 llvm_function: Builder.Function.Index,
2267 attributes: *Builder.FunctionAttributes.Wip,
2268 opt_extern: ?struct {
2269 name: []const u8,
2270 lib_name: ?[]const u8 = null,
2271 },
2272 fn_info: FuncInfo,
2273 ) Allocator.Error!void {
2274 const zcu = o.zcu;
2275 const target = zcu.getTarget();
2276
2277 if (fn_info.cc == .async) {
2278 @panic("TODO: LLVM backend lower async function");
2279 }
2280
2281 if (target.cpu.arch.isWasm()) if (opt_extern) |@"extern"| {
2282 try attributes.addFnAttr(.{ .string = .{
2283 .kind = try o.builder.string("wasm-import-name"),
2284 .value = try o.builder.string(@"extern".name),
2285 } }, &o.builder);
2286 if (@"extern".lib_name) |lib_name| {
2287 if (!std.mem.eql(u8, lib_name, "c")) try attributes.addFnAttr(.{ .string = .{
2288 .kind = try o.builder.string("wasm-import-module"),
2289 .value = try o.builder.string(lib_name),
2290 } }, &o.builder);
2291 }
2292 };
2293
2294 const cc_info = toLlvmCallConv(fn_info.cc, target).?;
2295
2296 llvm_function.setCallConv(cc_info.llvm_cc, &o.builder);
2297
2298 if (cc_info.align_stack) {
2299 try attributes.addFnAttr(.{ .string = .{ .kind = try o.builder.string("stackrealign"), .value = .empty } }, &o.builder);
2300 }
2301
2302 if (cc_info.naked) {
2303 try attributes.addFnAttr(.naked, &o.builder);
2304 }
2305
2306 switch (fn_info.cc) {
2307 inline .riscv64_interrupt,
2308 .riscv32_interrupt,
2309 .mips_interrupt,
2310 .mips64_interrupt,
2311 => |info| {
2312 try attributes.addFnAttr(.{ .string = .{
2313 .kind = try o.builder.string("interrupt"),
2314 .value = try o.builder.string(@tagName(info.mode)),
2315 } }, &o.builder);
2316 },
2317 .arm_interrupt,
2318 => |info| {
2319 try attributes.addFnAttr(.{ .string = .{
2320 .kind = try o.builder.string("interrupt"),
2321 .value = try o.builder.string(switch (info.type) {
2322 .generic => "",
2323 .irq => "IRQ",
2324 .fiq => "FIQ",
2325 .swi => "SWI",
2326 .abort => "ABORT",
2327 .undef => "UNDEF",
2328 }),
2329 } }, &o.builder);
2330 },
2331 // these function attributes serve as a backup against any mistakes LLVM makes.
2332 // clang sets both the function's calling convention and the function attributes
2333 // in its backend, so future patches to the AVR backend could end up checking only one,
2334 // possibly breaking our support. it's safer to just emit both.
2335 .avr_interrupt, .avr_signal, .csky_interrupt => {
2336 try attributes.addFnAttr(.{ .string = .{
2337 .kind = try o.builder.string(switch (fn_info.cc) {
2338 .avr_interrupt,
2339 .csky_interrupt,
2340 => "interrupt",
2341 .avr_signal => "signal",
2342 else => unreachable,
2343 }),
2344 .value = .empty,
2345 } }, &o.builder);
2346 },
2347 else => {},
2348 }
2349
2350 if (fn_info.return_type == .noreturn_type) try attributes.addFnAttr(.noreturn, &o.builder);
2351
2352 var it = iterateParamTypes(o, fn_info.cc, fn_info.param_types);
2353 if (try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type)) == .sret) {
2354 try o.addSRetFnAttributes(
2355 attributes,
2356 try o.lowerType(.fromInterned(fn_info.return_type), .in_memory),
2357 Type.fromInterned(fn_info.return_type).abiAlignment(zcu).toLlvm(),
2358 .declaration,
2359 );
2360 it.llvm_index += 1;
2361 } else if (ccAbiPromoteInt(fn_info.cc, zcu, Type.fromInterned(fn_info.return_type))) |s| switch (s) {
2362 .signed => try attributes.addRetAttr(.signext, &o.builder),
2363 .unsigned => try attributes.addRetAttr(.zeroext, &o.builder),
2364 };
2365
2366 const err_return_tracing = fn_info.cc == .auto and zcu.comp.config.any_error_tracing;
2367 if (err_return_tracing) {
2368 try attributes.addParamAttr(it.llvm_index, .nonnull, &o.builder);
2369 it.llvm_index += 1;
2370 }
2371
2372 var remaining_inreg_int = cc_info.inreg_int_params;
2373 var remaining_inreg_float = cc_info.inreg_float_params;
2374
2375 while (try it.next()) |lowering| switch (lowering) {
2376 .byval => {
2377 const param_index = it.zig_index - 1;
2378 const param_ty: Type = .fromInterned(fn_info.param_types[param_index]);
2379 if (!isByRef(param_ty, zcu)) {
2380 try o.addByValParamAttrs(pt, attributes, param_ty, param_index, fn_info, it.llvm_index - 1);
2381 }
2382
2383 if (remaining_inreg_int > 0 and
2384 (param_ty.isPtrAtRuntime(zcu) or
2385 (param_ty.isAbiInt(zcu) and param_ty.abiSize(zcu) <= Type.usize.abiSize(zcu))))
2386 {
2387 try attributes.addParamAttr(it.llvm_index - 1, .inreg, &o.builder);
2388 remaining_inreg_int -= 1;
2389 }
2390
2391 if (remaining_inreg_float > 0 and
2392 param_ty.zigTypeTag(zcu) == .float)
2393 {
2394 try attributes.addParamAttr(it.llvm_index - 1, .inreg, &o.builder);
2395 remaining_inreg_float -= 1;
2396 }
2397 },
2398 .byref => {
2399 const param_ty: Type = .fromInterned(fn_info.param_types[it.zig_index - 1]);
2400 try o.addByRefParamAttrs(attributes, it.llvm_index - 1, it.byval_attr, param_ty);
2401 },
2402 .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),
2403 .slice => {
2404 const param_ty: Type = .fromInterned(fn_info.param_types[it.zig_index - 1]);
2405 const ptr_info = param_ty.ptrInfo(zcu);
2406 const llvm_ptr_index = it.llvm_index - 2;
2407 if (std.math.cast(u5, it.zig_index - 1)) |i| {
2408 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
2409 try attributes.addParamAttr(llvm_ptr_index, .@"noalias", &o.builder);
2410 }
2411 }
2412 if (param_ty.zigTypeTag(zcu) != .optional and
2413 !ptr_info.flags.is_allowzero and
2414 ptr_info.flags.address_space == .generic)
2415 {
2416 try attributes.addParamAttr(llvm_ptr_index, .nonnull, &o.builder);
2417 }
2418 if (ptr_info.flags.is_const) {
2419 try attributes.addParamAttr(llvm_ptr_index, .readonly, &o.builder);
2420 }
2421 const elem_align: Builder.Alignment.Lazy = switch (ptr_info.flags.alignment) {
2422 else => |a| .wrap(a.toLlvm()),
2423 .none => try o.lazyAbiAlignment(pt, .fromInterned(ptr_info.child)),
2424 };
2425 try attributes.addParamAttr(llvm_ptr_index, .{ .@"align" = elem_align }, &o.builder);
2426 },
2427 // No attributes needed for these.
2428 .no_bits,
2429 .abi_sized_int,
2430 .multiple_llvm_types,
2431 .float_array,
2432 .i32_array,
2433 .i64_array,
2434 => continue,
2435 };
2436 }
2437
2438 pub fn addSRetFnAttributes(
2439 o: *Object,
2440 attributes: *Builder.FunctionAttributes.Wip,
2441 ret_ty: Builder.Type,
2442 ret_align: Builder.Alignment,
2443 location: enum { declaration, callsite },
2444 ) Allocator.Error!void {
2445 try attributes.addParamAttr(0, .dead_on_unwind, &o.builder);
2446 switch (location) {
2447 .declaration => try attributes.addParamAttr(0, .@"noalias", &o.builder),
2448 .callsite => {},
2449 }
2450 try attributes.addParamAttr(0, .writeonly, &o.builder);
2451 try attributes.addParamAttr(0, .{ .captures = .none }, &o.builder);
2452 try attributes.addParamAttr(0, .{ .sret = ret_ty }, &o.builder);
2453 try attributes.addParamAttr(0, .{ .@"align" = .wrap(ret_align) }, &o.builder);
2454 }
2455
2456 pub const TypeRepr = enum {
2457 /// The representation of the type when it is being manipulated as a value in a function.
2458 /// e.g. Zig `u90` -> LLVM `i90`
2459 as_value,
2460 /// The representation of the type when it is loaded from or stored to memory.
2461 /// e.g. Zig `u90` -> LLVM `i96`
2462 memory_access,
2463 /// The representation of the type when it is in memory.
2464 /// e.g. Zig `u90` -> LLVM `[12 x i8]`
2465 in_memory,
2466 };
2467
2468 pub fn intType(o: *Object, bits: u16, repr: TypeRepr) Allocator.Error!Builder.Type {
2469 switch (repr) {
2470 .as_value => return o.builder.intType(bits),
2471 .memory_access, .in_memory => {},
2472 }
2473 const target = o.zcu.getTarget();
2474 const abi_size = std.zig.target.intByteSize(target, bits);
2475 const llvm_bit_width = @as(u20, 8) * abi_size;
2476 switch (repr) {
2477 .as_value => unreachable,
2478 .memory_access => {},
2479 .in_memory => {
2480 const zig_align = std.zig.target.intAlignment(target, bits);
2481 const llvm_align = o.builder.data_layout.getIntegerSpec(llvm_bit_width).abi_align;
2482 if (zig_align < llvm_align.toByteUnits().?) return o.builder.arrayType(abi_size, .i8);
2483 },
2484 }
2485 return o.builder.intType(llvm_bit_width);
2486 }
2487
2488 pub fn errorIntType(o: *Object, repr: TypeRepr) Allocator.Error!Builder.Type {
2489 return o.intType(o.zcu.errorSetBits(), repr);
2490 }
2491
2492 pub const SoftF80Layout = struct {
2493 alignment: InternPool.Alignment,
2494 /// byte offset of u64 field
2495 mantissa_offset: u64,
2496 /// byte offset of u16 field
2497 exponent_offset: u64,
2498 llvm_fields_len: u32,
2499
2500 pub const LlvmFieldTag = enum { mantissa, exponent, padding };
2501 };
2502 pub fn softF80Layout(o: *Object, opts: struct {
2503 llvm_field_tags_buf: []SoftF80Layout.LlvmFieldTag = &.{},
2504 llvm_field_types_buf: []Builder.Type = &.{},
2505 }) Allocator.Error!SoftF80Layout {
2506 const zcu = o.zcu;
2507 const target = zcu.getTarget();
2508 assert(std.zig.target.compilerRtFloatAbi(target, 80) == .soft);
2509 // Current compiler rt soft abi, which is not yet affected by endianness for simplicity:
2510 //
2511 // typedef struct { uint64_t mantissa; uint16_t exponent; } f80;
2512 //
2513 var layout: SoftF80Layout = .{
2514 .alignment = Type.f80.abiAlignment(zcu),
2515 .mantissa_offset = undefined,
2516 .exponent_offset = undefined,
2517 .llvm_fields_len = 0,
2518 };
2519 var offset: u64 = 0;
2520 for ([2]SoftF80Layout.LlvmFieldTag{ .mantissa, .exponent }, [2]Type{ .u64, .u16 }) |field_tag, field_type| {
2521 const field_align = field_type.abiAlignment(zcu);
2522 assert(field_align.compareStrict(.lte, layout.alignment));
2523 const field_offset = field_align.forward(offset);
2524 switch (field_offset - offset) {
2525 0 => {},
2526 else => |padding| {
2527 if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len)
2528 opts.llvm_field_tags_buf[layout.llvm_fields_len] = .padding;
2529 if (layout.llvm_fields_len < opts.llvm_field_types_buf.len)
2530 opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.builder.arrayType(padding, .i8);
2531 layout.llvm_fields_len += 1;
2532 },
2533 }
2534 switch (field_tag) {
2535 .mantissa => layout.mantissa_offset = field_offset,
2536 .exponent => layout.exponent_offset = field_offset,
2537 .padding => unreachable,
2538 }
2539 if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len)
2540 opts.llvm_field_tags_buf[layout.llvm_fields_len] = field_tag;
2541 if (layout.llvm_fields_len < opts.llvm_field_types_buf.len)
2542 opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.lowerType(field_type, .in_memory);
2543 layout.llvm_fields_len += 1;
2544 offset = field_offset + field_type.abiSize(zcu);
2545 }
2546 const end = layout.alignment.forward(offset);
2547 assert(end == Type.f80.abiSize(zcu));
2548 switch (end - offset) {
2549 0 => {},
2550 else => |padding| {
2551 if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len)
2552 opts.llvm_field_tags_buf[layout.llvm_fields_len] = .padding;
2553 if (layout.llvm_fields_len < opts.llvm_field_types_buf.len)
2554 opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.builder.arrayType(padding, .i8);
2555 layout.llvm_fields_len += 1;
2556 },
2557 }
2558 return layout;
2559 }
2560
2561 pub const SoftF128Layout = struct {
2562 alignment: InternPool.Alignment,
2563 /// byte offset of u64 field
2564 lo_offset: u64,
2565 /// byte offset of u64 field
2566 hi_offset: u64,
2567 llvm_fields_len: u32,
2568
2569 pub const LlvmFieldTag = enum { lo, hi, padding };
2570 };
2571 pub fn softF128Layout(o: *Object, opts: struct {
2572 llvm_field_tags_buf: []SoftF128Layout.LlvmFieldTag = &.{},
2573 llvm_field_types_buf: []Builder.Type = &.{},
2574 }) Allocator.Error!SoftF128Layout {
2575 const zcu = o.zcu;
2576 const target = zcu.getTarget();
2577 assert(std.zig.target.compilerRtFloatAbi(target, 128) == .soft);
2578 // Current compiler rt soft abi:
2579 //
2580 // #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
2581 // typedef struct { uint64_t hi, lo; } f128;
2582 // #else
2583 // typedef struct { uint64_t lo, hi; } f128;
2584 // #endif
2585 //
2586 var layout: SoftF128Layout = .{
2587 .alignment = Type.f128.abiAlignment(zcu),
2588 .lo_offset = undefined,
2589 .hi_offset = undefined,
2590 .llvm_fields_len = 0,
2591 };
2592 var offset: u64 = 0;
2593 for (@as([2]SoftF128Layout.LlvmFieldTag, switch (target.cpu.arch.endian()) {
2594 .big => .{ .hi, .lo },
2595 .little => .{ .lo, .hi },
2596 }), [2]Type{ .u64, .u64 }) |field_tag, field_type| {
2597 const field_align = field_type.abiAlignment(zcu);
2598 assert(field_align.compareStrict(.lte, layout.alignment));
2599 const field_offset = field_align.forward(offset);
2600 switch (field_offset - offset) {
2601 0 => {},
2602 else => |padding| {
2603 if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len)
2604 opts.llvm_field_tags_buf[layout.llvm_fields_len] = .padding;
2605 if (layout.llvm_fields_len < opts.llvm_field_types_buf.len)
2606 opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.builder.arrayType(padding, .i8);
2607 layout.llvm_fields_len += 1;
2608 },
2609 }
2610 switch (field_tag) {
2611 .lo => layout.lo_offset = field_offset,
2612 .hi => layout.hi_offset = field_offset,
2613 .padding => unreachable,
2614 }
2615 if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len)
2616 opts.llvm_field_tags_buf[layout.llvm_fields_len] = field_tag;
2617 if (layout.llvm_fields_len < opts.llvm_field_types_buf.len)
2618 opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.lowerType(field_type, .in_memory);
2619 layout.llvm_fields_len += 1;
2620 offset = field_offset + field_type.abiSize(zcu);
2621 }
2622 const end = layout.alignment.forward(offset);
2623 assert(end == Type.f128.abiSize(zcu));
2624 switch (end - offset) {
2625 0 => {},
2626 else => |padding| {
2627 if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len)
2628 opts.llvm_field_tags_buf[layout.llvm_fields_len] = .padding;
2629 if (layout.llvm_fields_len < opts.llvm_field_types_buf.len)
2630 opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.builder.arrayType(padding, .i8);
2631 layout.llvm_fields_len += 1;
2632 },
2633 }
2634 return layout;
2635 }
2636
2637 pub fn lowerType(o: *Object, t: Type, repr: TypeRepr) Allocator.Error!Builder.Type {
2638 const zcu = o.zcu;
2639 const target = zcu.getTarget();
2640 const ip = &zcu.intern_pool;
2641
2642 switch (repr) {
2643 .as_value => assert(!isByRef(t, zcu)), // by-ref types must only be manipulated in memory
2644 .memory_access, .in_memory => {},
2645 }
2646
2647 return switch (t.toIntern()) {
2648 .u0_type => unreachable, // no runtime bits
2649 .u1_type, .bool_type => try o.intType(1, repr),
2650 .u8_type, .i8_type => try o.intType(8, repr),
2651 .u16_type, .i16_type => try o.intType(16, repr),
2652 .u29_type => try o.intType(29, repr),
2653 .u32_type, .i32_type => try o.intType(32, repr),
2654 .u64_type, .i64_type => try o.intType(64, repr),
2655 .u80_type => try o.intType(80, repr),
2656 .u128_type, .i128_type => try o.intType(128, repr),
2657 .usize_type, .isize_type => try o.intType(target.ptrBitWidth(), repr),
2658 .c_char_type => try o.intType(target.cTypeBitSize(.char).?, repr),
2659 .c_short_type => try o.intType(target.cTypeBitSize(.short).?, repr),
2660 .c_ushort_type => try o.intType(target.cTypeBitSize(.ushort).?, repr),
2661 .c_int_type => try o.intType(target.cTypeBitSize(.int).?, repr),
2662 .c_uint_type => try o.intType(target.cTypeBitSize(.uint).?, repr),
2663 .c_long_type => try o.intType(target.cTypeBitSize(.long).?, repr),
2664 .c_ulong_type => try o.intType(target.cTypeBitSize(.ulong).?, repr),
2665 .c_longlong_type => try o.intType(target.cTypeBitSize(.longlong).?, repr),
2666 .c_ulonglong_type => try o.intType(target.cTypeBitSize(.ulonglong).?, repr),
2667 .c_longdouble_type,
2668 .f16_type,
2669 .f32_type,
2670 .f64_type,
2671 .f80_type,
2672 .f128_type,
2673 => switch (t.floatBits(target)) {
2674 16 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) {
2675 .hard => .half,
2676 .soft => .i16,
2677 },
2678 32 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) {
2679 .hard => .float,
2680 .soft => .i32,
2681 },
2682 64 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) {
2683 .hard => .double,
2684 .soft => .i64,
2685 },
2686 80 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) {
2687 .hard => .x86_fp80,
2688 .soft => {
2689 var llvm_field_types_buf: [5]Builder.Type = undefined;
2690 const f80_layout = try o.softF80Layout(.{
2691 .llvm_field_types_buf = &llvm_field_types_buf,
2692 });
2693 return o.builder.structType(
2694 .normal,
2695 llvm_field_types_buf[0..f80_layout.llvm_fields_len],
2696 );
2697 },
2698 },
2699 128 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) {
2700 .hard => .fp128,
2701 .soft => {
2702 var llvm_field_types_buf: [5]Builder.Type = undefined;
2703 const f128_layout = try o.softF128Layout(.{
2704 .llvm_field_types_buf = &llvm_field_types_buf,
2705 });
2706 return o.builder.structType(
2707 .normal,
2708 llvm_field_types_buf[0..f128_layout.llvm_fields_len],
2709 );
2710 },
2711 },
2712 else => unreachable,
2713 },
2714 .anyopaque_type => {
2715 // This is unreachable except when used as the type for an extern global.
2716 // For example: `@extern(*anyopaque, .{ .name = "foo"})` should produce
2717 // @foo = external global i8
2718 return .i8;
2719 },
2720 .anyerror_type => try o.errorIntType(repr),
2721 .void_type => unreachable, // no runtime bits
2722 .type_type => unreachable, // no runtime bits
2723 .comptime_int_type => unreachable, // no runtime bits
2724 .comptime_float_type => unreachable, // no runtime bits
2725 .noreturn_type => unreachable, // no runtime bits
2726 .null_type => unreachable, // no runtime bits
2727 .undefined_type => unreachable, // no runtime bits
2728 .enum_literal_type => unreachable, // no runtime bits
2729 .optional_noreturn_type => unreachable, // no runtime bits
2730 .empty_tuple_type => unreachable, // no runtime bits
2731 .anyframe_type => @panic("TODO implement lowerType for AnyFrame types"),
2732 .ptr_usize_type,
2733 .ptr_const_comptime_int_type,
2734 .manyptr_u8_type,
2735 .manyptr_const_u8_type,
2736 .manyptr_const_u8_sentinel_0_type,
2737 => .ptr,
2738 .slice_const_u8_type,
2739 .slice_const_u8_sentinel_0_type,
2740 => try o.builder.structType(.normal, &.{ .ptr, try o.lowerType(.usize, repr) }),
2741 .anyerror_void_error_union_type,
2742 .adhoc_inferred_error_set_type,
2743 => try o.errorIntType(repr),
2744 .generic_poison_type => unreachable,
2745 // values, not types
2746 .undef,
2747 .undef_bool,
2748 .undef_usize,
2749 .undef_u1,
2750 .zero,
2751 .zero_usize,
2752 .zero_u1,
2753 .zero_u8,
2754 .one,
2755 .one_usize,
2756 .one_u1,
2757 .one_u8,
2758 .four_u8,
2759 .negative_one,
2760 .void_value,
2761 .unreachable_value,
2762 .null_value,
2763 .bool_true,
2764 .bool_false,
2765 .empty_tuple,
2766 .none,
2767 => unreachable,
2768 else => switch (ip.indexToKey(t.toIntern())) {
2769 .int_type => |int_type| o.intType(int_type.bits, repr),
2770 .ptr_type => |ptr_type| type: {
2771 const ptr_ty = try o.builder.ptrType(
2772 toLlvmAddressSpace(ptr_type.flags.address_space, target),
2773 );
2774 break :type switch (ptr_type.flags.size) {
2775 .one, .many, .c => ptr_ty,
2776 .slice => try o.builder.structType(.normal, &.{
2777 ptr_ty,
2778 try o.lowerType(.usize, repr),
2779 }),
2780 };
2781 },
2782 .array_type => |array_type| o.builder.arrayType(
2783 array_type.lenIncludingSentinel(),
2784 try o.lowerType(.fromInterned(array_type.child), repr),
2785 ),
2786 .vector_type => |vector_type| if (isByRef(t, zcu)) {
2787 const child_llvm_ty = try o.lowerType(.fromInterned(vector_type.child), repr);
2788 return o.builder.arrayType(vector_type.len, child_llvm_ty);
2789 } else {
2790 const child_llvm_ty = try o.lowerType(.fromInterned(vector_type.child), .as_value);
2791 return o.builder.vectorType(.normal, vector_type.len, child_llvm_ty);
2792 },
2793 .opt_type => |child_ty| {
2794 // Must stay in sync with `opt_payload` logic in `lowerPtr`.
2795 switch (Type.fromInterned(child_ty).classify(zcu)) {
2796 .no_possible_value, .fully_comptime => unreachable,
2797 .one_possible_value => return .i8,
2798 .runtime, .partially_comptime => {},
2799 }
2800
2801 if (t.optionalReprIsPayload(zcu)) {
2802 return o.lowerType(.fromInterned(child_ty), repr);
2803 }
2804
2805 const payload_ty = try o.lowerType(.fromInterned(child_ty), repr);
2806
2807 comptime assert(optional_layout_version == 3);
2808 var fields: [3]Builder.Type = .{ payload_ty, .i8, undefined };
2809 var fields_len: usize = 2;
2810 const offset = Type.fromInterned(child_ty).abiSize(zcu) + 1;
2811 const abi_size = t.abiSize(zcu);
2812 const padding_len = abi_size - offset;
2813 if (padding_len > 0) {
2814 fields[2] = try o.builder.arrayType(padding_len, .i8);
2815 fields_len = 3;
2816 }
2817 return o.builder.structType(.normal, fields[0..fields_len]);
2818 },
2819 .anyframe_type => @panic("TODO implement lowerType for AnyFrame types"),
2820 .error_union_type => |error_union_type| {
2821 // Must stay in sync with `codegen.errUnionPayloadOffset`.
2822 // See logic in `lowerPtr`.
2823 const error_type = try o.errorIntType(repr);
2824
2825 switch (Type.fromInterned(error_union_type.payload_type).classify(zcu)) {
2826 .fully_comptime => unreachable,
2827 .no_possible_value, .one_possible_value => return error_type,
2828 .runtime, .partially_comptime => {},
2829 }
2830
2831 const payload_type = try o.lowerType(.fromInterned(error_union_type.payload_type), repr);
2832
2833 const payload_align = Type.fromInterned(error_union_type.payload_type).abiAlignment(zcu);
2834 const error_align: InternPool.Alignment = .fromByteUnits(std.zig.target.intAlignment(target, zcu.errorSetBits()));
2835
2836 const payload_size = Type.fromInterned(error_union_type.payload_type).abiSize(zcu);
2837 const error_size = std.zig.target.intByteSize(target, zcu.errorSetBits());
2838
2839 var fields: [3]Builder.Type = undefined;
2840 var fields_len: usize = 2;
2841 const padding_len = if (error_align.compare(.gt, payload_align)) pad: {
2842 fields[0] = error_type;
2843 fields[1] = payload_type;
2844 const payload_end =
2845 payload_align.forward(error_size) +
2846 payload_size;
2847 const abi_size = error_align.forward(payload_end);
2848 break :pad abi_size - payload_end;
2849 } else pad: {
2850 fields[0] = payload_type;
2851 fields[1] = error_type;
2852 const error_end =
2853 error_align.forward(payload_size) +
2854 error_size;
2855 const abi_size = payload_align.forward(error_end);
2856 break :pad abi_size - error_end;
2857 };
2858 if (padding_len > 0) {
2859 fields[2] = try o.builder.arrayType(padding_len, .i8);
2860 fields_len = 3;
2861 }
2862 return o.builder.structType(.normal, fields[0..fields_len]);
2863 },
2864 .simple_type => unreachable,
2865 .struct_type => {
2866 const struct_type = ip.loadStructType(t.toIntern());
2867
2868 if (struct_type.layout == .@"packed") {
2869 return o.lowerType(.fromInterned(struct_type.packed_backing_int_type), repr);
2870 }
2871
2872 if (o.type_map.get(t.toIntern())) |value| return value;
2873
2874 assert(struct_type.size > 0);
2875
2876 var llvm_field_types: std.ArrayList(Builder.Type) = .empty;
2877 defer llvm_field_types.deinit(o.gpa);
2878 // Although we can estimate how much capacity to add, these cannot be
2879 // relied upon because of the recursive calls to lowerType below.
2880 try llvm_field_types.ensureUnusedCapacity(o.gpa, struct_type.field_types.len);
2881
2882 comptime assert(struct_layout_version == 2);
2883 var offset: u64 = 0;
2884 var struct_kind: Builder.Type.Structure.Kind = .normal;
2885 // When we encounter a zero-bit field, we place it here so we know to map it to the next non-zero-bit field (if any).
2886 var it = struct_type.iterateRuntimeOrder(ip);
2887 var max_field_ty_align: InternPool.Alignment = .@"1";
2888 while (it.next()) |field_index| {
2889 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
2890 const field_ty_align = field_ty.abiAlignment(zcu);
2891 max_field_ty_align = max_field_ty_align.maxStrict(field_ty_align);
2892
2893 const prev_offset = offset;
2894 offset = struct_type.field_offsets.get(ip)[field_index];
2895 if (@ctz(offset) < field_ty_align.toLog2Units()) {
2896 struct_kind = .@"packed"; // prevent unexpected padding before this field
2897 }
2898
2899 const padding_len = offset - prev_offset;
2900 if (padding_len > 0) try llvm_field_types.append(
2901 o.gpa,
2902 try o.builder.arrayType(padding_len, .i8),
2903 );
2904
2905 if (!field_ty.hasRuntimeBits(zcu)) continue;
2906
2907 try llvm_field_types.append(o.gpa, try o.lowerType(field_ty, repr));
2908
2909 offset += field_ty.abiSize(zcu);
2910 }
2911 {
2912 const prev_offset = offset;
2913 offset = struct_type.alignment.forward(offset);
2914 const padding_len = offset - prev_offset;
2915 if (padding_len > 0) try llvm_field_types.append(
2916 o.gpa,
2917 try o.builder.arrayType(padding_len, .i8),
2918 );
2919 if (@ctz(offset) < max_field_ty_align.toLog2Units()) {
2920 struct_kind = .@"packed"; // prevent unexpected trailing padding
2921 }
2922 }
2923
2924 const ty = try o.builder.opaqueType(try o.builder.string(t.containerTypeName(ip).fqn.toSlice(ip)));
2925 try o.type_map.put(o.gpa, t.toIntern(), ty);
2926
2927 o.builder.namedTypeSetBody(
2928 ty,
2929 try o.builder.structType(struct_kind, llvm_field_types.items),
2930 );
2931 return ty;
2932 },
2933 .tuple_type => |tuple_type| {
2934 var llvm_field_types: std.ArrayList(Builder.Type) = .empty;
2935 defer llvm_field_types.deinit(o.gpa);
2936 // Although we can estimate how much capacity to add, these cannot be
2937 // relied upon because of the recursive calls to lowerType below.
2938 try llvm_field_types.ensureUnusedCapacity(o.gpa, tuple_type.types.len);
2939
2940 comptime assert(struct_layout_version == 2);
2941 var offset: u64 = 0;
2942 var big_align: InternPool.Alignment = .@"1";
2943
2944 for (
2945 tuple_type.types.get(ip),
2946 tuple_type.values.get(ip),
2947 ) |field_ty, field_val| {
2948 if (field_val != .none) continue;
2949
2950 const field_align = Type.fromInterned(field_ty).abiAlignment(zcu);
2951 big_align = big_align.max(field_align);
2952 const prev_offset = offset;
2953 offset = field_align.forward(offset);
2954
2955 const padding_len = offset - prev_offset;
2956 if (padding_len > 0) try llvm_field_types.append(
2957 o.gpa,
2958 try o.builder.arrayType(padding_len, .i8),
2959 );
2960 if (!Type.fromInterned(field_ty).hasRuntimeBits(zcu)) {
2961 continue;
2962 }
2963 try llvm_field_types.append(o.gpa, try o.lowerType(.fromInterned(field_ty), repr));
2964
2965 offset += Type.fromInterned(field_ty).abiSize(zcu);
2966 }
2967 {
2968 const prev_offset = offset;
2969 offset = big_align.forward(offset);
2970 const padding_len = offset - prev_offset;
2971 if (padding_len > 0) try llvm_field_types.append(
2972 o.gpa,
2973 try o.builder.arrayType(padding_len, .i8),
2974 );
2975 }
2976 assert(offset > 0);
2977 return o.builder.structType(.normal, llvm_field_types.items);
2978 },
2979 .union_type => {
2980 const union_obj = ip.loadUnionType(t.toIntern());
2981
2982 if (union_obj.layout == .@"packed") {
2983 return o.lowerType(.fromInterned(union_obj.packed_backing_int_type), repr);
2984 }
2985
2986 const layout = Type.getUnionLayout(union_obj, zcu);
2987
2988 if (layout.payload_size == 0) {
2989 return o.lowerType(.fromInterned(union_obj.enum_tag_type), repr);
2990 }
2991
2992 if (o.type_map.get(t.toIntern())) |value| return value;
2993
2994 assert(union_obj.size > 0);
2995
2996 const aligned_field_ty = Type.fromInterned(union_obj.field_types.get(ip)[layout.most_aligned_field]);
2997 const aligned_field_llvm_ty = try o.lowerType(aligned_field_ty, repr);
2998
2999 const payload_ty = ty: {
3000 if (layout.most_aligned_field_size == layout.payload_size) {
3001 break :ty aligned_field_llvm_ty;
3002 }
3003 const padding_len = if (layout.tag_size == 0)
3004 layout.abi_size - layout.most_aligned_field_size
3005 else
3006 layout.payload_size - layout.most_aligned_field_size;
3007 break :ty try o.builder.structType(.@"packed", &.{
3008 aligned_field_llvm_ty,
3009 try o.builder.arrayType(padding_len, .i8),
3010 });
3011 };
3012
3013 if (layout.tag_size == 0) {
3014 const ty = try o.builder.opaqueType(try o.builder.string(t.containerTypeName(ip).fqn.toSlice(ip)));
3015 try o.type_map.put(o.gpa, t.toIntern(), ty);
3016
3017 o.builder.namedTypeSetBody(
3018 ty,
3019 try o.builder.structType(.normal, &.{payload_ty}),
3020 );
3021 return ty;
3022 }
3023 const enum_tag_ty = try o.lowerType(.fromInterned(union_obj.enum_tag_type), repr);
3024
3025 // Put the tag before or after the payload depending on which one's
3026 // alignment is greater.
3027 var llvm_fields: [3]Builder.Type = undefined;
3028 var llvm_fields_len: usize = 2;
3029
3030 if (layout.tag_align.compare(.gte, layout.payload_align)) {
3031 llvm_fields = .{ enum_tag_ty, payload_ty, .none };
3032 } else {
3033 llvm_fields = .{ payload_ty, enum_tag_ty, .none };
3034 }
3035
3036 // Insert padding to make the LLVM struct ABI size match the Zig union ABI size.
3037 if (layout.padding != 0) {
3038 llvm_fields[llvm_fields_len] = try o.builder.arrayType(layout.padding, .i8);
3039 llvm_fields_len += 1;
3040 }
3041
3042 const ty = try o.builder.opaqueType(try o.builder.string(t.containerTypeName(ip).fqn.toSlice(ip)));
3043 try o.type_map.put(o.gpa, t.toIntern(), ty);
3044
3045 o.builder.namedTypeSetBody(
3046 ty,
3047 try o.builder.structType(.normal, llvm_fields[0..llvm_fields_len]),
3048 );
3049 return ty;
3050 },
3051 .opaque_type, .spirv_type => unreachable, // no runtime bits
3052 .enum_type => try o.intType(t.backingIntType(zcu).intInfo(zcu).bits, repr),
3053 .func_type => |func_type| {
3054 assert(t.fnHasRuntimeBits(zcu));
3055 return o.lowerFnType(.fromIntern(func_type, ip));
3056 },
3057 .error_set_type, .inferred_error_set_type => try o.errorIntType(repr),
3058 // values, not types
3059 .undef,
3060 .simple_value,
3061 .@"extern",
3062 .func,
3063 .int,
3064 .err,
3065 .error_union,
3066 .enum_literal,
3067 .enum_tag,
3068 .float,
3069 .ptr,
3070 .slice,
3071 .opt,
3072 .aggregate,
3073 .un,
3074 .bitpack,
3075 // memoization, not types
3076 .memoized_call,
3077 => unreachable,
3078 },
3079 };
3080 }
3081
3082 pub const FuncInfo = struct {
3083 cc: std.lang.CallingConvention,
3084 noalias_bits: u32 = 0,
3085 param_types: []const InternPool.Index,
3086 return_type: InternPool.Index = .void_type,
3087 is_var_args: bool = false,
3088
3089 pub fn fromIntern(fn_info: InternPool.Key.FuncType, ip: *InternPool) FuncInfo {
3090 return .{
3091 .cc = fn_info.cc,
3092 .noalias_bits = fn_info.noalias_bits,
3093 .param_types = fn_info.param_types.get(ip),
3094 .return_type = fn_info.return_type,
3095 .is_var_args = fn_info.is_var_args,
3096 };
3097 }
3098 };
3099 pub fn lowerFnType(o: *Object, fn_info: FuncInfo) Allocator.Error!Builder.Type {
3100 const zcu = o.zcu;
3101 const target = zcu.getTarget();
3102
3103 const ret_strat = try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type));
3104
3105 var llvm_params: std.ArrayList(Builder.Type) = .empty;
3106 defer llvm_params.deinit(o.gpa);
3107
3108 if (ret_strat == .sret) {
3109 try llvm_params.append(o.gpa, .ptr);
3110 }
3111
3112 if (fn_info.cc == .auto and zcu.comp.config.any_error_tracing) {
3113 // First parameter is a pointer to `std.lang.StackTrace`.
3114 const llvm_ptr_ty = try o.builder.ptrType(toLlvmAddressSpace(.generic, target));
3115 try llvm_params.append(o.gpa, llvm_ptr_ty);
3116 }
3117
3118 var it = iterateParamTypes(o, fn_info.cc, fn_info.param_types);
3119 while (try it.next()) |lowering| switch (lowering) {
3120 .no_bits => continue,
3121 .byval => {
3122 const param_ty = Type.fromInterned(fn_info.param_types[it.zig_index - 1]);
3123 try llvm_params.append(o.gpa, try o.lowerType(param_ty, if (isByRef(param_ty, zcu)) .memory_access else .as_value));
3124 },
3125 .byref, .byref_mut => {
3126 try llvm_params.append(o.gpa, .ptr);
3127 },
3128 .abi_sized_int => {
3129 const param_ty = Type.fromInterned(fn_info.param_types[it.zig_index - 1]);
3130 try llvm_params.append(o.gpa, try o.builder.intType(
3131 @intCast(param_ty.abiSize(zcu) * 8),
3132 ));
3133 },
3134 .slice => {
3135 const param_ty = Type.fromInterned(fn_info.param_types[it.zig_index - 1]);
3136 try llvm_params.appendSlice(o.gpa, &.{
3137 try o.builder.ptrType(toLlvmAddressSpace(param_ty.ptrAddressSpace(zcu), target)),
3138 try o.lowerType(.usize, .as_value),
3139 });
3140 },
3141 .multiple_llvm_types => {
3142 try llvm_params.appendSlice(o.gpa, it.types_buffer[0..it.types_len]);
3143 },
3144 .float_array => |count| {
3145 const param_ty = Type.fromInterned(fn_info.param_types[it.zig_index - 1]);
3146 const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(param_ty, zcu).?, .memory_access);
3147 try llvm_params.append(o.gpa, try o.builder.arrayType(count, float_ty));
3148 },
3149 .i32_array, .i64_array => |arr_len| {
3150 try llvm_params.append(o.gpa, try o.builder.arrayType(arr_len, switch (lowering) {
3151 .i32_array => .i32,
3152 .i64_array => .i64,
3153 else => unreachable,
3154 }));
3155 },
3156 };
3157
3158 const llvm_ret_ty: Builder.Type = switch (ret_strat) {
3159 .void, .sret => .void,
3160 .by_val => try o.lowerType(.fromInterned(fn_info.return_type), .as_value),
3161 .mem_cast => |llvm_ret_ty| llvm_ret_ty,
3162 };
3163 const llvm_fn_kind: Builder.Type.Function.Kind = switch (fn_info.is_var_args) {
3164 true => .vararg,
3165 false => .normal,
3166 };
3167 return o.builder.fnType(llvm_ret_ty, llvm_params.items, llvm_fn_kind);
3168 }
3169
3170 pub fn lowerValue(o: *Object, arg_val: InternPool.Index, repr: TypeRepr) Allocator.Error!Builder.Constant {
3171 const zcu = o.zcu;
3172 const ip = &zcu.intern_pool;
3173 const target = zcu.getTarget();
3174
3175 const val: Value = .fromInterned(arg_val);
3176 const val_key = ip.indexToKey(val.toIntern());
3177
3178 const ty: Type = .fromInterned(val_key.typeOf());
3179 ty.assertHasLayout(zcu);
3180 assert(ty.hasRuntimeBits(zcu));
3181
3182 return switch (val_key) {
3183 .int_type,
3184 .ptr_type,
3185 .array_type,
3186 .vector_type,
3187 .opt_type,
3188 .anyframe_type,
3189 .error_union_type,
3190 .simple_type,
3191 .struct_type,
3192 .tuple_type,
3193 .union_type,
3194 .opaque_type,
3195 .spirv_type,
3196 .enum_type,
3197 .func_type,
3198 .error_set_type,
3199 .inferred_error_set_type,
3200 => unreachable, // types, not values
3201
3202 .undef => return o.builder.undefConst(try o.lowerType(ty, repr)),
3203 .simple_value => |simple_value| switch (simple_value) {
3204 .void => unreachable, // non-runtime value
3205 .null => unreachable, // non-runtime value
3206 .@"unreachable" => unreachable, // non-runtime value
3207
3208 .false => switch (repr) {
3209 .as_value => .false,
3210 .in_memory, .memory_access => try o.builder.intConst(.i8, 0),
3211 },
3212 .true => switch (repr) {
3213 .as_value => .true,
3214 .in_memory, .memory_access => try o.builder.intConst(.i8, 1),
3215 },
3216 },
3217 .enum_literal => unreachable, // non-runtime value
3218 .@"extern" => unreachable, // non-runtime value
3219 .func => unreachable, // non-runtime value
3220 .int => {
3221 var bigint_space: Value.BigIntSpace = undefined;
3222 const bigint = val.toBigInt(&bigint_space, zcu);
3223 const llvm_int_ty = try o.lowerType(ty, repr);
3224 if (llvm_int_ty.isInteger(&o.builder))
3225 return o.builder.bigIntConst(llvm_int_ty, bigint);
3226 const buffer = try o.gpa.alloc(u8, llvm_int_ty.aggregateLen(&o.builder));
3227 defer o.gpa.free(buffer);
3228 bigint.writeTwosComplement(buffer, target.cpu.arch.endian());
3229 return o.builder.stringConst(try o.builder.string(buffer));
3230 },
3231 .err => |err| {
3232 const int = zcu.intern_pool.getErrorValueIfExists(err.name).?;
3233 return o.builder.intConst(try o.errorIntType(repr), int);
3234 },
3235 .error_union => |error_union| {
3236 const llvm_error_ty = try o.errorIntType(repr);
3237 const llvm_error_value = switch (error_union.val) {
3238 .err_name => |name| try o.builder.intConst(
3239 llvm_error_ty,
3240 zcu.intern_pool.getErrorValueIfExists(name).?,
3241 ),
3242 .payload => try o.builder.intConst(llvm_error_ty, 0),
3243 };
3244
3245 const payload_type = ty.errorUnionPayload(zcu);
3246 if (!payload_type.hasRuntimeBits(zcu)) {
3247 // We use the error type directly as the type.
3248 return llvm_error_value;
3249 }
3250
3251 const payload_align = payload_type.abiAlignment(zcu);
3252 const error_align = Type.errorAbiAlignment(zcu);
3253 const llvm_payload_value = switch (error_union.val) {
3254 .err_name => try o.builder.undefConst(try o.lowerType(payload_type, repr)),
3255 .payload => |payload| try o.lowerValue(payload, repr),
3256 };
3257
3258 var fields: [3]Builder.Type = undefined;
3259 var vals: [3]Builder.Constant = undefined;
3260 if (error_align.compare(.gt, payload_align)) {
3261 vals[0] = llvm_error_value;
3262 vals[1] = llvm_payload_value;
3263 } else {
3264 vals[0] = llvm_payload_value;
3265 vals[1] = llvm_error_value;
3266 }
3267 fields[0] = vals[0].typeOf(&o.builder);
3268 fields[1] = vals[1].typeOf(&o.builder);
3269
3270 const llvm_ty = try o.lowerType(ty, repr);
3271 const llvm_ty_fields = llvm_ty.structFields(&o.builder);
3272 if (llvm_ty_fields.len > 2) {
3273 assert(llvm_ty_fields.len == 3);
3274 fields[2] = llvm_ty_fields[2];
3275 vals[2] = try o.builder.undefConst(fields[2]);
3276 }
3277 return o.builder.structConst(try o.builder.structType(
3278 llvm_ty.structKind(&o.builder),
3279 fields[0..llvm_ty_fields.len],
3280 ), vals[0..llvm_ty_fields.len]);
3281 },
3282 .enum_tag => |enum_tag| o.lowerValue(enum_tag.int, repr),
3283 .float => switch (ty.floatBits(target)) {
3284 else => unreachable,
3285 16 => try o.f16Const(val.toFloat(f16, zcu)),
3286 32 => try o.f32Const(val.toFloat(f32, zcu)),
3287 64 => try o.f64Const(val.toFloat(f64, zcu)),
3288 80 => try o.f80Const(val.toFloat(f80, zcu)),
3289 128 => try o.f128Const(val.toFloat(f128, zcu)),
3290 },
3291 .ptr => try o.lowerPtr(arg_val, 0),
3292 .slice => |slice| return o.builder.structConst(try o.lowerType(ty, repr), &.{
3293 try o.lowerValue(slice.ptr, repr),
3294 try o.lowerValue(slice.len, repr),
3295 }),
3296 .opt => |opt| {
3297 comptime assert(optional_layout_version == 3);
3298 const payload_ty = ty.optionalChild(zcu);
3299
3300 const non_null_bit = try o.builder.intConst(.i8, @intFromBool(opt.val != .none));
3301 if (!payload_ty.hasRuntimeBits(zcu)) {
3302 return non_null_bit;
3303 }
3304 const llvm_ty = try o.lowerType(ty, repr);
3305 if (ty.optionalReprIsPayload(zcu)) return switch (opt.val) {
3306 .none => switch (llvm_ty.tag(&o.builder)) {
3307 .integer => try o.builder.intConst(llvm_ty, 0),
3308 .pointer => try o.builder.nullConst(llvm_ty),
3309 .structure => try o.builder.zeroInitConst(llvm_ty),
3310 else => unreachable,
3311 },
3312 else => |payload| try o.lowerValue(payload, repr),
3313 };
3314 assert(payload_ty.zigTypeTag(zcu) != .@"fn");
3315
3316 var fields: [3]Builder.Type = undefined;
3317 var vals: [3]Builder.Constant = undefined;
3318 vals[0] = switch (opt.val) {
3319 .none => try o.builder.undefConst(try o.lowerType(payload_ty, repr)),
3320 else => |payload| try o.lowerValue(payload, repr),
3321 };
3322 vals[1] = non_null_bit;
3323 fields[0] = vals[0].typeOf(&o.builder);
3324 fields[1] = vals[1].typeOf(&o.builder);
3325
3326 const llvm_ty_fields = llvm_ty.structFields(&o.builder);
3327 if (llvm_ty_fields.len > 2) {
3328 assert(llvm_ty_fields.len == 3);
3329 fields[2] = llvm_ty_fields[2];
3330 vals[2] = try o.builder.undefConst(fields[2]);
3331 }
3332 return o.builder.structConst(try o.builder.structType(
3333 llvm_ty.structKind(&o.builder),
3334 fields[0..llvm_ty_fields.len],
3335 ), vals[0..llvm_ty_fields.len]);
3336 },
3337 .bitpack => |bitpack| return o.lowerValue(bitpack.backing_int_val, repr),
3338 .aggregate => |aggregate| switch (ip.indexToKey(ty.toIntern())) {
3339 .array_type => |array_type| switch (aggregate.storage) {
3340 .bytes => |bytes| try o.builder.stringConst(try o.builder.string(
3341 bytes.toSlice(array_type.lenIncludingSentinel(), ip),
3342 )),
3343 .elems => |elems| {
3344 const array_ty = try o.lowerType(ty, repr);
3345 const elem_ty = array_ty.childType(&o.builder);
3346 assert(elems.len == array_ty.aggregateLen(&o.builder));
3347
3348 const ExpectedContents = extern struct {
3349 vals: [Builder.expected_fields_len]Builder.Constant,
3350 fields: [Builder.expected_fields_len]Builder.Type,
3351 };
3352 var bfa_buf: ExpectedContents = undefined;
3353 var bfa: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), o.gpa);
3354 const allocator = bfa.allocator();
3355 const vals = try allocator.alloc(Builder.Constant, elems.len);
3356 defer allocator.free(vals);
3357 const fields = try allocator.alloc(Builder.Type, elems.len);
3358 defer allocator.free(fields);
3359
3360 var need_unnamed = false;
3361 for (vals, fields, elems) |*result_val, *result_field, elem| {
3362 result_val.* = try o.lowerValue(elem, repr);
3363 result_field.* = result_val.typeOf(&o.builder);
3364 if (result_field.* != elem_ty) need_unnamed = true;
3365 }
3366 return if (need_unnamed) try o.builder.structConst(
3367 try o.builder.structType(.normal, fields),
3368 vals,
3369 ) else try o.builder.arrayConst(array_ty, vals);
3370 },
3371 .repeated_elem => |elem| {
3372 const len: usize = @intCast(array_type.len);
3373 const len_including_sentinel: usize = @intCast(array_type.lenIncludingSentinel());
3374 const array_ty = try o.lowerType(ty, repr);
3375 const elem_ty = array_ty.childType(&o.builder);
3376
3377 const ExpectedContents = extern struct {
3378 vals: [Builder.expected_fields_len]Builder.Constant,
3379 fields: [Builder.expected_fields_len]Builder.Type,
3380 };
3381 var bfa_buf: ExpectedContents = undefined;
3382 var bfa: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), o.gpa);
3383 const allocator = bfa.allocator();
3384 const vals = try allocator.alloc(Builder.Constant, len_including_sentinel);
3385 defer allocator.free(vals);
3386 const fields = try allocator.alloc(Builder.Type, len_including_sentinel);
3387 defer allocator.free(fields);
3388
3389 var need_unnamed = false;
3390 @memset(vals[0..len], try o.lowerValue(elem, repr));
3391 @memset(fields[0..len], vals[0].typeOf(&o.builder));
3392 if (fields[0] != elem_ty) need_unnamed = true;
3393
3394 if (array_type.sentinel != .none) {
3395 vals[len] = try o.lowerValue(array_type.sentinel, repr);
3396 fields[len] = vals[len].typeOf(&o.builder);
3397 if (fields[len] != elem_ty) need_unnamed = true;
3398 }
3399
3400 return if (need_unnamed) try o.builder.structConst(
3401 try o.builder.structType(.@"packed", fields),
3402 vals,
3403 ) else try o.builder.arrayConst(array_ty, vals);
3404 },
3405 },
3406 .vector_type => |vector_type| {
3407 const vector_ty = try o.lowerType(ty, repr);
3408 const ExpectedContents = [Builder.expected_fields_len]Builder.Constant;
3409 var bfa_buf: ExpectedContents = undefined;
3410 var bfa: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), o.gpa);
3411 const allocator = bfa.allocator();
3412 const is_by_ref = isByRef(ty, zcu);
3413 switch (aggregate.storage) {
3414 .bytes, .elems => {
3415 const vals = try allocator.alloc(Builder.Constant, vector_type.len);
3416 defer allocator.free(vals);
3417
3418 switch (aggregate.storage) {
3419 .bytes => |bytes| for (vals, bytes.toSlice(vector_type.len, ip)) |*result_val, byte| {
3420 result_val.* = try o.builder.intConst(.i8, byte);
3421 },
3422 .elems => |elems| for (vals, elems) |*result_val, elem| {
3423 result_val.* = try o.lowerValue(elem, if (is_by_ref) repr else .as_value);
3424 },
3425 .repeated_elem => unreachable,
3426 }
3427 return if (is_by_ref)
3428 o.builder.arrayConst(vector_ty, vals)
3429 else
3430 o.builder.vectorConst(vector_ty, vals);
3431 },
3432 .repeated_elem => |elem| if (is_by_ref) {
3433 const vals = try allocator.alloc(Builder.Constant, vector_type.len);
3434 defer allocator.free(vals);
3435 @memset(vals, try o.lowerValue(elem, repr));
3436 return o.builder.arrayConst(vector_ty, vals);
3437 } else return o.builder.splatConst(vector_ty, try o.lowerValue(elem, .as_value)),
3438 }
3439 },
3440 .tuple_type => |tuple| {
3441 const struct_ty = try o.lowerType(ty, repr);
3442 const llvm_len = struct_ty.aggregateLen(&o.builder);
3443
3444 const ExpectedContents = extern struct {
3445 vals: [Builder.expected_fields_len]Builder.Constant,
3446 fields: [Builder.expected_fields_len]Builder.Type,
3447 };
3448 var bfa_buf: ExpectedContents = undefined;
3449 var bfa: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), o.gpa);
3450 const allocator = bfa.allocator();
3451 const vals = try allocator.alloc(Builder.Constant, llvm_len);
3452 defer allocator.free(vals);
3453 const fields = try allocator.alloc(Builder.Type, llvm_len);
3454 defer allocator.free(fields);
3455
3456 comptime assert(struct_layout_version == 2);
3457 var llvm_index: usize = 0;
3458 var offset: u64 = 0;
3459 var big_align: InternPool.Alignment = .@"1";
3460 var need_unnamed = false;
3461 for (
3462 tuple.types.get(ip),
3463 tuple.values.get(ip),
3464 0..,
3465 ) |field_ty, field_comptime_val, field_index| {
3466 if (field_comptime_val != .none) continue;
3467 if (!Type.fromInterned(field_ty).hasRuntimeBits(zcu)) continue;
3468
3469 const field_align = Type.fromInterned(field_ty).abiAlignment(zcu);
3470 big_align = big_align.max(field_align);
3471 const prev_offset = offset;
3472 offset = field_align.forward(offset);
3473
3474 const padding_len = offset - prev_offset;
3475 if (padding_len > 0) {
3476 // TODO make this and all other padding elsewhere in debug
3477 // builds be 0xaa not undef.
3478 fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);
3479 vals[llvm_index] = try o.builder.undefConst(fields[llvm_index]);
3480 assert(fields[llvm_index] == struct_ty.structFields(&o.builder)[llvm_index]);
3481 llvm_index += 1;
3482 }
3483
3484 vals[llvm_index] = switch (aggregate.storage) {
3485 .bytes => |bytes| try o.builder.intConst(.i8, bytes.at(field_index, ip)),
3486 .elems => |elems| try o.lowerValue(elems[field_index], repr),
3487 .repeated_elem => |elem| try o.lowerValue(elem, repr),
3488 };
3489 fields[llvm_index] = vals[llvm_index].typeOf(&o.builder);
3490 if (fields[llvm_index] != struct_ty.structFields(&o.builder)[llvm_index])
3491 need_unnamed = true;
3492 llvm_index += 1;
3493
3494 offset += Type.fromInterned(field_ty).abiSize(zcu);
3495 }
3496 {
3497 const prev_offset = offset;
3498 offset = big_align.forward(offset);
3499 const padding_len = offset - prev_offset;
3500 if (padding_len > 0) {
3501 fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);
3502 vals[llvm_index] = try o.builder.undefConst(fields[llvm_index]);
3503 assert(fields[llvm_index] == struct_ty.structFields(&o.builder)[llvm_index]);
3504 llvm_index += 1;
3505 }
3506 }
3507 assert(llvm_index == llvm_len);
3508
3509 return o.builder.structConst(if (need_unnamed)
3510 try o.builder.structType(struct_ty.structKind(&o.builder), fields)
3511 else
3512 struct_ty, vals);
3513 },
3514 .struct_type => {
3515 const struct_type = ip.loadStructType(ty.toIntern());
3516 const struct_ty = try o.lowerType(ty, repr);
3517 assert(struct_type.layout != .@"packed");
3518 const llvm_len = struct_ty.aggregateLen(&o.builder);
3519
3520 const ExpectedContents = extern struct {
3521 vals: [Builder.expected_fields_len]Builder.Constant,
3522 fields: [Builder.expected_fields_len]Builder.Type,
3523 };
3524 var bfa_buf: ExpectedContents = undefined;
3525 var bfa: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), o.gpa);
3526 const allocator = bfa.allocator();
3527 const vals = try allocator.alloc(Builder.Constant, llvm_len);
3528 defer allocator.free(vals);
3529 const fields = try allocator.alloc(Builder.Type, llvm_len);
3530 defer allocator.free(fields);
3531
3532 comptime assert(struct_layout_version == 2);
3533 var llvm_index: usize = 0;
3534 var offset: u64 = 0;
3535 var need_unnamed = false;
3536 var field_it = struct_type.iterateRuntimeOrder(ip);
3537 while (field_it.next()) |field_index| {
3538 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
3539 const prev_offset = offset;
3540 offset = struct_type.field_offsets.get(ip)[field_index];
3541
3542 const padding_len = offset - prev_offset;
3543 if (padding_len > 0) {
3544 // TODO make this and all other padding elsewhere in debug
3545 // builds be 0xaa not undef.
3546 fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);
3547 vals[llvm_index] = try o.builder.undefConst(fields[llvm_index]);
3548 assert(fields[llvm_index] ==
3549 struct_ty.structFields(&o.builder)[llvm_index]);
3550 llvm_index += 1;
3551 }
3552
3553 if (!field_ty.hasRuntimeBits(zcu)) {
3554 // This is a zero-bit field - we only needed it for the alignment.
3555 continue;
3556 }
3557
3558 vals[llvm_index] = switch (aggregate.storage) {
3559 .bytes => |bytes| try o.builder.intConst(.i8, bytes.at(field_index, ip)),
3560 .elems => |elems| try o.lowerValue(elems[field_index], repr),
3561 .repeated_elem => |elem| try o.lowerValue(elem, repr),
3562 };
3563 fields[llvm_index] = vals[llvm_index].typeOf(&o.builder);
3564 if (fields[llvm_index] != struct_ty.structFields(&o.builder)[llvm_index])
3565 need_unnamed = true;
3566 llvm_index += 1;
3567
3568 offset += field_ty.abiSize(zcu);
3569 }
3570 {
3571 const prev_offset = offset;
3572 offset = struct_type.alignment.forward(offset);
3573 const padding_len = offset - prev_offset;
3574 if (padding_len > 0) {
3575 fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);
3576 vals[llvm_index] = try o.builder.undefConst(fields[llvm_index]);
3577 assert(fields[llvm_index] == struct_ty.structFields(&o.builder)[llvm_index]);
3578 llvm_index += 1;
3579 }
3580 }
3581 assert(llvm_index == llvm_len);
3582
3583 return o.builder.structConst(if (need_unnamed)
3584 try o.builder.structType(struct_ty.structKind(&o.builder), fields)
3585 else
3586 struct_ty, vals);
3587 },
3588 else => unreachable,
3589 },
3590 .un => |un| {
3591 const union_ty = try o.lowerType(ty, repr);
3592 const layout = ty.unionGetLayout(zcu);
3593 if (layout.payload_size == 0) return o.lowerValue(un.tag, repr);
3594
3595 const union_obj = zcu.typeToUnion(ty).?;
3596 const container_layout = union_obj.layout;
3597 assert(container_layout != .@"packed");
3598
3599 var need_unnamed = false;
3600 const payload = if (un.tag != .none) p: {
3601 const field_index = zcu.unionTagFieldIndex(union_obj, Value.fromInterned(un.tag)).?;
3602 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
3603
3604 // Sometimes we must make an unnamed struct because LLVM does
3605 // not support bitcasting our payload struct to the true union payload type.
3606 // Instead we use an unnamed struct and every reference to the global
3607 // must pointer cast to the expected type before accessing the union.
3608 need_unnamed = layout.most_aligned_field != field_index;
3609
3610 if (!field_ty.hasRuntimeBits(zcu)) {
3611 const padding_len = layout.payload_size;
3612 break :p try o.builder.undefConst(try o.builder.arrayType(padding_len, .i8));
3613 }
3614 const payload = try o.lowerValue(un.val, repr);
3615 const payload_ty = payload.typeOf(&o.builder);
3616 if (payload_ty != union_ty.structFields(&o.builder)[
3617 @intFromBool(layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align))
3618 ]) need_unnamed = true;
3619 const field_size = field_ty.abiSize(zcu);
3620 if (field_size == layout.payload_size) break :p payload;
3621 const padding_len = layout.payload_size - field_size;
3622 const padding_ty = try o.builder.arrayType(padding_len, .i8);
3623 break :p try o.builder.structConst(
3624 try o.builder.structType(.@"packed", &.{ payload_ty, padding_ty }),
3625 &.{ payload, try o.builder.undefConst(padding_ty) },
3626 );
3627 } else p: {
3628 assert(layout.tag_size == 0);
3629 const union_val = try o.lowerValue(un.val, repr);
3630 need_unnamed = true;
3631 break :p union_val;
3632 };
3633
3634 const payload_ty = payload.typeOf(&o.builder);
3635 if (layout.tag_size == 0) return o.builder.structConst(if (need_unnamed)
3636 try o.builder.structType(union_ty.structKind(&o.builder), &.{payload_ty})
3637 else
3638 union_ty, &.{payload});
3639 const tag = try o.lowerValue(un.tag, repr);
3640 const tag_ty = tag.typeOf(&o.builder);
3641 var fields: [3]Builder.Type = undefined;
3642 var vals: [3]Builder.Constant = undefined;
3643 var len: usize = 2;
3644 if (layout.tag_align.compare(.gte, layout.payload_align)) {
3645 fields = .{ tag_ty, payload_ty, undefined };
3646 vals = .{ tag, payload, undefined };
3647 } else {
3648 fields = .{ payload_ty, tag_ty, undefined };
3649 vals = .{ payload, tag, undefined };
3650 }
3651 if (layout.padding != 0) {
3652 fields[2] = try o.builder.arrayType(layout.padding, .i8);
3653 vals[2] = try o.builder.undefConst(fields[2]);
3654 len = 3;
3655 }
3656 return o.builder.structConst(if (need_unnamed)
3657 try o.builder.structType(union_ty.structKind(&o.builder), fields[0..len])
3658 else
3659 union_ty, vals[0..len]);
3660 },
3661 .memoized_call => unreachable,
3662 };
3663 }
3664
3665 pub fn f16Const(o: *Object, val: f16) Allocator.Error!Builder.Constant {
3666 return switch (std.zig.target.compilerRtFloatAbi(o.zcu.getTarget(), 16)) {
3667 .hard => o.builder.halfConst(val),
3668 .soft => o.builder.intConst(.i16, @as(u16, @bitCast(val))),
3669 };
3670 }
3671
3672 pub fn f32Const(o: *Object, val: f32) Allocator.Error!Builder.Constant {
3673 return switch (std.zig.target.compilerRtFloatAbi(o.zcu.getTarget(), 32)) {
3674 .hard => o.builder.floatConst(val),
3675 .soft => o.builder.intConst(.i32, @as(u32, @bitCast(val))),
3676 };
3677 }
3678
3679 pub fn f64Const(o: *Object, val: f64) Allocator.Error!Builder.Constant {
3680 return switch (std.zig.target.compilerRtFloatAbi(o.zcu.getTarget(), 64)) {
3681 .hard => o.builder.doubleConst(val),
3682 .soft => o.builder.intConst(.i64, @as(u64, @bitCast(val))),
3683 };
3684 }
3685
3686 pub fn f80Const(o: *Object, val: f80) Allocator.Error!Builder.Constant {
3687 switch (std.zig.target.compilerRtFloatAbi(o.zcu.getTarget(), 80)) {
3688 .hard => return o.builder.x86_fp80Const(val),
3689 .soft => {},
3690 }
3691 var llvm_field_tags_buf: [5]SoftF80Layout.LlvmFieldTag = undefined;
3692 var llvm_field_types_buf: [5]Builder.Type = undefined;
3693 const f80_layout = try o.softF80Layout(.{
3694 .llvm_field_tags_buf = &llvm_field_tags_buf,
3695 .llvm_field_types_buf = &llvm_field_types_buf,
3696 });
3697 const llvm_field_types = llvm_field_types_buf[0..f80_layout.llvm_fields_len];
3698 const f80_llvm_ty = try o.builder.structType(.normal, llvm_field_types);
3699 const f80_repr: packed struct { mantissa: u64, exponent: u16 } = @bitCast(val);
3700 var llvm_field_vals_buf: [5]Builder.Constant = undefined;
3701 const llvm_field_vals = llvm_field_vals_buf[0..f80_layout.llvm_fields_len];
3702 for (
3703 llvm_field_vals,
3704 llvm_field_tags_buf[0..f80_layout.llvm_fields_len],
3705 llvm_field_types,
3706 ) |*llvm_field_val, llvm_field_tag, llvm_field_type|
3707 llvm_field_val.* = switch (llvm_field_tag) {
3708 .mantissa => try o.builder.intConst(llvm_field_type, f80_repr.mantissa),
3709 .exponent => try o.builder.intConst(llvm_field_type, f80_repr.exponent),
3710 .padding => try o.builder.undefConst(llvm_field_type),
3711 };
3712 return o.builder.structConst(f80_llvm_ty, llvm_field_vals);
3713 }
3714
3715 pub fn f128Const(o: *Object, val: f128) Allocator.Error!Builder.Constant {
3716 switch (std.zig.target.compilerRtFloatAbi(o.zcu.getTarget(), 128)) {
3717 .hard => return o.builder.fp128Const(val),
3718 .soft => {},
3719 }
3720 var llvm_field_tags_buf: [5]SoftF128Layout.LlvmFieldTag = undefined;
3721 var llvm_field_types_buf: [5]Builder.Type = undefined;
3722 const f128_layout = try o.softF128Layout(.{
3723 .llvm_field_tags_buf = &llvm_field_tags_buf,
3724 .llvm_field_types_buf = &llvm_field_types_buf,
3725 });
3726 const llvm_field_types = llvm_field_types_buf[0..f128_layout.llvm_fields_len];
3727 const f128_llvm_ty = try o.builder.structType(.normal, llvm_field_types);
3728 const f128_repr: packed struct { lo: u64, hi: u64 } = @bitCast(val);
3729 var llvm_field_vals_buf: [5]Builder.Constant = undefined;
3730 const llvm_field_vals = llvm_field_vals_buf[0..f128_layout.llvm_fields_len];
3731 for (
3732 llvm_field_vals,
3733 llvm_field_tags_buf[0..f128_layout.llvm_fields_len],
3734 llvm_field_types,
3735 ) |*llvm_field_val, llvm_field_tag, llvm_field_type|
3736 llvm_field_val.* = switch (llvm_field_tag) {
3737 .lo => try o.builder.intConst(llvm_field_type, f128_repr.lo),
3738 .hi => try o.builder.intConst(llvm_field_type, f128_repr.hi),
3739 .padding => try o.builder.undefConst(llvm_field_type),
3740 };
3741 return o.builder.structConst(f128_llvm_ty, llvm_field_vals);
3742 }
3743
3744 pub fn lowerConstRef(
3745 o: *Object,
3746 constant: Builder.Constant,
3747 @"align": Builder.Alignment,
3748 ) Allocator.Error!Builder.Constant {
3749 assert(@"align" != .default);
3750 const zcu = o.zcu;
3751 const gpa = zcu.comp.gpa;
3752 const gop = try o.const_map.getOrPut(gpa, constant);
3753 if (gop.found_existing) {
3754 // Keep the greater of the two alignments.
3755 const llvm_variable = gop.value_ptr.*;
3756 const llvm_old_align = llvm_variable.getAlignment(&o.builder);
3757 const llvm_new_align = llvm_old_align.max(@"align");
3758 llvm_variable.setAlignment(llvm_new_align, &o.builder);
3759 return llvm_variable.ptrConst(&o.builder).global.toConst();
3760 }
3761 errdefer assert(o.const_map.remove(constant));
3762
3763 const llvm_ty = constant.typeOf(&o.builder);
3764 const llvm_addrspace = toLlvmAddressSpace(.generic, zcu.getTarget());
3765 const llvm_variable = try o.builder.addVariable(.empty, llvm_ty, llvm_addrspace);
3766 gop.value_ptr.* = llvm_variable;
3767 try llvm_variable.setInitializer(constant, &o.builder);
3768 llvm_variable.setMutability(.constant, &o.builder);
3769 llvm_variable.setAlignment(@"align", &o.builder);
3770 const llvm_global = llvm_variable.ptrConst(&o.builder).global;
3771 llvm_global.setLinkage(.private, &o.builder);
3772 llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder);
3773 return llvm_global.toConst();
3774 }
3775
3776 fn lowerPtr(
3777 o: *Object,
3778 ptr_val: InternPool.Index,
3779 prev_offset: u64,
3780 ) Allocator.Error!Builder.Constant {
3781 const zcu = o.zcu;
3782 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;
3783 const offset: u64 = prev_offset + ptr.byte_offset;
3784 return switch (ptr.base_addr) {
3785 .nav => |nav| {
3786 const base_ptr = try o.lowerNavRef(nav);
3787 return o.builder.gepConst(.inbounds, .i8, base_ptr, null, &.{
3788 try o.builder.intConst(.i64, offset),
3789 });
3790 },
3791 .uav => |uav| {
3792 const orig_ptr_ty: Type = .fromInterned(uav.orig_ty);
3793 const base_ptr = try o.lowerUavRef(
3794 uav.val,
3795 orig_ptr_ty.ptrAlignment(zcu).toLlvm(),
3796 orig_ptr_ty.ptrAddressSpace(zcu),
3797 );
3798 return o.builder.gepConst(.inbounds, .i8, base_ptr, null, &.{
3799 try o.builder.intConst(.i64, offset),
3800 });
3801 },
3802 .int => try o.builder.castConst(
3803 .inttoptr,
3804 try o.builder.intConst(try o.lowerType(.usize, .as_value), offset),
3805 try o.lowerType(.fromInterned(ptr.ty), .as_value),
3806 ),
3807 .eu_payload => |eu_ptr| try o.lowerPtr(
3808 eu_ptr,
3809 offset + codegen.errUnionPayloadOffset(
3810 Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu),
3811 zcu,
3812 ),
3813 ),
3814 .opt_payload => |opt_ptr| try o.lowerPtr(opt_ptr, offset),
3815 .field => |field| {
3816 const agg_ty = Value.fromInterned(field.base).typeOf(zcu).childType(zcu);
3817 const field_off: u64 = switch (agg_ty.zigTypeTag(zcu)) {
3818 .pointer => off: {
3819 assert(agg_ty.isSlice(zcu));
3820 break :off switch (field.index) {
3821 Value.slice_ptr_index => 0,
3822 Value.slice_len_index => @divExact(zcu.getTarget().ptrBitWidth(), 8),
3823 else => unreachable,
3824 };
3825 },
3826 .@"struct", .@"union" => switch (agg_ty.containerLayout(zcu)) {
3827 .auto => agg_ty.structFieldOffset(@intCast(field.index), zcu),
3828 .@"extern", .@"packed" => unreachable,
3829 },
3830 else => unreachable,
3831 };
3832 return o.lowerPtr(field.base, offset + field_off);
3833 },
3834 .arr_elem => |arr_elem| {
3835 const base_ptr_ty = Value.fromInterned(arr_elem.base).typeOf(zcu);
3836 assert(base_ptr_ty.ptrSize(zcu) == .many);
3837 const elem_size = base_ptr_ty.childType(zcu).abiSize(zcu);
3838 return o.lowerPtr(arr_elem.base, offset + elem_size * arr_elem.index);
3839 },
3840 .comptime_field => unreachable,
3841 .comptime_alloc => unreachable,
3842 };
3843 }
3844
3845 pub fn lowerPtrToVoid(
3846 o: *Object,
3847 /// Must not be `.default`.
3848 @"align": Builder.Alignment,
3849 @"addrspace": std.lang.AddressSpace,
3850 ) Allocator.Error!Builder.Constant {
3851 const addr: u64 = @"align".toByteUnits().?;
3852 const llvm_usize = try o.lowerType(.usize, .as_value);
3853 const llvm_addr = try o.builder.intConst(llvm_usize, addr);
3854 const llvm_ptr_ty = try o.builder.ptrType(toLlvmAddressSpace(@"addrspace", o.zcu.getTarget()));
3855 return o.builder.castConst(.inttoptr, llvm_addr, llvm_ptr_ty);
3856 }
3857
3858 pub fn lowerUavRef(
3859 o: *Object,
3860 uav_val: InternPool.Index,
3861 /// Must not be `.default`.
3862 @"align": Builder.Alignment,
3863 @"addrspace": std.lang.AddressSpace,
3864 ) Allocator.Error!Builder.Constant {
3865 assert(@"align" != .default);
3866
3867 const zcu = o.zcu;
3868 const ip = &zcu.intern_pool;
3869 const gpa = zcu.comp.gpa;
3870
3871 const uav_ty: Type = .fromInterned(ip.typeOf(uav_val));
3872
3873 switch (ip.indexToKey(uav_val)) {
3874 .func => unreachable, // should be using a Nav ref
3875 .@"extern" => unreachable, // should be using a Nav ref
3876 else => {},
3877 }
3878
3879 if (!uav_ty.hasRuntimeBits(zcu)) {
3880 return o.lowerPtrToVoid(@"align", @"addrspace");
3881 }
3882
3883 const llvm_addrspace = toLlvmAddressSpace(@"addrspace", zcu.getTarget());
3884
3885 const gop = try o.uav_map.getOrPut(gpa, .{ .val = uav_val, .@"addrspace" = @"addrspace" });
3886 if (gop.found_existing) {
3887 // Keep the greater of the two alignments.
3888 const llvm_variable = gop.value_ptr.*;
3889 const llvm_old_align = llvm_variable.getAlignment(&o.builder);
3890 const llvm_new_align = llvm_old_align.max(@"align");
3891 llvm_variable.setAlignment(llvm_new_align, &o.builder);
3892 return llvm_variable.ptrConst(&o.builder).global.toConst();
3893 }
3894 errdefer assert(o.uav_map.remove(.{ .val = uav_val, .@"addrspace" = @"addrspace" }));
3895
3896 const llvm_name = try o.builder.strtabStringFmt("__anon_{d}", .{@backingInt(uav_val)});
3897 const llvm_variable = try o.builder.addVariable(llvm_name, .void, llvm_addrspace);
3898 gop.value_ptr.* = llvm_variable;
3899 try llvm_variable.setInitializer(try o.lowerValue(uav_val, .in_memory), &o.builder);
3900 llvm_variable.setMutability(.constant, &o.builder);
3901 llvm_variable.setAlignment(@"align", &o.builder);
3902 const llvm_global = llvm_variable.ptrConst(&o.builder).global;
3903 llvm_global.setLinkage(if (o.builder.strip) .private else .internal, &o.builder);
3904 llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder);
3905 return llvm_global.toConst();
3906 }
3907
3908 pub fn lowerNavRef(o: *Object, nav_id: InternPool.Nav.Index) Allocator.Error!Builder.Constant {
3909 const zcu = o.zcu;
3910 const ip = &zcu.intern_pool;
3911 const gpa = zcu.comp.gpa;
3912
3913 const nav = ip.getNav(nav_id);
3914 const nav_ty: Type = .fromInterned(nav.resolved.?.type);
3915 if (!nav_ty.isRuntimeFnOrHasRuntimeBits(zcu) and nav.getExtern(ip) == null) {
3916 const nav_align = switch (nav.resolved.?.@"align") {
3917 .none => nav_ty.abiAlignment(zcu),
3918 else => |a| a,
3919 };
3920 return o.lowerPtrToVoid(nav_align.toLlvm(), nav.resolved.?.@"addrspace");
3921 }
3922
3923 const gop = try o.nav_map.getOrPut(gpa, nav_id);
3924 if (!gop.found_existing) {
3925 errdefer assert(o.nav_map.remove(nav_id));
3926 // The NAV hasn't been lowered yet, so generate a placeholder global whose details will
3927 // be filled in later.
3928 const llvm_name = try o.builder.strtabString(nav.fqn.toSlice(ip));
3929 gop.value_ptr.* = try o.builder.addGlobal(llvm_name, .{
3930 .type = .void, // placeholder; populated by `updateNav`/`updateFunc`
3931 .kind = .{ .alias = .none }, // placeholder; populated by `updateNav`/`updateFunc`
3932 });
3933 }
3934 const llvm_global = gop.value_ptr.*;
3935
3936 // We need to make sure the global's address space is up to date, because that affects the
3937 // type of a pointer to this global. But everything else about the global will be populated
3938 // by `updateNav` or `updateFunc`.
3939 llvm_global.ptr(&o.builder).addr_space = toLlvmAddressSpace(nav.resolved.?.@"addrspace", zcu.getTarget());
3940 return llvm_global.toConst();
3941 }
3942
3943 pub fn addByValParamAttrs(
3944 o: *Object,
3945 pt: Zcu.PerThread,
3946 attributes: *Builder.FunctionAttributes.Wip,
3947 param_ty: Type,
3948 param_index: u32,
3949 fn_info: FuncInfo,
3950 llvm_arg_i: u32,
3951 ) Allocator.Error!void {
3952 const zcu = o.zcu;
3953 if (param_ty.isPtrAtRuntime(zcu)) {
3954 const ptr_info = param_ty.ptrInfo(zcu);
3955 if (std.math.cast(u5, param_index)) |i| {
3956 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
3957 try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
3958 }
3959 }
3960 if (!param_ty.isPtrLikeOptional(zcu) and
3961 !ptr_info.flags.is_allowzero and
3962 ptr_info.flags.address_space == .generic)
3963 {
3964 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
3965 }
3966 switch (fn_info.cc) {
3967 else => {},
3968 .x86_64_interrupt,
3969 .x86_interrupt,
3970 => {
3971 const child_type = try o.lowerType(.fromInterned(ptr_info.child), .in_memory);
3972 try attributes.addParamAttr(llvm_arg_i, .{ .byval = child_type }, &o.builder);
3973 },
3974 }
3975 if (ptr_info.flags.is_const) {
3976 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
3977 }
3978 const elem_align: Builder.Alignment.Lazy = switch (ptr_info.flags.alignment) {
3979 else => |a| .wrap(a.toLlvm()),
3980 .none => try o.lazyAbiAlignment(pt, .fromInterned(ptr_info.child)),
3981 };
3982 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
3983 } else if (ccAbiPromoteInt(fn_info.cc, zcu, param_ty)) |s| switch (s) {
3984 .signed => try attributes.addParamAttr(llvm_arg_i, .signext, &o.builder),
3985 .unsigned => try attributes.addParamAttr(llvm_arg_i, .zeroext, &o.builder),
3986 };
3987 }
3988
3989 pub const Byval = struct { alignment: InternPool.Alignment = .none };
3990 pub fn addByRefParamAttrs(
3991 o: *Object,
3992 attributes: *Builder.FunctionAttributes.Wip,
3993 llvm_arg_i: u32,
3994 maybe_byval: ?Byval,
3995 param_ty: Type,
3996 ) Allocator.Error!void {
3997 const llvm_param_ty = try o.lowerType(param_ty, .in_memory);
3998 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
3999 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
4000 try attributes.addParamAttr(llvm_arg_i, .noundef, &o.builder);
4001 const alignment = if (maybe_byval) |byval| alignment: {
4002 try attributes.addParamAttr(llvm_arg_i, .{ .byval = llvm_param_ty }, &o.builder);
4003 break :alignment byval.alignment;
4004 } else .none;
4005 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = .wrap(switch (alignment) {
4006 .none => param_ty.abiAlignment(o.zcu),
4007 else => alignment,
4008 }.toLlvm()) }, &o.builder);
4009 }
4010
4011 pub fn getErrorNameTable(o: *Object) Allocator.Error!Builder.Variable.Index {
4012 if (o.error_name_table != .none) return o.error_name_table;
4013
4014 const name = try o.builder.strtabString("__zig_error_name_table");
4015 // TODO: Address space
4016 const llvm_variable = try o.builder.addVariable(name, .ptr, .default);
4017 llvm_variable.setMutability(.constant, &o.builder);
4018 llvm_variable.setAlignment(
4019 Type.slice_const_u8_sentinel_0.abiAlignment(o.zcu).toLlvm(),
4020 &o.builder,
4021 );
4022 const llvm_global = llvm_variable.ptrConst(&o.builder).global;
4023 llvm_global.setLinkage(.private, &o.builder);
4024 llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder);
4025
4026 o.error_name_table = llvm_variable;
4027 return llvm_variable;
4028 }
4029
4030 pub fn getErrorsLen(o: *Object) Allocator.Error!Builder.Variable.Index {
4031 const builder = &o.builder;
4032 if (o.errors_len_variable == .none) {
4033 const llvm_err_int_ty = try o.errorIntType(.in_memory);
4034 const name = try builder.strtabString("__zig_errors_len");
4035 const llvm_variable = try builder.addVariable(name, llvm_err_int_ty, .default);
4036 llvm_variable.setMutability(.constant, builder);
4037 llvm_variable.setAlignment(Type.errorAbiAlignment(o.zcu).toLlvm(), builder);
4038 const llvm_global = llvm_variable.ptrConst(&o.builder).global;
4039 llvm_global.setLinkage(.private, builder);
4040 llvm_global.setUnnamedAddr(.unnamed_addr, builder);
4041 o.errors_len_variable = llvm_variable;
4042 }
4043 return o.errors_len_variable;
4044 }
4045
4046 pub fn getEnumTagNameFunction(o: *Object, enum_ty: Type) Allocator.Error!Builder.Function.Index {
4047 const zcu = o.zcu;
4048 const ip = &zcu.intern_pool;
4049
4050 const gop = try o.enum_tag_name_map.getOrPut(o.gpa, enum_ty.toIntern());
4051 if (gop.found_existing) return gop.value_ptr.*;
4052 errdefer assert(o.enum_tag_name_map.remove(enum_ty.toIntern()));
4053 const llvm_function = try o.builder.addFunction(
4054 // Dummy function type; `updateEnumTagNameFunction` will replace it with the correct type.
4055 // TODO: change the builder API so we don't need to do this.
4056 try o.builder.fnType(.void, &.{}, .normal),
4057 try o.builder.strtabStringFmt("__zig_tag_name_{f}", .{enum_ty.containerTypeName(ip).fqn.fmt(ip)}),
4058 toLlvmAddressSpace(.generic, zcu.getTarget()),
4059 );
4060 gop.value_ptr.* = llvm_function;
4061 try o.updateEnumTagNameFunction(enum_ty, llvm_function);
4062 return llvm_function;
4063 }
4064 fn updateEnumTagNameFunction(
4065 o: *Object,
4066 enum_ty: Type,
4067 llvm_function: Builder.Function.Index,
4068 ) Allocator.Error!void {
4069 const zcu = o.zcu;
4070 const ip = &zcu.intern_pool;
4071 const loaded_enum = ip.loadEnumType(enum_ty.toIntern());
4072
4073 const llvm_usize_ty = try o.lowerType(.usize, .as_value);
4074 const llvm_ret_ty = try o.lowerType(.slice_const_u8_sentinel_0, .as_value);
4075 const llvm_int_ty = try o.lowerType(.fromInterned(loaded_enum.int_tag_type), .as_value);
4076
4077 llvm_function.ptrConst(&o.builder).global.ptr(&o.builder).type =
4078 try o.builder.fnType(llvm_ret_ty, &.{llvm_int_ty}, .normal);
4079
4080 var attributes: Builder.FunctionAttributes.Wip = .{};
4081 defer attributes.deinit(&o.builder);
4082 try o.addCommonFnAttributes(&attributes, zcu.root_mod, zcu.root_mod.omit_frame_pointer);
4083
4084 llvm_function.setLinkage(if (o.builder.strip) .private else .internal, &o.builder);
4085 llvm_function.setCallConv(.fastcc, &o.builder);
4086 llvm_function.setAttributes(try attributes.finish(&o.builder), &o.builder);
4087
4088 var wip = try Builder.WipFunction.init(&o.builder, .{
4089 .function = llvm_function,
4090 .strip = true,
4091 });
4092 defer wip.deinit();
4093 wip.cursor = .{ .block = try wip.block(0, "Entry") };
4094
4095 const bad_value_block = try wip.block(1, "BadValue");
4096 const tag_int_value = wip.arg(0);
4097 var wip_switch = try wip.@"switch"(
4098 tag_int_value,
4099 bad_value_block,
4100 @intCast(loaded_enum.field_names.len),
4101 .none,
4102 );
4103 defer wip_switch.finish(&wip);
4104
4105 for (0..loaded_enum.field_names.len) |field_index| {
4106 const name = try o.builder.stringNull(loaded_enum.field_names.get(ip)[field_index].toSlice(ip));
4107 const name_init = try o.builder.stringConst(name);
4108 const name_llvm_variable = try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default);
4109 try name_llvm_variable.setInitializer(name_init, &o.builder);
4110 name_llvm_variable.setMutability(.constant, &o.builder);
4111 name_llvm_variable.setAlignment(comptime .fromByteUnits(1), &o.builder);
4112 const name_llvm_global = name_llvm_variable.ptrConst(&o.builder).global;
4113 name_llvm_global.setLinkage(.private, &o.builder);
4114 name_llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder);
4115
4116 const name_val = try o.builder.structValue(llvm_ret_ty, &.{
4117 name_llvm_global.toConst(),
4118 try o.builder.intConst(llvm_usize_ty, name.slice(&o.builder).?.len - 1),
4119 });
4120
4121 const return_block = try wip.block(1, "Name");
4122 const llvm_tag_val = switch (loaded_enum.field_values.getOrNone(ip, field_index)) {
4123 .none => try o.builder.intConst(llvm_int_ty, field_index), // auto-numbered
4124 else => |tag_val_ip| try o.lowerValue(tag_val_ip, .as_value),
4125 };
4126 try wip_switch.addCase(llvm_tag_val, return_block, &wip);
4127
4128 wip.cursor = .{ .block = return_block };
4129 _ = try wip.ret(name_val);
4130 }
4131
4132 wip.cursor = .{ .block = bad_value_block };
4133 _ = try wip.@"unreachable"();
4134
4135 try wip.finish();
4136 }
4137
4138 pub fn lazyAbiAlignment(o: *Object, pt: Zcu.PerThread, ty: Type) Allocator.Error!Builder.Alignment.Lazy {
4139 const index = o.type_pool.get(pt, .{ .llvm = o }, ty.toIntern()) catch |err| return @errorCast(err);
4140 return o.lazy_abi_aligns.items[@backingInt(index)];
4141 }
4142
4143 pub fn getIsNamedEnumValueFunction(o: *Object, enum_ty: Type) Allocator.Error!Builder.Function.Index {
4144 const zcu = o.zcu;
4145 const ip = &zcu.intern_pool;
4146
4147 const gop = try o.named_enum_map.getOrPut(o.gpa, enum_ty.toIntern());
4148 if (gop.found_existing) return gop.value_ptr.*;
4149 errdefer assert(o.named_enum_map.remove(enum_ty.toIntern()));
4150 const llvm_function = try o.builder.addFunction(
4151 // Dummy function type; `updateIsNamedEnumValue` will replace it with the correct type.
4152 // TODO: change the builder API so we don't need to do this.
4153 try o.builder.fnType(.void, &.{}, .normal),
4154 try o.builder.strtabStringFmt("__zig_is_named_enum_value_{f}", .{enum_ty.containerTypeName(ip).fqn.fmt(ip)}),
4155 toLlvmAddressSpace(.generic, zcu.getTarget()),
4156 );
4157 gop.value_ptr.* = llvm_function;
4158 try o.updateIsNamedEnumValueFunction(enum_ty, llvm_function);
4159 return llvm_function;
4160 }
4161 fn updateIsNamedEnumValueFunction(
4162 o: *Object,
4163 enum_ty: Type,
4164 llvm_function: Builder.Function.Index,
4165 ) Allocator.Error!void {
4166 const zcu = o.zcu;
4167 const ip = &zcu.intern_pool;
4168 const loaded_enum = ip.loadEnumType(enum_ty.toIntern());
4169
4170 const llvm_int_ty = try o.lowerType(.fromInterned(loaded_enum.int_tag_type), .as_value);
4171 llvm_function.ptrConst(&o.builder).global.ptr(&o.builder).type =
4172 try o.builder.fnType(.i1, &.{llvm_int_ty}, .normal);
4173
4174 var attributes: Builder.FunctionAttributes.Wip = .{};
4175 defer attributes.deinit(&o.builder);
4176 try o.addCommonFnAttributes(&attributes, zcu.root_mod, zcu.root_mod.omit_frame_pointer);
4177
4178 llvm_function.setLinkage(if (o.builder.strip) .private else .internal, &o.builder);
4179 llvm_function.setCallConv(.fastcc, &o.builder);
4180 llvm_function.setAttributes(try attributes.finish(&o.builder), &o.builder);
4181
4182 var wip: Builder.WipFunction = try .init(&o.builder, .{
4183 .function = llvm_function,
4184 .strip = true,
4185 });
4186 defer wip.deinit();
4187 wip.cursor = .{ .block = try wip.block(0, "Entry") };
4188
4189 const named_block = try wip.block(@intCast(loaded_enum.field_names.len), "Named");
4190 const unnamed_block = try wip.block(1, "Unnamed");
4191 const tag_int_value = wip.arg(0);
4192 var wip_switch = try wip.@"switch"(tag_int_value, unnamed_block, @intCast(loaded_enum.field_names.len), .none);
4193 defer wip_switch.finish(&wip);
4194
4195 if (loaded_enum.field_values.len > 0) {
4196 for (loaded_enum.field_values.get(ip)) |tag_val_ip| {
4197 const llvm_tag_val = try o.lowerValue(tag_val_ip, .as_value);
4198 try wip_switch.addCase(llvm_tag_val, named_block, &wip);
4199 }
4200 } else {
4201 // Auto-numbered.
4202 for (0..loaded_enum.field_names.len) |field_index| {
4203 const llvm_tag_val = try o.builder.intConst(llvm_int_ty, field_index);
4204 try wip_switch.addCase(llvm_tag_val, named_block, &wip);
4205 }
4206 }
4207
4208 wip.cursor = .{ .block = named_block };
4209 _ = try wip.ret(.true);
4210
4211 wip.cursor = .{ .block = unnamed_block };
4212 _ = try wip.ret(.false);
4213
4214 try wip.finish();
4215 }
4216
4217 pub fn getLibcFunction(
4218 o: *Object,
4219 pt: Zcu.PerThread,
4220 fn_name: Builder.StrtabString,
4221 fn_info: FuncInfo,
4222 ) Allocator.Error!Builder.Function.Index {
4223 if (o.builder.getGlobal(fn_name)) |global| return switch (global.ptrConst(&o.builder).kind) {
4224 .alias => |alias| alias.getAliasee(&o.builder).ptrConst(&o.builder).kind.function,
4225 .function => |function| function,
4226 .variable, .replaced => unreachable,
4227 };
4228 const llvm_function = try o.builder.addFunction(
4229 try o.lowerFnType(fn_info),
4230 fn_name,
4231 toLlvmAddressSpace(.generic, o.zcu.getTarget()),
4232 );
4233 var attributes: Builder.FunctionAttributes.Wip = .{};
4234 defer attributes.deinit(&o.builder);
4235 try o.addCallingConventionFnAttributes(pt, llvm_function, &attributes, .{
4236 .name = fn_name.slice(&o.builder).?,
4237 }, fn_info);
4238 llvm_function.setAttributes(try attributes.finish(&o.builder), &o.builder);
4239 return llvm_function;
4240 }
4241};
4242
4243const CallingConventionInfo = struct {
4244 /// The LLVM calling convention to use.
4245 llvm_cc: Builder.CallConv,
4246 /// Whether to use an `alignstack` attribute to forcibly re-align the stack pointer in the function's prologue.
4247 align_stack: bool,
4248 /// Whether the function needs a `naked` attribute.
4249 naked: bool,
4250 /// How many leading register-sized integer parameters to apply the `inreg` attribute to.
4251 inreg_int_params: u2 = 0,
4252 /// How many leading floating-point parameters to apply the `inreg` attribute to.
4253 inreg_float_params: u3 = 0,
4254};
4255
4256pub fn toLlvmCallConv(cc: std.lang.CallingConvention, target: *const std.Target) ?CallingConventionInfo {
4257 const llvm_cc = toLlvmCallConvTag(cc, target) orelse return null;
4258 const incoming_stack_alignment: ?u64, const inreg_int_params: u2, const inreg_float_params: u3 = switch (cc) {
4259 .x86_fastcall => |opts| .{ opts.incoming_stack_alignment, 2, 0 },
4260 .x86_vectorcall => |opts| .{ opts.incoming_stack_alignment, 2, 6 },
4261 inline else => |pl| switch (@TypeOf(pl)) {
4262 void => .{ null, 0, 0 },
4263 std.lang.CallingConvention.ArcInterruptOptions,
4264 std.lang.CallingConvention.ArmInterruptOptions,
4265 std.lang.CallingConvention.RiscvInterruptOptions,
4266 std.lang.CallingConvention.ShInterruptOptions,
4267 std.lang.CallingConvention.MicroblazeInterruptOptions,
4268 std.lang.CallingConvention.MipsInterruptOptions,
4269 std.lang.CallingConvention.CommonOptions,
4270 => .{ pl.incoming_stack_alignment, 0, 0 },
4271 std.lang.CallingConvention.X86RegparmOptions => .{ pl.incoming_stack_alignment, pl.register_params, 0 },
4272 std.lang.CallingConvention.SpirvKernelOptions,
4273 std.lang.CallingConvention.SpirvFragmentOptions,
4274 std.lang.CallingConvention.SpirvMeshOptions,
4275 => .{ null, 0, 0 },
4276 else => @compileError("TODO: toLlvmCallConv(." ++ @tagName(pl) ++ ")"),
4277 },
4278 };
4279 return .{
4280 .llvm_cc = llvm_cc,
4281 .align_stack = if (incoming_stack_alignment) |a| need_align: {
4282 const normal_stack_align = target.stackAlignment();
4283 break :need_align a < normal_stack_align;
4284 } else false,
4285 .naked = cc == .naked,
4286 .inreg_int_params = inreg_int_params,
4287 .inreg_float_params = inreg_float_params,
4288 };
4289}
4290pub fn toLlvmCallConvTag(cc_tag: std.lang.CallingConvention.Tag, target: *const std.Target) ?Builder.CallConv {
4291 if (target.cCallingConvention()) |default_c| {
4292 if (cc_tag == default_c) {
4293 return .ccc;
4294 }
4295 }
4296 return switch (cc_tag) {
4297 .@"inline" => unreachable,
4298 .auto, .async => .fastcc,
4299 .naked => .ccc,
4300 .x86_64_sysv => .x86_64_sysvcc,
4301 .x86_64_win => .win64cc,
4302 .x86_64_regcall_v3_sysv => if (target.cpu.arch == .x86_64 and target.os.tag != .windows)
4303 .x86_regcallcc
4304 else
4305 null,
4306 .x86_64_regcall_v4_win => if (target.cpu.arch == .x86_64 and target.os.tag == .windows)
4307 .x86_regcallcc // we use the "RegCallv4" module flag to make this correct
4308 else
4309 null,
4310 .x86_64_vectorcall => .x86_vectorcallcc,
4311 .x86_64_interrupt => .x86_intrcc,
4312 .x86_64_preserve_none => .preserve_nonecc,
4313 .x86_stdcall => .x86_stdcallcc,
4314 .x86_fastcall => .x86_fastcallcc,
4315 .x86_thiscall => .x86_thiscallcc,
4316 .x86_regcall_v3 => if (target.cpu.arch == .x86 and target.os.tag != .windows)
4317 .x86_regcallcc
4318 else
4319 null,
4320 .x86_regcall_v4_win => if (target.cpu.arch == .x86 and target.os.tag == .windows)
4321 .x86_regcallcc // we use the "RegCallv4" module flag to make this correct
4322 else
4323 null,
4324 .x86_vectorcall => .x86_vectorcallcc,
4325 .x86_interrupt => .x86_intrcc,
4326 .aarch64_vfabi => .aarch64_vector_pcs,
4327 .aarch64_vfabi_sve => .aarch64_sve_vector_pcs,
4328 .aarch64_preserve_none => .preserve_nonecc,
4329 .arm_aapcs => .arm_aapcscc,
4330 .arm_aapcs_vfp => .arm_aapcs_vfpcc,
4331 .riscv64_lp64_v => .riscv_vectorcallcc,
4332 .riscv32_ilp32_v => .riscv_vectorcallcc,
4333 .avr_builtin => .avr_builtincc,
4334 .avr_signal => .avr_signalcc,
4335 .avr_interrupt => .avr_intrcc,
4336 .m68k_rtd => .m68k_rtdcc,
4337 .m68k_interrupt => .m68k_intrcc,
4338 .msp430_interrupt => .msp430_intrcc,
4339 .amdgcn_kernel => .amdgpu_kernel,
4340 .amdgcn_cs => .amdgpu_cs,
4341 .nvptx_device => .ptx_device,
4342 .nvptx_kernel => .ptx_kernel,
4343
4344 // Calling conventions which LLVM uses function attributes for.
4345 .riscv64_interrupt,
4346 .riscv32_interrupt,
4347 .arm_interrupt,
4348 .mips64_interrupt,
4349 .mips_interrupt,
4350 .csky_interrupt,
4351 => .ccc,
4352
4353 // All the calling conventions which LLVM does not have a general representation for.
4354 // Note that these are often still supported through the `cCallingConvention` path above via `ccc`.
4355 .x86_16_cdecl,
4356 .x86_16_stdcall,
4357 .x86_16_regparmcall,
4358 .x86_16_interrupt,
4359 .x86_sysv,
4360 .x86_win,
4361 .x86_mingw,
4362 .x86_thiscall_mingw,
4363 .x86_64_x32,
4364 .aarch64_aapcs,
4365 .aarch64_aapcs_darwin,
4366 .aarch64_aapcs_win,
4367 .alpha_osf,
4368 .microblaze_std,
4369 .microblaze_interrupt,
4370 .mips64_n64,
4371 .mips64_n32,
4372 .mips_o32,
4373 .riscv64_lp64,
4374 .riscv32_ilp32,
4375 .sparc64_sysv,
4376 .sparc_sysv,
4377 .powerpc64_elf,
4378 .powerpc64_elf_altivec,
4379 .powerpc64_elf_v2,
4380 .powerpc_sysv,
4381 .powerpc_sysv_altivec,
4382 .powerpc_aix,
4383 .powerpc_aix_altivec,
4384 .wasm_mvp,
4385 .arc_sysv,
4386 .arc_interrupt,
4387 .avr_gnu,
4388 .bpf_std,
4389 .csky_sysv,
4390 .ez80_cet,
4391 .ez80_tiflags,
4392 .hexagon_sysv,
4393 .hexagon_sysv_hvx,
4394 .hppa_elf,
4395 .hppa64_elf,
4396 .kvx_lp64,
4397 .kvx_ilp32,
4398 .lanai_sysv,
4399 .loongarch64_lp64,
4400 .loongarch32_ilp32,
4401 .m68k_sysv,
4402 .m68k_gnu,
4403 .m88k_sysv,
4404 .msp430_eabi,
4405 .or1k_sysv,
4406 .propeller_sysv,
4407 .s390x_sysv,
4408 .s390x_sysv_vx,
4409 .sh_gnu,
4410 .sh_renesas,
4411 .sh_interrupt,
4412 .ve_sysv,
4413 .xcore_xs1,
4414 .xcore_xs2,
4415 .xtensa_call0,
4416 .xtensa_windowed,
4417 .amdgcn_device,
4418 .spirv_device,
4419 .spirv_kernel,
4420 .spirv_fragment,
4421 .spirv_vertex,
4422 .spirv_task,
4423 .spirv_mesh,
4424 .spork8,
4425 => null,
4426 };
4427}
4428
4429/// Convert a zig-address space to an llvm address space.
4430pub fn toLlvmAddressSpace(address_space: std.lang.AddressSpace, target: *const std.Target) Builder.AddrSpace {
4431 for (llvmAddrSpaceInfo(target)) |info| if (info.zig == address_space) return info.llvm;
4432 unreachable;
4433}
4434
4435const AddrSpaceInfo = struct {
4436 zig: ?std.lang.AddressSpace,
4437 llvm: Builder.AddrSpace,
4438 non_integral: bool = false,
4439 size: ?u16 = null,
4440 abi: ?u16 = null,
4441 pref: ?u16 = null,
4442 idx: ?u16 = null,
4443 force_in_data_layout: bool = false,
4444};
4445fn llvmAddrSpaceInfo(target: *const std.Target) []const AddrSpaceInfo {
4446 return switch (target.cpu.arch) {
4447 .x86, .x86_64 => &.{
4448 .{ .zig = .generic, .llvm = .default },
4449 .{ .zig = .gs, .llvm = Builder.AddrSpace.x86.gs },
4450 .{ .zig = .fs, .llvm = Builder.AddrSpace.x86.fs },
4451 .{ .zig = .ss, .llvm = Builder.AddrSpace.x86.ss },
4452 .{ .zig = null, .llvm = Builder.AddrSpace.x86.ptr32_sptr, .size = 32, .abi = 32, .force_in_data_layout = true },
4453 .{ .zig = null, .llvm = Builder.AddrSpace.x86.ptr32_uptr, .size = 32, .abi = 32, .force_in_data_layout = true },
4454 .{ .zig = null, .llvm = Builder.AddrSpace.x86.ptr64, .size = 64, .abi = 64, .force_in_data_layout = true },
4455 },
4456 .nvptx, .nvptx64 => &.{
4457 .{ .zig = .generic, .llvm = Builder.AddrSpace.nvptx.generic },
4458 .{ .zig = .global, .llvm = Builder.AddrSpace.nvptx.global },
4459 .{ .zig = .constant, .llvm = Builder.AddrSpace.nvptx.constant },
4460 .{ .zig = .param, .llvm = Builder.AddrSpace.nvptx.param },
4461 .{ .zig = .shared, .llvm = Builder.AddrSpace.nvptx.shared },
4462 .{ .zig = .local, .llvm = Builder.AddrSpace.nvptx.local },
4463 },
4464 .amdgcn => &.{
4465 .{ .zig = .generic, .llvm = Builder.AddrSpace.amdgpu.flat, .force_in_data_layout = true },
4466 .{ .zig = .global, .llvm = Builder.AddrSpace.amdgpu.global, .force_in_data_layout = true },
4467 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.region, .size = 32, .abi = 32 },
4468 .{ .zig = .shared, .llvm = Builder.AddrSpace.amdgpu.local, .size = 32, .abi = 32 },
4469 .{ .zig = .constant, .llvm = Builder.AddrSpace.amdgpu.constant, .force_in_data_layout = true },
4470 .{ .zig = .local, .llvm = Builder.AddrSpace.amdgpu.private, .size = 32, .abi = 32 },
4471 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.constant_32bit, .size = 32, .abi = 32 },
4472 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.buffer_fat_pointer, .non_integral = true, .size = 160, .abi = 256, .idx = 32 },
4473 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.buffer_resource, .non_integral = true, .size = 128, .abi = 128 },
4474 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.buffer_strided_pointer, .non_integral = true, .size = 192, .abi = 256, .idx = 32 },
4475 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.constant_buffer_0 },
4476 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.constant_buffer_1 },
4477 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.constant_buffer_2 },
4478 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.constant_buffer_3 },
4479 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.constant_buffer_4 },
4480 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.constant_buffer_5 },
4481 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.constant_buffer_6 },
4482 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.constant_buffer_7 },
4483 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.constant_buffer_8 },
4484 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.constant_buffer_9 },
4485 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.constant_buffer_10 },
4486 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.constant_buffer_11 },
4487 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.constant_buffer_12 },
4488 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.constant_buffer_13 },
4489 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.constant_buffer_14 },
4490 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.constant_buffer_15 },
4491 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.streamout_register },
4492 },
4493 .avr => &.{
4494 .{ .zig = .generic, .llvm = Builder.AddrSpace.avr.data, .abi = 8 },
4495 .{ .zig = .flash, .llvm = Builder.AddrSpace.avr.program, .abi = 8 },
4496 .{ .zig = .flash1, .llvm = Builder.AddrSpace.avr.program1, .abi = 8 },
4497 .{ .zig = .flash2, .llvm = Builder.AddrSpace.avr.program2, .abi = 8 },
4498 .{ .zig = .flash3, .llvm = Builder.AddrSpace.avr.program3, .abi = 8 },
4499 .{ .zig = .flash4, .llvm = Builder.AddrSpace.avr.program4, .abi = 8 },
4500 .{ .zig = .flash5, .llvm = Builder.AddrSpace.avr.program5, .abi = 8 },
4501 },
4502 .wasm32, .wasm64 => &.{
4503 .{ .zig = .generic, .llvm = Builder.AddrSpace.wasm.default, .force_in_data_layout = true },
4504 .{ .zig = null, .llvm = Builder.AddrSpace.wasm.variable, .non_integral = true },
4505 .{ .zig = .externref, .llvm = Builder.AddrSpace.wasm.externref, .non_integral = true, .size = 8, .abi = 8 },
4506 .{ .zig = .funcref, .llvm = Builder.AddrSpace.wasm.funcref, .non_integral = true, .size = 8, .abi = 8 },
4507 },
4508 .m68k => &.{
4509 .{ .zig = .generic, .llvm = .default, .abi = 16, .pref = 32 },
4510 },
4511 else => &.{
4512 .{ .zig = .generic, .llvm = .default },
4513 },
4514 };
4515}
4516
4517/// On some targets, global values that are in the generic address space must be generated into a
4518/// different address space, and then cast back to the generic address space.
4519fn llvmDefaultGlobalAddressSpace(target: *const std.Target) Builder.AddrSpace {
4520 return switch (target.cpu.arch) {
4521 // On amdgcn, globals must be explicitly allocated and uploaded so that the program can access
4522 // them.
4523 .amdgcn => Builder.AddrSpace.amdgpu.global,
4524 else => .default,
4525 };
4526}
4527
4528/// Return the actual address space that a value should be stored in if its a global address space.
4529/// When a value is placed in the resulting address space, it needs to be cast back into wanted_address_space.
4530fn toLlvmGlobalAddressSpace(wanted_address_space: std.lang.AddressSpace, target: *const std.Target) Builder.AddrSpace {
4531 return switch (wanted_address_space) {
4532 .generic => llvmDefaultGlobalAddressSpace(target),
4533 else => |as| toLlvmAddressSpace(as, target),
4534 };
4535}
4536
4537/// We need to insert extra padding if LLVM's isn't enough.
4538/// However we don't want to ever call LLVMABIAlignmentOfType or
4539/// LLVMABISizeOfType because these functions will trip assertions
4540/// when using them for self-referential types. So our strategy is
4541/// to use non-packed llvm structs but to emit all padding explicitly.
4542/// We can do this because for all types, Zig ABI alignment >= LLVM ABI
4543/// alignment.
4544const struct_layout_version = 2;
4545
4546// TODO: Restore the non_null field to i1 once
4547// https://github.com/llvm/llvm-project/issues/56585/ is fixed
4548pub const optional_layout_version = 3;
4549
4550var target_registry_mutex: std.Io.Mutex = .init;
4551
4552pub fn initializeLLVMTarget(io: Io, arch: std.Target.Cpu.Arch) void {
4553 // Repeated initialization is safe, as targets which have already been registered will be skipped.
4554 // It is however the client's responsibility to synchronize registry access.
4555 target_registry_mutex.lockUncancelable(io);
4556 defer target_registry_mutex.unlock(io);
4557
4558 switch (arch) {
4559 .aarch64, .aarch64_be => {
4560 bindings.LLVMInitializeAArch64Target();
4561 bindings.LLVMInitializeAArch64TargetInfo();
4562 bindings.LLVMInitializeAArch64TargetMC();
4563 bindings.LLVMInitializeAArch64AsmPrinter();
4564 bindings.LLVMInitializeAArch64AsmParser();
4565 },
4566 .amdgcn => {
4567 bindings.LLVMInitializeAMDGPUTarget();
4568 bindings.LLVMInitializeAMDGPUTargetInfo();
4569 bindings.LLVMInitializeAMDGPUTargetMC();
4570 bindings.LLVMInitializeAMDGPUAsmPrinter();
4571 bindings.LLVMInitializeAMDGPUAsmParser();
4572 },
4573 .thumb, .thumbeb, .arm, .armeb => {
4574 bindings.LLVMInitializeARMTarget();
4575 bindings.LLVMInitializeARMTargetInfo();
4576 bindings.LLVMInitializeARMTargetMC();
4577 bindings.LLVMInitializeARMAsmPrinter();
4578 bindings.LLVMInitializeARMAsmParser();
4579 },
4580 .avr => {
4581 bindings.LLVMInitializeAVRTarget();
4582 bindings.LLVMInitializeAVRTargetInfo();
4583 bindings.LLVMInitializeAVRTargetMC();
4584 bindings.LLVMInitializeAVRAsmPrinter();
4585 bindings.LLVMInitializeAVRAsmParser();
4586 },
4587 .bpfel, .bpfeb => {
4588 bindings.LLVMInitializeBPFTarget();
4589 bindings.LLVMInitializeBPFTargetInfo();
4590 bindings.LLVMInitializeBPFTargetMC();
4591 bindings.LLVMInitializeBPFAsmPrinter();
4592 bindings.LLVMInitializeBPFAsmParser();
4593 },
4594 .hexagon => {
4595 bindings.LLVMInitializeHexagonTarget();
4596 bindings.LLVMInitializeHexagonTargetInfo();
4597 bindings.LLVMInitializeHexagonTargetMC();
4598 bindings.LLVMInitializeHexagonAsmPrinter();
4599 bindings.LLVMInitializeHexagonAsmParser();
4600 },
4601 .lanai => {
4602 bindings.LLVMInitializeLanaiTarget();
4603 bindings.LLVMInitializeLanaiTargetInfo();
4604 bindings.LLVMInitializeLanaiTargetMC();
4605 bindings.LLVMInitializeLanaiAsmPrinter();
4606 bindings.LLVMInitializeLanaiAsmParser();
4607 },
4608 .mips, .mipsel, .mips64, .mips64el => {
4609 bindings.LLVMInitializeMipsTarget();
4610 bindings.LLVMInitializeMipsTargetInfo();
4611 bindings.LLVMInitializeMipsTargetMC();
4612 bindings.LLVMInitializeMipsAsmPrinter();
4613 bindings.LLVMInitializeMipsAsmParser();
4614 },
4615 .msp430 => {
4616 bindings.LLVMInitializeMSP430Target();
4617 bindings.LLVMInitializeMSP430TargetInfo();
4618 bindings.LLVMInitializeMSP430TargetMC();
4619 bindings.LLVMInitializeMSP430AsmPrinter();
4620 bindings.LLVMInitializeMSP430AsmParser();
4621 },
4622 .nvptx, .nvptx64 => {
4623 bindings.LLVMInitializeNVPTXTarget();
4624 bindings.LLVMInitializeNVPTXTargetInfo();
4625 bindings.LLVMInitializeNVPTXTargetMC();
4626 bindings.LLVMInitializeNVPTXAsmPrinter();
4627 // There is no LLVMInitializeNVPTXAsmParser function available.
4628 },
4629 .powerpc, .powerpcle, .powerpc64, .powerpc64le => {
4630 bindings.LLVMInitializePowerPCTarget();
4631 bindings.LLVMInitializePowerPCTargetInfo();
4632 bindings.LLVMInitializePowerPCTargetMC();
4633 bindings.LLVMInitializePowerPCAsmPrinter();
4634 bindings.LLVMInitializePowerPCAsmParser();
4635 },
4636 .riscv32, .riscv32be, .riscv64, .riscv64be => {
4637 bindings.LLVMInitializeRISCVTarget();
4638 bindings.LLVMInitializeRISCVTargetInfo();
4639 bindings.LLVMInitializeRISCVTargetMC();
4640 bindings.LLVMInitializeRISCVAsmPrinter();
4641 bindings.LLVMInitializeRISCVAsmParser();
4642 },
4643 .sparc, .sparc64 => {
4644 bindings.LLVMInitializeSparcTarget();
4645 bindings.LLVMInitializeSparcTargetInfo();
4646 bindings.LLVMInitializeSparcTargetMC();
4647 bindings.LLVMInitializeSparcAsmPrinter();
4648 bindings.LLVMInitializeSparcAsmParser();
4649 },
4650 .s390x => {
4651 bindings.LLVMInitializeSystemZTarget();
4652 bindings.LLVMInitializeSystemZTargetInfo();
4653 bindings.LLVMInitializeSystemZTargetMC();
4654 bindings.LLVMInitializeSystemZAsmPrinter();
4655 bindings.LLVMInitializeSystemZAsmParser();
4656 },
4657 .wasm32, .wasm64 => {
4658 bindings.LLVMInitializeWebAssemblyTarget();
4659 bindings.LLVMInitializeWebAssemblyTargetInfo();
4660 bindings.LLVMInitializeWebAssemblyTargetMC();
4661 bindings.LLVMInitializeWebAssemblyAsmPrinter();
4662 bindings.LLVMInitializeWebAssemblyAsmParser();
4663 },
4664 .x86, .x86_64 => {
4665 bindings.LLVMInitializeX86Target();
4666 bindings.LLVMInitializeX86TargetInfo();
4667 bindings.LLVMInitializeX86TargetMC();
4668 bindings.LLVMInitializeX86AsmPrinter();
4669 bindings.LLVMInitializeX86AsmParser();
4670 },
4671 .xtensa => {
4672 if (build_options.llvm_has_xtensa) {
4673 bindings.LLVMInitializeXtensaTarget();
4674 bindings.LLVMInitializeXtensaTargetInfo();
4675 bindings.LLVMInitializeXtensaTargetMC();
4676 bindings.LLVMInitializeXtensaAsmPrinter();
4677 bindings.LLVMInitializeXtensaAsmParser();
4678 }
4679 },
4680 .xcore => {
4681 bindings.LLVMInitializeXCoreTarget();
4682 bindings.LLVMInitializeXCoreTargetInfo();
4683 bindings.LLVMInitializeXCoreTargetMC();
4684 bindings.LLVMInitializeXCoreAsmPrinter();
4685 // There is no LLVMInitializeXCoreAsmParser function.
4686 },
4687 .m68k => {
4688 if (build_options.llvm_has_m68k) {
4689 bindings.LLVMInitializeM68kTarget();
4690 bindings.LLVMInitializeM68kTargetInfo();
4691 bindings.LLVMInitializeM68kTargetMC();
4692 bindings.LLVMInitializeM68kAsmPrinter();
4693 bindings.LLVMInitializeM68kAsmParser();
4694 }
4695 },
4696 .csky => {
4697 if (build_options.llvm_has_csky) {
4698 bindings.LLVMInitializeCSKYTarget();
4699 bindings.LLVMInitializeCSKYTargetInfo();
4700 bindings.LLVMInitializeCSKYTargetMC();
4701 // There is no LLVMInitializeCSKYAsmPrinter function.
4702 bindings.LLVMInitializeCSKYAsmParser();
4703 }
4704 },
4705 .ve => {
4706 bindings.LLVMInitializeVETarget();
4707 bindings.LLVMInitializeVETargetInfo();
4708 bindings.LLVMInitializeVETargetMC();
4709 bindings.LLVMInitializeVEAsmPrinter();
4710 bindings.LLVMInitializeVEAsmParser();
4711 },
4712 .arc => {
4713 if (build_options.llvm_has_arc) {
4714 bindings.LLVMInitializeARCTarget();
4715 bindings.LLVMInitializeARCTargetInfo();
4716 bindings.LLVMInitializeARCTargetMC();
4717 bindings.LLVMInitializeARCAsmPrinter();
4718 // There is no LLVMInitializeARCAsmParser function.
4719 }
4720 },
4721 .loongarch32, .loongarch64 => {
4722 bindings.LLVMInitializeLoongArchTarget();
4723 bindings.LLVMInitializeLoongArchTargetInfo();
4724 bindings.LLVMInitializeLoongArchTargetMC();
4725 bindings.LLVMInitializeLoongArchAsmPrinter();
4726 bindings.LLVMInitializeLoongArchAsmParser();
4727 },
4728 .spirv32,
4729 .spirv64,
4730 => {
4731 bindings.LLVMInitializeSPIRVTarget();
4732 bindings.LLVMInitializeSPIRVTargetInfo();
4733 bindings.LLVMInitializeSPIRVTargetMC();
4734 bindings.LLVMInitializeSPIRVAsmPrinter();
4735 },
4736
4737 // LLVM does does not have a backend for these.
4738 .alpha,
4739 .arceb,
4740 .ez80,
4741 .hppa,
4742 .hppa64,
4743 .kalimba,
4744 .kvx,
4745 .m88k,
4746 .microblaze,
4747 .microblazeel,
4748 .or1k,
4749 .propeller,
4750 .sh,
4751 .sheb,
4752 .spork8,
4753 .x86_16,
4754 .xtensaeb,
4755 => unreachable,
4756 }
4757}