zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

blob ffc19cb6 (493861B) - Raw


      1 const std = @import("std");
      2 const builtin = @import("builtin");
      3 const assert = std.debug.assert;
      4 const Allocator = std.mem.Allocator;
      5 const log = std.log.scoped(.codegen);
      6 const math = std.math;
      7 const native_endian = builtin.cpu.arch.endian();
      8 const DW = std.dwarf;
      9 
     10 const llvm = @import("llvm/bindings.zig");
     11 const link = @import("../link.zig");
     12 const Compilation = @import("../Compilation.zig");
     13 const build_options = @import("build_options");
     14 const Module = @import("../Module.zig");
     15 const Package = @import("../Package.zig");
     16 const TypedValue = @import("../TypedValue.zig");
     17 const Air = @import("../Air.zig");
     18 const Liveness = @import("../Liveness.zig");
     19 const target_util = @import("../target.zig");
     20 const Value = @import("../value.zig").Value;
     21 const Type = @import("../type.zig").Type;
     22 const LazySrcLoc = Module.LazySrcLoc;
     23 const CType = @import("../type.zig").CType;
     24 const x86_64_abi = @import("../arch/x86_64/abi.zig");
     25 const wasm_c_abi = @import("../arch/wasm/abi.zig");
     26 const aarch64_c_abi = @import("../arch/aarch64/abi.zig");
     27 const arm_c_abi = @import("../arch/arm/abi.zig");
     28 const riscv_c_abi = @import("../arch/riscv64/abi.zig");
     29 
     30 const Error = error{ OutOfMemory, CodegenFail };
     31 
     32 pub fn targetTriple(allocator: Allocator, target: std.Target) ![:0]u8 {
     33     var llvm_triple = std.ArrayList(u8).init(allocator);
     34     defer llvm_triple.deinit();
     35 
     36     const llvm_arch = switch (target.cpu.arch) {
     37         .arm => "arm",
     38         .armeb => "armeb",
     39         .aarch64 => "aarch64",
     40         .aarch64_be => "aarch64_be",
     41         .aarch64_32 => "aarch64_32",
     42         .arc => "arc",
     43         .avr => "avr",
     44         .bpfel => "bpfel",
     45         .bpfeb => "bpfeb",
     46         .csky => "csky",
     47         .dxil => "dxil",
     48         .hexagon => "hexagon",
     49         .loongarch32 => "loongarch32",
     50         .loongarch64 => "loongarch64",
     51         .m68k => "m68k",
     52         .mips => "mips",
     53         .mipsel => "mipsel",
     54         .mips64 => "mips64",
     55         .mips64el => "mips64el",
     56         .msp430 => "msp430",
     57         .powerpc => "powerpc",
     58         .powerpcle => "powerpcle",
     59         .powerpc64 => "powerpc64",
     60         .powerpc64le => "powerpc64le",
     61         .r600 => "r600",
     62         .amdgcn => "amdgcn",
     63         .riscv32 => "riscv32",
     64         .riscv64 => "riscv64",
     65         .sparc => "sparc",
     66         .sparc64 => "sparc64",
     67         .sparcel => "sparcel",
     68         .s390x => "s390x",
     69         .tce => "tce",
     70         .tcele => "tcele",
     71         .thumb => "thumb",
     72         .thumbeb => "thumbeb",
     73         .i386 => "i386",
     74         .x86_64 => "x86_64",
     75         .xcore => "xcore",
     76         .nvptx => "nvptx",
     77         .nvptx64 => "nvptx64",
     78         .le32 => "le32",
     79         .le64 => "le64",
     80         .amdil => "amdil",
     81         .amdil64 => "amdil64",
     82         .hsail => "hsail",
     83         .hsail64 => "hsail64",
     84         .spir => "spir",
     85         .spir64 => "spir64",
     86         .kalimba => "kalimba",
     87         .shave => "shave",
     88         .lanai => "lanai",
     89         .wasm32 => "wasm32",
     90         .wasm64 => "wasm64",
     91         .renderscript32 => "renderscript32",
     92         .renderscript64 => "renderscript64",
     93         .ve => "ve",
     94         .spu_2 => return error.@"LLVM backend does not support SPU Mark II",
     95         .spirv32 => return error.@"LLVM backend does not support SPIR-V",
     96         .spirv64 => return error.@"LLVM backend does not support SPIR-V",
     97     };
     98     try llvm_triple.appendSlice(llvm_arch);
     99     try llvm_triple.appendSlice("-unknown-");
    100 
    101     const llvm_os = switch (target.os.tag) {
    102         .freestanding => "unknown",
    103         .ananas => "ananas",
    104         .cloudabi => "cloudabi",
    105         .dragonfly => "dragonfly",
    106         .freebsd => "freebsd",
    107         .fuchsia => "fuchsia",
    108         .kfreebsd => "kfreebsd",
    109         .linux => "linux",
    110         .lv2 => "lv2",
    111         .netbsd => "netbsd",
    112         .openbsd => "openbsd",
    113         .solaris => "solaris",
    114         .windows => "windows",
    115         .zos => "zos",
    116         .haiku => "haiku",
    117         .minix => "minix",
    118         .rtems => "rtems",
    119         .nacl => "nacl",
    120         .aix => "aix",
    121         .cuda => "cuda",
    122         .nvcl => "nvcl",
    123         .amdhsa => "amdhsa",
    124         .ps4 => "ps4",
    125         .ps5 => "ps5",
    126         .elfiamcu => "elfiamcu",
    127         .mesa3d => "mesa3d",
    128         .contiki => "contiki",
    129         .amdpal => "amdpal",
    130         .hermit => "hermit",
    131         .hurd => "hurd",
    132         .wasi => "wasi",
    133         .emscripten => "emscripten",
    134         .uefi => "windows",
    135         .macos => "macosx",
    136         .ios => "ios",
    137         .tvos => "tvos",
    138         .watchos => "watchos",
    139         .driverkit => "driverkit",
    140         .shadermodel => "shadermodel",
    141         .opencl,
    142         .glsl450,
    143         .vulkan,
    144         .plan9,
    145         .other,
    146         => "unknown",
    147     };
    148     try llvm_triple.appendSlice(llvm_os);
    149 
    150     if (target.os.tag.isDarwin()) {
    151         const min_version = target.os.version_range.semver.min;
    152         try llvm_triple.writer().print("{d}.{d}.{d}", .{
    153             min_version.major,
    154             min_version.minor,
    155             min_version.patch,
    156         });
    157     }
    158     try llvm_triple.append('-');
    159 
    160     const llvm_abi = switch (target.abi) {
    161         .none => "unknown",
    162         .gnu => "gnu",
    163         .gnuabin32 => "gnuabin32",
    164         .gnuabi64 => "gnuabi64",
    165         .gnueabi => "gnueabi",
    166         .gnueabihf => "gnueabihf",
    167         .gnux32 => "gnux32",
    168         .gnuilp32 => "gnuilp32",
    169         .code16 => "code16",
    170         .eabi => "eabi",
    171         .eabihf => "eabihf",
    172         .android => "android",
    173         .musl => "musl",
    174         .musleabi => "musleabi",
    175         .musleabihf => "musleabihf",
    176         .muslx32 => "muslx32",
    177         .msvc => "msvc",
    178         .itanium => "itanium",
    179         .cygnus => "cygnus",
    180         .coreclr => "coreclr",
    181         .simulator => "simulator",
    182         .macabi => "macabi",
    183         .pixel => "pixel",
    184         .vertex => "vertex",
    185         .geometry => "geometry",
    186         .hull => "hull",
    187         .domain => "domain",
    188         .compute => "compute",
    189         .library => "library",
    190         .raygeneration => "raygeneration",
    191         .intersection => "intersection",
    192         .anyhit => "anyhit",
    193         .closesthit => "closesthit",
    194         .miss => "miss",
    195         .callable => "callable",
    196         .mesh => "mesh",
    197         .amplification => "amplification",
    198     };
    199     try llvm_triple.appendSlice(llvm_abi);
    200 
    201     return llvm_triple.toOwnedSliceSentinel(0);
    202 }
    203 
    204 pub fn targetOs(os_tag: std.Target.Os.Tag) llvm.OSType {
    205     return switch (os_tag) {
    206         .freestanding, .other, .opencl, .glsl450, .vulkan, .plan9 => .UnknownOS,
    207         .windows, .uefi => .Win32,
    208         .ananas => .Ananas,
    209         .cloudabi => .CloudABI,
    210         .dragonfly => .DragonFly,
    211         .freebsd => .FreeBSD,
    212         .fuchsia => .Fuchsia,
    213         .ios => .IOS,
    214         .kfreebsd => .KFreeBSD,
    215         .linux => .Linux,
    216         .lv2 => .Lv2,
    217         .macos => .MacOSX,
    218         .netbsd => .NetBSD,
    219         .openbsd => .OpenBSD,
    220         .solaris => .Solaris,
    221         .zos => .ZOS,
    222         .haiku => .Haiku,
    223         .minix => .Minix,
    224         .rtems => .RTEMS,
    225         .nacl => .NaCl,
    226         .aix => .AIX,
    227         .cuda => .CUDA,
    228         .nvcl => .NVCL,
    229         .amdhsa => .AMDHSA,
    230         .ps4 => .PS4,
    231         .ps5 => .PS5,
    232         .elfiamcu => .ELFIAMCU,
    233         .tvos => .TvOS,
    234         .watchos => .WatchOS,
    235         .mesa3d => .Mesa3D,
    236         .contiki => .Contiki,
    237         .amdpal => .AMDPAL,
    238         .hermit => .HermitCore,
    239         .hurd => .Hurd,
    240         .wasi => .WASI,
    241         .emscripten => .Emscripten,
    242         .driverkit => .DriverKit,
    243         .shadermodel => .ShaderModel,
    244     };
    245 }
    246 
    247 pub fn targetArch(arch_tag: std.Target.Cpu.Arch) llvm.ArchType {
    248     return switch (arch_tag) {
    249         .arm => .arm,
    250         .armeb => .armeb,
    251         .aarch64 => .aarch64,
    252         .aarch64_be => .aarch64_be,
    253         .aarch64_32 => .aarch64_32,
    254         .arc => .arc,
    255         .avr => .avr,
    256         .bpfel => .bpfel,
    257         .bpfeb => .bpfeb,
    258         .csky => .csky,
    259         .dxil => .dxil,
    260         .hexagon => .hexagon,
    261         .loongarch32 => .loongarch32,
    262         .loongarch64 => .loongarch64,
    263         .m68k => .m68k,
    264         .mips => .mips,
    265         .mipsel => .mipsel,
    266         .mips64 => .mips64,
    267         .mips64el => .mips64el,
    268         .msp430 => .msp430,
    269         .powerpc => .ppc,
    270         .powerpcle => .ppcle,
    271         .powerpc64 => .ppc64,
    272         .powerpc64le => .ppc64le,
    273         .r600 => .r600,
    274         .amdgcn => .amdgcn,
    275         .riscv32 => .riscv32,
    276         .riscv64 => .riscv64,
    277         .sparc => .sparc,
    278         .sparc64 => .sparcv9, // In LLVM, sparc64 == sparcv9.
    279         .sparcel => .sparcel,
    280         .s390x => .systemz,
    281         .tce => .tce,
    282         .tcele => .tcele,
    283         .thumb => .thumb,
    284         .thumbeb => .thumbeb,
    285         .i386 => .x86,
    286         .x86_64 => .x86_64,
    287         .xcore => .xcore,
    288         .nvptx => .nvptx,
    289         .nvptx64 => .nvptx64,
    290         .le32 => .le32,
    291         .le64 => .le64,
    292         .amdil => .amdil,
    293         .amdil64 => .amdil64,
    294         .hsail => .hsail,
    295         .hsail64 => .hsail64,
    296         .spir => .spir,
    297         .spir64 => .spir64,
    298         .kalimba => .kalimba,
    299         .shave => .shave,
    300         .lanai => .lanai,
    301         .wasm32 => .wasm32,
    302         .wasm64 => .wasm64,
    303         .renderscript32 => .renderscript32,
    304         .renderscript64 => .renderscript64,
    305         .ve => .ve,
    306         .spu_2, .spirv32, .spirv64 => .UnknownArch,
    307     };
    308 }
    309 
    310 pub fn supportsTailCall(target: std.Target) bool {
    311     switch (target.cpu.arch) {
    312         .wasm32, .wasm64 => return std.Target.wasm.featureSetHas(target.cpu.features, .tail_call),
    313         // Although these ISAs support tail calls, LLVM does not support tail calls on them.
    314         .mips, .mipsel, .mips64, .mips64el => return false,
    315         .powerpc, .powerpcle, .powerpc64, .powerpc64le => return false,
    316         else => return true,
    317     }
    318 }
    319 
    320 /// TODO can this be done with simpler logic / different API binding?
    321 fn deleteLlvmGlobal(llvm_global: *llvm.Value) void {
    322     if (llvm_global.globalGetValueType().getTypeKind() == .Function) {
    323         llvm_global.deleteFunction();
    324         return;
    325     }
    326     return llvm_global.deleteGlobal();
    327 }
    328 
    329 pub const Object = struct {
    330     gpa: Allocator,
    331     module: *Module,
    332     llvm_module: *llvm.Module,
    333     di_builder: ?*llvm.DIBuilder,
    334     /// One of these mappings:
    335     /// - *Module.File => *DIFile
    336     /// - *Module.Decl (Fn) => *DISubprogram
    337     /// - *Module.Decl (Non-Fn) => *DIGlobalVariable
    338     di_map: std.AutoHashMapUnmanaged(*const anyopaque, *llvm.DINode),
    339     di_compile_unit: ?*llvm.DICompileUnit,
    340     context: *llvm.Context,
    341     target_machine: *llvm.TargetMachine,
    342     target_data: *llvm.TargetData,
    343     target: std.Target,
    344     /// Ideally we would use `llvm_module.getNamedFunction` to go from *Decl to LLVM function,
    345     /// but that has some downsides:
    346     /// * we have to compute the fully qualified name every time we want to do the lookup
    347     /// * for externally linked functions, the name is not fully qualified, but when
    348     ///   a Decl goes from exported to not exported and vice-versa, we would use the wrong
    349     ///   version of the name and incorrectly get function not found in the llvm module.
    350     /// * it works for functions not all globals.
    351     /// Therefore, this table keeps track of the mapping.
    352     decl_map: std.AutoHashMapUnmanaged(Module.Decl.Index, *llvm.Value),
    353     /// Serves the same purpose as `decl_map` but only used for the `is_named_enum_value` instruction.
    354     named_enum_map: std.AutoHashMapUnmanaged(Module.Decl.Index, *llvm.Value),
    355     /// Maps Zig types to LLVM types. The table memory itself is backed by the GPA of
    356     /// the compiler, but the Type/Value memory here is backed by `type_map_arena`.
    357     /// TODO we need to remove entries from this map in response to incremental compilation
    358     /// but I think the frontend won't tell us about types that get deleted because
    359     /// hasRuntimeBits() is false for types.
    360     type_map: TypeMap,
    361     /// The backing memory for `type_map`. Periodically garbage collected after flush().
    362     /// The code for doing the periodical GC is not yet implemented.
    363     type_map_arena: std.heap.ArenaAllocator,
    364     di_type_map: DITypeMap,
    365     /// The LLVM global table which holds the names corresponding to Zig errors.
    366     /// Note that the values are not added until flushModule, when all errors in
    367     /// the compilation are known.
    368     error_name_table: ?*llvm.Value,
    369     /// This map is usually very close to empty. It tracks only the cases when a
    370     /// second extern Decl could not be emitted with the correct name due to a
    371     /// name collision.
    372     extern_collisions: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void),
    373 
    374     pub const TypeMap = std.HashMapUnmanaged(
    375         Type,
    376         *llvm.Type,
    377         Type.HashContext64,
    378         std.hash_map.default_max_load_percentage,
    379     );
    380 
    381     /// This is an ArrayHashMap as opposed to a HashMap because in `flushModule` we
    382     /// want to iterate over it while adding entries to it.
    383     pub const DITypeMap = std.ArrayHashMapUnmanaged(
    384         Type,
    385         AnnotatedDITypePtr,
    386         Type.HashContext32,
    387         true,
    388     );
    389 
    390     pub fn create(gpa: Allocator, options: link.Options) !*Object {
    391         const obj = try gpa.create(Object);
    392         errdefer gpa.destroy(obj);
    393         obj.* = try Object.init(gpa, options);
    394         return obj;
    395     }
    396 
    397     pub fn init(gpa: Allocator, options: link.Options) !Object {
    398         const context = llvm.Context.create();
    399         errdefer context.dispose();
    400 
    401         initializeLLVMTarget(options.target.cpu.arch);
    402 
    403         const llvm_module = llvm.Module.createWithName(options.root_name.ptr, context);
    404         errdefer llvm_module.dispose();
    405 
    406         const llvm_target_triple = try targetTriple(gpa, options.target);
    407         defer gpa.free(llvm_target_triple);
    408 
    409         var error_message: [*:0]const u8 = undefined;
    410         var target: *llvm.Target = undefined;
    411         if (llvm.Target.getFromTriple(llvm_target_triple.ptr, &target, &error_message).toBool()) {
    412             defer llvm.disposeMessage(error_message);
    413 
    414             log.err("LLVM failed to parse '{s}': {s}", .{ llvm_target_triple, error_message });
    415             return error.InvalidLlvmTriple;
    416         }
    417 
    418         llvm_module.setTarget(llvm_target_triple.ptr);
    419         var opt_di_builder: ?*llvm.DIBuilder = null;
    420         errdefer if (opt_di_builder) |di_builder| di_builder.dispose();
    421 
    422         var di_compile_unit: ?*llvm.DICompileUnit = null;
    423 
    424         if (!options.strip) {
    425             switch (options.target.ofmt) {
    426                 .coff => llvm_module.addModuleCodeViewFlag(),
    427                 else => llvm_module.addModuleDebugInfoFlag(),
    428             }
    429             const di_builder = llvm_module.createDIBuilder(true);
    430             opt_di_builder = di_builder;
    431 
    432             // Don't use the version string here; LLVM misparses it when it
    433             // includes the git revision.
    434             const producer = try std.fmt.allocPrintZ(gpa, "zig {d}.{d}.{d}", .{
    435                 build_options.semver.major,
    436                 build_options.semver.minor,
    437                 build_options.semver.patch,
    438             });
    439             defer gpa.free(producer);
    440 
    441             // For macOS stack traces, we want to avoid having to parse the compilation unit debug
    442             // info. As long as each debug info file has a path independent of the compilation unit
    443             // directory (DW_AT_comp_dir), then we never have to look at the compilation unit debug
    444             // info. If we provide an absolute path to LLVM here for the compilation unit debug
    445             // info, LLVM will emit DWARF info that depends on DW_AT_comp_dir. To avoid this, we
    446             // pass "." for the compilation unit directory. This forces each debug file to have a
    447             // directory rather than be relative to DW_AT_comp_dir. According to DWARF 5, debug
    448             // files will no longer reference DW_AT_comp_dir, for the purpose of being able to
    449             // support the common practice of stripping all but the line number sections from an
    450             // executable.
    451             const compile_unit_dir = d: {
    452                 if (options.target.isDarwin()) break :d ".";
    453                 const mod = options.module orelse break :d ".";
    454                 break :d mod.root_pkg.root_src_directory.path orelse ".";
    455             };
    456             const compile_unit_dir_z = try gpa.dupeZ(u8, compile_unit_dir);
    457             defer gpa.free(compile_unit_dir_z);
    458 
    459             di_compile_unit = di_builder.createCompileUnit(
    460                 DW.LANG.C99,
    461                 di_builder.createFile(options.root_name, compile_unit_dir_z),
    462                 producer,
    463                 options.optimize_mode != .Debug,
    464                 "", // flags
    465                 0, // runtime version
    466                 "", // split name
    467                 0, // dwo id
    468                 true, // emit debug info
    469             );
    470         }
    471 
    472         const opt_level: llvm.CodeGenOptLevel = if (options.optimize_mode == .Debug)
    473             .None
    474         else
    475             .Aggressive;
    476 
    477         const reloc_mode: llvm.RelocMode = if (options.pic)
    478             .PIC
    479         else if (options.link_mode == .Dynamic)
    480             llvm.RelocMode.DynamicNoPIC
    481         else
    482             .Static;
    483 
    484         const code_model: llvm.CodeModel = switch (options.machine_code_model) {
    485             .default => .Default,
    486             .tiny => .Tiny,
    487             .small => .Small,
    488             .kernel => .Kernel,
    489             .medium => .Medium,
    490             .large => .Large,
    491         };
    492 
    493         // TODO handle float ABI better- it should depend on the ABI portion of std.Target
    494         const float_abi: llvm.ABIType = .Default;
    495 
    496         const target_machine = llvm.TargetMachine.create(
    497             target,
    498             llvm_target_triple.ptr,
    499             if (options.target.cpu.model.llvm_name) |s| s.ptr else null,
    500             options.llvm_cpu_features,
    501             opt_level,
    502             reloc_mode,
    503             code_model,
    504             options.function_sections,
    505             float_abi,
    506             if (target_util.llvmMachineAbi(options.target)) |s| s.ptr else null,
    507         );
    508         errdefer target_machine.dispose();
    509 
    510         const target_data = target_machine.createTargetDataLayout();
    511         errdefer target_data.dispose();
    512 
    513         llvm_module.setModuleDataLayout(target_data);
    514 
    515         if (options.pic) llvm_module.setModulePICLevel();
    516         if (options.pie) llvm_module.setModulePIELevel();
    517         if (code_model != .Default) llvm_module.setModuleCodeModel(code_model);
    518 
    519         return Object{
    520             .gpa = gpa,
    521             .module = options.module.?,
    522             .llvm_module = llvm_module,
    523             .di_map = .{},
    524             .di_builder = opt_di_builder,
    525             .di_compile_unit = di_compile_unit,
    526             .context = context,
    527             .target_machine = target_machine,
    528             .target_data = target_data,
    529             .target = options.target,
    530             .decl_map = .{},
    531             .named_enum_map = .{},
    532             .type_map = .{},
    533             .type_map_arena = std.heap.ArenaAllocator.init(gpa),
    534             .di_type_map = .{},
    535             .error_name_table = null,
    536             .extern_collisions = .{},
    537         };
    538     }
    539 
    540     pub fn deinit(self: *Object, gpa: Allocator) void {
    541         if (self.di_builder) |dib| {
    542             dib.dispose();
    543             self.di_map.deinit(gpa);
    544             self.di_type_map.deinit(gpa);
    545         }
    546         self.target_data.dispose();
    547         self.target_machine.dispose();
    548         self.llvm_module.dispose();
    549         self.context.dispose();
    550         self.decl_map.deinit(gpa);
    551         self.named_enum_map.deinit(gpa);
    552         self.type_map.deinit(gpa);
    553         self.type_map_arena.deinit();
    554         self.extern_collisions.deinit(gpa);
    555         self.* = undefined;
    556     }
    557 
    558     pub fn destroy(self: *Object, gpa: Allocator) void {
    559         self.deinit(gpa);
    560         gpa.destroy(self);
    561     }
    562 
    563     fn locPath(
    564         arena: Allocator,
    565         opt_loc: ?Compilation.EmitLoc,
    566         cache_directory: Compilation.Directory,
    567     ) !?[*:0]u8 {
    568         const loc = opt_loc orelse return null;
    569         const directory = loc.directory orelse cache_directory;
    570         const slice = try directory.joinZ(arena, &[_][]const u8{loc.basename});
    571         return slice.ptr;
    572     }
    573 
    574     fn genErrorNameTable(self: *Object) !void {
    575         // If self.error_name_table is null, there was no instruction that actually referenced the error table.
    576         const error_name_table_ptr_global = self.error_name_table orelse return;
    577 
    578         const mod = self.module;
    579         const target = mod.getTarget();
    580 
    581         const llvm_ptr_ty = self.context.intType(8).pointerType(0); // TODO: Address space
    582         const llvm_usize_ty = self.context.intType(target.cpu.arch.ptrBitWidth());
    583         const type_fields = [_]*llvm.Type{
    584             llvm_ptr_ty,
    585             llvm_usize_ty,
    586         };
    587         const llvm_slice_ty = self.context.structType(&type_fields, type_fields.len, .False);
    588         const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
    589         const slice_alignment = slice_ty.abiAlignment(target);
    590 
    591         const error_name_list = mod.error_name_list.items;
    592         const llvm_errors = try mod.gpa.alloc(*llvm.Value, error_name_list.len);
    593         defer mod.gpa.free(llvm_errors);
    594 
    595         llvm_errors[0] = llvm_slice_ty.getUndef();
    596         for (llvm_errors[1..]) |*llvm_error, i| {
    597             const name = error_name_list[1..][i];
    598             const str_init = self.context.constString(name.ptr, @intCast(c_uint, name.len), .False);
    599             const str_global = self.llvm_module.addGlobal(str_init.typeOf(), "");
    600             str_global.setInitializer(str_init);
    601             str_global.setLinkage(.Private);
    602             str_global.setGlobalConstant(.True);
    603             str_global.setUnnamedAddr(.True);
    604             str_global.setAlignment(1);
    605 
    606             const slice_fields = [_]*llvm.Value{
    607                 str_global.constBitCast(llvm_ptr_ty),
    608                 llvm_usize_ty.constInt(name.len, .False),
    609             };
    610             llvm_error.* = llvm_slice_ty.constNamedStruct(&slice_fields, slice_fields.len);
    611         }
    612 
    613         const error_name_table_init = llvm_slice_ty.constArray(llvm_errors.ptr, @intCast(c_uint, error_name_list.len));
    614 
    615         const error_name_table_global = self.llvm_module.addGlobal(error_name_table_init.typeOf(), "");
    616         error_name_table_global.setInitializer(error_name_table_init);
    617         error_name_table_global.setLinkage(.Private);
    618         error_name_table_global.setGlobalConstant(.True);
    619         error_name_table_global.setUnnamedAddr(.True);
    620         error_name_table_global.setAlignment(slice_alignment); // TODO: Dont hardcode
    621 
    622         const error_name_table_ptr = error_name_table_global.constBitCast(llvm_slice_ty.pointerType(0)); // TODO: Address space
    623         error_name_table_ptr_global.setInitializer(error_name_table_ptr);
    624     }
    625 
    626     fn genCmpLtErrorsLenFunction(object: *Object) !void {
    627         // If there is no such function in the module, it means the source code does not need it.
    628         const llvm_fn = object.llvm_module.getNamedFunction(lt_errors_fn_name) orelse return;
    629         const mod = object.module;
    630         const errors_len = mod.global_error_set.count();
    631 
    632         // Delete previous implementation. We replace it with every flush() because the
    633         // total number of errors may have changed.
    634         while (llvm_fn.getFirstBasicBlock()) |bb| {
    635             bb.deleteBasicBlock();
    636         }
    637 
    638         const builder = object.context.createBuilder();
    639 
    640         const entry_block = object.context.appendBasicBlock(llvm_fn, "Entry");
    641         builder.positionBuilderAtEnd(entry_block);
    642         builder.clearCurrentDebugLocation();
    643 
    644         // Example source of the following LLVM IR:
    645         // fn __zig_lt_errors_len(index: u16) bool {
    646         //     return index < total_errors_len;
    647         // }
    648 
    649         const lhs = llvm_fn.getParam(0);
    650         const rhs = lhs.typeOf().constInt(errors_len, .False);
    651         const is_lt = builder.buildICmp(.ULT, lhs, rhs, "");
    652         _ = builder.buildRet(is_lt);
    653     }
    654 
    655     fn genModuleLevelAssembly(object: *Object) !void {
    656         const mod = object.module;
    657         if (mod.global_assembly.count() == 0) return;
    658         var buffer = std.ArrayList(u8).init(mod.gpa);
    659         defer buffer.deinit();
    660         var it = mod.global_assembly.iterator();
    661         while (it.next()) |kv| {
    662             try buffer.appendSlice(kv.value_ptr.*);
    663             try buffer.append('\n');
    664         }
    665         object.llvm_module.setModuleInlineAsm2(buffer.items.ptr, buffer.items.len - 1);
    666     }
    667 
    668     fn resolveExportExternCollisions(object: *Object) !void {
    669         const mod = object.module;
    670 
    671         // This map has externs with incorrect symbol names.
    672         for (object.extern_collisions.keys()) |decl_index| {
    673             const entry = object.decl_map.getEntry(decl_index) orelse continue;
    674             const llvm_global = entry.value_ptr.*;
    675             // Same logic as below but for externs instead of exports.
    676             const decl = mod.declPtr(decl_index);
    677             const other_global = object.getLlvmGlobal(decl.name) orelse continue;
    678             if (other_global == llvm_global) continue;
    679 
    680             const new_global_ptr = other_global.constBitCast(llvm_global.typeOf());
    681             llvm_global.replaceAllUsesWith(new_global_ptr);
    682             deleteLlvmGlobal(llvm_global);
    683             entry.value_ptr.* = new_global_ptr;
    684         }
    685         object.extern_collisions.clearRetainingCapacity();
    686 
    687         const export_keys = mod.decl_exports.keys();
    688         for (mod.decl_exports.values()) |export_list, i| {
    689             const decl_index = export_keys[i];
    690             const llvm_global = object.decl_map.get(decl_index) orelse continue;
    691             for (export_list) |exp| {
    692                 // Detect if the LLVM global has already been created as an extern. In such
    693                 // case, we need to replace all uses of it with this exported global.
    694                 // TODO update std.builtin.ExportOptions to have the name be a
    695                 // null-terminated slice.
    696                 const exp_name_z = try mod.gpa.dupeZ(u8, exp.options.name);
    697                 defer mod.gpa.free(exp_name_z);
    698 
    699                 const other_global = object.getLlvmGlobal(exp_name_z.ptr) orelse continue;
    700                 if (other_global == llvm_global) continue;
    701 
    702                 // replaceAllUsesWith requires the type to be unchanged. So we bitcast
    703                 // the new global to the old type and use that as the thing to replace
    704                 // old uses.
    705                 const new_global_ptr = llvm_global.constBitCast(other_global.typeOf());
    706                 other_global.replaceAllUsesWith(new_global_ptr);
    707                 llvm_global.takeName(other_global);
    708                 deleteLlvmGlobal(other_global);
    709                 // Problem: now we need to replace in the decl_map that
    710                 // the extern decl index points to this new global. However we don't
    711                 // know the decl index.
    712                 // Even if we did, a future incremental update to the extern would then
    713                 // treat the LLVM global as an extern rather than an export, so it would
    714                 // need a way to check that.
    715                 // This is a TODO that needs to be solved when making
    716                 // the LLVM backend support incremental compilation.
    717             }
    718         }
    719     }
    720 
    721     pub fn flushModule(self: *Object, comp: *Compilation, prog_node: *std.Progress.Node) !void {
    722         var sub_prog_node = prog_node.start("LLVM Emit Object", 0);
    723         sub_prog_node.activate();
    724         sub_prog_node.context.refresh();
    725         defer sub_prog_node.end();
    726 
    727         try self.resolveExportExternCollisions();
    728         try self.genErrorNameTable();
    729         try self.genCmpLtErrorsLenFunction();
    730         try self.genModuleLevelAssembly();
    731 
    732         if (self.di_builder) |dib| {
    733             // When lowering debug info for pointers, we emitted the element types as
    734             // forward decls. Now we must go flesh those out.
    735             // Here we iterate over a hash map while modifying it but it is OK because
    736             // we never add or remove entries during this loop.
    737             var i: usize = 0;
    738             while (i < self.di_type_map.count()) : (i += 1) {
    739                 const value_ptr = &self.di_type_map.values()[i];
    740                 const annotated = value_ptr.*;
    741                 if (!annotated.isFwdOnly()) continue;
    742                 const entry: Object.DITypeMap.Entry = .{
    743                     .key_ptr = &self.di_type_map.keys()[i],
    744                     .value_ptr = value_ptr,
    745                 };
    746                 _ = try self.lowerDebugTypeImpl(entry, .full, annotated.toDIType());
    747             }
    748 
    749             dib.finalize();
    750         }
    751 
    752         if (comp.verbose_llvm_ir) {
    753             self.llvm_module.dump();
    754         }
    755 
    756         var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
    757         defer arena_allocator.deinit();
    758         const arena = arena_allocator.allocator();
    759 
    760         const mod = comp.bin_file.options.module.?;
    761         const cache_dir = mod.zig_cache_artifact_directory;
    762 
    763         if (std.debug.runtime_safety) {
    764             var error_message: [*:0]const u8 = undefined;
    765             // verifyModule always allocs the error_message even if there is no error
    766             defer llvm.disposeMessage(error_message);
    767 
    768             if (self.llvm_module.verify(.ReturnStatus, &error_message).toBool()) {
    769                 std.debug.print("\n{s}\n", .{error_message});
    770 
    771                 if (try locPath(arena, comp.emit_llvm_ir, cache_dir)) |emit_llvm_ir_path| {
    772                     _ = self.llvm_module.printModuleToFile(emit_llvm_ir_path, &error_message);
    773                 }
    774 
    775                 @panic("LLVM module verification failed");
    776             }
    777         }
    778 
    779         var emit_bin_path: ?[*:0]const u8 = if (comp.bin_file.options.emit) |emit|
    780             try emit.basenamePath(arena, try arena.dupeZ(u8, comp.bin_file.intermediary_basename.?))
    781         else
    782             null;
    783 
    784         const emit_asm_path = try locPath(arena, comp.emit_asm, cache_dir);
    785         var emit_llvm_ir_path = try locPath(arena, comp.emit_llvm_ir, cache_dir);
    786         const emit_llvm_bc_path = try locPath(arena, comp.emit_llvm_bc, cache_dir);
    787 
    788         const emit_asm_msg = emit_asm_path orelse "(none)";
    789         const emit_bin_msg = emit_bin_path orelse "(none)";
    790         const emit_llvm_ir_msg = emit_llvm_ir_path orelse "(none)";
    791         const emit_llvm_bc_msg = emit_llvm_bc_path orelse "(none)";
    792         log.debug("emit LLVM object asm={s} bin={s} ir={s} bc={s}", .{
    793             emit_asm_msg, emit_bin_msg, emit_llvm_ir_msg, emit_llvm_bc_msg,
    794         });
    795 
    796         // Unfortunately, LLVM shits the bed when we ask for both binary and assembly.
    797         // So we call the entire pipeline multiple times if this is requested.
    798         var error_message: [*:0]const u8 = undefined;
    799         if (emit_asm_path != null and emit_bin_path != null) {
    800             if (self.target_machine.emitToFile(
    801                 self.llvm_module,
    802                 &error_message,
    803                 comp.bin_file.options.optimize_mode == .Debug,
    804                 comp.bin_file.options.optimize_mode == .ReleaseSmall,
    805                 comp.time_report,
    806                 comp.bin_file.options.tsan,
    807                 comp.bin_file.options.lto,
    808                 null,
    809                 emit_bin_path,
    810                 emit_llvm_ir_path,
    811                 null,
    812             )) {
    813                 defer llvm.disposeMessage(error_message);
    814 
    815                 log.err("LLVM failed to emit bin={s} ir={s}: {s}", .{
    816                     emit_bin_msg, emit_llvm_ir_msg, error_message,
    817                 });
    818                 return error.FailedToEmit;
    819             }
    820             emit_bin_path = null;
    821             emit_llvm_ir_path = null;
    822         }
    823 
    824         if (self.target_machine.emitToFile(
    825             self.llvm_module,
    826             &error_message,
    827             comp.bin_file.options.optimize_mode == .Debug,
    828             comp.bin_file.options.optimize_mode == .ReleaseSmall,
    829             comp.time_report,
    830             comp.bin_file.options.tsan,
    831             comp.bin_file.options.lto,
    832             emit_asm_path,
    833             emit_bin_path,
    834             emit_llvm_ir_path,
    835             emit_llvm_bc_path,
    836         )) {
    837             defer llvm.disposeMessage(error_message);
    838 
    839             log.err("LLVM failed to emit asm={s} bin={s} ir={s} bc={s}: {s}", .{
    840                 emit_asm_msg,  emit_bin_msg, emit_llvm_ir_msg, emit_llvm_bc_msg,
    841                 error_message,
    842             });
    843             return error.FailedToEmit;
    844         }
    845     }
    846 
    847     pub fn updateFunc(
    848         o: *Object,
    849         module: *Module,
    850         func: *Module.Fn,
    851         air: Air,
    852         liveness: Liveness,
    853     ) !void {
    854         const decl_index = func.owner_decl;
    855         const decl = module.declPtr(decl_index);
    856         const target = module.getTarget();
    857 
    858         var dg: DeclGen = .{
    859             .context = o.context,
    860             .object = o,
    861             .module = module,
    862             .decl_index = decl_index,
    863             .decl = decl,
    864             .err_msg = null,
    865             .gpa = module.gpa,
    866         };
    867 
    868         const llvm_func = try dg.resolveLlvmFunction(decl_index);
    869 
    870         if (module.align_stack_fns.get(func)) |align_info| {
    871             dg.addFnAttrInt(llvm_func, "alignstack", align_info.alignment);
    872             dg.addFnAttr(llvm_func, "noinline");
    873         } else {
    874             DeclGen.removeFnAttr(llvm_func, "alignstack");
    875             if (!func.is_noinline) DeclGen.removeFnAttr(llvm_func, "noinline");
    876         }
    877 
    878         if (func.is_cold) {
    879             dg.addFnAttr(llvm_func, "cold");
    880         } else {
    881             DeclGen.removeFnAttr(llvm_func, "cold");
    882         }
    883 
    884         if (func.is_noinline) {
    885             dg.addFnAttr(llvm_func, "noinline");
    886         } else {
    887             DeclGen.removeFnAttr(llvm_func, "noinline");
    888         }
    889 
    890         // TODO: disable this if safety is off for the function scope
    891         const ssp_buf_size = module.comp.bin_file.options.stack_protector;
    892         if (ssp_buf_size != 0) {
    893             var buf: [12]u8 = undefined;
    894             const arg = std.fmt.bufPrintZ(&buf, "{d}", .{ssp_buf_size}) catch unreachable;
    895             dg.addFnAttr(llvm_func, "sspstrong");
    896             dg.addFnAttrString(llvm_func, "stack-protector-buffer-size", arg);
    897         }
    898 
    899         // TODO: disable this if safety is off for the function scope
    900         if (module.comp.bin_file.options.stack_check) {
    901             dg.addFnAttrString(llvm_func, "probe-stack", "__zig_probe_stack");
    902         } else if (target.os.tag == .uefi) {
    903             dg.addFnAttrString(llvm_func, "no-stack-arg-probe", "");
    904         }
    905 
    906         if (decl.@"linksection") |section| {
    907             llvm_func.setSection(section);
    908         }
    909 
    910         // Remove all the basic blocks of a function in order to start over, generating
    911         // LLVM IR from an empty function body.
    912         while (llvm_func.getFirstBasicBlock()) |bb| {
    913             bb.deleteBasicBlock();
    914         }
    915 
    916         const builder = dg.context.createBuilder();
    917 
    918         const entry_block = dg.context.appendBasicBlock(llvm_func, "Entry");
    919         builder.positionBuilderAtEnd(entry_block);
    920 
    921         // This gets the LLVM values from the function and stores them in `dg.args`.
    922         const fn_info = decl.ty.fnInfo();
    923         const sret = firstParamSRet(fn_info, target);
    924         const ret_ptr = if (sret) llvm_func.getParam(0) else null;
    925         const gpa = dg.gpa;
    926 
    927         if (ccAbiPromoteInt(fn_info.cc, target, fn_info.return_type)) |s| switch (s) {
    928             .signed => dg.addAttr(llvm_func, 0, "signext"),
    929             .unsigned => dg.addAttr(llvm_func, 0, "zeroext"),
    930         };
    931 
    932         const err_return_tracing = fn_info.return_type.isError() and
    933             module.comp.bin_file.options.error_return_tracing;
    934 
    935         const err_ret_trace = if (err_return_tracing)
    936             llvm_func.getParam(@boolToInt(ret_ptr != null))
    937         else
    938             null;
    939 
    940         // This is the list of args we will use that correspond directly to the AIR arg
    941         // instructions. Depending on the calling convention, this list is not necessarily
    942         // a bijection with the actual LLVM parameters of the function.
    943         var args = std.ArrayList(*llvm.Value).init(gpa);
    944         defer args.deinit();
    945 
    946         {
    947             var llvm_arg_i = @as(c_uint, @boolToInt(ret_ptr != null)) + @boolToInt(err_return_tracing);
    948             var it = iterateParamTypes(&dg, fn_info);
    949             while (it.next()) |lowering| switch (lowering) {
    950                 .no_bits => continue,
    951                 .byval => {
    952                     assert(!it.byval_attr);
    953                     const param_index = it.zig_index - 1;
    954                     const param_ty = fn_info.param_types[param_index];
    955                     const param = llvm_func.getParam(llvm_arg_i);
    956                     try args.ensureUnusedCapacity(1);
    957 
    958                     if (isByRef(param_ty)) {
    959                         const alignment = param_ty.abiAlignment(target);
    960                         const param_llvm_ty = param.typeOf();
    961                         const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, alignment, target);
    962                         const store_inst = builder.buildStore(param, arg_ptr);
    963                         store_inst.setAlignment(alignment);
    964                         args.appendAssumeCapacity(arg_ptr);
    965                     } else {
    966                         args.appendAssumeCapacity(param);
    967 
    968                         dg.addByValParamAttrs(llvm_func, param_ty, param_index, fn_info, llvm_arg_i);
    969                     }
    970                     llvm_arg_i += 1;
    971                 },
    972                 .byref => {
    973                     const param_ty = fn_info.param_types[it.zig_index - 1];
    974                     const param_llvm_ty = try dg.lowerType(param_ty);
    975                     const param = llvm_func.getParam(llvm_arg_i);
    976                     const alignment = param_ty.abiAlignment(target);
    977 
    978                     dg.addByRefParamAttrs(llvm_func, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty);
    979                     llvm_arg_i += 1;
    980 
    981                     try args.ensureUnusedCapacity(1);
    982 
    983                     if (isByRef(param_ty)) {
    984                         args.appendAssumeCapacity(param);
    985                     } else {
    986                         const load_inst = builder.buildLoad(param_llvm_ty, param, "");
    987                         load_inst.setAlignment(alignment);
    988                         args.appendAssumeCapacity(load_inst);
    989                     }
    990                 },
    991                 .abi_sized_int => {
    992                     assert(!it.byval_attr);
    993                     const param_ty = fn_info.param_types[it.zig_index - 1];
    994                     const param = llvm_func.getParam(llvm_arg_i);
    995                     llvm_arg_i += 1;
    996 
    997                     const param_llvm_ty = try dg.lowerType(param_ty);
    998                     const abi_size = @intCast(c_uint, param_ty.abiSize(target));
    999                     const int_llvm_ty = dg.context.intType(abi_size * 8);
   1000                     const int_ptr_llvm_ty = int_llvm_ty.pointerType(0);
   1001                     const alignment = @max(
   1002                         param_ty.abiAlignment(target),
   1003                         dg.object.target_data.abiAlignmentOfType(int_llvm_ty),
   1004                     );
   1005                     const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, alignment, target);
   1006                     const casted_ptr = builder.buildBitCast(arg_ptr, int_ptr_llvm_ty, "");
   1007                     const store_inst = builder.buildStore(param, casted_ptr);
   1008                     store_inst.setAlignment(alignment);
   1009 
   1010                     try args.ensureUnusedCapacity(1);
   1011 
   1012                     if (isByRef(param_ty)) {
   1013                         args.appendAssumeCapacity(arg_ptr);
   1014                     } else {
   1015                         const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");
   1016                         load_inst.setAlignment(alignment);
   1017                         args.appendAssumeCapacity(load_inst);
   1018                     }
   1019                 },
   1020                 .slice => {
   1021                     assert(!it.byval_attr);
   1022                     const param_ty = fn_info.param_types[it.zig_index - 1];
   1023                     const ptr_info = param_ty.ptrInfo().data;
   1024 
   1025                     if (math.cast(u5, it.zig_index - 1)) |i| {
   1026                         if (@truncate(u1, fn_info.noalias_bits >> i) != 0) {
   1027                             dg.addArgAttr(llvm_func, llvm_arg_i, "noalias");
   1028                         }
   1029                     }
   1030                     dg.addArgAttr(llvm_func, llvm_arg_i, "nonnull");
   1031                     if (!ptr_info.mutable) {
   1032                         dg.addArgAttr(llvm_func, llvm_arg_i, "readonly");
   1033                     }
   1034                     if (ptr_info.@"align" != 0) {
   1035                         dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", ptr_info.@"align");
   1036                     } else {
   1037                         const elem_align = @max(ptr_info.pointee_type.abiAlignment(target), 1);
   1038                         dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", elem_align);
   1039                     }
   1040                     const ptr_param = llvm_func.getParam(llvm_arg_i);
   1041                     llvm_arg_i += 1;
   1042                     const len_param = llvm_func.getParam(llvm_arg_i);
   1043                     llvm_arg_i += 1;
   1044 
   1045                     const slice_llvm_ty = try dg.lowerType(param_ty);
   1046                     const partial = builder.buildInsertValue(slice_llvm_ty.getUndef(), ptr_param, 0, "");
   1047                     const aggregate = builder.buildInsertValue(partial, len_param, 1, "");
   1048                     try args.append(aggregate);
   1049                 },
   1050                 .multiple_llvm_ints => {
   1051                     assert(!it.byval_attr);
   1052                     const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len];
   1053                     const param_ty = fn_info.param_types[it.zig_index - 1];
   1054                     const param_llvm_ty = try dg.lowerType(param_ty);
   1055                     const param_alignment = param_ty.abiAlignment(target);
   1056                     const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, param_alignment, target);
   1057                     var field_types_buf: [8]*llvm.Type = undefined;
   1058                     const field_types = field_types_buf[0..llvm_ints.len];
   1059                     for (llvm_ints) |int_bits, i| {
   1060                         field_types[i] = dg.context.intType(int_bits);
   1061                     }
   1062                     const ints_llvm_ty = dg.context.structType(field_types.ptr, @intCast(c_uint, field_types.len), .False);
   1063                     const casted_ptr = builder.buildBitCast(arg_ptr, ints_llvm_ty.pointerType(0), "");
   1064                     for (llvm_ints) |_, field_i_usize| {
   1065                         const field_i = @intCast(c_uint, field_i_usize);
   1066                         const param = llvm_func.getParam(llvm_arg_i);
   1067                         llvm_arg_i += 1;
   1068                         const field_ptr = builder.buildStructGEP(ints_llvm_ty, casted_ptr, field_i, "");
   1069                         const store_inst = builder.buildStore(param, field_ptr);
   1070                         store_inst.setAlignment(target.cpu.arch.ptrBitWidth() / 8);
   1071                     }
   1072 
   1073                     const is_by_ref = isByRef(param_ty);
   1074                     const loaded = if (is_by_ref) arg_ptr else l: {
   1075                         const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");
   1076                         load_inst.setAlignment(param_alignment);
   1077                         break :l load_inst;
   1078                     };
   1079                     try args.append(loaded);
   1080                 },
   1081                 .multiple_llvm_float => {
   1082                     assert(!it.byval_attr);
   1083                     const llvm_floats = it.llvm_types_buffer[0..it.llvm_types_len];
   1084                     const param_ty = fn_info.param_types[it.zig_index - 1];
   1085                     const param_llvm_ty = try dg.lowerType(param_ty);
   1086                     const param_alignment = param_ty.abiAlignment(target);
   1087                     const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, param_alignment, target);
   1088                     var field_types_buf: [8]*llvm.Type = undefined;
   1089                     const field_types = field_types_buf[0..llvm_floats.len];
   1090                     for (llvm_floats) |float_bits, i| {
   1091                         switch (float_bits) {
   1092                             64 => field_types[i] = dg.context.doubleType(),
   1093                             80 => field_types[i] = dg.context.x86FP80Type(),
   1094                             else => {},
   1095                         }
   1096                     }
   1097                     const floats_llvm_ty = dg.context.structType(field_types.ptr, @intCast(c_uint, field_types.len), .False);
   1098                     const casted_ptr = builder.buildBitCast(arg_ptr, floats_llvm_ty.pointerType(0), "");
   1099                     for (llvm_floats) |_, field_i_usize| {
   1100                         const field_i = @intCast(c_uint, field_i_usize);
   1101                         const param = llvm_func.getParam(llvm_arg_i);
   1102                         llvm_arg_i += 1;
   1103                         const field_ptr = builder.buildStructGEP(floats_llvm_ty, casted_ptr, field_i, "");
   1104                         const store_inst = builder.buildStore(param, field_ptr);
   1105                         store_inst.setAlignment(target.cpu.arch.ptrBitWidth() / 8);
   1106                     }
   1107 
   1108                     const is_by_ref = isByRef(param_ty);
   1109                     const loaded = if (is_by_ref) arg_ptr else l: {
   1110                         const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");
   1111                         load_inst.setAlignment(param_alignment);
   1112                         break :l load_inst;
   1113                     };
   1114                     try args.append(loaded);
   1115                 },
   1116                 .as_u16 => {
   1117                     assert(!it.byval_attr);
   1118                     const param = llvm_func.getParam(llvm_arg_i);
   1119                     llvm_arg_i += 1;
   1120                     const casted = builder.buildBitCast(param, dg.context.halfType(), "");
   1121                     try args.ensureUnusedCapacity(1);
   1122                     args.appendAssumeCapacity(casted);
   1123                 },
   1124                 .float_array => {
   1125                     const param_ty = fn_info.param_types[it.zig_index - 1];
   1126                     const param_llvm_ty = try dg.lowerType(param_ty);
   1127                     const param = llvm_func.getParam(llvm_arg_i);
   1128                     llvm_arg_i += 1;
   1129 
   1130                     const alignment = param_ty.abiAlignment(target);
   1131                     const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, alignment, target);
   1132                     const casted_ptr = builder.buildBitCast(arg_ptr, param.typeOf().pointerType(0), "");
   1133                     _ = builder.buildStore(param, casted_ptr);
   1134 
   1135                     if (isByRef(param_ty)) {
   1136                         try args.append(arg_ptr);
   1137                     } else {
   1138                         const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");
   1139                         load_inst.setAlignment(alignment);
   1140                         try args.append(load_inst);
   1141                     }
   1142                 },
   1143                 .i32_array, .i64_array => {
   1144                     const param_ty = fn_info.param_types[it.zig_index - 1];
   1145                     const param_llvm_ty = try dg.lowerType(param_ty);
   1146                     const param = llvm_func.getParam(llvm_arg_i);
   1147                     llvm_arg_i += 1;
   1148 
   1149                     const alignment = param_ty.abiAlignment(target);
   1150                     const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, alignment, target);
   1151                     const casted_ptr = builder.buildBitCast(arg_ptr, param.typeOf().pointerType(0), "");
   1152                     _ = builder.buildStore(param, casted_ptr);
   1153 
   1154                     if (isByRef(param_ty)) {
   1155                         try args.append(arg_ptr);
   1156                     } else {
   1157                         const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");
   1158                         load_inst.setAlignment(alignment);
   1159                         try args.append(load_inst);
   1160                     }
   1161                 },
   1162             };
   1163         }
   1164 
   1165         var di_file: ?*llvm.DIFile = null;
   1166         var di_scope: ?*llvm.DIScope = null;
   1167 
   1168         if (dg.object.di_builder) |dib| {
   1169             di_file = try dg.object.getDIFile(gpa, decl.src_namespace.file_scope);
   1170 
   1171             const line_number = decl.src_line + 1;
   1172             const is_internal_linkage = decl.val.tag() != .extern_fn and
   1173                 !module.decl_exports.contains(decl_index);
   1174             const noret_bit: c_uint = if (fn_info.return_type.isNoReturn())
   1175                 llvm.DIFlags.NoReturn
   1176             else
   1177                 0;
   1178             const subprogram = dib.createFunction(
   1179                 di_file.?.toScope(),
   1180                 decl.name,
   1181                 llvm_func.getValueName(),
   1182                 di_file.?,
   1183                 line_number,
   1184                 try o.lowerDebugType(decl.ty, .full),
   1185                 is_internal_linkage,
   1186                 true, // is definition
   1187                 line_number + func.lbrace_line, // scope line
   1188                 llvm.DIFlags.StaticMember | noret_bit,
   1189                 module.comp.bin_file.options.optimize_mode != .Debug,
   1190                 null, // decl_subprogram
   1191             );
   1192             try dg.object.di_map.put(gpa, decl, subprogram.toNode());
   1193 
   1194             llvm_func.fnSetSubprogram(subprogram);
   1195 
   1196             const lexical_block = dib.createLexicalBlock(subprogram.toScope(), di_file.?, line_number, 1);
   1197             di_scope = lexical_block.toScope();
   1198         }
   1199 
   1200         var fg: FuncGen = .{
   1201             .gpa = gpa,
   1202             .air = air,
   1203             .liveness = liveness,
   1204             .context = dg.context,
   1205             .dg = &dg,
   1206             .builder = builder,
   1207             .ret_ptr = ret_ptr,
   1208             .args = args.items,
   1209             .arg_index = 0,
   1210             .func_inst_table = .{},
   1211             .llvm_func = llvm_func,
   1212             .blocks = .{},
   1213             .single_threaded = module.comp.bin_file.options.single_threaded,
   1214             .di_scope = di_scope,
   1215             .di_file = di_file,
   1216             .base_line = dg.decl.src_line,
   1217             .prev_dbg_line = 0,
   1218             .prev_dbg_column = 0,
   1219             .err_ret_trace = err_ret_trace,
   1220         };
   1221         defer fg.deinit();
   1222 
   1223         fg.genBody(air.getMainBody()) catch |err| switch (err) {
   1224             error.CodegenFail => {
   1225                 decl.analysis = .codegen_failure;
   1226                 try module.failed_decls.put(module.gpa, decl_index, dg.err_msg.?);
   1227                 dg.err_msg = null;
   1228                 return;
   1229             },
   1230             else => |e| return e,
   1231         };
   1232 
   1233         const decl_exports = module.decl_exports.get(decl_index) orelse &[0]*Module.Export{};
   1234         try o.updateDeclExports(module, decl_index, decl_exports);
   1235     }
   1236 
   1237     pub fn updateDecl(self: *Object, module: *Module, decl_index: Module.Decl.Index) !void {
   1238         const decl = module.declPtr(decl_index);
   1239         var dg: DeclGen = .{
   1240             .context = self.context,
   1241             .object = self,
   1242             .module = module,
   1243             .decl = decl,
   1244             .decl_index = decl_index,
   1245             .err_msg = null,
   1246             .gpa = module.gpa,
   1247         };
   1248         dg.genDecl() catch |err| switch (err) {
   1249             error.CodegenFail => {
   1250                 decl.analysis = .codegen_failure;
   1251                 try module.failed_decls.put(module.gpa, decl_index, dg.err_msg.?);
   1252                 dg.err_msg = null;
   1253                 return;
   1254             },
   1255             else => |e| return e,
   1256         };
   1257         const decl_exports = module.decl_exports.get(decl_index) orelse &[0]*Module.Export{};
   1258         try self.updateDeclExports(module, decl_index, decl_exports);
   1259     }
   1260 
   1261     /// TODO replace this with a call to `Module::getNamedValue`. This will require adding
   1262     /// a new wrapper in zig_llvm.h/zig_llvm.cpp.
   1263     fn getLlvmGlobal(o: Object, name: [*:0]const u8) ?*llvm.Value {
   1264         if (o.llvm_module.getNamedFunction(name)) |x| return x;
   1265         if (o.llvm_module.getNamedGlobal(name)) |x| return x;
   1266         return null;
   1267     }
   1268 
   1269     pub fn updateDeclExports(
   1270         self: *Object,
   1271         module: *Module,
   1272         decl_index: Module.Decl.Index,
   1273         exports: []const *Module.Export,
   1274     ) !void {
   1275         // If the module does not already have the function, we ignore this function call
   1276         // because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`.
   1277         const llvm_global = self.decl_map.get(decl_index) orelse return;
   1278         const decl = module.declPtr(decl_index);
   1279         if (decl.isExtern()) {
   1280             llvm_global.setValueName(decl.name);
   1281             if (self.getLlvmGlobal(decl.name)) |other_global| {
   1282                 if (other_global != llvm_global) {
   1283                     log.debug("updateDeclExports isExtern()=true setValueName({s}) conflict", .{decl.name});
   1284                     try self.extern_collisions.put(module.gpa, decl_index, {});
   1285                 }
   1286             }
   1287             llvm_global.setUnnamedAddr(.False);
   1288             llvm_global.setLinkage(.External);
   1289             if (module.wantDllExports()) llvm_global.setDLLStorageClass(.Default);
   1290             if (self.di_map.get(decl)) |di_node| {
   1291                 if (try decl.isFunction()) {
   1292                     const di_func = @ptrCast(*llvm.DISubprogram, di_node);
   1293                     const linkage_name = llvm.MDString.get(self.context, decl.name, std.mem.len(decl.name));
   1294                     di_func.replaceLinkageName(linkage_name);
   1295                 } else {
   1296                     const di_global = @ptrCast(*llvm.DIGlobalVariable, di_node);
   1297                     const linkage_name = llvm.MDString.get(self.context, decl.name, std.mem.len(decl.name));
   1298                     di_global.replaceLinkageName(linkage_name);
   1299                 }
   1300             }
   1301             if (decl.val.castTag(.variable)) |variable| {
   1302                 if (variable.data.is_threadlocal) {
   1303                     llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
   1304                 } else {
   1305                     llvm_global.setThreadLocalMode(.NotThreadLocal);
   1306                 }
   1307                 if (variable.data.is_weak_linkage) {
   1308                     llvm_global.setLinkage(.ExternalWeak);
   1309                 }
   1310             }
   1311         } else if (exports.len != 0) {
   1312             const exp_name = exports[0].options.name;
   1313             llvm_global.setValueName2(exp_name.ptr, exp_name.len);
   1314             llvm_global.setUnnamedAddr(.False);
   1315             if (module.wantDllExports()) llvm_global.setDLLStorageClass(.DLLExport);
   1316             if (self.di_map.get(decl)) |di_node| {
   1317                 if (try decl.isFunction()) {
   1318                     const di_func = @ptrCast(*llvm.DISubprogram, di_node);
   1319                     const linkage_name = llvm.MDString.get(self.context, exp_name.ptr, exp_name.len);
   1320                     di_func.replaceLinkageName(linkage_name);
   1321                 } else {
   1322                     const di_global = @ptrCast(*llvm.DIGlobalVariable, di_node);
   1323                     const linkage_name = llvm.MDString.get(self.context, exp_name.ptr, exp_name.len);
   1324                     di_global.replaceLinkageName(linkage_name);
   1325                 }
   1326             }
   1327             switch (exports[0].options.linkage) {
   1328                 .Internal => unreachable,
   1329                 .Strong => llvm_global.setLinkage(.External),
   1330                 .Weak => llvm_global.setLinkage(.WeakODR),
   1331                 .LinkOnce => llvm_global.setLinkage(.LinkOnceODR),
   1332             }
   1333             switch (exports[0].options.visibility) {
   1334                 .default => llvm_global.setVisibility(.Default),
   1335                 .hidden => llvm_global.setVisibility(.Hidden),
   1336                 .protected => llvm_global.setVisibility(.Protected),
   1337             }
   1338             if (exports[0].options.section) |section| {
   1339                 const section_z = try module.gpa.dupeZ(u8, section);
   1340                 defer module.gpa.free(section_z);
   1341                 llvm_global.setSection(section_z);
   1342             }
   1343             if (decl.val.castTag(.variable)) |variable| {
   1344                 if (variable.data.is_threadlocal) {
   1345                     llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
   1346                 }
   1347             }
   1348 
   1349             // If a Decl is exported more than one time (which is rare),
   1350             // we add aliases for all but the first export.
   1351             // TODO LLVM C API does not support deleting aliases. We need to
   1352             // patch it to support this or figure out how to wrap the C++ API ourselves.
   1353             // Until then we iterate over existing aliases and make them point
   1354             // to the correct decl, or otherwise add a new alias. Old aliases are leaked.
   1355             for (exports[1..]) |exp| {
   1356                 const exp_name_z = try module.gpa.dupeZ(u8, exp.options.name);
   1357                 defer module.gpa.free(exp_name_z);
   1358 
   1359                 if (self.llvm_module.getNamedGlobalAlias(exp_name_z.ptr, exp_name_z.len)) |alias| {
   1360                     alias.setAliasee(llvm_global);
   1361                 } else {
   1362                     _ = self.llvm_module.addAlias(
   1363                         llvm_global.globalGetValueType(),
   1364                         0,
   1365                         llvm_global,
   1366                         exp_name_z,
   1367                     );
   1368                 }
   1369             }
   1370         } else {
   1371             const fqn = try decl.getFullyQualifiedName(module);
   1372             defer module.gpa.free(fqn);
   1373             llvm_global.setValueName2(fqn.ptr, fqn.len);
   1374             llvm_global.setLinkage(.Internal);
   1375             if (module.wantDllExports()) llvm_global.setDLLStorageClass(.Default);
   1376             llvm_global.setUnnamedAddr(.True);
   1377             if (decl.val.castTag(.variable)) |variable| {
   1378                 const single_threaded = module.comp.bin_file.options.single_threaded;
   1379                 if (variable.data.is_threadlocal and !single_threaded) {
   1380                     llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
   1381                 } else {
   1382                     llvm_global.setThreadLocalMode(.NotThreadLocal);
   1383                 }
   1384             }
   1385         }
   1386     }
   1387 
   1388     pub fn freeDecl(self: *Object, decl_index: Module.Decl.Index) void {
   1389         const llvm_value = self.decl_map.get(decl_index) orelse return;
   1390         llvm_value.deleteGlobal();
   1391     }
   1392 
   1393     fn getDIFile(o: *Object, gpa: Allocator, file: *const Module.File) !*llvm.DIFile {
   1394         const gop = try o.di_map.getOrPut(gpa, file);
   1395         errdefer assert(o.di_map.remove(file));
   1396         if (gop.found_existing) {
   1397             return @ptrCast(*llvm.DIFile, gop.value_ptr.*);
   1398         }
   1399         const dir_path = file.pkg.root_src_directory.path orelse ".";
   1400         const sub_file_path_z = try gpa.dupeZ(u8, file.sub_file_path);
   1401         defer gpa.free(sub_file_path_z);
   1402         const dir_path_z = try gpa.dupeZ(u8, dir_path);
   1403         defer gpa.free(dir_path_z);
   1404         const di_file = o.di_builder.?.createFile(sub_file_path_z, dir_path_z);
   1405         gop.value_ptr.* = di_file.toNode();
   1406         return di_file;
   1407     }
   1408 
   1409     const DebugResolveStatus = enum { fwd, full };
   1410 
   1411     /// In the implementation of this function, it is required to store a forward decl
   1412     /// into `gop` before making any recursive calls (even directly).
   1413     fn lowerDebugType(
   1414         o: *Object,
   1415         ty: Type,
   1416         resolve: DebugResolveStatus,
   1417     ) Allocator.Error!*llvm.DIType {
   1418         const gpa = o.gpa;
   1419         // Be careful not to reference this `gop` variable after any recursive calls
   1420         // to `lowerDebugType`.
   1421         const gop = try o.di_type_map.getOrPutContext(gpa, ty, .{ .mod = o.module });
   1422         if (gop.found_existing) {
   1423             const annotated = gop.value_ptr.*;
   1424             const di_type = annotated.toDIType();
   1425             if (!annotated.isFwdOnly() or resolve == .fwd) {
   1426                 return di_type;
   1427             }
   1428             const entry: Object.DITypeMap.Entry = .{
   1429                 .key_ptr = gop.key_ptr,
   1430                 .value_ptr = gop.value_ptr,
   1431             };
   1432             return o.lowerDebugTypeImpl(entry, resolve, di_type);
   1433         }
   1434         errdefer assert(o.di_type_map.orderedRemoveContext(ty, .{ .mod = o.module }));
   1435         // The Type memory is ephemeral; since we want to store a longer-lived
   1436         // reference, we need to copy it here.
   1437         gop.key_ptr.* = try ty.copy(o.type_map_arena.allocator());
   1438         const entry: Object.DITypeMap.Entry = .{
   1439             .key_ptr = gop.key_ptr,
   1440             .value_ptr = gop.value_ptr,
   1441         };
   1442         return o.lowerDebugTypeImpl(entry, resolve, null);
   1443     }
   1444 
   1445     /// This is a helper function used by `lowerDebugType`.
   1446     fn lowerDebugTypeImpl(
   1447         o: *Object,
   1448         gop: Object.DITypeMap.Entry,
   1449         resolve: DebugResolveStatus,
   1450         opt_fwd_decl: ?*llvm.DIType,
   1451     ) Allocator.Error!*llvm.DIType {
   1452         const ty = gop.key_ptr.*;
   1453         const gpa = o.gpa;
   1454         const target = o.target;
   1455         const dib = o.di_builder.?;
   1456         switch (ty.zigTypeTag()) {
   1457             .Void, .NoReturn => {
   1458                 const di_type = dib.createBasicType("void", 0, DW.ATE.signed);
   1459                 gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_type);
   1460                 return di_type;
   1461             },
   1462             .Int => {
   1463                 const info = ty.intInfo(target);
   1464                 assert(info.bits != 0);
   1465                 const name = try ty.nameAlloc(gpa, o.module);
   1466                 defer gpa.free(name);
   1467                 const dwarf_encoding: c_uint = switch (info.signedness) {
   1468                     .signed => DW.ATE.signed,
   1469                     .unsigned => DW.ATE.unsigned,
   1470                 };
   1471                 const di_type = dib.createBasicType(name, info.bits, dwarf_encoding);
   1472                 gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_type);
   1473                 return di_type;
   1474             },
   1475             .Enum => {
   1476                 const owner_decl_index = ty.getOwnerDecl();
   1477                 const owner_decl = o.module.declPtr(owner_decl_index);
   1478 
   1479                 if (!ty.hasRuntimeBitsIgnoreComptime()) {
   1480                     const enum_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index);
   1481                     // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`
   1482                     // means we can't use `gop` anymore.
   1483                     try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(enum_di_ty), .{ .mod = o.module });
   1484                     return enum_di_ty;
   1485                 }
   1486 
   1487                 const field_names = ty.enumFields().keys();
   1488 
   1489                 const enumerators = try gpa.alloc(*llvm.DIEnumerator, field_names.len);
   1490                 defer gpa.free(enumerators);
   1491 
   1492                 var buf_field_index: Value.Payload.U32 = .{
   1493                     .base = .{ .tag = .enum_field_index },
   1494                     .data = undefined,
   1495                 };
   1496                 const field_index_val = Value.initPayload(&buf_field_index.base);
   1497 
   1498                 for (field_names) |field_name, i| {
   1499                     const field_name_z = try gpa.dupeZ(u8, field_name);
   1500                     defer gpa.free(field_name_z);
   1501 
   1502                     buf_field_index.data = @intCast(u32, i);
   1503                     var buf_u64: Value.Payload.U64 = undefined;
   1504                     const field_int_val = field_index_val.enumToInt(ty, &buf_u64);
   1505                     // See https://github.com/ziglang/zig/issues/645
   1506                     const field_int = field_int_val.toSignedInt();
   1507                     enumerators[i] = dib.createEnumerator(field_name_z, field_int);
   1508                 }
   1509 
   1510                 const di_file = try o.getDIFile(gpa, owner_decl.src_namespace.file_scope);
   1511                 const di_scope = try o.namespaceToDebugScope(owner_decl.src_namespace);
   1512 
   1513                 const name = try ty.nameAlloc(gpa, o.module);
   1514                 defer gpa.free(name);
   1515                 var buffer: Type.Payload.Bits = undefined;
   1516                 const int_ty = ty.intTagType(&buffer);
   1517 
   1518                 const enum_di_ty = dib.createEnumerationType(
   1519                     di_scope,
   1520                     name,
   1521                     di_file,
   1522                     owner_decl.src_node + 1,
   1523                     ty.abiSize(target) * 8,
   1524                     ty.abiAlignment(target) * 8,
   1525                     enumerators.ptr,
   1526                     @intCast(c_int, enumerators.len),
   1527                     try o.lowerDebugType(int_ty, .full),
   1528                     "",
   1529                 );
   1530                 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
   1531                 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(enum_di_ty), .{ .mod = o.module });
   1532                 return enum_di_ty;
   1533             },
   1534             .Float => {
   1535                 const bits = ty.floatBits(target);
   1536                 const name = try ty.nameAlloc(gpa, o.module);
   1537                 defer gpa.free(name);
   1538                 const di_type = dib.createBasicType(name, bits, DW.ATE.float);
   1539                 gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_type);
   1540                 return di_type;
   1541             },
   1542             .Bool => {
   1543                 const di_type = dib.createBasicType("bool", 1, DW.ATE.boolean);
   1544                 gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_type);
   1545                 return di_type;
   1546             },
   1547             .Pointer => {
   1548                 // Normalize everything that the debug info does not represent.
   1549                 const ptr_info = ty.ptrInfo().data;
   1550 
   1551                 if (ptr_info.sentinel != null or
   1552                     ptr_info.@"addrspace" != .generic or
   1553                     ptr_info.bit_offset != 0 or
   1554                     ptr_info.host_size != 0 or
   1555                     ptr_info.@"allowzero" or
   1556                     !ptr_info.mutable or
   1557                     ptr_info.@"volatile" or
   1558                     ptr_info.size == .Many or ptr_info.size == .C or
   1559                     !ptr_info.pointee_type.hasRuntimeBitsIgnoreComptime())
   1560                 {
   1561                     var payload: Type.Payload.Pointer = .{
   1562                         .data = .{
   1563                             .pointee_type = ptr_info.pointee_type,
   1564                             .sentinel = null,
   1565                             .@"align" = ptr_info.@"align",
   1566                             .@"addrspace" = .generic,
   1567                             .bit_offset = 0,
   1568                             .host_size = 0,
   1569                             .@"allowzero" = false,
   1570                             .mutable = true,
   1571                             .@"volatile" = false,
   1572                             .size = switch (ptr_info.size) {
   1573                                 .Many, .C, .One => .One,
   1574                                 .Slice => .Slice,
   1575                             },
   1576                         },
   1577                     };
   1578                     if (!ptr_info.pointee_type.hasRuntimeBitsIgnoreComptime()) {
   1579                         payload.data.pointee_type = Type.anyopaque;
   1580                     }
   1581                     const bland_ptr_ty = Type.initPayload(&payload.base);
   1582                     const ptr_di_ty = try o.lowerDebugType(bland_ptr_ty, resolve);
   1583                     // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
   1584                     try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.init(ptr_di_ty, resolve), .{ .mod = o.module });
   1585                     return ptr_di_ty;
   1586                 }
   1587 
   1588                 if (ty.isSlice()) {
   1589                     var buf: Type.SlicePtrFieldTypeBuffer = undefined;
   1590                     const ptr_ty = ty.slicePtrFieldType(&buf);
   1591                     const len_ty = Type.usize;
   1592 
   1593                     const name = try ty.nameAlloc(gpa, o.module);
   1594                     defer gpa.free(name);
   1595                     const di_file: ?*llvm.DIFile = null;
   1596                     const line = 0;
   1597                     const compile_unit_scope = o.di_compile_unit.?.toScope();
   1598 
   1599                     const fwd_decl = opt_fwd_decl orelse blk: {
   1600                         const fwd_decl = dib.createReplaceableCompositeType(
   1601                             DW.TAG.structure_type,
   1602                             name.ptr,
   1603                             compile_unit_scope,
   1604                             di_file,
   1605                             line,
   1606                         );
   1607                         gop.value_ptr.* = AnnotatedDITypePtr.initFwd(fwd_decl);
   1608                         if (resolve == .fwd) return fwd_decl;
   1609                         break :blk fwd_decl;
   1610                     };
   1611 
   1612                     const ptr_size = ptr_ty.abiSize(target);
   1613                     const ptr_align = ptr_ty.abiAlignment(target);
   1614                     const len_size = len_ty.abiSize(target);
   1615                     const len_align = len_ty.abiAlignment(target);
   1616 
   1617                     var offset: u64 = 0;
   1618                     offset += ptr_size;
   1619                     offset = std.mem.alignForwardGeneric(u64, offset, len_align);
   1620                     const len_offset = offset;
   1621 
   1622                     const fields: [2]*llvm.DIType = .{
   1623                         dib.createMemberType(
   1624                             fwd_decl.toScope(),
   1625                             "ptr",
   1626                             di_file,
   1627                             line,
   1628                             ptr_size * 8, // size in bits
   1629                             ptr_align * 8, // align in bits
   1630                             0, // offset in bits
   1631                             0, // flags
   1632                             try o.lowerDebugType(ptr_ty, .full),
   1633                         ),
   1634                         dib.createMemberType(
   1635                             fwd_decl.toScope(),
   1636                             "len",
   1637                             di_file,
   1638                             line,
   1639                             len_size * 8, // size in bits
   1640                             len_align * 8, // align in bits
   1641                             len_offset * 8, // offset in bits
   1642                             0, // flags
   1643                             try o.lowerDebugType(len_ty, .full),
   1644                         ),
   1645                     };
   1646 
   1647                     const full_di_ty = dib.createStructType(
   1648                         compile_unit_scope,
   1649                         name.ptr,
   1650                         di_file,
   1651                         line,
   1652                         ty.abiSize(target) * 8, // size in bits
   1653                         ty.abiAlignment(target) * 8, // align in bits
   1654                         0, // flags
   1655                         null, // derived from
   1656                         &fields,
   1657                         fields.len,
   1658                         0, // run time lang
   1659                         null, // vtable holder
   1660                         "", // unique id
   1661                     );
   1662                     dib.replaceTemporary(fwd_decl, full_di_ty);
   1663                     // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
   1664                     try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .mod = o.module });
   1665                     return full_di_ty;
   1666                 }
   1667 
   1668                 const elem_di_ty = try o.lowerDebugType(ptr_info.pointee_type, .fwd);
   1669                 const name = try ty.nameAlloc(gpa, o.module);
   1670                 defer gpa.free(name);
   1671                 const ptr_di_ty = dib.createPointerType(
   1672                     elem_di_ty,
   1673                     target.cpu.arch.ptrBitWidth(),
   1674                     ty.ptrAlignment(target) * 8,
   1675                     name,
   1676                 );
   1677                 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
   1678                 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(ptr_di_ty), .{ .mod = o.module });
   1679                 return ptr_di_ty;
   1680             },
   1681             .Opaque => {
   1682                 if (ty.tag() == .anyopaque) {
   1683                     const di_ty = dib.createBasicType("anyopaque", 0, DW.ATE.signed);
   1684                     gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty);
   1685                     return di_ty;
   1686                 }
   1687                 const name = try ty.nameAlloc(gpa, o.module);
   1688                 defer gpa.free(name);
   1689                 const owner_decl_index = ty.getOwnerDecl();
   1690                 const owner_decl = o.module.declPtr(owner_decl_index);
   1691                 const opaque_di_ty = dib.createForwardDeclType(
   1692                     DW.TAG.structure_type,
   1693                     name,
   1694                     try o.namespaceToDebugScope(owner_decl.src_namespace),
   1695                     try o.getDIFile(gpa, owner_decl.src_namespace.file_scope),
   1696                     owner_decl.src_node + 1,
   1697                 );
   1698                 // The recursive call to `lowerDebugType` va `namespaceToDebugScope`
   1699                 // means we can't use `gop` anymore.
   1700                 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(opaque_di_ty), .{ .mod = o.module });
   1701                 return opaque_di_ty;
   1702             },
   1703             .Array => {
   1704                 const array_di_ty = dib.createArrayType(
   1705                     ty.abiSize(target) * 8,
   1706                     ty.abiAlignment(target) * 8,
   1707                     try o.lowerDebugType(ty.childType(), .full),
   1708                     @intCast(c_int, ty.arrayLen()),
   1709                 );
   1710                 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
   1711                 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(array_di_ty), .{ .mod = o.module });
   1712                 return array_di_ty;
   1713             },
   1714             .Vector => {
   1715                 const vector_di_ty = dib.createVectorType(
   1716                     ty.abiSize(target) * 8,
   1717                     ty.abiAlignment(target) * 8,
   1718                     try o.lowerDebugType(ty.childType(), .full),
   1719                     ty.vectorLen(),
   1720                 );
   1721                 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
   1722                 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(vector_di_ty), .{ .mod = o.module });
   1723                 return vector_di_ty;
   1724             },
   1725             .Optional => {
   1726                 const name = try ty.nameAlloc(gpa, o.module);
   1727                 defer gpa.free(name);
   1728                 var buf: Type.Payload.ElemType = undefined;
   1729                 const child_ty = ty.optionalChild(&buf);
   1730                 if (!child_ty.hasRuntimeBitsIgnoreComptime()) {
   1731                     const di_ty = dib.createBasicType(name, 1, DW.ATE.boolean);
   1732                     gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty);
   1733                     return di_ty;
   1734                 }
   1735                 if (ty.optionalReprIsPayload()) {
   1736                     const ptr_di_ty = try o.lowerDebugType(child_ty, resolve);
   1737                     // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
   1738                     try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(ptr_di_ty), .{ .mod = o.module });
   1739                     return ptr_di_ty;
   1740                 }
   1741 
   1742                 const di_file: ?*llvm.DIFile = null;
   1743                 const line = 0;
   1744                 const compile_unit_scope = o.di_compile_unit.?.toScope();
   1745                 const fwd_decl = opt_fwd_decl orelse blk: {
   1746                     const fwd_decl = dib.createReplaceableCompositeType(
   1747                         DW.TAG.structure_type,
   1748                         name.ptr,
   1749                         compile_unit_scope,
   1750                         di_file,
   1751                         line,
   1752                     );
   1753                     gop.value_ptr.* = AnnotatedDITypePtr.initFwd(fwd_decl);
   1754                     if (resolve == .fwd) return fwd_decl;
   1755                     break :blk fwd_decl;
   1756                 };
   1757 
   1758                 const non_null_ty = Type.u8;
   1759                 const payload_size = child_ty.abiSize(target);
   1760                 const payload_align = child_ty.abiAlignment(target);
   1761                 const non_null_size = non_null_ty.abiSize(target);
   1762                 const non_null_align = non_null_ty.abiAlignment(target);
   1763 
   1764                 var offset: u64 = 0;
   1765                 offset += payload_size;
   1766                 offset = std.mem.alignForwardGeneric(u64, offset, non_null_align);
   1767                 const non_null_offset = offset;
   1768 
   1769                 const fields: [2]*llvm.DIType = .{
   1770                     dib.createMemberType(
   1771                         fwd_decl.toScope(),
   1772                         "data",
   1773                         di_file,
   1774                         line,
   1775                         payload_size * 8, // size in bits
   1776                         payload_align * 8, // align in bits
   1777                         0, // offset in bits
   1778                         0, // flags
   1779                         try o.lowerDebugType(child_ty, .full),
   1780                     ),
   1781                     dib.createMemberType(
   1782                         fwd_decl.toScope(),
   1783                         "some",
   1784                         di_file,
   1785                         line,
   1786                         non_null_size * 8, // size in bits
   1787                         non_null_align * 8, // align in bits
   1788                         non_null_offset * 8, // offset in bits
   1789                         0, // flags
   1790                         try o.lowerDebugType(non_null_ty, .full),
   1791                     ),
   1792                 };
   1793 
   1794                 const full_di_ty = dib.createStructType(
   1795                     compile_unit_scope,
   1796                     name.ptr,
   1797                     di_file,
   1798                     line,
   1799                     ty.abiSize(target) * 8, // size in bits
   1800                     ty.abiAlignment(target) * 8, // align in bits
   1801                     0, // flags
   1802                     null, // derived from
   1803                     &fields,
   1804                     fields.len,
   1805                     0, // run time lang
   1806                     null, // vtable holder
   1807                     "", // unique id
   1808                 );
   1809                 dib.replaceTemporary(fwd_decl, full_di_ty);
   1810                 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
   1811                 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .mod = o.module });
   1812                 return full_di_ty;
   1813             },
   1814             .ErrorUnion => {
   1815                 const payload_ty = ty.errorUnionPayload();
   1816                 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
   1817                     const err_set_di_ty = try o.lowerDebugType(Type.anyerror, .full);
   1818                     // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
   1819                     try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(err_set_di_ty), .{ .mod = o.module });
   1820                     return err_set_di_ty;
   1821                 }
   1822                 const name = try ty.nameAlloc(gpa, o.module);
   1823                 defer gpa.free(name);
   1824                 const di_file: ?*llvm.DIFile = null;
   1825                 const line = 0;
   1826                 const compile_unit_scope = o.di_compile_unit.?.toScope();
   1827                 const fwd_decl = opt_fwd_decl orelse blk: {
   1828                     const fwd_decl = dib.createReplaceableCompositeType(
   1829                         DW.TAG.structure_type,
   1830                         name.ptr,
   1831                         compile_unit_scope,
   1832                         di_file,
   1833                         line,
   1834                     );
   1835                     gop.value_ptr.* = AnnotatedDITypePtr.initFwd(fwd_decl);
   1836                     if (resolve == .fwd) return fwd_decl;
   1837                     break :blk fwd_decl;
   1838                 };
   1839 
   1840                 const error_size = Type.anyerror.abiSize(target);
   1841                 const error_align = Type.anyerror.abiAlignment(target);
   1842                 const payload_size = payload_ty.abiSize(target);
   1843                 const payload_align = payload_ty.abiAlignment(target);
   1844 
   1845                 var error_index: u32 = undefined;
   1846                 var payload_index: u32 = undefined;
   1847                 var error_offset: u64 = undefined;
   1848                 var payload_offset: u64 = undefined;
   1849                 if (error_align > payload_align) {
   1850                     error_index = 0;
   1851                     payload_index = 1;
   1852                     error_offset = 0;
   1853                     payload_offset = std.mem.alignForwardGeneric(u64, error_size, payload_align);
   1854                 } else {
   1855                     payload_index = 0;
   1856                     error_index = 1;
   1857                     payload_offset = 0;
   1858                     error_offset = std.mem.alignForwardGeneric(u64, payload_size, error_align);
   1859                 }
   1860 
   1861                 var fields: [2]*llvm.DIType = undefined;
   1862                 fields[error_index] = dib.createMemberType(
   1863                     fwd_decl.toScope(),
   1864                     "tag",
   1865                     di_file,
   1866                     line,
   1867                     error_size * 8, // size in bits
   1868                     error_align * 8, // align in bits
   1869                     error_offset * 8, // offset in bits
   1870                     0, // flags
   1871                     try o.lowerDebugType(Type.anyerror, .full),
   1872                 );
   1873                 fields[payload_index] = dib.createMemberType(
   1874                     fwd_decl.toScope(),
   1875                     "value",
   1876                     di_file,
   1877                     line,
   1878                     payload_size * 8, // size in bits
   1879                     payload_align * 8, // align in bits
   1880                     payload_offset * 8, // offset in bits
   1881                     0, // flags
   1882                     try o.lowerDebugType(payload_ty, .full),
   1883                 );
   1884 
   1885                 const full_di_ty = dib.createStructType(
   1886                     compile_unit_scope,
   1887                     name.ptr,
   1888                     di_file,
   1889                     line,
   1890                     ty.abiSize(target) * 8, // size in bits
   1891                     ty.abiAlignment(target) * 8, // align in bits
   1892                     0, // flags
   1893                     null, // derived from
   1894                     &fields,
   1895                     fields.len,
   1896                     0, // run time lang
   1897                     null, // vtable holder
   1898                     "", // unique id
   1899                 );
   1900                 dib.replaceTemporary(fwd_decl, full_di_ty);
   1901                 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
   1902                 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .mod = o.module });
   1903                 return full_di_ty;
   1904             },
   1905             .ErrorSet => {
   1906                 // TODO make this a proper enum with all the error codes in it.
   1907                 // will need to consider how to take incremental compilation into account.
   1908                 const di_ty = dib.createBasicType("anyerror", 16, DW.ATE.unsigned);
   1909                 gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty);
   1910                 return di_ty;
   1911             },
   1912             .Struct => {
   1913                 const compile_unit_scope = o.di_compile_unit.?.toScope();
   1914                 const name = try ty.nameAlloc(gpa, o.module);
   1915                 defer gpa.free(name);
   1916 
   1917                 if (ty.castTag(.@"struct")) |payload| {
   1918                     const struct_obj = payload.data;
   1919                     if (struct_obj.layout == .Packed) {
   1920                         const info = struct_obj.backing_int_ty.intInfo(target);
   1921                         const dwarf_encoding: c_uint = switch (info.signedness) {
   1922                             .signed => DW.ATE.signed,
   1923                             .unsigned => DW.ATE.unsigned,
   1924                         };
   1925                         const di_ty = dib.createBasicType(name, info.bits, dwarf_encoding);
   1926                         gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty);
   1927                         return di_ty;
   1928                     }
   1929                 }
   1930 
   1931                 const fwd_decl = opt_fwd_decl orelse blk: {
   1932                     const fwd_decl = dib.createReplaceableCompositeType(
   1933                         DW.TAG.structure_type,
   1934                         name.ptr,
   1935                         compile_unit_scope,
   1936                         null, // file
   1937                         0, // line
   1938                     );
   1939                     gop.value_ptr.* = AnnotatedDITypePtr.initFwd(fwd_decl);
   1940                     if (resolve == .fwd) return fwd_decl;
   1941                     break :blk fwd_decl;
   1942                 };
   1943 
   1944                 if (ty.isTupleOrAnonStruct()) {
   1945                     const tuple = ty.tupleFields();
   1946 
   1947                     var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
   1948                     defer di_fields.deinit(gpa);
   1949 
   1950                     try di_fields.ensureUnusedCapacity(gpa, tuple.types.len);
   1951 
   1952                     comptime assert(struct_layout_version == 2);
   1953                     var offset: u64 = 0;
   1954 
   1955                     for (tuple.types) |field_ty, i| {
   1956                         const field_val = tuple.values[i];
   1957                         if (field_val.tag() != .unreachable_value) continue;
   1958 
   1959                         const field_size = field_ty.abiSize(target);
   1960                         const field_align = field_ty.abiAlignment(target);
   1961                         const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align);
   1962                         offset = field_offset + field_size;
   1963 
   1964                         const field_name = if (ty.castTag(.anon_struct)) |payload|
   1965                             try gpa.dupeZ(u8, payload.data.names[i])
   1966                         else
   1967                             try std.fmt.allocPrintZ(gpa, "{d}", .{i});
   1968                         defer gpa.free(field_name);
   1969 
   1970                         try di_fields.append(gpa, dib.createMemberType(
   1971                             fwd_decl.toScope(),
   1972                             field_name,
   1973                             null, // file
   1974                             0, // line
   1975                             field_size * 8, // size in bits
   1976                             field_align * 8, // align in bits
   1977                             field_offset * 8, // offset in bits
   1978                             0, // flags
   1979                             try o.lowerDebugType(field_ty, .full),
   1980                         ));
   1981                     }
   1982 
   1983                     const full_di_ty = dib.createStructType(
   1984                         compile_unit_scope,
   1985                         name.ptr,
   1986                         null, // file
   1987                         0, // line
   1988                         ty.abiSize(target) * 8, // size in bits
   1989                         ty.abiAlignment(target) * 8, // align in bits
   1990                         0, // flags
   1991                         null, // derived from
   1992                         di_fields.items.ptr,
   1993                         @intCast(c_int, di_fields.items.len),
   1994                         0, // run time lang
   1995                         null, // vtable holder
   1996                         "", // unique id
   1997                     );
   1998                     dib.replaceTemporary(fwd_decl, full_di_ty);
   1999                     // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
   2000                     try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .mod = o.module });
   2001                     return full_di_ty;
   2002                 }
   2003 
   2004                 if (ty.castTag(.@"struct")) |payload| {
   2005                     const struct_obj = payload.data;
   2006                     if (!struct_obj.haveFieldTypes()) {
   2007                         // This can happen if a struct type makes it all the way to
   2008                         // flush() without ever being instantiated or referenced (even
   2009                         // via pointer). The only reason we are hearing about it now is
   2010                         // that it is being used as a namespace to put other debug types
   2011                         // into. Therefore we can satisfy this by making an empty namespace,
   2012                         // rather than changing the frontend to unnecessarily resolve the
   2013                         // struct field types.
   2014                         const owner_decl_index = ty.getOwnerDecl();
   2015                         const struct_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index);
   2016                         dib.replaceTemporary(fwd_decl, struct_di_ty);
   2017                         // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`
   2018                         // means we can't use `gop` anymore.
   2019                         try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(struct_di_ty), .{ .mod = o.module });
   2020                         return struct_di_ty;
   2021                     }
   2022                 }
   2023 
   2024                 if (!ty.hasRuntimeBitsIgnoreComptime()) {
   2025                     const owner_decl_index = ty.getOwnerDecl();
   2026                     const struct_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index);
   2027                     dib.replaceTemporary(fwd_decl, struct_di_ty);
   2028                     // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`
   2029                     // means we can't use `gop` anymore.
   2030                     try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(struct_di_ty), .{ .mod = o.module });
   2031                     return struct_di_ty;
   2032                 }
   2033 
   2034                 const fields = ty.structFields();
   2035                 const layout = ty.containerLayout();
   2036 
   2037                 var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
   2038                 defer di_fields.deinit(gpa);
   2039 
   2040                 try di_fields.ensureUnusedCapacity(gpa, fields.count());
   2041 
   2042                 comptime assert(struct_layout_version == 2);
   2043                 var offset: u64 = 0;
   2044 
   2045                 for (fields.values()) |field, i| {
   2046                     if (field.is_comptime or !field.ty.hasRuntimeBits()) continue;
   2047 
   2048                     const field_size = field.ty.abiSize(target);
   2049                     const field_align = field.alignment(target, layout);
   2050                     const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align);
   2051                     offset = field_offset + field_size;
   2052 
   2053                     const field_name = try gpa.dupeZ(u8, fields.keys()[i]);
   2054                     defer gpa.free(field_name);
   2055 
   2056                     try di_fields.append(gpa, dib.createMemberType(
   2057                         fwd_decl.toScope(),
   2058                         field_name,
   2059                         null, // file
   2060                         0, // line
   2061                         field_size * 8, // size in bits
   2062                         field_align * 8, // align in bits
   2063                         field_offset * 8, // offset in bits
   2064                         0, // flags
   2065                         try o.lowerDebugType(field.ty, .full),
   2066                     ));
   2067                 }
   2068 
   2069                 const full_di_ty = dib.createStructType(
   2070                     compile_unit_scope,
   2071                     name.ptr,
   2072                     null, // file
   2073                     0, // line
   2074                     ty.abiSize(target) * 8, // size in bits
   2075                     ty.abiAlignment(target) * 8, // align in bits
   2076                     0, // flags
   2077                     null, // derived from
   2078                     di_fields.items.ptr,
   2079                     @intCast(c_int, di_fields.items.len),
   2080                     0, // run time lang
   2081                     null, // vtable holder
   2082                     "", // unique id
   2083                 );
   2084                 dib.replaceTemporary(fwd_decl, full_di_ty);
   2085                 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
   2086                 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .mod = o.module });
   2087                 return full_di_ty;
   2088             },
   2089             .Union => {
   2090                 const compile_unit_scope = o.di_compile_unit.?.toScope();
   2091                 const owner_decl_index = ty.getOwnerDecl();
   2092 
   2093                 const name = try ty.nameAlloc(gpa, o.module);
   2094                 defer gpa.free(name);
   2095 
   2096                 const fwd_decl = opt_fwd_decl orelse blk: {
   2097                     const fwd_decl = dib.createReplaceableCompositeType(
   2098                         DW.TAG.structure_type,
   2099                         name.ptr,
   2100                         o.di_compile_unit.?.toScope(),
   2101                         null, // file
   2102                         0, // line
   2103                     );
   2104                     gop.value_ptr.* = AnnotatedDITypePtr.initFwd(fwd_decl);
   2105                     if (resolve == .fwd) return fwd_decl;
   2106                     break :blk fwd_decl;
   2107                 };
   2108 
   2109                 if (!ty.hasRuntimeBitsIgnoreComptime()) {
   2110                     const union_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index);
   2111                     dib.replaceTemporary(fwd_decl, union_di_ty);
   2112                     // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`
   2113                     // means we can't use `gop` anymore.
   2114                     try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(union_di_ty), .{ .mod = o.module });
   2115                     return union_di_ty;
   2116                 }
   2117 
   2118                 const layout = ty.unionGetLayout(target);
   2119                 const union_obj = ty.cast(Type.Payload.Union).?.data;
   2120 
   2121                 if (layout.payload_size == 0) {
   2122                     const tag_di_ty = try o.lowerDebugType(union_obj.tag_ty, .full);
   2123                     const di_fields = [_]*llvm.DIType{tag_di_ty};
   2124                     const full_di_ty = dib.createStructType(
   2125                         compile_unit_scope,
   2126                         name.ptr,
   2127                         null, // file
   2128                         0, // line
   2129                         ty.abiSize(target) * 8, // size in bits
   2130                         ty.abiAlignment(target) * 8, // align in bits
   2131                         0, // flags
   2132                         null, // derived from
   2133                         &di_fields,
   2134                         di_fields.len,
   2135                         0, // run time lang
   2136                         null, // vtable holder
   2137                         "", // unique id
   2138                     );
   2139                     dib.replaceTemporary(fwd_decl, full_di_ty);
   2140                     // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`
   2141                     // means we can't use `gop` anymore.
   2142                     try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .mod = o.module });
   2143                     return full_di_ty;
   2144                 }
   2145 
   2146                 var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
   2147                 defer di_fields.deinit(gpa);
   2148 
   2149                 try di_fields.ensureUnusedCapacity(gpa, union_obj.fields.count());
   2150 
   2151                 var it = union_obj.fields.iterator();
   2152                 while (it.next()) |kv| {
   2153                     const field_name = kv.key_ptr.*;
   2154                     const field = kv.value_ptr.*;
   2155 
   2156                     if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue;
   2157 
   2158                     const field_size = field.ty.abiSize(target);
   2159                     const field_align = field.normalAlignment(target);
   2160 
   2161                     const field_name_copy = try gpa.dupeZ(u8, field_name);
   2162                     defer gpa.free(field_name_copy);
   2163 
   2164                     di_fields.appendAssumeCapacity(dib.createMemberType(
   2165                         fwd_decl.toScope(),
   2166                         field_name_copy,
   2167                         null, // file
   2168                         0, // line
   2169                         field_size * 8, // size in bits
   2170                         field_align * 8, // align in bits
   2171                         0, // offset in bits
   2172                         0, // flags
   2173                         try o.lowerDebugType(field.ty, .full),
   2174                     ));
   2175                 }
   2176 
   2177                 const union_name = if (layout.tag_size == 0) name.ptr else "AnonUnion";
   2178 
   2179                 const union_di_ty = dib.createUnionType(
   2180                     compile_unit_scope,
   2181                     union_name,
   2182                     null, // file
   2183                     0, // line
   2184                     ty.abiSize(target) * 8, // size in bits
   2185                     ty.abiAlignment(target) * 8, // align in bits
   2186                     0, // flags
   2187                     di_fields.items.ptr,
   2188                     @intCast(c_int, di_fields.items.len),
   2189                     0, // run time lang
   2190                     "", // unique id
   2191                 );
   2192 
   2193                 if (layout.tag_size == 0) {
   2194                     dib.replaceTemporary(fwd_decl, union_di_ty);
   2195                     // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
   2196                     try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(union_di_ty), .{ .mod = o.module });
   2197                     return union_di_ty;
   2198                 }
   2199 
   2200                 var tag_offset: u64 = undefined;
   2201                 var payload_offset: u64 = undefined;
   2202                 if (layout.tag_align >= layout.payload_align) {
   2203                     tag_offset = 0;
   2204                     payload_offset = std.mem.alignForwardGeneric(u64, layout.tag_size, layout.payload_align);
   2205                 } else {
   2206                     payload_offset = 0;
   2207                     tag_offset = std.mem.alignForwardGeneric(u64, layout.payload_size, layout.tag_align);
   2208                 }
   2209 
   2210                 const tag_di = dib.createMemberType(
   2211                     fwd_decl.toScope(),
   2212                     "tag",
   2213                     null, // file
   2214                     0, // line
   2215                     layout.tag_size * 8,
   2216                     layout.tag_align * 8, // align in bits
   2217                     tag_offset * 8, // offset in bits
   2218                     0, // flags
   2219                     try o.lowerDebugType(union_obj.tag_ty, .full),
   2220                 );
   2221 
   2222                 const payload_di = dib.createMemberType(
   2223                     fwd_decl.toScope(),
   2224                     "payload",
   2225                     null, // file
   2226                     0, // line
   2227                     layout.payload_size * 8, // size in bits
   2228                     layout.payload_align * 8, // align in bits
   2229                     payload_offset * 8, // offset in bits
   2230                     0, // flags
   2231                     union_di_ty,
   2232                 );
   2233 
   2234                 const full_di_fields: [2]*llvm.DIType =
   2235                     if (layout.tag_align >= layout.payload_align)
   2236                 .{ tag_di, payload_di } else .{ payload_di, tag_di };
   2237 
   2238                 const full_di_ty = dib.createStructType(
   2239                     compile_unit_scope,
   2240                     name.ptr,
   2241                     null, // file
   2242                     0, // line
   2243                     ty.abiSize(target) * 8, // size in bits
   2244                     ty.abiAlignment(target) * 8, // align in bits
   2245                     0, // flags
   2246                     null, // derived from
   2247                     &full_di_fields,
   2248                     full_di_fields.len,
   2249                     0, // run time lang
   2250                     null, // vtable holder
   2251                     "", // unique id
   2252                 );
   2253                 dib.replaceTemporary(fwd_decl, full_di_ty);
   2254                 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
   2255                 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .mod = o.module });
   2256                 return full_di_ty;
   2257             },
   2258             .Fn => {
   2259                 const fn_info = ty.fnInfo();
   2260 
   2261                 var param_di_types = std.ArrayList(*llvm.DIType).init(gpa);
   2262                 defer param_di_types.deinit();
   2263 
   2264                 // Return type goes first.
   2265                 if (fn_info.return_type.hasRuntimeBitsIgnoreComptime()) {
   2266                     const sret = firstParamSRet(fn_info, target);
   2267                     const di_ret_ty = if (sret) Type.void else fn_info.return_type;
   2268                     try param_di_types.append(try o.lowerDebugType(di_ret_ty, .full));
   2269 
   2270                     if (sret) {
   2271                         var ptr_ty_payload: Type.Payload.ElemType = .{
   2272                             .base = .{ .tag = .single_mut_pointer },
   2273                             .data = fn_info.return_type,
   2274                         };
   2275                         const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
   2276                         try param_di_types.append(try o.lowerDebugType(ptr_ty, .full));
   2277                     }
   2278                 } else {
   2279                     try param_di_types.append(try o.lowerDebugType(Type.void, .full));
   2280                 }
   2281 
   2282                 if (fn_info.return_type.isError() and
   2283                     o.module.comp.bin_file.options.error_return_tracing)
   2284                 {
   2285                     var ptr_ty_payload: Type.Payload.ElemType = .{
   2286                         .base = .{ .tag = .single_mut_pointer },
   2287                         .data = o.getStackTraceType(),
   2288                     };
   2289                     const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
   2290                     try param_di_types.append(try o.lowerDebugType(ptr_ty, .full));
   2291                 }
   2292 
   2293                 for (fn_info.param_types) |param_ty| {
   2294                     if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue;
   2295 
   2296                     if (isByRef(param_ty)) {
   2297                         var ptr_ty_payload: Type.Payload.ElemType = .{
   2298                             .base = .{ .tag = .single_mut_pointer },
   2299                             .data = param_ty,
   2300                         };
   2301                         const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
   2302                         try param_di_types.append(try o.lowerDebugType(ptr_ty, .full));
   2303                     } else {
   2304                         try param_di_types.append(try o.lowerDebugType(param_ty, .full));
   2305                     }
   2306                 }
   2307 
   2308                 const fn_di_ty = dib.createSubroutineType(
   2309                     param_di_types.items.ptr,
   2310                     @intCast(c_int, param_di_types.items.len),
   2311                     0,
   2312                 );
   2313                 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
   2314                 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(fn_di_ty), .{ .mod = o.module });
   2315                 return fn_di_ty;
   2316             },
   2317             .ComptimeInt => unreachable,
   2318             .ComptimeFloat => unreachable,
   2319             .Type => unreachable,
   2320             .Undefined => unreachable,
   2321             .Null => unreachable,
   2322             .EnumLiteral => unreachable,
   2323 
   2324             .BoundFn => @panic("TODO remove BoundFn from the language"),
   2325 
   2326             .Frame => @panic("TODO implement lowerDebugType for Frame types"),
   2327             .AnyFrame => @panic("TODO implement lowerDebugType for AnyFrame types"),
   2328         }
   2329     }
   2330 
   2331     fn namespaceToDebugScope(o: *Object, namespace: *const Module.Namespace) !*llvm.DIScope {
   2332         if (namespace.parent == null) {
   2333             const di_file = try o.getDIFile(o.gpa, namespace.file_scope);
   2334             return di_file.toScope();
   2335         }
   2336         const di_type = try o.lowerDebugType(namespace.ty, .fwd);
   2337         return di_type.toScope();
   2338     }
   2339 
   2340     /// This is to be used instead of void for debug info types, to avoid tripping
   2341     /// Assertion `!isa<DIType>(Scope) && "shouldn't make a namespace scope for a type"'
   2342     /// when targeting CodeView (Windows).
   2343     fn makeEmptyNamespaceDIType(o: *Object, decl_index: Module.Decl.Index) !*llvm.DIType {
   2344         const decl = o.module.declPtr(decl_index);
   2345         const fields: [0]*llvm.DIType = .{};
   2346         return o.di_builder.?.createStructType(
   2347             try o.namespaceToDebugScope(decl.src_namespace),
   2348             decl.name, // TODO use fully qualified name
   2349             try o.getDIFile(o.gpa, decl.src_namespace.file_scope),
   2350             decl.src_line + 1,
   2351             0, // size in bits
   2352             0, // align in bits
   2353             0, // flags
   2354             null, // derived from
   2355             undefined, // TODO should be able to pass &fields,
   2356             fields.len,
   2357             0, // run time lang
   2358             null, // vtable holder
   2359             "", // unique id
   2360         );
   2361     }
   2362 
   2363     fn getStackTraceType(o: *Object) Type {
   2364         const mod = o.module;
   2365 
   2366         const std_pkg = mod.main_pkg.table.get("std").?;
   2367         const std_file = (mod.importPkg(std_pkg) catch unreachable).file;
   2368 
   2369         const builtin_str: []const u8 = "builtin";
   2370         const std_namespace = mod.declPtr(std_file.root_decl.unwrap().?).src_namespace;
   2371         const builtin_decl = std_namespace.decls
   2372             .getKeyAdapted(builtin_str, Module.DeclAdapter{ .mod = mod }).?;
   2373 
   2374         const stack_trace_str: []const u8 = "StackTrace";
   2375         // buffer is only used for int_type, `builtin` is a struct.
   2376         const builtin_ty = mod.declPtr(builtin_decl).val.toType(undefined);
   2377         const builtin_namespace = builtin_ty.getNamespace().?;
   2378         const stack_trace_decl_index = builtin_namespace.decls
   2379             .getKeyAdapted(stack_trace_str, Module.DeclAdapter{ .mod = mod }).?;
   2380         const stack_trace_decl = mod.declPtr(stack_trace_decl_index);
   2381 
   2382         // Sema should have ensured that StackTrace was analyzed.
   2383         assert(stack_trace_decl.has_tv);
   2384         return stack_trace_decl.val.toType(undefined);
   2385     }
   2386 };
   2387 
   2388 pub const DeclGen = struct {
   2389     context: *llvm.Context,
   2390     object: *Object,
   2391     module: *Module,
   2392     decl: *Module.Decl,
   2393     decl_index: Module.Decl.Index,
   2394     gpa: Allocator,
   2395     err_msg: ?*Module.ErrorMsg,
   2396 
   2397     fn todo(self: *DeclGen, comptime format: []const u8, args: anytype) Error {
   2398         @setCold(true);
   2399         assert(self.err_msg == null);
   2400         const src_loc = LazySrcLoc.nodeOffset(0).toSrcLoc(self.decl);
   2401         self.err_msg = try Module.ErrorMsg.create(self.gpa, src_loc, "TODO (LLVM): " ++ format, args);
   2402         return error.CodegenFail;
   2403     }
   2404 
   2405     fn llvmModule(self: *DeclGen) *llvm.Module {
   2406         return self.object.llvm_module;
   2407     }
   2408 
   2409     fn genDecl(dg: *DeclGen) !void {
   2410         const decl = dg.decl;
   2411         const decl_index = dg.decl_index;
   2412         assert(decl.has_tv);
   2413 
   2414         log.debug("gen: {s} type: {}, value: {}", .{
   2415             decl.name, decl.ty.fmtDebug(), decl.val.fmtDebug(),
   2416         });
   2417         assert(decl.val.tag() != .function);
   2418         if (decl.val.castTag(.extern_fn)) |extern_fn| {
   2419             _ = try dg.resolveLlvmFunction(extern_fn.data.owner_decl);
   2420         } else {
   2421             const target = dg.module.getTarget();
   2422             var global = try dg.resolveGlobalDecl(decl_index);
   2423             global.setAlignment(decl.getAlignment(target));
   2424             if (decl.@"linksection") |section| global.setSection(section);
   2425             assert(decl.has_tv);
   2426             const init_val = if (decl.val.castTag(.variable)) |payload| init_val: {
   2427                 const variable = payload.data;
   2428                 break :init_val variable.init;
   2429             } else init_val: {
   2430                 global.setGlobalConstant(.True);
   2431                 break :init_val decl.val;
   2432             };
   2433             if (init_val.tag() != .unreachable_value) {
   2434                 const llvm_init = try dg.lowerValue(.{ .ty = decl.ty, .val = init_val });
   2435                 if (global.globalGetValueType() == llvm_init.typeOf()) {
   2436                     global.setInitializer(llvm_init);
   2437                 } else {
   2438                     // LLVM does not allow us to change the type of globals. So we must
   2439                     // create a new global with the correct type, copy all its attributes,
   2440                     // and then update all references to point to the new global,
   2441                     // delete the original, and rename the new one to the old one's name.
   2442                     // This is necessary because LLVM does not support const bitcasting
   2443                     // a struct with padding bytes, which is needed to lower a const union value
   2444                     // to LLVM, when a field other than the most-aligned is active. Instead,
   2445                     // we must lower to an unnamed struct, and pointer cast at usage sites
   2446                     // of the global. Such an unnamed struct is the cause of the global type
   2447                     // mismatch, because we don't have the LLVM type until the *value* is created,
   2448                     // whereas the global needs to be created based on the type alone, because
   2449                     // lowering the value may reference the global as a pointer.
   2450                     const llvm_global_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);
   2451                     const new_global = dg.object.llvm_module.addGlobalInAddressSpace(
   2452                         llvm_init.typeOf(),
   2453                         "",
   2454                         llvm_global_addrspace,
   2455                     );
   2456                     new_global.setLinkage(global.getLinkage());
   2457                     new_global.setUnnamedAddr(global.getUnnamedAddress());
   2458                     new_global.setAlignment(global.getAlignment());
   2459                     if (decl.@"linksection") |section| new_global.setSection(section);
   2460                     new_global.setInitializer(llvm_init);
   2461                     // replaceAllUsesWith requires the type to be unchanged. So we convert
   2462                     // the new global to the old type and use that as the thing to replace
   2463                     // old uses.
   2464                     // TODO: How should this work then the address space of a global changed?
   2465                     const new_global_ptr = new_global.constBitCast(global.typeOf());
   2466                     global.replaceAllUsesWith(new_global_ptr);
   2467                     dg.object.decl_map.putAssumeCapacity(decl_index, new_global);
   2468                     new_global.takeName(global);
   2469                     global.deleteGlobal();
   2470                     global = new_global;
   2471                 }
   2472             }
   2473 
   2474             if (dg.object.di_builder) |dib| {
   2475                 const di_file = try dg.object.getDIFile(dg.gpa, decl.src_namespace.file_scope);
   2476 
   2477                 const line_number = decl.src_line + 1;
   2478                 const is_internal_linkage = !dg.module.decl_exports.contains(decl_index);
   2479                 const di_global = dib.createGlobalVariable(
   2480                     di_file.toScope(),
   2481                     decl.name,
   2482                     global.getValueName(),
   2483                     di_file,
   2484                     line_number,
   2485                     try dg.object.lowerDebugType(decl.ty, .full),
   2486                     is_internal_linkage,
   2487                 );
   2488 
   2489                 try dg.object.di_map.put(dg.gpa, dg.decl, di_global.toNode());
   2490             }
   2491         }
   2492     }
   2493 
   2494     /// If the llvm function does not exist, create it.
   2495     /// Note that this can be called before the function's semantic analysis has
   2496     /// completed, so if any attributes rely on that, they must be done in updateFunc, not here.
   2497     fn resolveLlvmFunction(dg: *DeclGen, decl_index: Module.Decl.Index) !*llvm.Value {
   2498         const decl = dg.module.declPtr(decl_index);
   2499         const zig_fn_type = decl.ty;
   2500         const gop = try dg.object.decl_map.getOrPut(dg.gpa, decl_index);
   2501         if (gop.found_existing) return gop.value_ptr.*;
   2502 
   2503         assert(decl.has_tv);
   2504         const fn_info = zig_fn_type.fnInfo();
   2505         const target = dg.module.getTarget();
   2506         const sret = firstParamSRet(fn_info, target);
   2507 
   2508         const fn_type = try dg.lowerType(zig_fn_type);
   2509 
   2510         const fqn = try decl.getFullyQualifiedName(dg.module);
   2511         defer dg.gpa.free(fqn);
   2512 
   2513         const llvm_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);
   2514         const llvm_fn = dg.llvmModule().addFunctionInAddressSpace(fqn, fn_type, llvm_addrspace);
   2515         gop.value_ptr.* = llvm_fn;
   2516 
   2517         const is_extern = decl.isExtern();
   2518         if (!is_extern) {
   2519             llvm_fn.setLinkage(.Internal);
   2520             llvm_fn.setUnnamedAddr(.True);
   2521         } else {
   2522             if (dg.module.getTarget().isWasm()) {
   2523                 dg.addFnAttrString(llvm_fn, "wasm-import-name", std.mem.sliceTo(decl.name, 0));
   2524                 if (decl.getExternFn().?.lib_name) |lib_name| {
   2525                     const module_name = std.mem.sliceTo(lib_name, 0);
   2526                     if (!std.mem.eql(u8, module_name, "c")) {
   2527                         dg.addFnAttrString(llvm_fn, "wasm-import-module", module_name);
   2528                     }
   2529                 }
   2530             }
   2531         }
   2532 
   2533         if (sret) {
   2534             dg.addArgAttr(llvm_fn, 0, "nonnull"); // Sret pointers must not be address 0
   2535             dg.addArgAttr(llvm_fn, 0, "noalias");
   2536 
   2537             const raw_llvm_ret_ty = try dg.lowerType(fn_info.return_type);
   2538             llvm_fn.addSretAttr(raw_llvm_ret_ty);
   2539         }
   2540 
   2541         const err_return_tracing = fn_info.return_type.isError() and
   2542             dg.module.comp.bin_file.options.error_return_tracing;
   2543 
   2544         if (err_return_tracing) {
   2545             dg.addArgAttr(llvm_fn, @boolToInt(sret), "nonnull");
   2546         }
   2547 
   2548         switch (fn_info.cc) {
   2549             .Unspecified, .Inline => {
   2550                 llvm_fn.setFunctionCallConv(.Fast);
   2551             },
   2552             .Naked => {
   2553                 dg.addFnAttr(llvm_fn, "naked");
   2554             },
   2555             .Async => {
   2556                 llvm_fn.setFunctionCallConv(.Fast);
   2557                 @panic("TODO: LLVM backend lower async function");
   2558             },
   2559             else => {
   2560                 llvm_fn.setFunctionCallConv(toLlvmCallConv(fn_info.cc, target));
   2561             },
   2562         }
   2563 
   2564         if (fn_info.alignment != 0) {
   2565             llvm_fn.setAlignment(fn_info.alignment);
   2566         }
   2567 
   2568         // Function attributes that are independent of analysis results of the function body.
   2569         dg.addCommonFnAttributes(llvm_fn);
   2570 
   2571         if (fn_info.return_type.isNoReturn()) {
   2572             dg.addFnAttr(llvm_fn, "noreturn");
   2573         }
   2574 
   2575         // Add parameter attributes. We handle only the case of extern functions (no body)
   2576         // because functions with bodies are handled in `updateFunc`.
   2577         if (is_extern) {
   2578             var it = iterateParamTypes(dg, fn_info);
   2579             it.llvm_index += @boolToInt(sret);
   2580             it.llvm_index += @boolToInt(err_return_tracing);
   2581             while (it.next()) |lowering| switch (lowering) {
   2582                 .byval => {
   2583                     const param_index = it.zig_index - 1;
   2584                     const param_ty = fn_info.param_types[param_index];
   2585                     if (!isByRef(param_ty)) {
   2586                         dg.addByValParamAttrs(llvm_fn, param_ty, param_index, fn_info, it.llvm_index - 1);
   2587                     }
   2588                 },
   2589                 .byref => {
   2590                     const param_ty = fn_info.param_types[it.zig_index - 1];
   2591                     const param_llvm_ty = try dg.lowerType(param_ty);
   2592                     const alignment = param_ty.abiAlignment(target);
   2593                     dg.addByRefParamAttrs(llvm_fn, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
   2594                 },
   2595                 // No attributes needed for these.
   2596                 .no_bits,
   2597                 .abi_sized_int,
   2598                 .multiple_llvm_ints,
   2599                 .multiple_llvm_float,
   2600                 .as_u16,
   2601                 .float_array,
   2602                 .i32_array,
   2603                 .i64_array,
   2604                 => continue,
   2605 
   2606                 .slice => unreachable, // extern functions do not support slice types.
   2607 
   2608             };
   2609         }
   2610 
   2611         return llvm_fn;
   2612     }
   2613 
   2614     fn addCommonFnAttributes(dg: *DeclGen, llvm_fn: *llvm.Value) void {
   2615         const comp = dg.module.comp;
   2616 
   2617         if (!comp.bin_file.options.red_zone) {
   2618             dg.addFnAttr(llvm_fn, "noredzone");
   2619         }
   2620         if (comp.bin_file.options.omit_frame_pointer) {
   2621             dg.addFnAttrString(llvm_fn, "frame-pointer", "none");
   2622         } else {
   2623             dg.addFnAttrString(llvm_fn, "frame-pointer", "all");
   2624         }
   2625         dg.addFnAttr(llvm_fn, "nounwind");
   2626         if (comp.unwind_tables) {
   2627             dg.addFnAttrInt(llvm_fn, "uwtable", 2);
   2628         }
   2629         if (comp.bin_file.options.skip_linker_dependencies or
   2630             comp.bin_file.options.no_builtin)
   2631         {
   2632             // The intent here is for compiler-rt and libc functions to not generate
   2633             // infinite recursion. For example, if we are compiling the memcpy function,
   2634             // and llvm detects that the body is equivalent to memcpy, it may replace the
   2635             // body of memcpy with a call to memcpy, which would then cause a stack
   2636             // overflow instead of performing memcpy.
   2637             dg.addFnAttr(llvm_fn, "nobuiltin");
   2638         }
   2639         if (comp.bin_file.options.optimize_mode == .ReleaseSmall) {
   2640             dg.addFnAttr(llvm_fn, "minsize");
   2641             dg.addFnAttr(llvm_fn, "optsize");
   2642         }
   2643         if (comp.bin_file.options.tsan) {
   2644             dg.addFnAttr(llvm_fn, "sanitize_thread");
   2645         }
   2646         if (comp.getTarget().cpu.model.llvm_name) |s| {
   2647             llvm_fn.addFunctionAttr("target-cpu", s);
   2648         }
   2649         if (comp.bin_file.options.llvm_cpu_features) |s| {
   2650             llvm_fn.addFunctionAttr("target-features", s);
   2651         }
   2652     }
   2653 
   2654     fn resolveGlobalDecl(dg: *DeclGen, decl_index: Module.Decl.Index) Error!*llvm.Value {
   2655         const gop = try dg.object.decl_map.getOrPut(dg.gpa, decl_index);
   2656         if (gop.found_existing) return gop.value_ptr.*;
   2657         errdefer assert(dg.object.decl_map.remove(decl_index));
   2658 
   2659         const decl = dg.module.declPtr(decl_index);
   2660         const fqn = try decl.getFullyQualifiedName(dg.module);
   2661         defer dg.gpa.free(fqn);
   2662 
   2663         const target = dg.module.getTarget();
   2664 
   2665         const llvm_type = try dg.lowerType(decl.ty);
   2666         const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);
   2667 
   2668         const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace(
   2669             llvm_type,
   2670             fqn,
   2671             llvm_actual_addrspace,
   2672         );
   2673         gop.value_ptr.* = llvm_global;
   2674 
   2675         // This is needed for declarations created by `@extern`.
   2676         if (decl.isExtern()) {
   2677             llvm_global.setValueName(decl.name);
   2678             llvm_global.setUnnamedAddr(.False);
   2679             llvm_global.setLinkage(.External);
   2680             if (decl.val.castTag(.variable)) |variable| {
   2681                 const single_threaded = dg.module.comp.bin_file.options.single_threaded;
   2682                 if (variable.data.is_threadlocal and !single_threaded) {
   2683                     llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
   2684                 } else {
   2685                     llvm_global.setThreadLocalMode(.NotThreadLocal);
   2686                 }
   2687                 if (variable.data.is_weak_linkage) llvm_global.setLinkage(.ExternalWeak);
   2688             }
   2689         } else {
   2690             llvm_global.setLinkage(.Internal);
   2691             llvm_global.setUnnamedAddr(.True);
   2692         }
   2693 
   2694         return llvm_global;
   2695     }
   2696 
   2697     fn isUnnamedType(dg: *DeclGen, ty: Type, val: *llvm.Value) bool {
   2698         // Once `lowerType` succeeds, successive calls to it with the same Zig type
   2699         // are guaranteed to succeed. So if a call to `lowerType` fails here it means
   2700         // it is the first time lowering the type, which means the value can't possible
   2701         // have that type.
   2702         const llvm_ty = dg.lowerType(ty) catch return true;
   2703         return val.typeOf() != llvm_ty;
   2704     }
   2705 
   2706     fn lowerType(dg: *DeclGen, t: Type) Allocator.Error!*llvm.Type {
   2707         const llvm_ty = try lowerTypeInner(dg, t);
   2708         if (std.debug.runtime_safety and false) check: {
   2709             if (t.zigTypeTag() == .Opaque) break :check;
   2710             if (!t.hasRuntimeBits()) break :check;
   2711             if (!llvm_ty.isSized().toBool()) break :check;
   2712 
   2713             const zig_size = t.abiSize(dg.module.getTarget());
   2714             const llvm_size = dg.object.target_data.abiSizeOfType(llvm_ty);
   2715             if (llvm_size != zig_size) {
   2716                 log.err("when lowering {}, Zig ABI size = {d} but LLVM ABI size = {d}", .{
   2717                     t.fmt(dg.module), zig_size, llvm_size,
   2718                 });
   2719             }
   2720         }
   2721         return llvm_ty;
   2722     }
   2723 
   2724     fn lowerTypeInner(dg: *DeclGen, t: Type) Allocator.Error!*llvm.Type {
   2725         const gpa = dg.gpa;
   2726         const target = dg.module.getTarget();
   2727         switch (t.zigTypeTag()) {
   2728             .Void, .NoReturn => return dg.context.voidType(),
   2729             .Int => {
   2730                 const info = t.intInfo(target);
   2731                 assert(info.bits != 0);
   2732                 return dg.context.intType(info.bits);
   2733             },
   2734             .Enum => {
   2735                 var buffer: Type.Payload.Bits = undefined;
   2736                 const int_ty = t.intTagType(&buffer);
   2737                 const bit_count = int_ty.intInfo(target).bits;
   2738                 assert(bit_count != 0);
   2739                 return dg.context.intType(bit_count);
   2740             },
   2741             .Float => switch (t.floatBits(target)) {
   2742                 16 => return if (backendSupportsF16(target)) dg.context.halfType() else dg.context.intType(16),
   2743                 32 => return dg.context.floatType(),
   2744                 64 => return dg.context.doubleType(),
   2745                 80 => return if (backendSupportsF80(target)) dg.context.x86FP80Type() else dg.context.intType(80),
   2746                 128 => return dg.context.fp128Type(),
   2747                 else => unreachable,
   2748             },
   2749             .Bool => return dg.context.intType(1),
   2750             .Pointer => {
   2751                 if (t.isSlice()) {
   2752                     var buf: Type.SlicePtrFieldTypeBuffer = undefined;
   2753                     const ptr_type = t.slicePtrFieldType(&buf);
   2754 
   2755                     const fields: [2]*llvm.Type = .{
   2756                         try dg.lowerType(ptr_type),
   2757                         try dg.lowerType(Type.usize),
   2758                     };
   2759                     return dg.context.structType(&fields, fields.len, .False);
   2760                 }
   2761                 const ptr_info = t.ptrInfo().data;
   2762                 const llvm_addrspace = toLlvmAddressSpace(ptr_info.@"addrspace", target);
   2763                 if (ptr_info.host_size != 0) {
   2764                     return dg.context.intType(ptr_info.host_size * 8).pointerType(llvm_addrspace);
   2765                 }
   2766                 const llvm_elem_ty = try dg.lowerPtrElemTy(ptr_info.pointee_type);
   2767                 return llvm_elem_ty.pointerType(llvm_addrspace);
   2768             },
   2769             .Opaque => switch (t.tag()) {
   2770                 .@"opaque" => {
   2771                     const gop = try dg.object.type_map.getOrPutContext(gpa, t, .{ .mod = dg.module });
   2772                     if (gop.found_existing) return gop.value_ptr.*;
   2773 
   2774                     // The Type memory is ephemeral; since we want to store a longer-lived
   2775                     // reference, we need to copy it here.
   2776                     gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator());
   2777 
   2778                     const opaque_obj = t.castTag(.@"opaque").?.data;
   2779                     const name = try opaque_obj.getFullyQualifiedName(dg.module);
   2780                     defer gpa.free(name);
   2781 
   2782                     const llvm_struct_ty = dg.context.structCreateNamed(name);
   2783                     gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls
   2784                     return llvm_struct_ty;
   2785                 },
   2786                 .anyopaque => return dg.context.intType(8),
   2787                 else => unreachable,
   2788             },
   2789             .Array => {
   2790                 const elem_ty = t.childType();
   2791                 assert(elem_ty.onePossibleValue() == null);
   2792                 const elem_llvm_ty = try dg.lowerType(elem_ty);
   2793                 const total_len = t.arrayLen() + @boolToInt(t.sentinel() != null);
   2794                 return elem_llvm_ty.arrayType(@intCast(c_uint, total_len));
   2795             },
   2796             .Vector => {
   2797                 const elem_type = try dg.lowerType(t.childType());
   2798                 return elem_type.vectorType(t.vectorLen());
   2799             },
   2800             .Optional => {
   2801                 var buf: Type.Payload.ElemType = undefined;
   2802                 const child_ty = t.optionalChild(&buf);
   2803                 if (!child_ty.hasRuntimeBitsIgnoreComptime()) {
   2804                     return dg.context.intType(8);
   2805                 }
   2806                 const payload_llvm_ty = try dg.lowerType(child_ty);
   2807                 if (t.optionalReprIsPayload()) {
   2808                     return payload_llvm_ty;
   2809                 }
   2810 
   2811                 comptime assert(optional_layout_version == 3);
   2812                 var fields_buf: [3]*llvm.Type = .{
   2813                     payload_llvm_ty, dg.context.intType(8), undefined,
   2814                 };
   2815                 const offset = child_ty.abiSize(target) + 1;
   2816                 const abi_size = t.abiSize(target);
   2817                 const padding = @intCast(c_uint, abi_size - offset);
   2818                 if (padding == 0) {
   2819                     return dg.context.structType(&fields_buf, 2, .False);
   2820                 }
   2821                 fields_buf[2] = dg.context.intType(8).arrayType(padding);
   2822                 return dg.context.structType(&fields_buf, 3, .False);
   2823             },
   2824             .ErrorUnion => {
   2825                 const payload_ty = t.errorUnionPayload();
   2826                 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
   2827                     return try dg.lowerType(Type.anyerror);
   2828                 }
   2829                 const llvm_error_type = try dg.lowerType(Type.anyerror);
   2830                 const llvm_payload_type = try dg.lowerType(payload_ty);
   2831 
   2832                 const payload_align = payload_ty.abiAlignment(target);
   2833                 const error_align = Type.anyerror.abiAlignment(target);
   2834 
   2835                 const payload_size = payload_ty.abiSize(target);
   2836                 const error_size = Type.anyerror.abiSize(target);
   2837 
   2838                 var fields_buf: [3]*llvm.Type = undefined;
   2839                 if (error_align > payload_align) {
   2840                     fields_buf[0] = llvm_error_type;
   2841                     fields_buf[1] = llvm_payload_type;
   2842                     const payload_end =
   2843                         std.mem.alignForwardGeneric(u64, error_size, payload_align) +
   2844                         payload_size;
   2845                     const abi_size = std.mem.alignForwardGeneric(u64, payload_end, error_align);
   2846                     const padding = @intCast(c_uint, abi_size - payload_end);
   2847                     if (padding == 0) {
   2848                         return dg.context.structType(&fields_buf, 2, .False);
   2849                     }
   2850                     fields_buf[2] = dg.context.intType(8).arrayType(padding);
   2851                     return dg.context.structType(&fields_buf, 3, .False);
   2852                 } else {
   2853                     fields_buf[0] = llvm_payload_type;
   2854                     fields_buf[1] = llvm_error_type;
   2855                     const error_end =
   2856                         std.mem.alignForwardGeneric(u64, payload_size, error_align) +
   2857                         error_size;
   2858                     const abi_size = std.mem.alignForwardGeneric(u64, error_end, payload_align);
   2859                     const padding = @intCast(c_uint, abi_size - error_end);
   2860                     if (padding == 0) {
   2861                         return dg.context.structType(&fields_buf, 2, .False);
   2862                     }
   2863                     fields_buf[2] = dg.context.intType(8).arrayType(padding);
   2864                     return dg.context.structType(&fields_buf, 3, .False);
   2865                 }
   2866             },
   2867             .ErrorSet => return dg.context.intType(16),
   2868             .Struct => {
   2869                 const gop = try dg.object.type_map.getOrPutContext(gpa, t, .{ .mod = dg.module });
   2870                 if (gop.found_existing) return gop.value_ptr.*;
   2871 
   2872                 // The Type memory is ephemeral; since we want to store a longer-lived
   2873                 // reference, we need to copy it here.
   2874                 gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator());
   2875 
   2876                 if (t.isTupleOrAnonStruct()) {
   2877                     const tuple = t.tupleFields();
   2878                     const llvm_struct_ty = dg.context.structCreateNamed("");
   2879                     gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls
   2880 
   2881                     var llvm_field_types: std.ArrayListUnmanaged(*llvm.Type) = .{};
   2882                     defer llvm_field_types.deinit(gpa);
   2883 
   2884                     try llvm_field_types.ensureUnusedCapacity(gpa, tuple.types.len);
   2885 
   2886                     comptime assert(struct_layout_version == 2);
   2887                     var offset: u64 = 0;
   2888                     var big_align: u32 = 0;
   2889 
   2890                     for (tuple.types) |field_ty, i| {
   2891                         const field_val = tuple.values[i];
   2892                         if (field_val.tag() != .unreachable_value) continue;
   2893 
   2894                         const field_align = field_ty.abiAlignment(target);
   2895                         big_align = @max(big_align, field_align);
   2896                         const prev_offset = offset;
   2897                         offset = std.mem.alignForwardGeneric(u64, offset, field_align);
   2898 
   2899                         const padding_len = offset - prev_offset;
   2900                         if (padding_len > 0) {
   2901                             const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
   2902                             try llvm_field_types.append(gpa, llvm_array_ty);
   2903                         }
   2904                         const field_llvm_ty = try dg.lowerType(field_ty);
   2905                         try llvm_field_types.append(gpa, field_llvm_ty);
   2906 
   2907                         offset += field_ty.abiSize(target);
   2908                     }
   2909                     {
   2910                         const prev_offset = offset;
   2911                         offset = std.mem.alignForwardGeneric(u64, offset, big_align);
   2912                         const padding_len = offset - prev_offset;
   2913                         if (padding_len > 0) {
   2914                             const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
   2915                             try llvm_field_types.append(gpa, llvm_array_ty);
   2916                         }
   2917                     }
   2918 
   2919                     llvm_struct_ty.structSetBody(
   2920                         llvm_field_types.items.ptr,
   2921                         @intCast(c_uint, llvm_field_types.items.len),
   2922                         .False,
   2923                     );
   2924 
   2925                     return llvm_struct_ty;
   2926                 }
   2927 
   2928                 const struct_obj = t.castTag(.@"struct").?.data;
   2929 
   2930                 if (struct_obj.layout == .Packed) {
   2931                     const int_llvm_ty = try dg.lowerType(struct_obj.backing_int_ty);
   2932                     gop.value_ptr.* = int_llvm_ty;
   2933                     return int_llvm_ty;
   2934                 }
   2935 
   2936                 const name = try struct_obj.getFullyQualifiedName(dg.module);
   2937                 defer gpa.free(name);
   2938 
   2939                 const llvm_struct_ty = dg.context.structCreateNamed(name);
   2940                 gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls
   2941 
   2942                 assert(struct_obj.haveFieldTypes());
   2943 
   2944                 var llvm_field_types: std.ArrayListUnmanaged(*llvm.Type) = .{};
   2945                 defer llvm_field_types.deinit(gpa);
   2946 
   2947                 try llvm_field_types.ensureUnusedCapacity(gpa, struct_obj.fields.count());
   2948 
   2949                 comptime assert(struct_layout_version == 2);
   2950                 var offset: u64 = 0;
   2951                 var big_align: u32 = 0;
   2952                 var any_underaligned_fields = false;
   2953 
   2954                 for (struct_obj.fields.values()) |field| {
   2955                     if (field.is_comptime or !field.ty.hasRuntimeBits()) continue;
   2956 
   2957                     const field_align = field.alignment(target, struct_obj.layout);
   2958                     const field_ty_align = field.ty.abiAlignment(target);
   2959                     any_underaligned_fields = any_underaligned_fields or
   2960                         field_align < field_ty_align;
   2961                     big_align = @max(big_align, field_align);
   2962                     const prev_offset = offset;
   2963                     offset = std.mem.alignForwardGeneric(u64, offset, field_align);
   2964 
   2965                     const padding_len = offset - prev_offset;
   2966                     if (padding_len > 0) {
   2967                         const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
   2968                         try llvm_field_types.append(gpa, llvm_array_ty);
   2969                     }
   2970                     const field_llvm_ty = try dg.lowerType(field.ty);
   2971                     try llvm_field_types.append(gpa, field_llvm_ty);
   2972 
   2973                     offset += field.ty.abiSize(target);
   2974                 }
   2975                 {
   2976                     const prev_offset = offset;
   2977                     offset = std.mem.alignForwardGeneric(u64, offset, big_align);
   2978                     const padding_len = offset - prev_offset;
   2979                     if (padding_len > 0) {
   2980                         const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
   2981                         try llvm_field_types.append(gpa, llvm_array_ty);
   2982                     }
   2983                 }
   2984 
   2985                 llvm_struct_ty.structSetBody(
   2986                     llvm_field_types.items.ptr,
   2987                     @intCast(c_uint, llvm_field_types.items.len),
   2988                     llvm.Bool.fromBool(any_underaligned_fields),
   2989                 );
   2990 
   2991                 return llvm_struct_ty;
   2992             },
   2993             .Union => {
   2994                 const gop = try dg.object.type_map.getOrPutContext(gpa, t, .{ .mod = dg.module });
   2995                 if (gop.found_existing) return gop.value_ptr.*;
   2996 
   2997                 // The Type memory is ephemeral; since we want to store a longer-lived
   2998                 // reference, we need to copy it here.
   2999                 gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator());
   3000 
   3001                 const layout = t.unionGetLayout(target);
   3002                 const union_obj = t.cast(Type.Payload.Union).?.data;
   3003 
   3004                 if (layout.payload_size == 0) {
   3005                     const enum_tag_llvm_ty = try dg.lowerType(union_obj.tag_ty);
   3006                     gop.value_ptr.* = enum_tag_llvm_ty;
   3007                     return enum_tag_llvm_ty;
   3008                 }
   3009 
   3010                 const name = try union_obj.getFullyQualifiedName(dg.module);
   3011                 defer gpa.free(name);
   3012 
   3013                 const llvm_union_ty = dg.context.structCreateNamed(name);
   3014                 gop.value_ptr.* = llvm_union_ty; // must be done before any recursive calls
   3015 
   3016                 const aligned_field = union_obj.fields.values()[layout.most_aligned_field];
   3017                 const llvm_aligned_field_ty = try dg.lowerType(aligned_field.ty);
   3018 
   3019                 const llvm_payload_ty = t: {
   3020                     if (layout.most_aligned_field_size == layout.payload_size) {
   3021                         break :t llvm_aligned_field_ty;
   3022                     }
   3023                     const padding_len = if (layout.tag_size == 0)
   3024                         @intCast(c_uint, layout.abi_size - layout.most_aligned_field_size)
   3025                     else
   3026                         @intCast(c_uint, layout.payload_size - layout.most_aligned_field_size);
   3027                     const fields: [2]*llvm.Type = .{
   3028                         llvm_aligned_field_ty,
   3029                         dg.context.intType(8).arrayType(padding_len),
   3030                     };
   3031                     break :t dg.context.structType(&fields, fields.len, .True);
   3032                 };
   3033 
   3034                 if (layout.tag_size == 0) {
   3035                     var llvm_fields: [1]*llvm.Type = .{llvm_payload_ty};
   3036                     llvm_union_ty.structSetBody(&llvm_fields, llvm_fields.len, .False);
   3037                     return llvm_union_ty;
   3038                 }
   3039                 const enum_tag_llvm_ty = try dg.lowerType(union_obj.tag_ty);
   3040 
   3041                 // Put the tag before or after the payload depending on which one's
   3042                 // alignment is greater.
   3043                 var llvm_fields: [3]*llvm.Type = undefined;
   3044                 var llvm_fields_len: c_uint = 2;
   3045 
   3046                 if (layout.tag_align >= layout.payload_align) {
   3047                     llvm_fields = .{ enum_tag_llvm_ty, llvm_payload_ty, undefined };
   3048                 } else {
   3049                     llvm_fields = .{ llvm_payload_ty, enum_tag_llvm_ty, undefined };
   3050                 }
   3051 
   3052                 // Insert padding to make the LLVM struct ABI size match the Zig union ABI size.
   3053                 if (layout.padding != 0) {
   3054                     llvm_fields[2] = dg.context.intType(8).arrayType(layout.padding);
   3055                     llvm_fields_len = 3;
   3056                 }
   3057 
   3058                 llvm_union_ty.structSetBody(&llvm_fields, llvm_fields_len, .False);
   3059                 return llvm_union_ty;
   3060             },
   3061             .Fn => return lowerTypeFn(dg, t),
   3062             .ComptimeInt => unreachable,
   3063             .ComptimeFloat => unreachable,
   3064             .Type => unreachable,
   3065             .Undefined => unreachable,
   3066             .Null => unreachable,
   3067             .EnumLiteral => unreachable,
   3068 
   3069             .BoundFn => @panic("TODO remove BoundFn from the language"),
   3070 
   3071             .Frame => @panic("TODO implement llvmType for Frame types"),
   3072             .AnyFrame => @panic("TODO implement llvmType for AnyFrame types"),
   3073         }
   3074     }
   3075 
   3076     fn lowerTypeFn(dg: *DeclGen, fn_ty: Type) Allocator.Error!*llvm.Type {
   3077         const target = dg.module.getTarget();
   3078         const fn_info = fn_ty.fnInfo();
   3079         const llvm_ret_ty = try lowerFnRetTy(dg, fn_info);
   3080 
   3081         var llvm_params = std.ArrayList(*llvm.Type).init(dg.gpa);
   3082         defer llvm_params.deinit();
   3083 
   3084         if (firstParamSRet(fn_info, target)) {
   3085             const llvm_sret_ty = try dg.lowerType(fn_info.return_type);
   3086             try llvm_params.append(llvm_sret_ty.pointerType(0));
   3087         }
   3088 
   3089         if (fn_info.return_type.isError() and
   3090             dg.module.comp.bin_file.options.error_return_tracing)
   3091         {
   3092             var ptr_ty_payload: Type.Payload.ElemType = .{
   3093                 .base = .{ .tag = .single_mut_pointer },
   3094                 .data = dg.object.getStackTraceType(),
   3095             };
   3096             const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
   3097             try llvm_params.append(try dg.lowerType(ptr_ty));
   3098         }
   3099 
   3100         var it = iterateParamTypes(dg, fn_info);
   3101         while (it.next()) |lowering| switch (lowering) {
   3102             .no_bits => continue,
   3103             .byval => {
   3104                 const param_ty = fn_info.param_types[it.zig_index - 1];
   3105                 try llvm_params.append(try dg.lowerType(param_ty));
   3106             },
   3107             .byref => {
   3108                 const param_ty = fn_info.param_types[it.zig_index - 1];
   3109                 const raw_llvm_ty = try dg.lowerType(param_ty);
   3110                 try llvm_params.append(raw_llvm_ty.pointerType(0));
   3111             },
   3112             .abi_sized_int => {
   3113                 const param_ty = fn_info.param_types[it.zig_index - 1];
   3114                 const abi_size = @intCast(c_uint, param_ty.abiSize(target));
   3115                 try llvm_params.append(dg.context.intType(abi_size * 8));
   3116             },
   3117             .slice => {
   3118                 const param_ty = fn_info.param_types[it.zig_index - 1];
   3119                 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
   3120                 const ptr_ty = param_ty.slicePtrFieldType(&buf);
   3121                 const ptr_llvm_ty = try dg.lowerType(ptr_ty);
   3122                 const len_llvm_ty = try dg.lowerType(Type.usize);
   3123 
   3124                 try llvm_params.ensureUnusedCapacity(2);
   3125                 llvm_params.appendAssumeCapacity(ptr_llvm_ty);
   3126                 llvm_params.appendAssumeCapacity(len_llvm_ty);
   3127             },
   3128             .multiple_llvm_ints => {
   3129                 const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len];
   3130                 try llvm_params.ensureUnusedCapacity(it.llvm_types_len);
   3131                 for (llvm_ints) |int_bits| {
   3132                     const big_int_ty = dg.context.intType(int_bits);
   3133                     llvm_params.appendAssumeCapacity(big_int_ty);
   3134                 }
   3135             },
   3136             .multiple_llvm_float => {
   3137                 const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len];
   3138                 try llvm_params.ensureUnusedCapacity(it.llvm_types_len);
   3139                 for (llvm_ints) |float_bits| {
   3140                     const float_ty = switch (float_bits) {
   3141                         64 => dg.context.doubleType(),
   3142                         80 => dg.context.x86FP80Type(),
   3143                         else => unreachable,
   3144                     };
   3145                     llvm_params.appendAssumeCapacity(float_ty);
   3146                 }
   3147             },
   3148             .as_u16 => {
   3149                 try llvm_params.append(dg.context.intType(16));
   3150             },
   3151             .float_array => |count| {
   3152                 const param_ty = fn_info.param_types[it.zig_index - 1];
   3153                 const float_ty = try dg.lowerType(aarch64_c_abi.getFloatArrayType(param_ty).?);
   3154                 const field_count = @intCast(c_uint, count);
   3155                 const arr_ty = float_ty.arrayType(field_count);
   3156                 try llvm_params.append(arr_ty);
   3157             },
   3158             .i32_array, .i64_array => |arr_len| {
   3159                 const elem_size: u8 = if (lowering == .i32_array) 32 else 64;
   3160                 const arr_ty = dg.context.intType(elem_size).arrayType(arr_len);
   3161                 try llvm_params.append(arr_ty);
   3162             },
   3163         };
   3164 
   3165         return llvm.functionType(
   3166             llvm_ret_ty,
   3167             llvm_params.items.ptr,
   3168             @intCast(c_uint, llvm_params.items.len),
   3169             llvm.Bool.fromBool(fn_info.is_var_args),
   3170         );
   3171     }
   3172 
   3173     /// Use this instead of lowerType when you want to handle correctly the case of elem_ty
   3174     /// being a zero bit type, but it should still be lowered as an i8 in such case.
   3175     /// There are other similar cases handled here as well.
   3176     fn lowerPtrElemTy(dg: *DeclGen, elem_ty: Type) Allocator.Error!*llvm.Type {
   3177         const lower_elem_ty = switch (elem_ty.zigTypeTag()) {
   3178             .Opaque, .Fn => true,
   3179             .Array => elem_ty.childType().hasRuntimeBitsIgnoreComptime(),
   3180             else => elem_ty.hasRuntimeBitsIgnoreComptime(),
   3181         };
   3182         const llvm_elem_ty = if (lower_elem_ty)
   3183             try dg.lowerType(elem_ty)
   3184         else
   3185             dg.context.intType(8);
   3186 
   3187         return llvm_elem_ty;
   3188     }
   3189 
   3190     fn lowerValue(dg: *DeclGen, tv: TypedValue) Error!*llvm.Value {
   3191         if (tv.val.isUndef()) {
   3192             const llvm_type = try dg.lowerType(tv.ty);
   3193             return llvm_type.getUndef();
   3194         }
   3195         const target = dg.module.getTarget();
   3196 
   3197         switch (tv.ty.zigTypeTag()) {
   3198             .Bool => {
   3199                 const llvm_type = try dg.lowerType(tv.ty);
   3200                 return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull();
   3201             },
   3202             // TODO this duplicates code with Pointer but they should share the handling
   3203             // of the tv.val.tag() and then Int should do extra constPtrToInt on top
   3204             .Int => switch (tv.val.tag()) {
   3205                 .decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl_index),
   3206                 .decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data),
   3207                 else => {
   3208                     var bigint_space: Value.BigIntSpace = undefined;
   3209                     const bigint = tv.val.toBigInt(&bigint_space, target);
   3210                     const int_info = tv.ty.intInfo(target);
   3211                     assert(int_info.bits != 0);
   3212                     const llvm_type = dg.context.intType(int_info.bits);
   3213 
   3214                     const unsigned_val = v: {
   3215                         if (bigint.limbs.len == 1) {
   3216                             break :v llvm_type.constInt(bigint.limbs[0], .False);
   3217                         }
   3218                         if (@sizeOf(usize) == @sizeOf(u64)) {
   3219                             break :v llvm_type.constIntOfArbitraryPrecision(
   3220                                 @intCast(c_uint, bigint.limbs.len),
   3221                                 bigint.limbs.ptr,
   3222                             );
   3223                         }
   3224                         @panic("TODO implement bigint to llvm int for 32-bit compiler builds");
   3225                     };
   3226                     if (!bigint.positive) {
   3227                         return llvm.constNeg(unsigned_val);
   3228                     }
   3229                     return unsigned_val;
   3230                 },
   3231             },
   3232             .Enum => {
   3233                 var int_buffer: Value.Payload.U64 = undefined;
   3234                 const int_val = tv.enumToInt(&int_buffer);
   3235 
   3236                 var bigint_space: Value.BigIntSpace = undefined;
   3237                 const bigint = int_val.toBigInt(&bigint_space, target);
   3238 
   3239                 const int_info = tv.ty.intInfo(target);
   3240                 const llvm_type = dg.context.intType(int_info.bits);
   3241 
   3242                 const unsigned_val = v: {
   3243                     if (bigint.limbs.len == 1) {
   3244                         break :v llvm_type.constInt(bigint.limbs[0], .False);
   3245                     }
   3246                     if (@sizeOf(usize) == @sizeOf(u64)) {
   3247                         break :v llvm_type.constIntOfArbitraryPrecision(
   3248                             @intCast(c_uint, bigint.limbs.len),
   3249                             bigint.limbs.ptr,
   3250                         );
   3251                     }
   3252                     @panic("TODO implement bigint to llvm int for 32-bit compiler builds");
   3253                 };
   3254                 if (!bigint.positive) {
   3255                     return llvm.constNeg(unsigned_val);
   3256                 }
   3257                 return unsigned_val;
   3258             },
   3259             .Float => {
   3260                 const llvm_ty = try dg.lowerType(tv.ty);
   3261                 switch (tv.ty.floatBits(target)) {
   3262                     16 => if (intrinsicsAllowed(tv.ty, target)) {
   3263                         return llvm_ty.constReal(tv.val.toFloat(f16));
   3264                     } else {
   3265                         const repr = @bitCast(u16, tv.val.toFloat(f16));
   3266                         const llvm_i16 = dg.context.intType(16);
   3267                         const int = llvm_i16.constInt(repr, .False);
   3268                         return int.constBitCast(llvm_ty);
   3269                     },
   3270                     32, 64 => return llvm_ty.constReal(tv.val.toFloat(f64)),
   3271                     80 => {
   3272                         const float = tv.val.toFloat(f80);
   3273                         const repr = std.math.break_f80(float);
   3274                         const llvm_i80 = dg.context.intType(80);
   3275                         var x = llvm_i80.constInt(repr.exp, .False);
   3276                         x = x.constShl(llvm_i80.constInt(64, .False));
   3277                         x = x.constOr(llvm_i80.constInt(repr.fraction, .False));
   3278                         if (backendSupportsF80(target)) {
   3279                             return x.constBitCast(llvm_ty);
   3280                         } else {
   3281                             return x;
   3282                         }
   3283                     },
   3284                     128 => {
   3285                         var buf: [2]u64 = @bitCast([2]u64, tv.val.toFloat(f128));
   3286                         // LLVM seems to require that the lower half of the f128 be placed first
   3287                         // in the buffer.
   3288                         if (native_endian == .Big) {
   3289                             std.mem.swap(u64, &buf[0], &buf[1]);
   3290                         }
   3291                         const int = dg.context.intType(128).constIntOfArbitraryPrecision(buf.len, &buf);
   3292                         return int.constBitCast(llvm_ty);
   3293                     },
   3294                     else => unreachable,
   3295                 }
   3296             },
   3297             .Pointer => switch (tv.val.tag()) {
   3298                 .decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl_index),
   3299                 .decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data),
   3300                 .variable => {
   3301                     const decl_index = tv.val.castTag(.variable).?.data.owner_decl;
   3302                     const decl = dg.module.declPtr(decl_index);
   3303                     dg.module.markDeclAlive(decl);
   3304 
   3305                     const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);
   3306                     const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);
   3307 
   3308                     const llvm_var_type = try dg.lowerType(tv.ty);
   3309                     const llvm_actual_ptr_type = llvm_var_type.pointerType(llvm_actual_addrspace);
   3310 
   3311                     const val = try dg.resolveGlobalDecl(decl_index);
   3312                     const val_ptr = val.constBitCast(llvm_actual_ptr_type);
   3313                     if (llvm_actual_addrspace != llvm_wanted_addrspace) {
   3314                         const llvm_wanted_ptr_type = llvm_var_type.pointerType(llvm_wanted_addrspace);
   3315                         return val_ptr.constAddrSpaceCast(llvm_wanted_ptr_type);
   3316                     }
   3317                     return val_ptr;
   3318                 },
   3319                 .slice => {
   3320                     const slice = tv.val.castTag(.slice).?.data;
   3321                     var buf: Type.SlicePtrFieldTypeBuffer = undefined;
   3322                     const fields: [2]*llvm.Value = .{
   3323                         try dg.lowerValue(.{
   3324                             .ty = tv.ty.slicePtrFieldType(&buf),
   3325                             .val = slice.ptr,
   3326                         }),
   3327                         try dg.lowerValue(.{
   3328                             .ty = Type.usize,
   3329                             .val = slice.len,
   3330                         }),
   3331                     };
   3332                     return dg.context.constStruct(&fields, fields.len, .False);
   3333                 },
   3334                 .int_u64, .one, .int_big_positive => {
   3335                     const llvm_usize = try dg.lowerType(Type.usize);
   3336                     const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(target), .False);
   3337                     return llvm_int.constIntToPtr(try dg.lowerType(tv.ty));
   3338                 },
   3339                 .field_ptr, .opt_payload_ptr, .eu_payload_ptr, .elem_ptr => {
   3340                     return dg.lowerParentPtr(tv.val, tv.ty.childType());
   3341                 },
   3342                 .null_value, .zero => {
   3343                     const llvm_type = try dg.lowerType(tv.ty);
   3344                     return llvm_type.constNull();
   3345                 },
   3346                 else => |tag| return dg.todo("implement const of pointer type '{}' ({})", .{
   3347                     tv.ty.fmtDebug(), tag,
   3348                 }),
   3349             },
   3350             .Array => switch (tv.val.tag()) {
   3351                 .bytes => {
   3352                     const bytes = tv.val.castTag(.bytes).?.data;
   3353                     return dg.context.constString(
   3354                         bytes.ptr,
   3355                         @intCast(c_uint, tv.ty.arrayLenIncludingSentinel()),
   3356                         .True, // Don't null terminate. Bytes has the sentinel, if any.
   3357                     );
   3358                 },
   3359                 .str_lit => {
   3360                     const str_lit = tv.val.castTag(.str_lit).?.data;
   3361                     const bytes = dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len];
   3362                     if (tv.ty.sentinel()) |sent_val| {
   3363                         const byte = @intCast(u8, sent_val.toUnsignedInt(target));
   3364                         if (byte == 0 and bytes.len > 0) {
   3365                             return dg.context.constString(
   3366                                 bytes.ptr,
   3367                                 @intCast(c_uint, bytes.len),
   3368                                 .False, // Yes, null terminate.
   3369                             );
   3370                         }
   3371                         var array = std.ArrayList(u8).init(dg.gpa);
   3372                         defer array.deinit();
   3373                         try array.ensureUnusedCapacity(bytes.len + 1);
   3374                         array.appendSliceAssumeCapacity(bytes);
   3375                         array.appendAssumeCapacity(byte);
   3376                         return dg.context.constString(
   3377                             array.items.ptr,
   3378                             @intCast(c_uint, array.items.len),
   3379                             .True, // Don't null terminate.
   3380                         );
   3381                     } else {
   3382                         return dg.context.constString(
   3383                             bytes.ptr,
   3384                             @intCast(c_uint, bytes.len),
   3385                             .True, // Don't null terminate. `bytes` has the sentinel, if any.
   3386                         );
   3387                     }
   3388                 },
   3389                 .aggregate => {
   3390                     const elem_vals = tv.val.castTag(.aggregate).?.data;
   3391                     const elem_ty = tv.ty.elemType();
   3392                     const gpa = dg.gpa;
   3393                     const len = @intCast(usize, tv.ty.arrayLenIncludingSentinel());
   3394                     const llvm_elems = try gpa.alloc(*llvm.Value, len);
   3395                     defer gpa.free(llvm_elems);
   3396                     var need_unnamed = false;
   3397                     for (elem_vals[0..len]) |elem_val, i| {
   3398                         llvm_elems[i] = try dg.lowerValue(.{ .ty = elem_ty, .val = elem_val });
   3399                         need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[i]);
   3400                     }
   3401                     if (need_unnamed) {
   3402                         return dg.context.constStruct(
   3403                             llvm_elems.ptr,
   3404                             @intCast(c_uint, llvm_elems.len),
   3405                             .True,
   3406                         );
   3407                     } else {
   3408                         const llvm_elem_ty = try dg.lowerType(elem_ty);
   3409                         return llvm_elem_ty.constArray(
   3410                             llvm_elems.ptr,
   3411                             @intCast(c_uint, llvm_elems.len),
   3412                         );
   3413                     }
   3414                 },
   3415                 .repeated => {
   3416                     const val = tv.val.castTag(.repeated).?.data;
   3417                     const elem_ty = tv.ty.elemType();
   3418                     const sentinel = tv.ty.sentinel();
   3419                     const len = @intCast(usize, tv.ty.arrayLen());
   3420                     const len_including_sent = len + @boolToInt(sentinel != null);
   3421                     const gpa = dg.gpa;
   3422                     const llvm_elems = try gpa.alloc(*llvm.Value, len_including_sent);
   3423                     defer gpa.free(llvm_elems);
   3424 
   3425                     var need_unnamed = false;
   3426                     if (len != 0) {
   3427                         for (llvm_elems[0..len]) |*elem| {
   3428                             elem.* = try dg.lowerValue(.{ .ty = elem_ty, .val = val });
   3429                         }
   3430                         need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[0]);
   3431                     }
   3432 
   3433                     if (sentinel) |sent| {
   3434                         llvm_elems[len] = try dg.lowerValue(.{ .ty = elem_ty, .val = sent });
   3435                         need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[len]);
   3436                     }
   3437 
   3438                     if (need_unnamed) {
   3439                         return dg.context.constStruct(
   3440                             llvm_elems.ptr,
   3441                             @intCast(c_uint, llvm_elems.len),
   3442                             .True,
   3443                         );
   3444                     } else {
   3445                         const llvm_elem_ty = try dg.lowerType(elem_ty);
   3446                         return llvm_elem_ty.constArray(
   3447                             llvm_elems.ptr,
   3448                             @intCast(c_uint, llvm_elems.len),
   3449                         );
   3450                     }
   3451                 },
   3452                 .empty_array_sentinel => {
   3453                     const elem_ty = tv.ty.elemType();
   3454                     const sent_val = tv.ty.sentinel().?;
   3455                     const sentinel = try dg.lowerValue(.{ .ty = elem_ty, .val = sent_val });
   3456                     const llvm_elems: [1]*llvm.Value = .{sentinel};
   3457                     const need_unnamed = dg.isUnnamedType(elem_ty, llvm_elems[0]);
   3458                     if (need_unnamed) {
   3459                         return dg.context.constStruct(&llvm_elems, llvm_elems.len, .True);
   3460                     } else {
   3461                         const llvm_elem_ty = try dg.lowerType(elem_ty);
   3462                         return llvm_elem_ty.constArray(&llvm_elems, llvm_elems.len);
   3463                     }
   3464                 },
   3465                 else => unreachable,
   3466             },
   3467             .Optional => {
   3468                 comptime assert(optional_layout_version == 3);
   3469                 var buf: Type.Payload.ElemType = undefined;
   3470                 const payload_ty = tv.ty.optionalChild(&buf);
   3471 
   3472                 const llvm_i8 = dg.context.intType(8);
   3473                 const is_pl = !tv.val.isNull();
   3474                 const non_null_bit = if (is_pl) llvm_i8.constInt(1, .False) else llvm_i8.constNull();
   3475                 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
   3476                     return non_null_bit;
   3477                 }
   3478                 const llvm_ty = try dg.lowerType(tv.ty);
   3479                 if (tv.ty.optionalReprIsPayload()) {
   3480                     if (tv.val.castTag(.opt_payload)) |payload| {
   3481                         return dg.lowerValue(.{ .ty = payload_ty, .val = payload.data });
   3482                     } else if (is_pl) {
   3483                         return dg.lowerValue(.{ .ty = payload_ty, .val = tv.val });
   3484                     } else {
   3485                         return llvm_ty.constNull();
   3486                     }
   3487                 }
   3488                 assert(payload_ty.zigTypeTag() != .Fn);
   3489 
   3490                 const llvm_field_count = llvm_ty.countStructElementTypes();
   3491                 var fields_buf: [3]*llvm.Value = undefined;
   3492                 fields_buf[0] = try dg.lowerValue(.{
   3493                     .ty = payload_ty,
   3494                     .val = if (tv.val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef),
   3495                 });
   3496                 fields_buf[1] = non_null_bit;
   3497                 if (llvm_field_count > 2) {
   3498                     assert(llvm_field_count == 3);
   3499                     fields_buf[2] = llvm_ty.structGetTypeAtIndex(2).getUndef();
   3500                 }
   3501                 return dg.context.constStruct(&fields_buf, llvm_field_count, .False);
   3502             },
   3503             .Fn => {
   3504                 const fn_decl_index = switch (tv.val.tag()) {
   3505                     .extern_fn => tv.val.castTag(.extern_fn).?.data.owner_decl,
   3506                     .function => tv.val.castTag(.function).?.data.owner_decl,
   3507                     else => unreachable,
   3508                 };
   3509                 const fn_decl = dg.module.declPtr(fn_decl_index);
   3510                 dg.module.markDeclAlive(fn_decl);
   3511                 return dg.resolveLlvmFunction(fn_decl_index);
   3512             },
   3513             .ErrorSet => {
   3514                 const llvm_ty = try dg.lowerType(Type.anyerror);
   3515                 switch (tv.val.tag()) {
   3516                     .@"error" => {
   3517                         const err_name = tv.val.castTag(.@"error").?.data.name;
   3518                         const kv = try dg.module.getErrorValue(err_name);
   3519                         return llvm_ty.constInt(kv.value, .False);
   3520                     },
   3521                     else => {
   3522                         // In this case we are rendering an error union which has a 0 bits payload.
   3523                         return llvm_ty.constNull();
   3524                     },
   3525                 }
   3526             },
   3527             .ErrorUnion => {
   3528                 const payload_type = tv.ty.errorUnionPayload();
   3529                 const is_pl = tv.val.errorUnionIsPayload();
   3530 
   3531                 if (!payload_type.hasRuntimeBitsIgnoreComptime()) {
   3532                     // We use the error type directly as the type.
   3533                     const err_val = if (!is_pl) tv.val else Value.initTag(.zero);
   3534                     return dg.lowerValue(.{ .ty = Type.anyerror, .val = err_val });
   3535                 }
   3536 
   3537                 const payload_align = payload_type.abiAlignment(target);
   3538                 const error_align = Type.anyerror.abiAlignment(target);
   3539                 const llvm_error_value = try dg.lowerValue(.{
   3540                     .ty = Type.anyerror,
   3541                     .val = if (is_pl) Value.initTag(.zero) else tv.val,
   3542                 });
   3543                 const llvm_payload_value = try dg.lowerValue(.{
   3544                     .ty = payload_type,
   3545                     .val = if (tv.val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef),
   3546                 });
   3547                 var fields_buf: [3]*llvm.Value = undefined;
   3548 
   3549                 const llvm_ty = try dg.lowerType(tv.ty);
   3550                 const llvm_field_count = llvm_ty.countStructElementTypes();
   3551                 if (llvm_field_count > 2) {
   3552                     assert(llvm_field_count == 3);
   3553                     fields_buf[2] = llvm_ty.structGetTypeAtIndex(2).getUndef();
   3554                 }
   3555 
   3556                 if (error_align > payload_align) {
   3557                     fields_buf[0] = llvm_error_value;
   3558                     fields_buf[1] = llvm_payload_value;
   3559                     return dg.context.constStruct(&fields_buf, llvm_field_count, .False);
   3560                 } else {
   3561                     fields_buf[0] = llvm_payload_value;
   3562                     fields_buf[1] = llvm_error_value;
   3563                     return dg.context.constStruct(&fields_buf, llvm_field_count, .False);
   3564                 }
   3565             },
   3566             .Struct => {
   3567                 const llvm_struct_ty = try dg.lowerType(tv.ty);
   3568                 const field_vals = tv.val.castTag(.aggregate).?.data;
   3569                 const gpa = dg.gpa;
   3570 
   3571                 if (tv.ty.isTupleOrAnonStruct()) {
   3572                     const tuple = tv.ty.tupleFields();
   3573                     var llvm_fields: std.ArrayListUnmanaged(*llvm.Value) = .{};
   3574                     defer llvm_fields.deinit(gpa);
   3575 
   3576                     try llvm_fields.ensureUnusedCapacity(gpa, tuple.types.len);
   3577 
   3578                     comptime assert(struct_layout_version == 2);
   3579                     var offset: u64 = 0;
   3580                     var big_align: u32 = 0;
   3581                     var need_unnamed = false;
   3582 
   3583                     for (tuple.types) |field_ty, i| {
   3584                         if (tuple.values[i].tag() != .unreachable_value) continue;
   3585                         if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
   3586 
   3587                         const field_align = field_ty.abiAlignment(target);
   3588                         big_align = @max(big_align, field_align);
   3589                         const prev_offset = offset;
   3590                         offset = std.mem.alignForwardGeneric(u64, offset, field_align);
   3591 
   3592                         const padding_len = offset - prev_offset;
   3593                         if (padding_len > 0) {
   3594                             const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
   3595                             // TODO make this and all other padding elsewhere in debug
   3596                             // builds be 0xaa not undef.
   3597                             llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef());
   3598                         }
   3599 
   3600                         const field_llvm_val = try dg.lowerValue(.{
   3601                             .ty = field_ty,
   3602                             .val = field_vals[i],
   3603                         });
   3604 
   3605                         need_unnamed = need_unnamed or dg.isUnnamedType(field_ty, field_llvm_val);
   3606 
   3607                         llvm_fields.appendAssumeCapacity(field_llvm_val);
   3608 
   3609                         offset += field_ty.abiSize(target);
   3610                     }
   3611                     {
   3612                         const prev_offset = offset;
   3613                         offset = std.mem.alignForwardGeneric(u64, offset, big_align);
   3614                         const padding_len = offset - prev_offset;
   3615                         if (padding_len > 0) {
   3616                             const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
   3617                             llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef());
   3618                         }
   3619                     }
   3620 
   3621                     if (need_unnamed) {
   3622                         return dg.context.constStruct(
   3623                             llvm_fields.items.ptr,
   3624                             @intCast(c_uint, llvm_fields.items.len),
   3625                             .False,
   3626                         );
   3627                     } else {
   3628                         return llvm_struct_ty.constNamedStruct(
   3629                             llvm_fields.items.ptr,
   3630                             @intCast(c_uint, llvm_fields.items.len),
   3631                         );
   3632                     }
   3633                 }
   3634 
   3635                 const struct_obj = tv.ty.castTag(.@"struct").?.data;
   3636 
   3637                 if (struct_obj.layout == .Packed) {
   3638                     const big_bits = struct_obj.backing_int_ty.bitSize(target);
   3639                     const int_llvm_ty = dg.context.intType(@intCast(c_uint, big_bits));
   3640                     const fields = struct_obj.fields.values();
   3641                     comptime assert(Type.packed_struct_layout_version == 2);
   3642                     var running_int: *llvm.Value = int_llvm_ty.constNull();
   3643                     var running_bits: u16 = 0;
   3644                     for (field_vals) |field_val, i| {
   3645                         const field = fields[i];
   3646                         if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue;
   3647 
   3648                         const non_int_val = try dg.lowerValue(.{
   3649                             .ty = field.ty,
   3650                             .val = field_val,
   3651                         });
   3652                         const ty_bit_size = @intCast(u16, field.ty.bitSize(target));
   3653                         const small_int_ty = dg.context.intType(ty_bit_size);
   3654                         const small_int_val = if (field.ty.isPtrAtRuntime())
   3655                             non_int_val.constPtrToInt(small_int_ty)
   3656                         else
   3657                             non_int_val.constBitCast(small_int_ty);
   3658                         const shift_rhs = int_llvm_ty.constInt(running_bits, .False);
   3659                         // If the field is as large as the entire packed struct, this
   3660                         // zext would go from, e.g. i16 to i16. This is legal with
   3661                         // constZExtOrBitCast but not legal with constZExt.
   3662                         const extended_int_val = small_int_val.constZExtOrBitCast(int_llvm_ty);
   3663                         const shifted = extended_int_val.constShl(shift_rhs);
   3664                         running_int = running_int.constOr(shifted);
   3665                         running_bits += ty_bit_size;
   3666                     }
   3667                     return running_int;
   3668                 }
   3669 
   3670                 const llvm_field_count = llvm_struct_ty.countStructElementTypes();
   3671                 var llvm_fields = try std.ArrayListUnmanaged(*llvm.Value).initCapacity(gpa, llvm_field_count);
   3672                 defer llvm_fields.deinit(gpa);
   3673 
   3674                 comptime assert(struct_layout_version == 2);
   3675                 var offset: u64 = 0;
   3676                 var big_align: u32 = 0;
   3677                 var need_unnamed = false;
   3678 
   3679                 for (struct_obj.fields.values()) |field, i| {
   3680                     if (field.is_comptime or !field.ty.hasRuntimeBits()) continue;
   3681 
   3682                     const field_align = field.alignment(target, struct_obj.layout);
   3683                     big_align = @max(big_align, field_align);
   3684                     const prev_offset = offset;
   3685                     offset = std.mem.alignForwardGeneric(u64, offset, field_align);
   3686 
   3687                     const padding_len = offset - prev_offset;
   3688                     if (padding_len > 0) {
   3689                         const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
   3690                         // TODO make this and all other padding elsewhere in debug
   3691                         // builds be 0xaa not undef.
   3692                         llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef());
   3693                     }
   3694 
   3695                     const field_llvm_val = try dg.lowerValue(.{
   3696                         .ty = field.ty,
   3697                         .val = field_vals[i],
   3698                     });
   3699 
   3700                     need_unnamed = need_unnamed or dg.isUnnamedType(field.ty, field_llvm_val);
   3701 
   3702                     llvm_fields.appendAssumeCapacity(field_llvm_val);
   3703 
   3704                     offset += field.ty.abiSize(target);
   3705                 }
   3706                 {
   3707                     const prev_offset = offset;
   3708                     offset = std.mem.alignForwardGeneric(u64, offset, big_align);
   3709                     const padding_len = offset - prev_offset;
   3710                     if (padding_len > 0) {
   3711                         const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
   3712                         llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef());
   3713                     }
   3714                 }
   3715 
   3716                 if (need_unnamed) {
   3717                     return dg.context.constStruct(
   3718                         llvm_fields.items.ptr,
   3719                         @intCast(c_uint, llvm_fields.items.len),
   3720                         .False,
   3721                     );
   3722                 } else {
   3723                     return llvm_struct_ty.constNamedStruct(
   3724                         llvm_fields.items.ptr,
   3725                         @intCast(c_uint, llvm_fields.items.len),
   3726                     );
   3727                 }
   3728             },
   3729             .Union => {
   3730                 const llvm_union_ty = try dg.lowerType(tv.ty);
   3731                 const tag_and_val = tv.val.castTag(.@"union").?.data;
   3732 
   3733                 const layout = tv.ty.unionGetLayout(target);
   3734 
   3735                 if (layout.payload_size == 0) {
   3736                     return lowerValue(dg, .{
   3737                         .ty = tv.ty.unionTagTypeSafety().?,
   3738                         .val = tag_and_val.tag,
   3739                     });
   3740                 }
   3741                 const union_obj = tv.ty.cast(Type.Payload.Union).?.data;
   3742                 const field_index = tv.ty.unionTagFieldIndex(tag_and_val.tag, dg.module).?;
   3743                 assert(union_obj.haveFieldTypes());
   3744 
   3745                 // Sometimes we must make an unnamed struct because LLVM does
   3746                 // not support bitcasting our payload struct to the true union payload type.
   3747                 // Instead we use an unnamed struct and every reference to the global
   3748                 // must pointer cast to the expected type before accessing the union.
   3749                 var need_unnamed: bool = layout.most_aligned_field != field_index;
   3750 
   3751                 const field_ty = union_obj.fields.values()[field_index].ty;
   3752                 const payload = p: {
   3753                     if (!field_ty.hasRuntimeBitsIgnoreComptime()) {
   3754                         const padding_len = @intCast(c_uint, layout.payload_size);
   3755                         break :p dg.context.intType(8).arrayType(padding_len).getUndef();
   3756                     }
   3757                     const field = try lowerValue(dg, .{ .ty = field_ty, .val = tag_and_val.val });
   3758                     need_unnamed = need_unnamed or dg.isUnnamedType(field_ty, field);
   3759                     const field_size = field_ty.abiSize(target);
   3760                     if (field_size == layout.payload_size) {
   3761                         break :p field;
   3762                     }
   3763                     const padding_len = @intCast(c_uint, layout.payload_size - field_size);
   3764                     const fields: [2]*llvm.Value = .{
   3765                         field, dg.context.intType(8).arrayType(padding_len).getUndef(),
   3766                     };
   3767                     break :p dg.context.constStruct(&fields, fields.len, .True);
   3768                 };
   3769 
   3770                 if (layout.tag_size == 0) {
   3771                     const fields: [1]*llvm.Value = .{payload};
   3772                     if (need_unnamed) {
   3773                         return dg.context.constStruct(&fields, fields.len, .False);
   3774                     } else {
   3775                         return llvm_union_ty.constNamedStruct(&fields, fields.len);
   3776                     }
   3777                 }
   3778                 const llvm_tag_value = try lowerValue(dg, .{
   3779                     .ty = tv.ty.unionTagTypeSafety().?,
   3780                     .val = tag_and_val.tag,
   3781                 });
   3782                 var fields: [3]*llvm.Value = undefined;
   3783                 var fields_len: c_uint = 2;
   3784                 if (layout.tag_align >= layout.payload_align) {
   3785                     fields = .{ llvm_tag_value, payload, undefined };
   3786                 } else {
   3787                     fields = .{ payload, llvm_tag_value, undefined };
   3788                 }
   3789                 if (layout.padding != 0) {
   3790                     fields[2] = dg.context.intType(8).arrayType(layout.padding).getUndef();
   3791                     fields_len = 3;
   3792                 }
   3793                 if (need_unnamed) {
   3794                     return dg.context.constStruct(&fields, fields_len, .False);
   3795                 } else {
   3796                     return llvm_union_ty.constNamedStruct(&fields, fields_len);
   3797                 }
   3798             },
   3799             .Vector => switch (tv.val.tag()) {
   3800                 .bytes => {
   3801                     // Note, sentinel is not stored even if the type has a sentinel.
   3802                     const bytes = tv.val.castTag(.bytes).?.data;
   3803                     const vector_len = @intCast(usize, tv.ty.arrayLen());
   3804                     assert(vector_len == bytes.len or vector_len + 1 == bytes.len);
   3805 
   3806                     const elem_ty = tv.ty.elemType();
   3807                     const llvm_elems = try dg.gpa.alloc(*llvm.Value, vector_len);
   3808                     defer dg.gpa.free(llvm_elems);
   3809                     for (llvm_elems) |*elem, i| {
   3810                         var byte_payload: Value.Payload.U64 = .{
   3811                             .base = .{ .tag = .int_u64 },
   3812                             .data = bytes[i],
   3813                         };
   3814 
   3815                         elem.* = try dg.lowerValue(.{
   3816                             .ty = elem_ty,
   3817                             .val = Value.initPayload(&byte_payload.base),
   3818                         });
   3819                     }
   3820                     return llvm.constVector(
   3821                         llvm_elems.ptr,
   3822                         @intCast(c_uint, llvm_elems.len),
   3823                     );
   3824                 },
   3825                 .aggregate => {
   3826                     // Note, sentinel is not stored even if the type has a sentinel.
   3827                     // The value includes the sentinel in those cases.
   3828                     const elem_vals = tv.val.castTag(.aggregate).?.data;
   3829                     const vector_len = @intCast(usize, tv.ty.arrayLen());
   3830                     assert(vector_len == elem_vals.len or vector_len + 1 == elem_vals.len);
   3831                     const elem_ty = tv.ty.elemType();
   3832                     const llvm_elems = try dg.gpa.alloc(*llvm.Value, vector_len);
   3833                     defer dg.gpa.free(llvm_elems);
   3834                     for (llvm_elems) |*elem, i| {
   3835                         elem.* = try dg.lowerValue(.{ .ty = elem_ty, .val = elem_vals[i] });
   3836                     }
   3837                     return llvm.constVector(
   3838                         llvm_elems.ptr,
   3839                         @intCast(c_uint, llvm_elems.len),
   3840                     );
   3841                 },
   3842                 .repeated => {
   3843                     // Note, sentinel is not stored even if the type has a sentinel.
   3844                     const val = tv.val.castTag(.repeated).?.data;
   3845                     const elem_ty = tv.ty.elemType();
   3846                     const len = @intCast(usize, tv.ty.arrayLen());
   3847                     const llvm_elems = try dg.gpa.alloc(*llvm.Value, len);
   3848                     defer dg.gpa.free(llvm_elems);
   3849                     for (llvm_elems) |*elem| {
   3850                         elem.* = try dg.lowerValue(.{ .ty = elem_ty, .val = val });
   3851                     }
   3852                     return llvm.constVector(
   3853                         llvm_elems.ptr,
   3854                         @intCast(c_uint, llvm_elems.len),
   3855                     );
   3856                 },
   3857                 else => unreachable,
   3858             },
   3859 
   3860             .ComptimeInt => unreachable,
   3861             .ComptimeFloat => unreachable,
   3862             .Type => unreachable,
   3863             .EnumLiteral => unreachable,
   3864             .Void => unreachable,
   3865             .NoReturn => unreachable,
   3866             .Undefined => unreachable,
   3867             .Null => unreachable,
   3868             .BoundFn => unreachable,
   3869             .Opaque => unreachable,
   3870 
   3871             .Frame,
   3872             .AnyFrame,
   3873             => return dg.todo("implement const of type '{}'", .{tv.ty.fmtDebug()}),
   3874         }
   3875     }
   3876 
   3877     const ParentPtr = struct {
   3878         ty: Type,
   3879         llvm_ptr: *llvm.Value,
   3880     };
   3881 
   3882     fn lowerParentPtrDecl(
   3883         dg: *DeclGen,
   3884         ptr_val: Value,
   3885         decl_index: Module.Decl.Index,
   3886         ptr_child_ty: Type,
   3887     ) Error!*llvm.Value {
   3888         const decl = dg.module.declPtr(decl_index);
   3889         dg.module.markDeclAlive(decl);
   3890         var ptr_ty_payload: Type.Payload.ElemType = .{
   3891             .base = .{ .tag = .single_mut_pointer },
   3892             .data = decl.ty,
   3893         };
   3894         const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
   3895         const llvm_ptr = try dg.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index);
   3896 
   3897         if (ptr_child_ty.eql(decl.ty, dg.module)) {
   3898             return llvm_ptr;
   3899         } else {
   3900             return llvm_ptr.constBitCast((try dg.lowerType(ptr_child_ty)).pointerType(0));
   3901         }
   3902     }
   3903 
   3904     fn lowerParentPtr(dg: *DeclGen, ptr_val: Value, ptr_child_ty: Type) Error!*llvm.Value {
   3905         const target = dg.module.getTarget();
   3906         var bitcast_needed: bool = undefined;
   3907         const llvm_ptr = switch (ptr_val.tag()) {
   3908             .decl_ref_mut => {
   3909                 const decl = ptr_val.castTag(.decl_ref_mut).?.data.decl_index;
   3910                 return dg.lowerParentPtrDecl(ptr_val, decl, ptr_child_ty);
   3911             },
   3912             .decl_ref => {
   3913                 const decl = ptr_val.castTag(.decl_ref).?.data;
   3914                 return dg.lowerParentPtrDecl(ptr_val, decl, ptr_child_ty);
   3915             },
   3916             .variable => {
   3917                 const decl = ptr_val.castTag(.variable).?.data.owner_decl;
   3918                 return dg.lowerParentPtrDecl(ptr_val, decl, ptr_child_ty);
   3919             },
   3920             .int_i64 => {
   3921                 const int = ptr_val.castTag(.int_i64).?.data;
   3922                 const llvm_usize = try dg.lowerType(Type.usize);
   3923                 const llvm_int = llvm_usize.constInt(@bitCast(u64, int), .False);
   3924                 return llvm_int.constIntToPtr((try dg.lowerType(ptr_child_ty)).pointerType(0));
   3925             },
   3926             .int_u64 => {
   3927                 const int = ptr_val.castTag(.int_u64).?.data;
   3928                 const llvm_usize = try dg.lowerType(Type.usize);
   3929                 const llvm_int = llvm_usize.constInt(int, .False);
   3930                 return llvm_int.constIntToPtr((try dg.lowerType(ptr_child_ty)).pointerType(0));
   3931             },
   3932             .field_ptr => blk: {
   3933                 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
   3934                 const parent_llvm_ptr = try dg.lowerParentPtr(field_ptr.container_ptr, field_ptr.container_ty);
   3935                 const parent_ty = field_ptr.container_ty;
   3936 
   3937                 const field_index = @intCast(u32, field_ptr.field_index);
   3938                 const llvm_u32 = dg.context.intType(32);
   3939                 switch (parent_ty.zigTypeTag()) {
   3940                     .Union => {
   3941                         bitcast_needed = true;
   3942 
   3943                         const layout = parent_ty.unionGetLayout(target);
   3944                         if (layout.payload_size == 0) {
   3945                             // In this case a pointer to the union and a pointer to any
   3946                             // (void) payload is the same.
   3947                             break :blk parent_llvm_ptr;
   3948                         }
   3949                         const llvm_pl_index = if (layout.tag_size == 0)
   3950                             0
   3951                         else
   3952                             @boolToInt(layout.tag_align >= layout.payload_align);
   3953                         const indices: [2]*llvm.Value = .{
   3954                             llvm_u32.constInt(0, .False),
   3955                             llvm_u32.constInt(llvm_pl_index, .False),
   3956                         };
   3957                         const parent_llvm_ty = try dg.lowerType(parent_ty);
   3958                         break :blk parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
   3959                     },
   3960                     .Struct => {
   3961                         const field_ty = parent_ty.structFieldType(field_index);
   3962                         if (parent_ty.containerLayout() == .Packed) {
   3963                             const llvm_usize = dg.context.intType(target.cpu.arch.ptrBitWidth());
   3964                             const base_addr = parent_llvm_ptr.constPtrToInt(llvm_usize);
   3965                             // count bits of fields before this one
   3966                             const prev_bits = b: {
   3967                                 var b: usize = 0;
   3968                                 for (parent_ty.structFields().values()[0..field_index]) |field| {
   3969                                     if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;
   3970                                     b += @intCast(usize, field.ty.bitSize(target));
   3971                                 }
   3972                                 break :b b;
   3973                             };
   3974                             const byte_offset = llvm_usize.constInt(prev_bits / 8, .False);
   3975                             const field_addr = base_addr.constAdd(byte_offset);
   3976                             bitcast_needed = false;
   3977                             const final_llvm_ty = (try dg.lowerType(ptr_child_ty)).pointerType(0);
   3978                             break :blk field_addr.constIntToPtr(final_llvm_ty);
   3979                         }
   3980                         bitcast_needed = !field_ty.eql(ptr_child_ty, dg.module);
   3981 
   3982                         var ty_buf: Type.Payload.Pointer = undefined;
   3983                         const llvm_field_index = llvmFieldIndex(parent_ty, field_index, target, &ty_buf).?;
   3984                         const indices: [2]*llvm.Value = .{
   3985                             llvm_u32.constInt(0, .False),
   3986                             llvm_u32.constInt(llvm_field_index, .False),
   3987                         };
   3988                         const parent_llvm_ty = try dg.lowerType(parent_ty);
   3989                         break :blk parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
   3990                     },
   3991                     .Pointer => {
   3992                         assert(parent_ty.isSlice());
   3993                         const indices: [2]*llvm.Value = .{
   3994                             llvm_u32.constInt(0, .False),
   3995                             llvm_u32.constInt(field_index, .False),
   3996                         };
   3997                         const parent_llvm_ty = try dg.lowerType(parent_ty);
   3998                         break :blk parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
   3999                     },
   4000                     else => unreachable,
   4001                 }
   4002             },
   4003             .elem_ptr => blk: {
   4004                 const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
   4005                 const parent_llvm_ptr = try dg.lowerParentPtr(elem_ptr.array_ptr, elem_ptr.elem_ty);
   4006                 bitcast_needed = !elem_ptr.elem_ty.eql(ptr_child_ty, dg.module);
   4007 
   4008                 const llvm_usize = try dg.lowerType(Type.usize);
   4009                 const indices: [1]*llvm.Value = .{
   4010                     llvm_usize.constInt(elem_ptr.index, .False),
   4011                 };
   4012                 const elem_llvm_ty = try dg.lowerType(elem_ptr.elem_ty);
   4013                 break :blk elem_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
   4014             },
   4015             .opt_payload_ptr => blk: {
   4016                 const opt_payload_ptr = ptr_val.castTag(.opt_payload_ptr).?.data;
   4017                 const parent_llvm_ptr = try dg.lowerParentPtr(opt_payload_ptr.container_ptr, opt_payload_ptr.container_ty);
   4018                 var buf: Type.Payload.ElemType = undefined;
   4019 
   4020                 const payload_ty = opt_payload_ptr.container_ty.optionalChild(&buf);
   4021                 bitcast_needed = !payload_ty.eql(ptr_child_ty, dg.module);
   4022 
   4023                 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or
   4024                     payload_ty.optionalReprIsPayload())
   4025                 {
   4026                     // In this case, we represent pointer to optional the same as pointer
   4027                     // to the payload.
   4028                     break :blk parent_llvm_ptr;
   4029                 }
   4030 
   4031                 const llvm_u32 = dg.context.intType(32);
   4032                 const indices: [2]*llvm.Value = .{
   4033                     llvm_u32.constInt(0, .False),
   4034                     llvm_u32.constInt(0, .False),
   4035                 };
   4036                 const opt_llvm_ty = try dg.lowerType(opt_payload_ptr.container_ty);
   4037                 break :blk opt_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
   4038             },
   4039             .eu_payload_ptr => blk: {
   4040                 const eu_payload_ptr = ptr_val.castTag(.eu_payload_ptr).?.data;
   4041                 const parent_llvm_ptr = try dg.lowerParentPtr(eu_payload_ptr.container_ptr, eu_payload_ptr.container_ty);
   4042 
   4043                 const payload_ty = eu_payload_ptr.container_ty.errorUnionPayload();
   4044                 bitcast_needed = !payload_ty.eql(ptr_child_ty, dg.module);
   4045 
   4046                 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
   4047                     // In this case, we represent pointer to error union the same as pointer
   4048                     // to the payload.
   4049                     break :blk parent_llvm_ptr;
   4050                 }
   4051 
   4052                 const payload_offset: u8 = if (payload_ty.abiAlignment(target) > Type.anyerror.abiSize(target)) 2 else 1;
   4053                 const llvm_u32 = dg.context.intType(32);
   4054                 const indices: [2]*llvm.Value = .{
   4055                     llvm_u32.constInt(0, .False),
   4056                     llvm_u32.constInt(payload_offset, .False),
   4057                 };
   4058                 const eu_llvm_ty = try dg.lowerType(eu_payload_ptr.container_ty);
   4059                 break :blk eu_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
   4060             },
   4061             else => unreachable,
   4062         };
   4063         if (bitcast_needed) {
   4064             return llvm_ptr.constBitCast((try dg.lowerType(ptr_child_ty)).pointerType(0));
   4065         } else {
   4066             return llvm_ptr;
   4067         }
   4068     }
   4069 
   4070     fn lowerDeclRefValue(
   4071         self: *DeclGen,
   4072         tv: TypedValue,
   4073         decl_index: Module.Decl.Index,
   4074     ) Error!*llvm.Value {
   4075         if (tv.ty.isSlice()) {
   4076             var buf: Type.SlicePtrFieldTypeBuffer = undefined;
   4077             const ptr_ty = tv.ty.slicePtrFieldType(&buf);
   4078             var slice_len: Value.Payload.U64 = .{
   4079                 .base = .{ .tag = .int_u64 },
   4080                 .data = tv.val.sliceLen(self.module),
   4081             };
   4082             const fields: [2]*llvm.Value = .{
   4083                 try self.lowerValue(.{
   4084                     .ty = ptr_ty,
   4085                     .val = tv.val,
   4086                 }),
   4087                 try self.lowerValue(.{
   4088                     .ty = Type.usize,
   4089                     .val = Value.initPayload(&slice_len.base),
   4090                 }),
   4091             };
   4092             return self.context.constStruct(&fields, fields.len, .False);
   4093         }
   4094 
   4095         // In the case of something like:
   4096         // fn foo() void {}
   4097         // const bar = foo;
   4098         // ... &bar;
   4099         // `bar` is just an alias and we actually want to lower a reference to `foo`.
   4100         const decl = self.module.declPtr(decl_index);
   4101         if (decl.val.castTag(.function)) |func| {
   4102             if (func.data.owner_decl != decl_index) {
   4103                 return self.lowerDeclRefValue(tv, func.data.owner_decl);
   4104             }
   4105         }
   4106 
   4107         const is_fn_body = decl.ty.zigTypeTag() == .Fn;
   4108         if (!is_fn_body and !decl.ty.hasRuntimeBits()) {
   4109             return self.lowerPtrToVoid(tv.ty);
   4110         }
   4111 
   4112         self.module.markDeclAlive(decl);
   4113 
   4114         const llvm_decl_val = if (is_fn_body)
   4115             try self.resolveLlvmFunction(decl_index)
   4116         else
   4117             try self.resolveGlobalDecl(decl_index);
   4118 
   4119         const target = self.module.getTarget();
   4120         const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);
   4121         const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);
   4122         const llvm_val = if (llvm_wanted_addrspace != llvm_actual_addrspace) blk: {
   4123             const llvm_decl_ty = try self.lowerType(decl.ty);
   4124             const llvm_decl_wanted_ptr_ty = llvm_decl_ty.pointerType(llvm_wanted_addrspace);
   4125             break :blk llvm_decl_val.constAddrSpaceCast(llvm_decl_wanted_ptr_ty);
   4126         } else llvm_decl_val;
   4127 
   4128         const llvm_type = try self.lowerType(tv.ty);
   4129         if (tv.ty.zigTypeTag() == .Int) {
   4130             return llvm_val.constPtrToInt(llvm_type);
   4131         } else {
   4132             return llvm_val.constBitCast(llvm_type);
   4133         }
   4134     }
   4135 
   4136     fn lowerPtrToVoid(dg: *DeclGen, ptr_ty: Type) !*llvm.Value {
   4137         const alignment = ptr_ty.ptrInfo().data.@"align";
   4138         // Even though we are pointing at something which has zero bits (e.g. `void`),
   4139         // Pointers are defined to have bits. So we must return something here.
   4140         // The value cannot be undefined, because we use the `nonnull` annotation
   4141         // for non-optional pointers. We also need to respect the alignment, even though
   4142         // the address will never be dereferenced.
   4143         const llvm_usize = try dg.lowerType(Type.usize);
   4144         const llvm_ptr_ty = try dg.lowerType(ptr_ty);
   4145         if (alignment != 0) {
   4146             return llvm_usize.constInt(alignment, .False).constIntToPtr(llvm_ptr_ty);
   4147         }
   4148         // Note that these 0xaa values are appropriate even in release-optimized builds
   4149         // because we need a well-defined value that is not null, and LLVM does not
   4150         // have an "undef_but_not_null" attribute. As an example, if this `alloc` AIR
   4151         // instruction is followed by a `wrap_optional`, it will return this value
   4152         // verbatim, and the result should test as non-null.
   4153         const target = dg.module.getTarget();
   4154         const int = switch (target.cpu.arch.ptrBitWidth()) {
   4155             32 => llvm_usize.constInt(0xaaaaaaaa, .False),
   4156             64 => llvm_usize.constInt(0xaaaaaaaa_aaaaaaaa, .False),
   4157             else => unreachable,
   4158         };
   4159         return int.constIntToPtr(llvm_ptr_ty);
   4160     }
   4161 
   4162     fn addAttr(dg: DeclGen, val: *llvm.Value, index: llvm.AttributeIndex, name: []const u8) void {
   4163         return dg.addAttrInt(val, index, name, 0);
   4164     }
   4165 
   4166     fn addArgAttr(dg: DeclGen, fn_val: *llvm.Value, param_index: u32, attr_name: []const u8) void {
   4167         return dg.addAttr(fn_val, param_index + 1, attr_name);
   4168     }
   4169 
   4170     fn addArgAttrInt(dg: DeclGen, fn_val: *llvm.Value, param_index: u32, attr_name: []const u8, int: u64) void {
   4171         return dg.addAttrInt(fn_val, param_index + 1, attr_name, int);
   4172     }
   4173 
   4174     fn removeAttr(val: *llvm.Value, index: llvm.AttributeIndex, name: []const u8) void {
   4175         const kind_id = llvm.getEnumAttributeKindForName(name.ptr, name.len);
   4176         assert(kind_id != 0);
   4177         val.removeEnumAttributeAtIndex(index, kind_id);
   4178     }
   4179 
   4180     fn addAttrInt(
   4181         dg: DeclGen,
   4182         val: *llvm.Value,
   4183         index: llvm.AttributeIndex,
   4184         name: []const u8,
   4185         int: u64,
   4186     ) void {
   4187         const kind_id = llvm.getEnumAttributeKindForName(name.ptr, name.len);
   4188         assert(kind_id != 0);
   4189         const llvm_attr = dg.context.createEnumAttribute(kind_id, int);
   4190         val.addAttributeAtIndex(index, llvm_attr);
   4191     }
   4192 
   4193     fn addAttrString(
   4194         dg: *DeclGen,
   4195         val: *llvm.Value,
   4196         index: llvm.AttributeIndex,
   4197         name: []const u8,
   4198         value: []const u8,
   4199     ) void {
   4200         const llvm_attr = dg.context.createStringAttribute(
   4201             name.ptr,
   4202             @intCast(c_uint, name.len),
   4203             value.ptr,
   4204             @intCast(c_uint, value.len),
   4205         );
   4206         val.addAttributeAtIndex(index, llvm_attr);
   4207     }
   4208 
   4209     fn addFnAttr(dg: DeclGen, val: *llvm.Value, name: []const u8) void {
   4210         dg.addAttr(val, std.math.maxInt(llvm.AttributeIndex), name);
   4211     }
   4212 
   4213     fn addFnAttrString(dg: *DeclGen, val: *llvm.Value, name: []const u8, value: []const u8) void {
   4214         dg.addAttrString(val, std.math.maxInt(llvm.AttributeIndex), name, value);
   4215     }
   4216 
   4217     fn removeFnAttr(fn_val: *llvm.Value, name: []const u8) void {
   4218         removeAttr(fn_val, std.math.maxInt(llvm.AttributeIndex), name);
   4219     }
   4220 
   4221     fn addFnAttrInt(dg: DeclGen, fn_val: *llvm.Value, name: []const u8, int: u64) void {
   4222         return dg.addAttrInt(fn_val, std.math.maxInt(llvm.AttributeIndex), name, int);
   4223     }
   4224 
   4225     /// If the operand type of an atomic operation is not byte sized we need to
   4226     /// widen it before using it and then truncate the result.
   4227     /// RMW exchange of floating-point values is bitcasted to same-sized integer
   4228     /// types to work around a LLVM deficiency when targeting ARM/AArch64.
   4229     fn getAtomicAbiType(dg: *DeclGen, ty: Type, is_rmw_xchg: bool) ?*llvm.Type {
   4230         const target = dg.module.getTarget();
   4231         var buffer: Type.Payload.Bits = undefined;
   4232         const int_ty = switch (ty.zigTypeTag()) {
   4233             .Int => ty,
   4234             .Enum => ty.intTagType(&buffer),
   4235             .Float => {
   4236                 if (!is_rmw_xchg) return null;
   4237                 return dg.context.intType(@intCast(c_uint, ty.abiSize(target) * 8));
   4238             },
   4239             .Bool => return dg.context.intType(8),
   4240             else => return null,
   4241         };
   4242         const bit_count = int_ty.intInfo(target).bits;
   4243         if (!std.math.isPowerOfTwo(bit_count) or (bit_count % 8) != 0) {
   4244             return dg.context.intType(@intCast(c_uint, int_ty.abiSize(target) * 8));
   4245         } else {
   4246             return null;
   4247         }
   4248     }
   4249 
   4250     fn addByValParamAttrs(
   4251         dg: DeclGen,
   4252         llvm_fn: *llvm.Value,
   4253         param_ty: Type,
   4254         param_index: u32,
   4255         fn_info: Type.Payload.Function.Data,
   4256         llvm_arg_i: u32,
   4257     ) void {
   4258         const target = dg.module.getTarget();
   4259         if (param_ty.isPtrAtRuntime()) {
   4260             const ptr_info = param_ty.ptrInfo().data;
   4261             if (math.cast(u5, param_index)) |i| {
   4262                 if (@truncate(u1, fn_info.noalias_bits >> i) != 0) {
   4263                     dg.addArgAttr(llvm_fn, llvm_arg_i, "noalias");
   4264                 }
   4265             }
   4266             if (!param_ty.isPtrLikeOptional() and !ptr_info.@"allowzero") {
   4267                 dg.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");
   4268             }
   4269             if (!ptr_info.mutable) {
   4270                 dg.addArgAttr(llvm_fn, llvm_arg_i, "readonly");
   4271             }
   4272             if (ptr_info.@"align" != 0) {
   4273                 dg.addArgAttrInt(llvm_fn, llvm_arg_i, "align", ptr_info.@"align");
   4274             } else {
   4275                 const elem_align = @max(
   4276                     ptr_info.pointee_type.abiAlignment(target),
   4277                     1,
   4278                 );
   4279                 dg.addArgAttrInt(llvm_fn, llvm_arg_i, "align", elem_align);
   4280             }
   4281         } else if (ccAbiPromoteInt(fn_info.cc, target, param_ty)) |s| switch (s) {
   4282             .signed => dg.addArgAttr(llvm_fn, llvm_arg_i, "signext"),
   4283             .unsigned => dg.addArgAttr(llvm_fn, llvm_arg_i, "zeroext"),
   4284         };
   4285     }
   4286 
   4287     fn addByRefParamAttrs(
   4288         dg: DeclGen,
   4289         llvm_fn: *llvm.Value,
   4290         llvm_arg_i: u32,
   4291         alignment: u32,
   4292         byval_attr: bool,
   4293         param_llvm_ty: *llvm.Type,
   4294     ) void {
   4295         dg.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");
   4296         dg.addArgAttr(llvm_fn, llvm_arg_i, "readonly");
   4297         dg.addArgAttrInt(llvm_fn, llvm_arg_i, "align", alignment);
   4298         if (byval_attr) {
   4299             llvm_fn.addByValAttr(llvm_arg_i, param_llvm_ty);
   4300         }
   4301     }
   4302 };
   4303 
   4304 pub const FuncGen = struct {
   4305     gpa: Allocator,
   4306     dg: *DeclGen,
   4307     air: Air,
   4308     liveness: Liveness,
   4309     context: *llvm.Context,
   4310     builder: *llvm.Builder,
   4311     di_scope: ?*llvm.DIScope,
   4312     di_file: ?*llvm.DIFile,
   4313     base_line: u32,
   4314     prev_dbg_line: c_uint,
   4315     prev_dbg_column: c_uint,
   4316 
   4317     /// Stack of locations where a call was inlined.
   4318     dbg_inlined: std.ArrayListUnmanaged(DbgState) = .{},
   4319 
   4320     /// Stack of `DILexicalBlock`s. dbg_block instructions cannot happend accross
   4321     /// dbg_inline instructions so no special handling there is required.
   4322     dbg_block_stack: std.ArrayListUnmanaged(*llvm.DIScope) = .{},
   4323 
   4324     /// This stores the LLVM values used in a function, such that they can be referred to
   4325     /// in other instructions. This table is cleared before every function is generated.
   4326     func_inst_table: std.AutoHashMapUnmanaged(Air.Inst.Ref, *llvm.Value),
   4327 
   4328     /// If the return type is sret, this is the result pointer. Otherwise null.
   4329     /// Note that this can disagree with isByRef for the return type in the case
   4330     /// of C ABI functions.
   4331     ret_ptr: ?*llvm.Value,
   4332     /// Any function that needs to perform Valgrind client requests needs an array alloca
   4333     /// instruction, however a maximum of one per function is needed.
   4334     valgrind_client_request_array: ?*llvm.Value = null,
   4335     /// These fields are used to refer to the LLVM value of the function parameters
   4336     /// in an Arg instruction.
   4337     /// This list may be shorter than the list according to the zig type system;
   4338     /// it omits 0-bit types. If the function uses sret as the first parameter,
   4339     /// this slice does not include it.
   4340     args: []const *llvm.Value,
   4341     arg_index: c_uint,
   4342 
   4343     llvm_func: *llvm.Value,
   4344 
   4345     err_ret_trace: ?*llvm.Value = null,
   4346 
   4347     /// This data structure is used to implement breaking to blocks.
   4348     blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, struct {
   4349         parent_bb: *llvm.BasicBlock,
   4350         breaks: *BreakList,
   4351     }),
   4352 
   4353     single_threaded: bool,
   4354 
   4355     const DbgState = struct { loc: *llvm.DILocation, scope: *llvm.DIScope, base_line: u32 };
   4356     const BreakList = std.MultiArrayList(struct {
   4357         bb: *llvm.BasicBlock,
   4358         val: *llvm.Value,
   4359     });
   4360 
   4361     fn deinit(self: *FuncGen) void {
   4362         self.builder.dispose();
   4363         self.dbg_inlined.deinit(self.gpa);
   4364         self.dbg_block_stack.deinit(self.gpa);
   4365         self.func_inst_table.deinit(self.gpa);
   4366         self.blocks.deinit(self.gpa);
   4367     }
   4368 
   4369     fn todo(self: *FuncGen, comptime format: []const u8, args: anytype) Error {
   4370         @setCold(true);
   4371         return self.dg.todo(format, args);
   4372     }
   4373 
   4374     fn llvmModule(self: *FuncGen) *llvm.Module {
   4375         return self.dg.object.llvm_module;
   4376     }
   4377 
   4378     fn resolveInst(self: *FuncGen, inst: Air.Inst.Ref) !*llvm.Value {
   4379         const gop = try self.func_inst_table.getOrPut(self.dg.gpa, inst);
   4380         if (gop.found_existing) return gop.value_ptr.*;
   4381 
   4382         const llvm_val = try self.resolveValue(.{
   4383             .ty = self.air.typeOf(inst),
   4384             .val = self.air.value(inst).?,
   4385         });
   4386         gop.value_ptr.* = llvm_val;
   4387         return llvm_val;
   4388     }
   4389 
   4390     fn resolveValue(self: *FuncGen, tv: TypedValue) !*llvm.Value {
   4391         const llvm_val = try self.dg.lowerValue(tv);
   4392         if (!isByRef(tv.ty)) return llvm_val;
   4393 
   4394         // We have an LLVM value but we need to create a global constant and
   4395         // set the value as its initializer, and then return a pointer to the global.
   4396         const target = self.dg.module.getTarget();
   4397         const llvm_wanted_addrspace = toLlvmAddressSpace(.generic, target);
   4398         const llvm_actual_addrspace = toLlvmGlobalAddressSpace(.generic, target);
   4399         const global = self.dg.object.llvm_module.addGlobalInAddressSpace(llvm_val.typeOf(), "", llvm_actual_addrspace);
   4400         global.setInitializer(llvm_val);
   4401         global.setLinkage(.Private);
   4402         global.setGlobalConstant(.True);
   4403         global.setUnnamedAddr(.True);
   4404         global.setAlignment(tv.ty.abiAlignment(target));
   4405         // Because of LLVM limitations for lowering certain types such as unions,
   4406         // the type of global constants might not match the type it is supposed to
   4407         // be, and so we must bitcast the pointer at the usage sites.
   4408         const wanted_llvm_ty = try self.dg.lowerType(tv.ty);
   4409         const wanted_bitcasted_llvm_ptr_ty = wanted_llvm_ty.pointerType(llvm_actual_addrspace);
   4410         const bitcasted_ptr = global.constBitCast(wanted_bitcasted_llvm_ptr_ty);
   4411         const wanted_llvm_ptr_ty = wanted_llvm_ty.pointerType(llvm_wanted_addrspace);
   4412         const casted_ptr = if (llvm_wanted_addrspace != llvm_actual_addrspace)
   4413             bitcasted_ptr.constAddrSpaceCast(wanted_llvm_ptr_ty)
   4414         else
   4415             bitcasted_ptr;
   4416         return casted_ptr;
   4417     }
   4418 
   4419     fn genBody(self: *FuncGen, body: []const Air.Inst.Index) Error!void {
   4420         const air_tags = self.air.instructions.items(.tag);
   4421         for (body) |inst, i| {
   4422             const opt_value: ?*llvm.Value = switch (air_tags[inst]) {
   4423                 // zig fmt: off
   4424                 .add       => try self.airAdd(inst, false),
   4425                 .addwrap   => try self.airAddWrap(inst, false),
   4426                 .add_sat   => try self.airAddSat(inst),
   4427                 .sub       => try self.airSub(inst, false),
   4428                 .subwrap   => try self.airSubWrap(inst, false),
   4429                 .sub_sat   => try self.airSubSat(inst),
   4430                 .mul       => try self.airMul(inst, false),
   4431                 .mulwrap   => try self.airMulWrap(inst, false),
   4432                 .mul_sat   => try self.airMulSat(inst),
   4433                 .div_float => try self.airDivFloat(inst, false),
   4434                 .div_trunc => try self.airDivTrunc(inst, false),
   4435                 .div_floor => try self.airDivFloor(inst, false),
   4436                 .div_exact => try self.airDivExact(inst, false),
   4437                 .rem       => try self.airRem(inst, false),
   4438                 .mod       => try self.airMod(inst, false),
   4439                 .ptr_add   => try self.airPtrAdd(inst),
   4440                 .ptr_sub   => try self.airPtrSub(inst),
   4441                 .shl       => try self.airShl(inst),
   4442                 .shl_sat   => try self.airShlSat(inst),
   4443                 .shl_exact => try self.airShlExact(inst),
   4444                 .min       => try self.airMin(inst),
   4445                 .max       => try self.airMax(inst),
   4446                 .slice     => try self.airSlice(inst),
   4447                 .mul_add   => try self.airMulAdd(inst),
   4448 
   4449                 .add_optimized       => try self.airAdd(inst, true),
   4450                 .addwrap_optimized   => try self.airAddWrap(inst, true),
   4451                 .sub_optimized       => try self.airSub(inst, true),
   4452                 .subwrap_optimized   => try self.airSubWrap(inst, true),
   4453                 .mul_optimized       => try self.airMul(inst, true),
   4454                 .mulwrap_optimized   => try self.airMulWrap(inst, true),
   4455                 .div_float_optimized => try self.airDivFloat(inst, true),
   4456                 .div_trunc_optimized => try self.airDivTrunc(inst, true),
   4457                 .div_floor_optimized => try self.airDivFloor(inst, true),
   4458                 .div_exact_optimized => try self.airDivExact(inst, true),
   4459                 .rem_optimized       => try self.airRem(inst, true),
   4460                 .mod_optimized       => try self.airMod(inst, true),
   4461 
   4462                 .add_with_overflow => try self.airOverflow(inst, "llvm.sadd.with.overflow", "llvm.uadd.with.overflow"),
   4463                 .sub_with_overflow => try self.airOverflow(inst, "llvm.ssub.with.overflow", "llvm.usub.with.overflow"),
   4464                 .mul_with_overflow => try self.airOverflow(inst, "llvm.smul.with.overflow", "llvm.umul.with.overflow"),
   4465                 .shl_with_overflow => try self.airShlWithOverflow(inst),
   4466 
   4467                 .bit_and, .bool_and => try self.airAnd(inst),
   4468                 .bit_or, .bool_or   => try self.airOr(inst),
   4469                 .xor                => try self.airXor(inst),
   4470                 .shr                => try self.airShr(inst, false),
   4471                 .shr_exact          => try self.airShr(inst, true),
   4472 
   4473                 .sqrt         => try self.airUnaryOp(inst, .sqrt),
   4474                 .sin          => try self.airUnaryOp(inst, .sin),
   4475                 .cos          => try self.airUnaryOp(inst, .cos),
   4476                 .tan          => try self.airUnaryOp(inst, .tan),
   4477                 .exp          => try self.airUnaryOp(inst, .exp),
   4478                 .exp2         => try self.airUnaryOp(inst, .exp2),
   4479                 .log          => try self.airUnaryOp(inst, .log),
   4480                 .log2         => try self.airUnaryOp(inst, .log2),
   4481                 .log10        => try self.airUnaryOp(inst, .log10),
   4482                 .fabs         => try self.airUnaryOp(inst, .fabs),
   4483                 .floor        => try self.airUnaryOp(inst, .floor),
   4484                 .ceil         => try self.airUnaryOp(inst, .ceil),
   4485                 .round        => try self.airUnaryOp(inst, .round),
   4486                 .trunc_float  => try self.airUnaryOp(inst, .trunc),
   4487 
   4488                 .neg           => try self.airNeg(inst, false),
   4489                 .neg_optimized => try self.airNeg(inst, true),
   4490 
   4491                 .cmp_eq  => try self.airCmp(inst, .eq, false),
   4492                 .cmp_gt  => try self.airCmp(inst, .gt, false),
   4493                 .cmp_gte => try self.airCmp(inst, .gte, false),
   4494                 .cmp_lt  => try self.airCmp(inst, .lt, false),
   4495                 .cmp_lte => try self.airCmp(inst, .lte, false),
   4496                 .cmp_neq => try self.airCmp(inst, .neq, false),
   4497 
   4498                 .cmp_eq_optimized  => try self.airCmp(inst, .eq, true),
   4499                 .cmp_gt_optimized  => try self.airCmp(inst, .gt, true),
   4500                 .cmp_gte_optimized => try self.airCmp(inst, .gte, true),
   4501                 .cmp_lt_optimized  => try self.airCmp(inst, .lt, true),
   4502                 .cmp_lte_optimized => try self.airCmp(inst, .lte, true),
   4503                 .cmp_neq_optimized => try self.airCmp(inst, .neq, true),
   4504 
   4505                 .cmp_vector           => try self.airCmpVector(inst, false),
   4506                 .cmp_vector_optimized => try self.airCmpVector(inst, true),
   4507                 .cmp_lt_errors_len    => try self.airCmpLtErrorsLen(inst),
   4508 
   4509                 .is_non_null     => try self.airIsNonNull(inst, false, .NE),
   4510                 .is_non_null_ptr => try self.airIsNonNull(inst, true , .NE),
   4511                 .is_null         => try self.airIsNonNull(inst, false, .EQ),
   4512                 .is_null_ptr     => try self.airIsNonNull(inst, true , .EQ),
   4513 
   4514                 .is_non_err      => try self.airIsErr(inst, .EQ, false),
   4515                 .is_non_err_ptr  => try self.airIsErr(inst, .EQ, true),
   4516                 .is_err          => try self.airIsErr(inst, .NE, false),
   4517                 .is_err_ptr      => try self.airIsErr(inst, .NE, true),
   4518 
   4519                 .alloc          => try self.airAlloc(inst),
   4520                 .ret_ptr        => try self.airRetPtr(inst),
   4521                 .arg            => try self.airArg(inst),
   4522                 .bitcast        => try self.airBitCast(inst),
   4523                 .bool_to_int    => try self.airBoolToInt(inst),
   4524                 .block          => try self.airBlock(inst),
   4525                 .br             => try self.airBr(inst),
   4526                 .switch_br      => try self.airSwitchBr(inst),
   4527                 .breakpoint     => try self.airBreakpoint(inst),
   4528                 .ret_addr       => try self.airRetAddr(inst),
   4529                 .frame_addr     => try self.airFrameAddress(inst),
   4530                 .cond_br        => try self.airCondBr(inst),
   4531                 .@"try"         => try self.airTry(inst),
   4532                 .try_ptr        => try self.airTryPtr(inst),
   4533                 .intcast        => try self.airIntCast(inst),
   4534                 .trunc          => try self.airTrunc(inst),
   4535                 .fptrunc        => try self.airFptrunc(inst),
   4536                 .fpext          => try self.airFpext(inst),
   4537                 .ptrtoint       => try self.airPtrToInt(inst),
   4538                 .load           => try self.airLoad(inst, body, i + 1),
   4539                 .loop           => try self.airLoop(inst),
   4540                 .not            => try self.airNot(inst),
   4541                 .ret            => try self.airRet(inst),
   4542                 .ret_load       => try self.airRetLoad(inst),
   4543                 .store          => try self.airStore(inst),
   4544                 .assembly       => try self.airAssembly(inst),
   4545                 .slice_ptr      => try self.airSliceField(inst, 0),
   4546                 .slice_len      => try self.airSliceField(inst, 1),
   4547 
   4548                 .call              => try self.airCall(inst, .Auto),
   4549                 .call_always_tail  => try self.airCall(inst, .AlwaysTail),
   4550                 .call_never_tail   => try self.airCall(inst, .NeverTail),
   4551                 .call_never_inline => try self.airCall(inst, .NeverInline),
   4552 
   4553                 .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0),
   4554                 .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1),
   4555 
   4556                 .float_to_int           => try self.airFloatToInt(inst, false),
   4557                 .float_to_int_optimized => try self.airFloatToInt(inst, true),
   4558 
   4559                 .array_to_slice => try self.airArrayToSlice(inst),
   4560                 .int_to_float   => try self.airIntToFloat(inst),
   4561                 .cmpxchg_weak   => try self.airCmpxchg(inst, true),
   4562                 .cmpxchg_strong => try self.airCmpxchg(inst, false),
   4563                 .fence          => try self.airFence(inst),
   4564                 .atomic_rmw     => try self.airAtomicRmw(inst),
   4565                 .atomic_load    => try self.airAtomicLoad(inst),
   4566                 .memset         => try self.airMemset(inst),
   4567                 .memcpy         => try self.airMemcpy(inst),
   4568                 .set_union_tag  => try self.airSetUnionTag(inst),
   4569                 .get_union_tag  => try self.airGetUnionTag(inst),
   4570                 .clz            => try self.airClzCtz(inst, "llvm.ctlz"),
   4571                 .ctz            => try self.airClzCtz(inst, "llvm.cttz"),
   4572                 .popcount       => try self.airBitOp(inst, "llvm.ctpop"),
   4573                 .byte_swap      => try self.airByteSwap(inst, "llvm.bswap"),
   4574                 .bit_reverse    => try self.airBitOp(inst, "llvm.bitreverse"),
   4575                 .tag_name       => try self.airTagName(inst),
   4576                 .error_name     => try self.airErrorName(inst),
   4577                 .splat          => try self.airSplat(inst),
   4578                 .select         => try self.airSelect(inst),
   4579                 .shuffle        => try self.airShuffle(inst),
   4580                 .aggregate_init => try self.airAggregateInit(inst),
   4581                 .union_init     => try self.airUnionInit(inst),
   4582                 .prefetch       => try self.airPrefetch(inst),
   4583                 .addrspace_cast => try self.airAddrSpaceCast(inst),
   4584 
   4585                 .is_named_enum_value => try self.airIsNamedEnumValue(inst),
   4586                 .error_set_has_value => try self.airErrorSetHasValue(inst),
   4587 
   4588                 .reduce           => try self.airReduce(inst, false),
   4589                 .reduce_optimized => try self.airReduce(inst, true),
   4590 
   4591                 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
   4592                 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
   4593                 .atomic_store_release   => try self.airAtomicStore(inst, .Release),
   4594                 .atomic_store_seq_cst   => try self.airAtomicStore(inst, .SequentiallyConsistent),
   4595 
   4596                 .struct_field_ptr => try self.airStructFieldPtr(inst),
   4597                 .struct_field_val => try self.airStructFieldVal(inst),
   4598 
   4599                 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
   4600                 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
   4601                 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
   4602                 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
   4603 
   4604                 .field_parent_ptr => try self.airFieldParentPtr(inst),
   4605 
   4606                 .array_elem_val     => try self.airArrayElemVal(inst),
   4607                 .slice_elem_val     => try self.airSliceElemVal(inst),
   4608                 .slice_elem_ptr     => try self.airSliceElemPtr(inst),
   4609                 .ptr_elem_val       => try self.airPtrElemVal(inst),
   4610                 .ptr_elem_ptr       => try self.airPtrElemPtr(inst),
   4611 
   4612                 .optional_payload         => try self.airOptionalPayload(inst),
   4613                 .optional_payload_ptr     => try self.airOptionalPayloadPtr(inst),
   4614                 .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
   4615 
   4616                 .unwrap_errunion_payload     => try self.airErrUnionPayload(inst, false),
   4617                 .unwrap_errunion_payload_ptr => try self.airErrUnionPayload(inst, true),
   4618                 .unwrap_errunion_err         => try self.airErrUnionErr(inst, false),
   4619                 .unwrap_errunion_err_ptr     => try self.airErrUnionErr(inst, true),
   4620                 .errunion_payload_ptr_set    => try self.airErrUnionPayloadPtrSet(inst),
   4621                 .err_return_trace            => try self.airErrReturnTrace(inst),
   4622                 .set_err_return_trace        => try self.airSetErrReturnTrace(inst),
   4623                 .save_err_return_trace_index => try self.airSaveErrReturnTraceIndex(inst),
   4624 
   4625                 .wrap_optional         => try self.airWrapOptional(inst),
   4626                 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
   4627                 .wrap_errunion_err     => try self.airWrapErrUnionErr(inst),
   4628 
   4629                 .wasm_memory_size => try self.airWasmMemorySize(inst),
   4630                 .wasm_memory_grow => try self.airWasmMemoryGrow(inst),
   4631 
   4632                 .constant => unreachable,
   4633                 .const_ty => unreachable,
   4634                 .unreach  => self.airUnreach(inst),
   4635                 .dbg_stmt => self.airDbgStmt(inst),
   4636                 .dbg_inline_begin => try self.airDbgInlineBegin(inst),
   4637                 .dbg_inline_end => try self.airDbgInlineEnd(inst),
   4638                 .dbg_block_begin => try self.airDbgBlockBegin(),
   4639                 .dbg_block_end => try self.airDbgBlockEnd(),
   4640                 .dbg_var_ptr => try self.airDbgVarPtr(inst),
   4641                 .dbg_var_val => try self.airDbgVarVal(inst),
   4642                 // zig fmt: on
   4643             };
   4644             if (opt_value) |val| {
   4645                 const ref = Air.indexToRef(inst);
   4646                 try self.func_inst_table.putNoClobber(self.gpa, ref, val);
   4647             }
   4648         }
   4649     }
   4650 
   4651     fn airCall(self: *FuncGen, inst: Air.Inst.Index, attr: llvm.CallAttr) !?*llvm.Value {
   4652         const pl_op = self.air.instructions.items(.data)[inst].pl_op;
   4653         const extra = self.air.extraData(Air.Call, pl_op.payload);
   4654         const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]);
   4655         const callee_ty = self.air.typeOf(pl_op.operand);
   4656         const zig_fn_ty = switch (callee_ty.zigTypeTag()) {
   4657             .Fn => callee_ty,
   4658             .Pointer => callee_ty.childType(),
   4659             else => unreachable,
   4660         };
   4661         const fn_info = zig_fn_ty.fnInfo();
   4662         const return_type = fn_info.return_type;
   4663         const llvm_fn = try self.resolveInst(pl_op.operand);
   4664         const target = self.dg.module.getTarget();
   4665         const sret = firstParamSRet(fn_info, target);
   4666 
   4667         var llvm_args = std.ArrayList(*llvm.Value).init(self.gpa);
   4668         defer llvm_args.deinit();
   4669 
   4670         const ret_ptr = if (!sret) null else blk: {
   4671             const llvm_ret_ty = try self.dg.lowerType(return_type);
   4672             const ret_ptr = self.buildAlloca(llvm_ret_ty, return_type.abiAlignment(target));
   4673             try llvm_args.append(ret_ptr);
   4674             break :blk ret_ptr;
   4675         };
   4676 
   4677         if (fn_info.return_type.isError() and
   4678             self.dg.module.comp.bin_file.options.error_return_tracing)
   4679         {
   4680             try llvm_args.append(self.err_ret_trace.?);
   4681         }
   4682 
   4683         var it = iterateParamTypes(self.dg, fn_info);
   4684         while (it.nextCall(self, args)) |lowering| switch (lowering) {
   4685             .no_bits => continue,
   4686             .byval => {
   4687                 const arg = args[it.zig_index - 1];
   4688                 const param_ty = self.air.typeOf(arg);
   4689                 const llvm_arg = try self.resolveInst(arg);
   4690                 const llvm_param_ty = try self.dg.lowerType(param_ty);
   4691                 if (isByRef(param_ty)) {
   4692                     const alignment = param_ty.abiAlignment(target);
   4693                     const load_inst = self.builder.buildLoad(llvm_param_ty, llvm_arg, "");
   4694                     load_inst.setAlignment(alignment);
   4695                     try llvm_args.append(load_inst);
   4696                 } else {
   4697                     if (param_ty.zigTypeTag() == .Pointer) {
   4698                         // We need a bitcast in case of two possibilities:
   4699                         // 1. The parameter type is a pointer to zero-sized type,
   4700                         //    which is always lowered to an LLVM type of `*i8`.
   4701                         // 2. The argument is a global which does act as a pointer, however
   4702                         //    a bitcast is needed in order for the LLVM types to match.
   4703                         const casted_ptr = self.builder.buildBitCast(llvm_arg, llvm_param_ty, "");
   4704                         try llvm_args.append(casted_ptr);
   4705                     } else {
   4706                         try llvm_args.append(llvm_arg);
   4707                     }
   4708                 }
   4709             },
   4710             .byref => {
   4711                 const arg = args[it.zig_index - 1];
   4712                 const param_ty = self.air.typeOf(arg);
   4713                 const llvm_arg = try self.resolveInst(arg);
   4714                 if (isByRef(param_ty)) {
   4715                     try llvm_args.append(llvm_arg);
   4716                 } else {
   4717                     const alignment = param_ty.abiAlignment(target);
   4718                     const param_llvm_ty = llvm_arg.typeOf();
   4719                     const arg_ptr = self.buildAlloca(param_llvm_ty, alignment);
   4720                     const store_inst = self.builder.buildStore(llvm_arg, arg_ptr);
   4721                     store_inst.setAlignment(alignment);
   4722                     try llvm_args.append(arg_ptr);
   4723                 }
   4724             },
   4725             .abi_sized_int => {
   4726                 const arg = args[it.zig_index - 1];
   4727                 const param_ty = self.air.typeOf(arg);
   4728                 const llvm_arg = try self.resolveInst(arg);
   4729                 const abi_size = @intCast(c_uint, param_ty.abiSize(target));
   4730                 const int_llvm_ty = self.dg.context.intType(abi_size * 8);
   4731                 const int_ptr_llvm_ty = int_llvm_ty.pointerType(0);
   4732 
   4733                 if (isByRef(param_ty)) {
   4734                     const alignment = param_ty.abiAlignment(target);
   4735                     const casted_ptr = self.builder.buildBitCast(llvm_arg, int_ptr_llvm_ty, "");
   4736                     const load_inst = self.builder.buildLoad(int_llvm_ty, casted_ptr, "");
   4737                     load_inst.setAlignment(alignment);
   4738                     try llvm_args.append(load_inst);
   4739                 } else {
   4740                     // LLVM does not allow bitcasting structs so we must allocate
   4741                     // a local, bitcast its pointer, store, and then load.
   4742                     const alignment = @max(
   4743                         param_ty.abiAlignment(target),
   4744                         self.dg.object.target_data.abiAlignmentOfType(int_llvm_ty),
   4745                     );
   4746                     const int_ptr = self.buildAlloca(int_llvm_ty, alignment);
   4747                     const param_llvm_ty = try self.dg.lowerType(param_ty);
   4748                     const casted_ptr = self.builder.buildBitCast(int_ptr, param_llvm_ty.pointerType(0), "");
   4749                     const store_inst = self.builder.buildStore(llvm_arg, casted_ptr);
   4750                     store_inst.setAlignment(alignment);
   4751                     const load_inst = self.builder.buildLoad(int_llvm_ty, int_ptr, "");
   4752                     load_inst.setAlignment(alignment);
   4753                     try llvm_args.append(load_inst);
   4754                 }
   4755             },
   4756             .slice => {
   4757                 const arg = args[it.zig_index - 1];
   4758                 const llvm_arg = try self.resolveInst(arg);
   4759                 const ptr = self.builder.buildExtractValue(llvm_arg, 0, "");
   4760                 const len = self.builder.buildExtractValue(llvm_arg, 1, "");
   4761                 try llvm_args.ensureUnusedCapacity(2);
   4762                 llvm_args.appendAssumeCapacity(ptr);
   4763                 llvm_args.appendAssumeCapacity(len);
   4764             },
   4765             .multiple_llvm_ints => {
   4766                 const arg = args[it.zig_index - 1];
   4767                 const param_ty = self.air.typeOf(arg);
   4768                 const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len];
   4769                 const llvm_arg = try self.resolveInst(arg);
   4770                 const is_by_ref = isByRef(param_ty);
   4771                 const arg_ptr = if (is_by_ref) llvm_arg else p: {
   4772                     const p = self.buildAlloca(llvm_arg.typeOf(), null);
   4773                     const store_inst = self.builder.buildStore(llvm_arg, p);
   4774                     store_inst.setAlignment(param_ty.abiAlignment(target));
   4775                     break :p p;
   4776                 };
   4777 
   4778                 var field_types_buf: [8]*llvm.Type = undefined;
   4779                 const field_types = field_types_buf[0..llvm_ints.len];
   4780                 for (llvm_ints) |int_bits, i| {
   4781                     field_types[i] = self.dg.context.intType(int_bits);
   4782                 }
   4783                 const ints_llvm_ty = self.dg.context.structType(field_types.ptr, @intCast(c_uint, field_types.len), .False);
   4784                 const casted_ptr = self.builder.buildBitCast(arg_ptr, ints_llvm_ty.pointerType(0), "");
   4785                 try llvm_args.ensureUnusedCapacity(it.llvm_types_len);
   4786                 for (llvm_ints) |_, i_usize| {
   4787                     const i = @intCast(c_uint, i_usize);
   4788                     const field_ptr = self.builder.buildStructGEP(ints_llvm_ty, casted_ptr, i, "");
   4789                     const load_inst = self.builder.buildLoad(field_types[i], field_ptr, "");
   4790                     load_inst.setAlignment(target.cpu.arch.ptrBitWidth() / 8);
   4791                     llvm_args.appendAssumeCapacity(load_inst);
   4792                 }
   4793             },
   4794             .multiple_llvm_float => {
   4795                 const arg = args[it.zig_index - 1];
   4796                 const param_ty = self.air.typeOf(arg);
   4797                 const llvm_floats = it.llvm_types_buffer[0..it.llvm_types_len];
   4798                 const llvm_arg = try self.resolveInst(arg);
   4799                 const is_by_ref = isByRef(param_ty);
   4800                 const arg_ptr = if (is_by_ref) llvm_arg else p: {
   4801                     const p = self.buildAlloca(llvm_arg.typeOf(), null);
   4802                     const store_inst = self.builder.buildStore(llvm_arg, p);
   4803                     store_inst.setAlignment(param_ty.abiAlignment(target));
   4804                     break :p p;
   4805                 };
   4806 
   4807                 var field_types_buf: [8]*llvm.Type = undefined;
   4808                 const field_types = field_types_buf[0..llvm_floats.len];
   4809                 for (llvm_floats) |float_bits, i| {
   4810                     switch (float_bits) {
   4811                         64 => field_types[i] = self.dg.context.doubleType(),
   4812                         80 => field_types[i] = self.dg.context.x86FP80Type(),
   4813                         else => {},
   4814                     }
   4815                 }
   4816                 const floats_llvm_ty = self.dg.context.structType(field_types.ptr, @intCast(c_uint, field_types.len), .False);
   4817                 const casted_ptr = self.builder.buildBitCast(arg_ptr, floats_llvm_ty.pointerType(0), "");
   4818                 try llvm_args.ensureUnusedCapacity(it.llvm_types_len);
   4819                 for (llvm_floats) |_, i_usize| {
   4820                     const i = @intCast(c_uint, i_usize);
   4821                     const field_ptr = self.builder.buildStructGEP(floats_llvm_ty, casted_ptr, i, "");
   4822                     const load_inst = self.builder.buildLoad(field_types[i], field_ptr, "");
   4823                     load_inst.setAlignment(target.cpu.arch.ptrBitWidth() / 8);
   4824                     llvm_args.appendAssumeCapacity(load_inst);
   4825                 }
   4826             },
   4827             .as_u16 => {
   4828                 const arg = args[it.zig_index - 1];
   4829                 const llvm_arg = try self.resolveInst(arg);
   4830                 const casted = self.builder.buildBitCast(llvm_arg, self.dg.context.intType(16), "");
   4831                 try llvm_args.append(casted);
   4832             },
   4833             .float_array => |count| {
   4834                 const arg = args[it.zig_index - 1];
   4835                 const arg_ty = self.air.typeOf(arg);
   4836                 var llvm_arg = try self.resolveInst(arg);
   4837                 if (!isByRef(arg_ty)) {
   4838                     const p = self.buildAlloca(llvm_arg.typeOf(), null);
   4839                     const store_inst = self.builder.buildStore(llvm_arg, p);
   4840                     store_inst.setAlignment(arg_ty.abiAlignment(target));
   4841                     llvm_arg = store_inst;
   4842                 }
   4843 
   4844                 const float_ty = try self.dg.lowerType(aarch64_c_abi.getFloatArrayType(arg_ty).?);
   4845                 const array_llvm_ty = float_ty.arrayType(count);
   4846 
   4847                 const casted = self.builder.buildBitCast(llvm_arg, array_llvm_ty.pointerType(0), "");
   4848                 const alignment = arg_ty.abiAlignment(target);
   4849                 const load_inst = self.builder.buildLoad(array_llvm_ty, casted, "");
   4850                 load_inst.setAlignment(alignment);
   4851                 try llvm_args.append(load_inst);
   4852             },
   4853             .i32_array, .i64_array => |arr_len| {
   4854                 const elem_size: u8 = if (lowering == .i32_array) 32 else 64;
   4855                 const arg = args[it.zig_index - 1];
   4856                 const arg_ty = self.air.typeOf(arg);
   4857                 var llvm_arg = try self.resolveInst(arg);
   4858                 if (!isByRef(arg_ty)) {
   4859                     const p = self.buildAlloca(llvm_arg.typeOf(), null);
   4860                     const store_inst = self.builder.buildStore(llvm_arg, p);
   4861                     store_inst.setAlignment(arg_ty.abiAlignment(target));
   4862                     llvm_arg = store_inst;
   4863                 }
   4864 
   4865                 const array_llvm_ty = self.dg.context.intType(elem_size).arrayType(arr_len);
   4866                 const casted = self.builder.buildBitCast(llvm_arg, array_llvm_ty.pointerType(0), "");
   4867                 const alignment = arg_ty.abiAlignment(target);
   4868                 const load_inst = self.builder.buildLoad(array_llvm_ty, casted, "");
   4869                 load_inst.setAlignment(alignment);
   4870                 try llvm_args.append(load_inst);
   4871             },
   4872         };
   4873 
   4874         const call = self.builder.buildCall(
   4875             try self.dg.lowerType(zig_fn_ty),
   4876             llvm_fn,
   4877             llvm_args.items.ptr,
   4878             @intCast(c_uint, llvm_args.items.len),
   4879             toLlvmCallConv(fn_info.cc, target),
   4880             attr,
   4881             "",
   4882         );
   4883 
   4884         if (return_type.isNoReturn() and attr != .AlwaysTail) {
   4885             _ = self.builder.buildUnreachable();
   4886             return null;
   4887         }
   4888 
   4889         if (self.liveness.isUnused(inst) or !return_type.hasRuntimeBitsIgnoreComptime()) {
   4890             return null;
   4891         }
   4892 
   4893         const llvm_ret_ty = try self.dg.lowerType(return_type);
   4894 
   4895         if (ret_ptr) |rp| {
   4896             call.setCallSret(llvm_ret_ty);
   4897             if (isByRef(return_type)) {
   4898                 return rp;
   4899             } else {
   4900                 // our by-ref status disagrees with sret so we must load.
   4901                 const loaded = self.builder.buildLoad(llvm_ret_ty, rp, "");
   4902                 loaded.setAlignment(return_type.abiAlignment(target));
   4903                 return loaded;
   4904             }
   4905         }
   4906 
   4907         const abi_ret_ty = try lowerFnRetTy(self.dg, fn_info);
   4908 
   4909         if (abi_ret_ty != llvm_ret_ty) {
   4910             // In this case the function return type is honoring the calling convention by having
   4911             // a different LLVM type than the usual one. We solve this here at the callsite
   4912             // by bitcasting a pointer to our canonical type, then loading it if necessary.
   4913             const alignment = return_type.abiAlignment(target);
   4914             const rp = self.buildAlloca(llvm_ret_ty, alignment);
   4915             const ptr_abi_ty = abi_ret_ty.pointerType(0);
   4916             const casted_ptr = self.builder.buildBitCast(rp, ptr_abi_ty, "");
   4917             const store_inst = self.builder.buildStore(call, casted_ptr);
   4918             store_inst.setAlignment(alignment);
   4919             if (isByRef(return_type)) {
   4920                 return rp;
   4921             } else {
   4922                 const load_inst = self.builder.buildLoad(llvm_ret_ty, rp, "");
   4923                 load_inst.setAlignment(alignment);
   4924                 return load_inst;
   4925             }
   4926         }
   4927 
   4928         if (isByRef(return_type)) {
   4929             // our by-ref status disagrees with sret so we must allocate, store,
   4930             // and return the allocation pointer.
   4931             const alignment = return_type.abiAlignment(target);
   4932             const rp = self.buildAlloca(llvm_ret_ty, alignment);
   4933             const store_inst = self.builder.buildStore(call, rp);
   4934             store_inst.setAlignment(alignment);
   4935             return rp;
   4936         } else {
   4937             return call;
   4938         }
   4939     }
   4940 
   4941     fn airRet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   4942         const un_op = self.air.instructions.items(.data)[inst].un_op;
   4943         const ret_ty = self.air.typeOf(un_op);
   4944         if (self.ret_ptr) |ret_ptr| {
   4945             const operand = try self.resolveInst(un_op);
   4946             var ptr_ty_payload: Type.Payload.ElemType = .{
   4947                 .base = .{ .tag = .single_mut_pointer },
   4948                 .data = ret_ty,
   4949             };
   4950             const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
   4951             self.store(ret_ptr, ptr_ty, operand, .NotAtomic);
   4952             _ = self.builder.buildRetVoid();
   4953             return null;
   4954         }
   4955         const fn_info = self.dg.decl.ty.fnInfo();
   4956         if (!ret_ty.hasRuntimeBitsIgnoreComptime()) {
   4957             if (fn_info.return_type.isError()) {
   4958                 // Functions with an empty error set are emitted with an error code
   4959                 // return type and return zero so they can be function pointers coerced
   4960                 // to functions that return anyerror.
   4961                 const err_int = try self.dg.lowerType(Type.anyerror);
   4962                 _ = self.builder.buildRet(err_int.constInt(0, .False));
   4963             } else {
   4964                 _ = self.builder.buildRetVoid();
   4965             }
   4966             return null;
   4967         }
   4968 
   4969         const abi_ret_ty = try lowerFnRetTy(self.dg, fn_info);
   4970         const ptr_abi_ty = abi_ret_ty.pointerType(0);
   4971         const operand = try self.resolveInst(un_op);
   4972         const target = self.dg.module.getTarget();
   4973         const alignment = ret_ty.abiAlignment(target);
   4974 
   4975         if (isByRef(ret_ty)) {
   4976             // operand is a pointer however self.ret_ptr is null so that means
   4977             // we need to return a value.
   4978             const casted_ptr = self.builder.buildBitCast(operand, ptr_abi_ty, "");
   4979             const load_inst = self.builder.buildLoad(abi_ret_ty, casted_ptr, "");
   4980             load_inst.setAlignment(alignment);
   4981             _ = self.builder.buildRet(load_inst);
   4982             return null;
   4983         }
   4984 
   4985         const llvm_ret_ty = operand.typeOf();
   4986         if (abi_ret_ty == llvm_ret_ty) {
   4987             _ = self.builder.buildRet(operand);
   4988             return null;
   4989         }
   4990 
   4991         const rp = self.buildAlloca(llvm_ret_ty, alignment);
   4992         const store_inst = self.builder.buildStore(operand, rp);
   4993         store_inst.setAlignment(alignment);
   4994         const casted_ptr = self.builder.buildBitCast(rp, ptr_abi_ty, "");
   4995         const load_inst = self.builder.buildLoad(abi_ret_ty, casted_ptr, "");
   4996         load_inst.setAlignment(alignment);
   4997         _ = self.builder.buildRet(load_inst);
   4998         return null;
   4999     }
   5000 
   5001     fn airRetLoad(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5002         const un_op = self.air.instructions.items(.data)[inst].un_op;
   5003         const ptr_ty = self.air.typeOf(un_op);
   5004         const ret_ty = ptr_ty.childType();
   5005         const fn_info = self.dg.decl.ty.fnInfo();
   5006         if (!ret_ty.hasRuntimeBitsIgnoreComptime()) {
   5007             if (fn_info.return_type.isError()) {
   5008                 // Functions with an empty error set are emitted with an error code
   5009                 // return type and return zero so they can be function pointers coerced
   5010                 // to functions that return anyerror.
   5011                 const err_int = try self.dg.lowerType(Type.anyerror);
   5012                 _ = self.builder.buildRet(err_int.constInt(0, .False));
   5013             } else {
   5014                 _ = self.builder.buildRetVoid();
   5015             }
   5016             return null;
   5017         }
   5018         if (self.ret_ptr != null) {
   5019             _ = self.builder.buildRetVoid();
   5020             return null;
   5021         }
   5022         const ptr = try self.resolveInst(un_op);
   5023         const target = self.dg.module.getTarget();
   5024         const abi_ret_ty = try lowerFnRetTy(self.dg, fn_info);
   5025         const llvm_ret_ty = try self.dg.lowerType(ret_ty);
   5026         const casted_ptr = if (abi_ret_ty == llvm_ret_ty) ptr else p: {
   5027             const ptr_abi_ty = abi_ret_ty.pointerType(0);
   5028             break :p self.builder.buildBitCast(ptr, ptr_abi_ty, "");
   5029         };
   5030         const loaded = self.builder.buildLoad(abi_ret_ty, casted_ptr, "");
   5031         loaded.setAlignment(ret_ty.abiAlignment(target));
   5032         _ = self.builder.buildRet(loaded);
   5033         return null;
   5034     }
   5035 
   5036     fn airCmp(self: *FuncGen, inst: Air.Inst.Index, op: math.CompareOperator, want_fast_math: bool) !?*llvm.Value {
   5037         if (self.liveness.isUnused(inst)) return null;
   5038         self.builder.setFastMath(want_fast_math);
   5039 
   5040         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   5041         const lhs = try self.resolveInst(bin_op.lhs);
   5042         const rhs = try self.resolveInst(bin_op.rhs);
   5043         const operand_ty = self.air.typeOf(bin_op.lhs);
   5044 
   5045         return self.cmp(lhs, rhs, operand_ty, op);
   5046     }
   5047 
   5048     fn airCmpVector(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
   5049         if (self.liveness.isUnused(inst)) return null;
   5050         self.builder.setFastMath(want_fast_math);
   5051 
   5052         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
   5053         const extra = self.air.extraData(Air.VectorCmp, ty_pl.payload).data;
   5054 
   5055         const lhs = try self.resolveInst(extra.lhs);
   5056         const rhs = try self.resolveInst(extra.rhs);
   5057         const vec_ty = self.air.typeOf(extra.lhs);
   5058         const cmp_op = extra.compareOperator();
   5059 
   5060         return self.cmp(lhs, rhs, vec_ty, cmp_op);
   5061     }
   5062 
   5063     fn airCmpLtErrorsLen(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5064         if (self.liveness.isUnused(inst)) return null;
   5065 
   5066         const un_op = self.air.instructions.items(.data)[inst].un_op;
   5067         const operand = try self.resolveInst(un_op);
   5068         const llvm_fn = try self.getCmpLtErrorsLenFunction();
   5069         const args: [1]*llvm.Value = .{operand};
   5070         return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");
   5071     }
   5072 
   5073     fn cmp(
   5074         self: *FuncGen,
   5075         lhs: *llvm.Value,
   5076         rhs: *llvm.Value,
   5077         operand_ty: Type,
   5078         op: math.CompareOperator,
   5079     ) Allocator.Error!*llvm.Value {
   5080         var int_buffer: Type.Payload.Bits = undefined;
   5081         var opt_buffer: Type.Payload.ElemType = undefined;
   5082 
   5083         const scalar_ty = operand_ty.scalarType();
   5084         const int_ty = switch (scalar_ty.zigTypeTag()) {
   5085             .Enum => scalar_ty.intTagType(&int_buffer),
   5086             .Int, .Bool, .Pointer, .ErrorSet => scalar_ty,
   5087             .Optional => blk: {
   5088                 const payload_ty = operand_ty.optionalChild(&opt_buffer);
   5089                 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or
   5090                     operand_ty.optionalReprIsPayload())
   5091                 {
   5092                     break :blk operand_ty;
   5093                 }
   5094                 // We need to emit instructions to check for equality/inequality
   5095                 // of optionals that are not pointers.
   5096                 const is_by_ref = isByRef(scalar_ty);
   5097                 const opt_llvm_ty = try self.dg.lowerType(scalar_ty);
   5098                 const lhs_non_null = self.optIsNonNull(opt_llvm_ty, lhs, is_by_ref);
   5099                 const rhs_non_null = self.optIsNonNull(opt_llvm_ty, rhs, is_by_ref);
   5100                 const llvm_i2 = self.context.intType(2);
   5101                 const lhs_non_null_i2 = self.builder.buildZExt(lhs_non_null, llvm_i2, "");
   5102                 const rhs_non_null_i2 = self.builder.buildZExt(rhs_non_null, llvm_i2, "");
   5103                 const lhs_shifted = self.builder.buildShl(lhs_non_null_i2, llvm_i2.constInt(1, .False), "");
   5104                 const lhs_rhs_ored = self.builder.buildOr(lhs_shifted, rhs_non_null_i2, "");
   5105                 const both_null_block = self.context.appendBasicBlock(self.llvm_func, "BothNull");
   5106                 const mixed_block = self.context.appendBasicBlock(self.llvm_func, "Mixed");
   5107                 const both_pl_block = self.context.appendBasicBlock(self.llvm_func, "BothNonNull");
   5108                 const end_block = self.context.appendBasicBlock(self.llvm_func, "End");
   5109                 const llvm_switch = self.builder.buildSwitch(lhs_rhs_ored, mixed_block, 2);
   5110                 const llvm_i2_00 = llvm_i2.constInt(0b00, .False);
   5111                 const llvm_i2_11 = llvm_i2.constInt(0b11, .False);
   5112                 llvm_switch.addCase(llvm_i2_00, both_null_block);
   5113                 llvm_switch.addCase(llvm_i2_11, both_pl_block);
   5114 
   5115                 self.builder.positionBuilderAtEnd(both_null_block);
   5116                 _ = self.builder.buildBr(end_block);
   5117 
   5118                 self.builder.positionBuilderAtEnd(mixed_block);
   5119                 _ = self.builder.buildBr(end_block);
   5120 
   5121                 self.builder.positionBuilderAtEnd(both_pl_block);
   5122                 const lhs_payload = try self.optPayloadHandle(opt_llvm_ty, lhs, scalar_ty);
   5123                 const rhs_payload = try self.optPayloadHandle(opt_llvm_ty, rhs, scalar_ty);
   5124                 const payload_cmp = try self.cmp(lhs_payload, rhs_payload, payload_ty, op);
   5125                 _ = self.builder.buildBr(end_block);
   5126                 const both_pl_block_end = self.builder.getInsertBlock();
   5127 
   5128                 self.builder.positionBuilderAtEnd(end_block);
   5129                 const incoming_blocks: [3]*llvm.BasicBlock = .{
   5130                     both_null_block,
   5131                     mixed_block,
   5132                     both_pl_block_end,
   5133                 };
   5134                 const llvm_i1 = self.context.intType(1);
   5135                 const llvm_i1_0 = llvm_i1.constInt(0, .False);
   5136                 const llvm_i1_1 = llvm_i1.constInt(1, .False);
   5137                 const incoming_values: [3]*llvm.Value = .{
   5138                     switch (op) {
   5139                         .eq => llvm_i1_1,
   5140                         .neq => llvm_i1_0,
   5141                         else => unreachable,
   5142                     },
   5143                     switch (op) {
   5144                         .eq => llvm_i1_0,
   5145                         .neq => llvm_i1_1,
   5146                         else => unreachable,
   5147                     },
   5148                     payload_cmp,
   5149                 };
   5150 
   5151                 const phi_node = self.builder.buildPhi(llvm_i1, "");
   5152                 comptime assert(incoming_values.len == incoming_blocks.len);
   5153                 phi_node.addIncoming(
   5154                     &incoming_values,
   5155                     &incoming_blocks,
   5156                     incoming_values.len,
   5157                 );
   5158                 return phi_node;
   5159             },
   5160             .Float => return self.buildFloatCmp(op, operand_ty, .{ lhs, rhs }),
   5161             else => unreachable,
   5162         };
   5163         const is_signed = int_ty.isSignedInt();
   5164         const operation: llvm.IntPredicate = switch (op) {
   5165             .eq => .EQ,
   5166             .neq => .NE,
   5167             .lt => if (is_signed) llvm.IntPredicate.SLT else .ULT,
   5168             .lte => if (is_signed) llvm.IntPredicate.SLE else .ULE,
   5169             .gt => if (is_signed) llvm.IntPredicate.SGT else .UGT,
   5170             .gte => if (is_signed) llvm.IntPredicate.SGE else .UGE,
   5171         };
   5172         return self.builder.buildICmp(operation, lhs, rhs, "");
   5173     }
   5174 
   5175     fn airBlock(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5176         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
   5177         const extra = self.air.extraData(Air.Block, ty_pl.payload);
   5178         const body = self.air.extra[extra.end..][0..extra.data.body_len];
   5179         const inst_ty = self.air.typeOfIndex(inst);
   5180         const parent_bb = self.context.createBasicBlock("Block");
   5181 
   5182         if (inst_ty.isNoReturn()) {
   5183             try self.genBody(body);
   5184             return null;
   5185         }
   5186 
   5187         var breaks: BreakList = .{};
   5188         defer breaks.deinit(self.gpa);
   5189 
   5190         try self.blocks.putNoClobber(self.gpa, inst, .{
   5191             .parent_bb = parent_bb,
   5192             .breaks = &breaks,
   5193         });
   5194         defer assert(self.blocks.remove(inst));
   5195 
   5196         try self.genBody(body);
   5197 
   5198         self.llvm_func.appendExistingBasicBlock(parent_bb);
   5199         self.builder.positionBuilderAtEnd(parent_bb);
   5200 
   5201         // Create a phi node only if the block returns a value.
   5202         const is_body = inst_ty.zigTypeTag() == .Fn;
   5203         if (!is_body and !inst_ty.hasRuntimeBitsIgnoreComptime()) return null;
   5204 
   5205         const raw_llvm_ty = try self.dg.lowerType(inst_ty);
   5206 
   5207         const llvm_ty = ty: {
   5208             // If the zig tag type is a function, this represents an actual function body; not
   5209             // a pointer to it. LLVM IR allows the call instruction to use function bodies instead
   5210             // of function pointers, however the phi makes it a runtime value and therefore
   5211             // the LLVM type has to be wrapped in a pointer.
   5212             if (is_body or isByRef(inst_ty)) {
   5213                 break :ty raw_llvm_ty.pointerType(0);
   5214             }
   5215             break :ty raw_llvm_ty;
   5216         };
   5217 
   5218         const phi_node = self.builder.buildPhi(llvm_ty, "");
   5219         phi_node.addIncoming(
   5220             breaks.items(.val).ptr,
   5221             breaks.items(.bb).ptr,
   5222             @intCast(c_uint, breaks.len),
   5223         );
   5224         return phi_node;
   5225     }
   5226 
   5227     fn airBr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5228         const branch = self.air.instructions.items(.data)[inst].br;
   5229         const block = self.blocks.get(branch.block_inst).?;
   5230 
   5231         // Add the values to the lists only if the break provides a value.
   5232         const operand_ty = self.air.typeOf(branch.operand);
   5233         if (operand_ty.hasRuntimeBitsIgnoreComptime() or operand_ty.zigTypeTag() == .Fn) {
   5234             const val = try self.resolveInst(branch.operand);
   5235 
   5236             // For the phi node, we need the basic blocks and the values of the
   5237             // break instructions.
   5238             try block.breaks.append(self.gpa, .{
   5239                 .bb = self.builder.getInsertBlock(),
   5240                 .val = val,
   5241             });
   5242         }
   5243         _ = self.builder.buildBr(block.parent_bb);
   5244         return null;
   5245     }
   5246 
   5247     fn airCondBr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5248         const pl_op = self.air.instructions.items(.data)[inst].pl_op;
   5249         const cond = try self.resolveInst(pl_op.operand);
   5250         const extra = self.air.extraData(Air.CondBr, pl_op.payload);
   5251         const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len];
   5252         const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
   5253 
   5254         const then_block = self.context.appendBasicBlock(self.llvm_func, "Then");
   5255         const else_block = self.context.appendBasicBlock(self.llvm_func, "Else");
   5256         _ = self.builder.buildCondBr(cond, then_block, else_block);
   5257 
   5258         self.builder.positionBuilderAtEnd(then_block);
   5259         try self.genBody(then_body);
   5260 
   5261         self.builder.positionBuilderAtEnd(else_block);
   5262         try self.genBody(else_body);
   5263 
   5264         // No need to reset the insert cursor since this instruction is noreturn.
   5265         return null;
   5266     }
   5267 
   5268     fn airTry(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5269         const pl_op = self.air.instructions.items(.data)[inst].pl_op;
   5270         const err_union = try self.resolveInst(pl_op.operand);
   5271         const extra = self.air.extraData(Air.Try, pl_op.payload);
   5272         const body = self.air.extra[extra.end..][0..extra.data.body_len];
   5273         const err_union_ty = self.air.typeOf(pl_op.operand);
   5274         const result_ty = self.air.typeOfIndex(inst);
   5275         return lowerTry(self, err_union, body, err_union_ty, false, result_ty);
   5276     }
   5277 
   5278     fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5279         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
   5280         const extra = self.air.extraData(Air.TryPtr, ty_pl.payload);
   5281         const err_union_ptr = try self.resolveInst(extra.data.ptr);
   5282         const body = self.air.extra[extra.end..][0..extra.data.body_len];
   5283         const err_union_ty = self.air.typeOf(extra.data.ptr).childType();
   5284         const result_ty = self.air.typeOfIndex(inst);
   5285         return lowerTry(self, err_union_ptr, body, err_union_ty, true, result_ty);
   5286     }
   5287 
   5288     fn lowerTry(
   5289         fg: *FuncGen,
   5290         err_union: *llvm.Value,
   5291         body: []const Air.Inst.Index,
   5292         err_union_ty: Type,
   5293         operand_is_ptr: bool,
   5294         result_ty: Type,
   5295     ) !?*llvm.Value {
   5296         const payload_ty = err_union_ty.errorUnionPayload();
   5297         const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime();
   5298         const target = fg.dg.module.getTarget();
   5299         const err_union_llvm_ty = try fg.dg.lowerType(err_union_ty);
   5300 
   5301         if (!err_union_ty.errorUnionSet().errorSetIsEmpty()) {
   5302             const is_err = err: {
   5303                 const err_set_ty = try fg.dg.lowerType(Type.anyerror);
   5304                 const zero = err_set_ty.constNull();
   5305                 if (!payload_has_bits) {
   5306                     // TODO add alignment to this load
   5307                     const loaded = if (operand_is_ptr)
   5308                         fg.builder.buildLoad(err_set_ty, err_union, "")
   5309                     else
   5310                         err_union;
   5311                     break :err fg.builder.buildICmp(.NE, loaded, zero, "");
   5312                 }
   5313                 const err_field_index = errUnionErrorOffset(payload_ty, target);
   5314                 if (operand_is_ptr or isByRef(err_union_ty)) {
   5315                     const err_field_ptr = fg.builder.buildStructGEP(err_union_llvm_ty, err_union, err_field_index, "");
   5316                     // TODO add alignment to this load
   5317                     const loaded = fg.builder.buildLoad(err_set_ty, err_field_ptr, "");
   5318                     break :err fg.builder.buildICmp(.NE, loaded, zero, "");
   5319                 }
   5320                 const loaded = fg.builder.buildExtractValue(err_union, err_field_index, "");
   5321                 break :err fg.builder.buildICmp(.NE, loaded, zero, "");
   5322             };
   5323 
   5324             const return_block = fg.context.appendBasicBlock(fg.llvm_func, "TryRet");
   5325             const continue_block = fg.context.appendBasicBlock(fg.llvm_func, "TryCont");
   5326             _ = fg.builder.buildCondBr(is_err, return_block, continue_block);
   5327 
   5328             fg.builder.positionBuilderAtEnd(return_block);
   5329             try fg.genBody(body);
   5330 
   5331             fg.builder.positionBuilderAtEnd(continue_block);
   5332         }
   5333         if (!payload_has_bits) {
   5334             if (!operand_is_ptr) return null;
   5335 
   5336             // TODO once we update to an LLVM version with opaque pointers
   5337             // this bitcast won't be necessary.
   5338             const res_ptr_ty = try fg.dg.lowerType(result_ty);
   5339             return fg.builder.buildBitCast(err_union, res_ptr_ty, "");
   5340         }
   5341         const offset = errUnionPayloadOffset(payload_ty, target);
   5342         if (operand_is_ptr or isByRef(payload_ty)) {
   5343             return fg.builder.buildStructGEP(err_union_llvm_ty, err_union, offset, "");
   5344         } else if (isByRef(err_union_ty)) {
   5345             const payload_ptr = fg.builder.buildStructGEP(err_union_llvm_ty, err_union, offset, "");
   5346             if (isByRef(payload_ty)) {
   5347                 return payload_ptr;
   5348             }
   5349             const load_inst = fg.builder.buildLoad(payload_ptr.getGEPResultElementType(), payload_ptr, "");
   5350             load_inst.setAlignment(payload_ty.abiAlignment(target));
   5351             return load_inst;
   5352         }
   5353         return fg.builder.buildExtractValue(err_union, offset, "");
   5354     }
   5355 
   5356     fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5357         const pl_op = self.air.instructions.items(.data)[inst].pl_op;
   5358         const cond = try self.resolveInst(pl_op.operand);
   5359         const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload);
   5360         const else_block = self.context.appendBasicBlock(self.llvm_func, "Else");
   5361         const target = self.dg.module.getTarget();
   5362         const llvm_usize = self.context.intType(target.cpu.arch.ptrBitWidth());
   5363         const cond_int = if (cond.typeOf().getTypeKind() == .Pointer)
   5364             self.builder.buildPtrToInt(cond, llvm_usize, "")
   5365         else
   5366             cond;
   5367         const llvm_switch = self.builder.buildSwitch(cond_int, else_block, switch_br.data.cases_len);
   5368 
   5369         var extra_index: usize = switch_br.end;
   5370         var case_i: u32 = 0;
   5371 
   5372         while (case_i < switch_br.data.cases_len) : (case_i += 1) {
   5373             const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
   5374             const items = @ptrCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]);
   5375             const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
   5376             extra_index = case.end + case.data.items_len + case_body.len;
   5377 
   5378             const case_block = self.context.appendBasicBlock(self.llvm_func, "Case");
   5379 
   5380             for (items) |item| {
   5381                 const llvm_item = try self.resolveInst(item);
   5382                 const llvm_int_item = if (llvm_item.typeOf().getTypeKind() == .Pointer)
   5383                     llvm_item.constPtrToInt(llvm_usize)
   5384                 else
   5385                     llvm_item;
   5386                 llvm_switch.addCase(llvm_int_item, case_block);
   5387             }
   5388 
   5389             self.builder.positionBuilderAtEnd(case_block);
   5390             try self.genBody(case_body);
   5391         }
   5392 
   5393         self.builder.positionBuilderAtEnd(else_block);
   5394         const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];
   5395         if (else_body.len != 0) {
   5396             try self.genBody(else_body);
   5397         } else {
   5398             _ = self.builder.buildUnreachable();
   5399         }
   5400 
   5401         // No need to reset the insert cursor since this instruction is noreturn.
   5402         return null;
   5403     }
   5404 
   5405     fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5406         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
   5407         const loop = self.air.extraData(Air.Block, ty_pl.payload);
   5408         const body = self.air.extra[loop.end..][0..loop.data.body_len];
   5409         const loop_block = self.context.appendBasicBlock(self.llvm_func, "Loop");
   5410         _ = self.builder.buildBr(loop_block);
   5411 
   5412         self.builder.positionBuilderAtEnd(loop_block);
   5413         try self.genBody(body);
   5414 
   5415         // TODO instead of this logic, change AIR to have the property that
   5416         // every block is guaranteed to end with a noreturn instruction.
   5417         // Then we can simply rely on the fact that a repeat or break instruction
   5418         // would have been emitted already. Also the main loop in genBody can
   5419         // be while(true) instead of for(body), which will eliminate 1 branch on
   5420         // a hot path.
   5421         if (body.len == 0 or !self.air.typeOfIndex(body[body.len - 1]).isNoReturn()) {
   5422             _ = self.builder.buildBr(loop_block);
   5423         }
   5424         return null;
   5425     }
   5426 
   5427     fn airArrayToSlice(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5428         if (self.liveness.isUnused(inst))
   5429             return null;
   5430 
   5431         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   5432         const operand_ty = self.air.typeOf(ty_op.operand);
   5433         const array_ty = operand_ty.childType();
   5434         const llvm_usize = try self.dg.lowerType(Type.usize);
   5435         const len = llvm_usize.constInt(array_ty.arrayLen(), .False);
   5436         const slice_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
   5437         if (!array_ty.hasRuntimeBitsIgnoreComptime()) {
   5438             return self.builder.buildInsertValue(slice_llvm_ty.getUndef(), len, 1, "");
   5439         }
   5440         const operand = try self.resolveInst(ty_op.operand);
   5441         const indices: [2]*llvm.Value = .{
   5442             llvm_usize.constNull(), llvm_usize.constNull(),
   5443         };
   5444         const array_llvm_ty = try self.dg.lowerType(array_ty);
   5445         const ptr = self.builder.buildInBoundsGEP(array_llvm_ty, operand, &indices, indices.len, "");
   5446         const partial = self.builder.buildInsertValue(slice_llvm_ty.getUndef(), ptr, 0, "");
   5447         return self.builder.buildInsertValue(partial, len, 1, "");
   5448     }
   5449 
   5450     fn airIntToFloat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5451         if (self.liveness.isUnused(inst))
   5452             return null;
   5453 
   5454         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   5455 
   5456         const operand = try self.resolveInst(ty_op.operand);
   5457         const operand_ty = self.air.typeOf(ty_op.operand);
   5458         const operand_scalar_ty = operand_ty.scalarType();
   5459 
   5460         const dest_ty = self.air.typeOfIndex(inst);
   5461         const dest_scalar_ty = dest_ty.scalarType();
   5462         const dest_llvm_ty = try self.dg.lowerType(dest_ty);
   5463         const target = self.dg.module.getTarget();
   5464 
   5465         if (intrinsicsAllowed(dest_scalar_ty, target)) {
   5466             if (operand_scalar_ty.isSignedInt()) {
   5467                 return self.builder.buildSIToFP(operand, dest_llvm_ty, "");
   5468             } else {
   5469                 return self.builder.buildUIToFP(operand, dest_llvm_ty, "");
   5470             }
   5471         }
   5472 
   5473         const operand_bits = @intCast(u16, operand_scalar_ty.bitSize(target));
   5474         const rt_int_bits = compilerRtIntBits(operand_bits);
   5475         const rt_int_ty = self.context.intType(rt_int_bits);
   5476         var extended = e: {
   5477             if (operand_scalar_ty.isSignedInt()) {
   5478                 break :e self.builder.buildSExtOrBitCast(operand, rt_int_ty, "");
   5479             } else {
   5480                 break :e self.builder.buildZExtOrBitCast(operand, rt_int_ty, "");
   5481             }
   5482         };
   5483         const dest_bits = dest_scalar_ty.floatBits(target);
   5484         const compiler_rt_operand_abbrev = compilerRtIntAbbrev(rt_int_bits);
   5485         const compiler_rt_dest_abbrev = compilerRtFloatAbbrev(dest_bits);
   5486         const sign_prefix = if (operand_scalar_ty.isSignedInt()) "" else "un";
   5487         var fn_name_buf: [64]u8 = undefined;
   5488         const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__float{s}{s}i{s}f", .{
   5489             sign_prefix,
   5490             compiler_rt_operand_abbrev,
   5491             compiler_rt_dest_abbrev,
   5492         }) catch unreachable;
   5493 
   5494         var param_types = [1]*llvm.Type{rt_int_ty};
   5495         if (rt_int_bits == 128 and (target.os.tag == .windows and target.cpu.arch == .x86_64)) {
   5496             // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard
   5497             // i128 calling convention to adhere to the ABI that LLVM expects compiler-rt to have.
   5498             const v2i64 = self.context.intType(64).vectorType(2);
   5499             extended = self.builder.buildBitCast(extended, v2i64, "");
   5500             param_types = [1]*llvm.Type{v2i64};
   5501         }
   5502 
   5503         const libc_fn = self.getLibcFunction(fn_name, &param_types, dest_llvm_ty);
   5504         const params = [1]*llvm.Value{extended};
   5505 
   5506         return self.builder.buildCall(libc_fn.globalGetValueType(), libc_fn, &params, params.len, .C, .Auto, "");
   5507     }
   5508 
   5509     fn airFloatToInt(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
   5510         if (self.liveness.isUnused(inst))
   5511             return null;
   5512 
   5513         self.builder.setFastMath(want_fast_math);
   5514 
   5515         const target = self.dg.module.getTarget();
   5516         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   5517 
   5518         const operand = try self.resolveInst(ty_op.operand);
   5519         const operand_ty = self.air.typeOf(ty_op.operand);
   5520         const operand_scalar_ty = operand_ty.scalarType();
   5521 
   5522         const dest_ty = self.air.typeOfIndex(inst);
   5523         const dest_scalar_ty = dest_ty.scalarType();
   5524         const dest_llvm_ty = try self.dg.lowerType(dest_ty);
   5525 
   5526         if (intrinsicsAllowed(operand_scalar_ty, target)) {
   5527             // TODO set fast math flag
   5528             if (dest_scalar_ty.isSignedInt()) {
   5529                 return self.builder.buildFPToSI(operand, dest_llvm_ty, "");
   5530             } else {
   5531                 return self.builder.buildFPToUI(operand, dest_llvm_ty, "");
   5532             }
   5533         }
   5534 
   5535         const rt_int_bits = compilerRtIntBits(@intCast(u16, dest_scalar_ty.bitSize(target)));
   5536         const ret_ty = self.context.intType(rt_int_bits);
   5537         const libc_ret_ty = if (rt_int_bits == 128 and (target.os.tag == .windows and target.cpu.arch == .x86_64)) b: {
   5538             // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard
   5539             // i128 calling convention to adhere to the ABI that LLVM expects compiler-rt to have.
   5540             break :b self.context.intType(64).vectorType(2);
   5541         } else ret_ty;
   5542 
   5543         const operand_bits = operand_scalar_ty.floatBits(target);
   5544         const compiler_rt_operand_abbrev = compilerRtFloatAbbrev(operand_bits);
   5545 
   5546         const compiler_rt_dest_abbrev = compilerRtIntAbbrev(rt_int_bits);
   5547         const sign_prefix = if (dest_scalar_ty.isSignedInt()) "" else "uns";
   5548 
   5549         var fn_name_buf: [64]u8 = undefined;
   5550         const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__fix{s}{s}f{s}i", .{
   5551             sign_prefix,
   5552             compiler_rt_operand_abbrev,
   5553             compiler_rt_dest_abbrev,
   5554         }) catch unreachable;
   5555 
   5556         const operand_llvm_ty = try self.dg.lowerType(operand_ty);
   5557         const param_types = [1]*llvm.Type{operand_llvm_ty};
   5558         const libc_fn = self.getLibcFunction(fn_name, &param_types, libc_ret_ty);
   5559         const params = [1]*llvm.Value{operand};
   5560 
   5561         var result = self.builder.buildCall(libc_fn.globalGetValueType(), libc_fn, &params, params.len, .C, .Auto, "");
   5562 
   5563         if (libc_ret_ty != ret_ty) result = self.builder.buildBitCast(result, ret_ty, "");
   5564         if (ret_ty != dest_llvm_ty) result = self.builder.buildTrunc(result, dest_llvm_ty, "");
   5565         return result;
   5566     }
   5567 
   5568     fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*llvm.Value {
   5569         if (self.liveness.isUnused(inst)) return null;
   5570 
   5571         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   5572         const operand = try self.resolveInst(ty_op.operand);
   5573         return self.builder.buildExtractValue(operand, index, "");
   5574     }
   5575 
   5576     fn airPtrSliceFieldPtr(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*llvm.Value {
   5577         if (self.liveness.isUnused(inst)) return null;
   5578 
   5579         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   5580         const slice_ptr = try self.resolveInst(ty_op.operand);
   5581         const slice_ptr_ty = self.air.typeOf(ty_op.operand);
   5582         const slice_llvm_ty = try self.dg.lowerPtrElemTy(slice_ptr_ty.childType());
   5583 
   5584         return self.builder.buildStructGEP(slice_llvm_ty, slice_ptr, index, "");
   5585     }
   5586 
   5587     fn airSliceElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5588         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   5589         const slice_ty = self.air.typeOf(bin_op.lhs);
   5590         if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) return null;
   5591 
   5592         const slice = try self.resolveInst(bin_op.lhs);
   5593         const index = try self.resolveInst(bin_op.rhs);
   5594         const llvm_elem_ty = try self.dg.lowerPtrElemTy(slice_ty.childType());
   5595         const base_ptr = self.builder.buildExtractValue(slice, 0, "");
   5596         const indices: [1]*llvm.Value = .{index};
   5597         const ptr = self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
   5598         return self.load(ptr, slice_ty);
   5599     }
   5600 
   5601     fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5602         if (self.liveness.isUnused(inst)) return null;
   5603         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
   5604         const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
   5605         const slice_ty = self.air.typeOf(bin_op.lhs);
   5606 
   5607         const slice = try self.resolveInst(bin_op.lhs);
   5608         const index = try self.resolveInst(bin_op.rhs);
   5609         const llvm_elem_ty = try self.dg.lowerPtrElemTy(slice_ty.childType());
   5610         const base_ptr = self.builder.buildExtractValue(slice, 0, "");
   5611         const indices: [1]*llvm.Value = .{index};
   5612         return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
   5613     }
   5614 
   5615     fn airArrayElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5616         if (self.liveness.isUnused(inst)) return null;
   5617 
   5618         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   5619         const array_ty = self.air.typeOf(bin_op.lhs);
   5620         const array_llvm_val = try self.resolveInst(bin_op.lhs);
   5621         const rhs = try self.resolveInst(bin_op.rhs);
   5622         if (isByRef(array_ty)) {
   5623             const array_llvm_ty = try self.dg.lowerType(array_ty);
   5624             const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), rhs };
   5625             const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, array_llvm_val, &indices, indices.len, "");
   5626             const elem_ty = array_ty.childType();
   5627             if (isByRef(elem_ty)) {
   5628                 return elem_ptr;
   5629             } else {
   5630                 const elem_llvm_ty = try self.dg.lowerType(elem_ty);
   5631                 return self.builder.buildLoad(elem_llvm_ty, elem_ptr, "");
   5632             }
   5633         }
   5634 
   5635         // This branch can be reached for vectors, which are always by-value.
   5636         return self.builder.buildExtractElement(array_llvm_val, rhs, "");
   5637     }
   5638 
   5639     fn airPtrElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5640         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   5641         const ptr_ty = self.air.typeOf(bin_op.lhs);
   5642         if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst)) return null;
   5643 
   5644         const llvm_elem_ty = try self.dg.lowerPtrElemTy(ptr_ty.childType());
   5645         const base_ptr = try self.resolveInst(bin_op.lhs);
   5646         const rhs = try self.resolveInst(bin_op.rhs);
   5647         // TODO: when we go fully opaque pointers in LLVM 16 we can remove this branch
   5648         const ptr = if (ptr_ty.isSinglePointer()) ptr: {
   5649             // If this is a single-item pointer to an array, we need another index in the GEP.
   5650             const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), rhs };
   5651             break :ptr self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
   5652         } else ptr: {
   5653             const indices: [1]*llvm.Value = .{rhs};
   5654             break :ptr self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
   5655         };
   5656         return self.load(ptr, ptr_ty);
   5657     }
   5658 
   5659     fn airPtrElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5660         if (self.liveness.isUnused(inst)) return null;
   5661 
   5662         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
   5663         const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
   5664         const ptr_ty = self.air.typeOf(bin_op.lhs);
   5665         const elem_ty = ptr_ty.childType();
   5666         if (!elem_ty.hasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty);
   5667 
   5668         const base_ptr = try self.resolveInst(bin_op.lhs);
   5669         const rhs = try self.resolveInst(bin_op.rhs);
   5670         const llvm_elem_ty = try self.dg.lowerPtrElemTy(elem_ty);
   5671         if (ptr_ty.isSinglePointer()) {
   5672             // If this is a single-item pointer to an array, we need another index in the GEP.
   5673             const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), rhs };
   5674             return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
   5675         } else {
   5676             const indices: [1]*llvm.Value = .{rhs};
   5677             return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
   5678         }
   5679     }
   5680 
   5681     fn airStructFieldPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5682         if (self.liveness.isUnused(inst))
   5683             return null;
   5684 
   5685         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
   5686         const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
   5687         const struct_ptr = try self.resolveInst(struct_field.struct_operand);
   5688         const struct_ptr_ty = self.air.typeOf(struct_field.struct_operand);
   5689         return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, struct_field.field_index);
   5690     }
   5691 
   5692     fn airStructFieldPtrIndex(
   5693         self: *FuncGen,
   5694         inst: Air.Inst.Index,
   5695         field_index: u32,
   5696     ) !?*llvm.Value {
   5697         if (self.liveness.isUnused(inst)) return null;
   5698 
   5699         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   5700         const struct_ptr = try self.resolveInst(ty_op.operand);
   5701         const struct_ptr_ty = self.air.typeOf(ty_op.operand);
   5702         return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, field_index);
   5703     }
   5704 
   5705     fn airStructFieldVal(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5706         if (self.liveness.isUnused(inst)) return null;
   5707 
   5708         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
   5709         const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
   5710         const struct_ty = self.air.typeOf(struct_field.struct_operand);
   5711         const struct_llvm_val = try self.resolveInst(struct_field.struct_operand);
   5712         const field_index = struct_field.field_index;
   5713         const field_ty = struct_ty.structFieldType(field_index);
   5714         if (!field_ty.hasRuntimeBitsIgnoreComptime()) {
   5715             return null;
   5716         }
   5717         const target = self.dg.module.getTarget();
   5718 
   5719         if (!isByRef(struct_ty)) {
   5720             assert(!isByRef(field_ty));
   5721             switch (struct_ty.zigTypeTag()) {
   5722                 .Struct => switch (struct_ty.containerLayout()) {
   5723                     .Packed => {
   5724                         const struct_obj = struct_ty.castTag(.@"struct").?.data;
   5725                         const bit_offset = struct_obj.packedFieldBitOffset(target, field_index);
   5726                         const containing_int = struct_llvm_val;
   5727                         const shift_amt = containing_int.typeOf().constInt(bit_offset, .False);
   5728                         const shifted_value = self.builder.buildLShr(containing_int, shift_amt, "");
   5729                         const elem_llvm_ty = try self.dg.lowerType(field_ty);
   5730                         if (field_ty.zigTypeTag() == .Float) {
   5731                             const elem_bits = @intCast(c_uint, field_ty.bitSize(target));
   5732                             const same_size_int = self.context.intType(elem_bits);
   5733                             const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
   5734                             return self.builder.buildBitCast(truncated_int, elem_llvm_ty, "");
   5735                         } else if (field_ty.isPtrAtRuntime()) {
   5736                             const elem_bits = @intCast(c_uint, field_ty.bitSize(target));
   5737                             const same_size_int = self.context.intType(elem_bits);
   5738                             const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
   5739                             return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, "");
   5740                         }
   5741                         return self.builder.buildTrunc(shifted_value, elem_llvm_ty, "");
   5742                     },
   5743                     else => {
   5744                         var ptr_ty_buf: Type.Payload.Pointer = undefined;
   5745                         const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?;
   5746                         return self.builder.buildExtractValue(struct_llvm_val, llvm_field_index, "");
   5747                     },
   5748                 },
   5749                 .Union => {
   5750                     return self.todo("airStructFieldVal byval union", .{});
   5751                 },
   5752                 else => unreachable,
   5753             }
   5754         }
   5755 
   5756         switch (struct_ty.zigTypeTag()) {
   5757             .Struct => {
   5758                 assert(struct_ty.containerLayout() != .Packed);
   5759                 var ptr_ty_buf: Type.Payload.Pointer = undefined;
   5760                 const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?;
   5761                 const struct_llvm_ty = try self.dg.lowerType(struct_ty);
   5762                 const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, struct_llvm_val, llvm_field_index, "");
   5763                 const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base);
   5764                 return self.load(field_ptr, field_ptr_ty);
   5765             },
   5766             .Union => {
   5767                 const union_llvm_ty = try self.dg.lowerType(struct_ty);
   5768                 const layout = struct_ty.unionGetLayout(target);
   5769                 const payload_index = @boolToInt(layout.tag_align >= layout.payload_align);
   5770                 const union_field_ptr = self.builder.buildStructGEP(union_llvm_ty, struct_llvm_val, payload_index, "");
   5771                 const llvm_field_ty = try self.dg.lowerType(field_ty);
   5772                 const field_ptr = self.builder.buildBitCast(union_field_ptr, llvm_field_ty.pointerType(0), "");
   5773                 if (isByRef(field_ty)) {
   5774                     return field_ptr;
   5775                 } else {
   5776                     return self.builder.buildLoad(llvm_field_ty, field_ptr, "");
   5777                 }
   5778             },
   5779             else => unreachable,
   5780         }
   5781     }
   5782 
   5783     fn airFieldParentPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5784         if (self.liveness.isUnused(inst)) return null;
   5785 
   5786         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
   5787         const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
   5788 
   5789         const field_ptr = try self.resolveInst(extra.field_ptr);
   5790 
   5791         const target = self.dg.module.getTarget();
   5792         const struct_ty = self.air.getRefType(ty_pl.ty).childType();
   5793         const field_offset = struct_ty.structFieldOffset(extra.field_index, target);
   5794 
   5795         const res_ty = try self.dg.lowerType(self.air.getRefType(ty_pl.ty));
   5796         if (field_offset == 0) {
   5797             return self.builder.buildBitCast(field_ptr, res_ty, "");
   5798         }
   5799         const llvm_usize_ty = self.context.intType(target.cpu.arch.ptrBitWidth());
   5800 
   5801         const field_ptr_int = self.builder.buildPtrToInt(field_ptr, llvm_usize_ty, "");
   5802         const base_ptr_int = self.builder.buildNUWSub(field_ptr_int, llvm_usize_ty.constInt(field_offset, .False), "");
   5803         return self.builder.buildIntToPtr(base_ptr_int, res_ty, "");
   5804     }
   5805 
   5806     fn airNot(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5807         if (self.liveness.isUnused(inst))
   5808             return null;
   5809 
   5810         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   5811         const operand = try self.resolveInst(ty_op.operand);
   5812 
   5813         return self.builder.buildNot(operand, "");
   5814     }
   5815 
   5816     fn airUnreach(self: *FuncGen, inst: Air.Inst.Index) ?*llvm.Value {
   5817         _ = inst;
   5818         _ = self.builder.buildUnreachable();
   5819         return null;
   5820     }
   5821 
   5822     fn airDbgStmt(self: *FuncGen, inst: Air.Inst.Index) ?*llvm.Value {
   5823         const di_scope = self.di_scope orelse return null;
   5824         const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
   5825         self.prev_dbg_line = @intCast(c_uint, self.base_line + dbg_stmt.line + 1);
   5826         self.prev_dbg_column = @intCast(c_uint, dbg_stmt.column + 1);
   5827         const inlined_at = if (self.dbg_inlined.items.len > 0)
   5828             self.dbg_inlined.items[self.dbg_inlined.items.len - 1].loc
   5829         else
   5830             null;
   5831         self.builder.setCurrentDebugLocation(self.prev_dbg_line, self.prev_dbg_column, di_scope, inlined_at);
   5832         return null;
   5833     }
   5834 
   5835     fn airDbgInlineBegin(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5836         const dib = self.dg.object.di_builder orelse return null;
   5837         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
   5838 
   5839         const func = self.air.values[ty_pl.payload].castTag(.function).?.data;
   5840         const decl_index = func.owner_decl;
   5841         const decl = self.dg.module.declPtr(decl_index);
   5842         const di_file = try self.dg.object.getDIFile(self.gpa, decl.src_namespace.file_scope);
   5843         self.di_file = di_file;
   5844         const line_number = decl.src_line + 1;
   5845         const cur_debug_location = self.builder.getCurrentDebugLocation2();
   5846 
   5847         try self.dbg_inlined.append(self.gpa, .{
   5848             .loc = @ptrCast(*llvm.DILocation, cur_debug_location),
   5849             .scope = self.di_scope.?,
   5850             .base_line = self.base_line,
   5851         });
   5852 
   5853         const fqn = try decl.getFullyQualifiedName(self.dg.module);
   5854         defer self.gpa.free(fqn);
   5855 
   5856         const is_internal_linkage = !self.dg.module.decl_exports.contains(decl_index);
   5857         const subprogram = dib.createFunction(
   5858             di_file.toScope(),
   5859             decl.name,
   5860             fqn,
   5861             di_file,
   5862             line_number,
   5863             try self.dg.object.lowerDebugType(Type.initTag(.fn_void_no_args), .full),
   5864             is_internal_linkage,
   5865             true, // is definition
   5866             line_number + func.lbrace_line, // scope line
   5867             llvm.DIFlags.StaticMember,
   5868             self.dg.module.comp.bin_file.options.optimize_mode != .Debug,
   5869             null, // decl_subprogram
   5870         );
   5871 
   5872         const lexical_block = dib.createLexicalBlock(subprogram.toScope(), di_file, line_number, 1);
   5873         self.di_scope = lexical_block.toScope();
   5874         self.base_line = decl.src_line;
   5875         return null;
   5876     }
   5877 
   5878     fn airDbgInlineEnd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5879         if (self.dg.object.di_builder == null) return null;
   5880         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
   5881 
   5882         const func = self.air.values[ty_pl.payload].castTag(.function).?.data;
   5883         const mod = self.dg.module;
   5884         const decl = mod.declPtr(func.owner_decl);
   5885         const di_file = try self.dg.object.getDIFile(self.gpa, decl.src_namespace.file_scope);
   5886         self.di_file = di_file;
   5887         const old = self.dbg_inlined.pop();
   5888         self.di_scope = old.scope;
   5889         self.base_line = old.base_line;
   5890         return null;
   5891     }
   5892 
   5893     fn airDbgBlockBegin(self: *FuncGen) !?*llvm.Value {
   5894         const dib = self.dg.object.di_builder orelse return null;
   5895         const old_scope = self.di_scope.?;
   5896         try self.dbg_block_stack.append(self.gpa, old_scope);
   5897         const lexical_block = dib.createLexicalBlock(old_scope, self.di_file.?, self.prev_dbg_line, self.prev_dbg_column);
   5898         self.di_scope = lexical_block.toScope();
   5899         return null;
   5900     }
   5901 
   5902     fn airDbgBlockEnd(self: *FuncGen) !?*llvm.Value {
   5903         if (self.dg.object.di_builder == null) return null;
   5904         self.di_scope = self.dbg_block_stack.pop();
   5905         return null;
   5906     }
   5907 
   5908     fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5909         const dib = self.dg.object.di_builder orelse return null;
   5910         const pl_op = self.air.instructions.items(.data)[inst].pl_op;
   5911         const operand = try self.resolveInst(pl_op.operand);
   5912         const name = self.air.nullTerminatedString(pl_op.payload);
   5913         const ptr_ty = self.air.typeOf(pl_op.operand);
   5914 
   5915         const di_local_var = dib.createAutoVariable(
   5916             self.di_scope.?,
   5917             name.ptr,
   5918             self.di_file.?,
   5919             self.prev_dbg_line,
   5920             try self.dg.object.lowerDebugType(ptr_ty.childType(), .full),
   5921             true, // always preserve
   5922             0, // flags
   5923         );
   5924         const inlined_at = if (self.dbg_inlined.items.len > 0)
   5925             self.dbg_inlined.items[self.dbg_inlined.items.len - 1].loc
   5926         else
   5927             null;
   5928         const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?, inlined_at);
   5929         const insert_block = self.builder.getInsertBlock();
   5930         _ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block);
   5931         return null;
   5932     }
   5933 
   5934     fn airDbgVarVal(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5935         const dib = self.dg.object.di_builder orelse return null;
   5936         const pl_op = self.air.instructions.items(.data)[inst].pl_op;
   5937         const operand = try self.resolveInst(pl_op.operand);
   5938         const operand_ty = self.air.typeOf(pl_op.operand);
   5939         const name = self.air.nullTerminatedString(pl_op.payload);
   5940 
   5941         if (needDbgVarWorkaround(self.dg)) {
   5942             return null;
   5943         }
   5944 
   5945         const di_local_var = dib.createAutoVariable(
   5946             self.di_scope.?,
   5947             name.ptr,
   5948             self.di_file.?,
   5949             self.prev_dbg_line,
   5950             try self.dg.object.lowerDebugType(operand_ty, .full),
   5951             true, // always preserve
   5952             0, // flags
   5953         );
   5954         const inlined_at = if (self.dbg_inlined.items.len > 0)
   5955             self.dbg_inlined.items[self.dbg_inlined.items.len - 1].loc
   5956         else
   5957             null;
   5958         const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?, inlined_at);
   5959         const insert_block = self.builder.getInsertBlock();
   5960         if (isByRef(operand_ty)) {
   5961             _ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block);
   5962         } else {
   5963             _ = dib.insertDbgValueIntrinsicAtEnd(operand, di_local_var, debug_loc, insert_block);
   5964         }
   5965         return null;
   5966     }
   5967 
   5968     fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   5969         // Eventually, the Zig compiler needs to be reworked to have inline assembly go
   5970         // through the same parsing code regardless of backend, and have LLVM-flavored
   5971         // inline assembly be *output* from that assembler.
   5972         // We don't have such an assembler implemented yet though. For now, this
   5973         // implementation feeds the inline assembly code directly to LLVM, same
   5974         // as stage1.
   5975 
   5976         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
   5977         const extra = self.air.extraData(Air.Asm, ty_pl.payload);
   5978         const is_volatile = @truncate(u1, extra.data.flags >> 31) != 0;
   5979         const clobbers_len = @truncate(u31, extra.data.flags);
   5980         var extra_i: usize = extra.end;
   5981 
   5982         if (!is_volatile and self.liveness.isUnused(inst)) return null;
   5983 
   5984         const outputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]);
   5985         extra_i += outputs.len;
   5986         const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);
   5987         extra_i += inputs.len;
   5988 
   5989         var llvm_constraints: std.ArrayListUnmanaged(u8) = .{};
   5990         defer llvm_constraints.deinit(self.gpa);
   5991 
   5992         var arena_allocator = std.heap.ArenaAllocator.init(self.gpa);
   5993         defer arena_allocator.deinit();
   5994         const arena = arena_allocator.allocator();
   5995 
   5996         // The exact number of return / parameter values depends on which output values
   5997         // are passed by reference as indirect outputs (determined below).
   5998         const max_return_count = outputs.len;
   5999         const llvm_ret_types = try arena.alloc(*llvm.Type, max_return_count);
   6000         const llvm_ret_indirect = try arena.alloc(bool, max_return_count);
   6001 
   6002         const max_param_count = inputs.len + outputs.len;
   6003         const llvm_param_types = try arena.alloc(*llvm.Type, max_param_count);
   6004         const llvm_param_values = try arena.alloc(*llvm.Value, max_param_count);
   6005         // This stores whether we need to add an elementtype attribute and
   6006         // if so, the element type itself.
   6007         const llvm_param_attrs = try arena.alloc(?*llvm.Type, max_param_count);
   6008         const target = self.dg.module.getTarget();
   6009 
   6010         var llvm_ret_i: usize = 0;
   6011         var llvm_param_i: usize = 0;
   6012         var total_i: u16 = 0;
   6013 
   6014         var name_map: std.StringArrayHashMapUnmanaged(u16) = .{};
   6015         try name_map.ensureUnusedCapacity(arena, max_param_count);
   6016 
   6017         for (outputs) |output, i| {
   6018             const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
   6019             const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
   6020             const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
   6021             // This equation accounts for the fact that even if we have exactly 4 bytes
   6022             // for the string, we still use the next u32 for the null terminator.
   6023             extra_i += (constraint.len + name.len + (2 + 3)) / 4;
   6024 
   6025             try llvm_constraints.ensureUnusedCapacity(self.gpa, constraint.len + 3);
   6026             if (total_i != 0) {
   6027                 llvm_constraints.appendAssumeCapacity(',');
   6028             }
   6029             llvm_constraints.appendAssumeCapacity('=');
   6030 
   6031             // Pass any non-return outputs indirectly, if the constraint accepts a memory location
   6032             llvm_ret_indirect[i] = (output != .none) and constraintAllowsMemory(constraint);
   6033             if (output != .none) {
   6034                 const output_inst = try self.resolveInst(output);
   6035                 const output_ty = self.air.typeOf(output);
   6036                 assert(output_ty.zigTypeTag() == .Pointer);
   6037                 const elem_llvm_ty = try self.dg.lowerPtrElemTy(output_ty.childType());
   6038 
   6039                 if (llvm_ret_indirect[i]) {
   6040                     // Pass the result by reference as an indirect output (e.g. "=*m")
   6041                     llvm_constraints.appendAssumeCapacity('*');
   6042 
   6043                     llvm_param_values[llvm_param_i] = output_inst;
   6044                     llvm_param_types[llvm_param_i] = output_inst.typeOf();
   6045                     llvm_param_attrs[llvm_param_i] = elem_llvm_ty;
   6046                     llvm_param_i += 1;
   6047                 } else {
   6048                     // Pass the result directly (e.g. "=r")
   6049                     llvm_ret_types[llvm_ret_i] = elem_llvm_ty;
   6050                     llvm_ret_i += 1;
   6051                 }
   6052             } else {
   6053                 const ret_ty = self.air.typeOfIndex(inst);
   6054                 llvm_ret_types[llvm_ret_i] = try self.dg.lowerType(ret_ty);
   6055                 llvm_ret_i += 1;
   6056             }
   6057 
   6058             // LLVM uses commas internally to separate different constraints,
   6059             // alternative constraints are achieved with pipes.
   6060             // We still allow the user to use commas in a way that is similar
   6061             // to GCC's inline assembly.
   6062             // http://llvm.org/docs/LangRef.html#constraint-codes
   6063             for (constraint[1..]) |byte| {
   6064                 switch (byte) {
   6065                     ',' => llvm_constraints.appendAssumeCapacity('|'),
   6066                     '*' => {}, // Indirect outputs are handled above
   6067                     else => llvm_constraints.appendAssumeCapacity(byte),
   6068                 }
   6069             }
   6070 
   6071             if (!std.mem.eql(u8, name, "_")) {
   6072                 const gop = name_map.getOrPutAssumeCapacity(name);
   6073                 if (gop.found_existing) return self.todo("duplicate asm output name '{s}'", .{name});
   6074                 gop.value_ptr.* = total_i;
   6075             }
   6076             total_i += 1;
   6077         }
   6078 
   6079         for (inputs) |input| {
   6080             const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
   6081             const constraint = std.mem.sliceTo(extra_bytes, 0);
   6082             const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
   6083             // This equation accounts for the fact that even if we have exactly 4 bytes
   6084             // for the string, we still use the next u32 for the null terminator.
   6085             extra_i += (constraint.len + name.len + (2 + 3)) / 4;
   6086 
   6087             const arg_llvm_value = try self.resolveInst(input);
   6088             const arg_ty = self.air.typeOf(input);
   6089             var llvm_elem_ty: ?*llvm.Type = null;
   6090             if (isByRef(arg_ty)) {
   6091                 llvm_elem_ty = try self.dg.lowerPtrElemTy(arg_ty);
   6092                 if (constraintAllowsMemory(constraint)) {
   6093                     llvm_param_values[llvm_param_i] = arg_llvm_value;
   6094                     llvm_param_types[llvm_param_i] = arg_llvm_value.typeOf();
   6095                 } else {
   6096                     const alignment = arg_ty.abiAlignment(target);
   6097                     const arg_llvm_ty = try self.dg.lowerType(arg_ty);
   6098                     const load_inst = self.builder.buildLoad(arg_llvm_ty, arg_llvm_value, "");
   6099                     load_inst.setAlignment(alignment);
   6100                     llvm_param_values[llvm_param_i] = load_inst;
   6101                     llvm_param_types[llvm_param_i] = arg_llvm_ty;
   6102                 }
   6103             } else {
   6104                 if (constraintAllowsRegister(constraint)) {
   6105                     llvm_param_values[llvm_param_i] = arg_llvm_value;
   6106                     llvm_param_types[llvm_param_i] = arg_llvm_value.typeOf();
   6107                 } else {
   6108                     const alignment = arg_ty.abiAlignment(target);
   6109                     const arg_ptr = self.buildAlloca(arg_llvm_value.typeOf(), alignment);
   6110                     const store_inst = self.builder.buildStore(arg_llvm_value, arg_ptr);
   6111                     store_inst.setAlignment(alignment);
   6112                     llvm_param_values[llvm_param_i] = arg_ptr;
   6113                     llvm_param_types[llvm_param_i] = arg_ptr.typeOf();
   6114                 }
   6115             }
   6116 
   6117             try llvm_constraints.ensureUnusedCapacity(self.gpa, constraint.len + 1);
   6118             if (total_i != 0) {
   6119                 llvm_constraints.appendAssumeCapacity(',');
   6120             }
   6121             for (constraint) |byte| {
   6122                 llvm_constraints.appendAssumeCapacity(switch (byte) {
   6123                     ',' => '|',
   6124                     else => byte,
   6125                 });
   6126             }
   6127 
   6128             if (!std.mem.eql(u8, name, "_")) {
   6129                 const gop = name_map.getOrPutAssumeCapacity(name);
   6130                 if (gop.found_existing) return self.todo("duplicate asm input name '{s}'", .{name});
   6131                 gop.value_ptr.* = total_i;
   6132             }
   6133 
   6134             // In the case of indirect inputs, LLVM requires the callsite to have
   6135             // an elementtype(<ty>) attribute.
   6136             if (constraint[0] == '*') {
   6137                 llvm_param_attrs[llvm_param_i] = llvm_elem_ty orelse
   6138                     try self.dg.lowerPtrElemTy(arg_ty.childType());
   6139             } else {
   6140                 llvm_param_attrs[llvm_param_i] = null;
   6141             }
   6142 
   6143             llvm_param_i += 1;
   6144             total_i += 1;
   6145         }
   6146 
   6147         {
   6148             var clobber_i: u32 = 0;
   6149             while (clobber_i < clobbers_len) : (clobber_i += 1) {
   6150                 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
   6151                 // This equation accounts for the fact that even if we have exactly 4 bytes
   6152                 // for the string, we still use the next u32 for the null terminator.
   6153                 extra_i += clobber.len / 4 + 1;
   6154 
   6155                 try llvm_constraints.ensureUnusedCapacity(self.gpa, clobber.len + 4);
   6156                 if (total_i != 0) {
   6157                     llvm_constraints.appendAssumeCapacity(',');
   6158                 }
   6159                 llvm_constraints.appendSliceAssumeCapacity("~{");
   6160                 llvm_constraints.appendSliceAssumeCapacity(clobber);
   6161                 llvm_constraints.appendSliceAssumeCapacity("}");
   6162 
   6163                 total_i += 1;
   6164             }
   6165         }
   6166 
   6167         // We have finished scanning through all inputs/outputs, so the number of
   6168         // parameters and return values is known.
   6169         const param_count = llvm_param_i;
   6170         const return_count = llvm_ret_i;
   6171 
   6172         // For some targets, Clang unconditionally adds some clobbers to all inline assembly.
   6173         // While this is probably not strictly necessary, if we don't follow Clang's lead
   6174         // here then we may risk tripping LLVM bugs since anything not used by Clang tends
   6175         // to be buggy and regress often.
   6176         switch (target.cpu.arch) {
   6177             .x86_64, .i386 => {
   6178                 if (total_i != 0) try llvm_constraints.append(self.gpa, ',');
   6179                 try llvm_constraints.appendSlice(self.gpa, "~{dirflag},~{fpsr},~{flags}");
   6180                 total_i += 3;
   6181             },
   6182             .mips, .mipsel, .mips64, .mips64el => {
   6183                 if (total_i != 0) try llvm_constraints.append(self.gpa, ',');
   6184                 try llvm_constraints.appendSlice(self.gpa, "~{$1}");
   6185                 total_i += 1;
   6186             },
   6187             else => {},
   6188         }
   6189 
   6190         const asm_source = std.mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len];
   6191 
   6192         // hackety hacks until stage2 has proper inline asm in the frontend.
   6193         var rendered_template = std.ArrayList(u8).init(self.gpa);
   6194         defer rendered_template.deinit();
   6195 
   6196         const State = enum { start, percent, input };
   6197 
   6198         var state: State = .start;
   6199 
   6200         var name_start: usize = undefined;
   6201         for (asm_source) |byte, i| {
   6202             switch (state) {
   6203                 .start => switch (byte) {
   6204                     '%' => state = .percent,
   6205                     '$' => try rendered_template.appendSlice("$$"),
   6206                     else => try rendered_template.append(byte),
   6207                 },
   6208                 .percent => switch (byte) {
   6209                     '%' => {
   6210                         try rendered_template.append('%');
   6211                         state = .start;
   6212                     },
   6213                     '[' => {
   6214                         try rendered_template.append('$');
   6215                         name_start = i + 1;
   6216                         state = .input;
   6217                     },
   6218                     else => {
   6219                         try rendered_template.append('%');
   6220                         try rendered_template.append(byte);
   6221                         state = .start;
   6222                     },
   6223                 },
   6224                 .input => switch (byte) {
   6225                     ']' => {
   6226                         const name = asm_source[name_start..i];
   6227                         state = .start;
   6228 
   6229                         const index = name_map.get(name) orelse {
   6230                             // we should validate the assembly in Sema; by now it is too late
   6231                             return self.todo("unknown input or output name: '{s}'", .{name});
   6232                         };
   6233                         try rendered_template.writer().print("{d}", .{index});
   6234                     },
   6235                     else => {},
   6236                 },
   6237             }
   6238         }
   6239 
   6240         const ret_llvm_ty = switch (return_count) {
   6241             0 => self.context.voidType(),
   6242             1 => llvm_ret_types[0],
   6243             else => self.context.structType(
   6244                 llvm_ret_types.ptr,
   6245                 @intCast(c_uint, return_count),
   6246                 .False,
   6247             ),
   6248         };
   6249 
   6250         const llvm_fn_ty = llvm.functionType(
   6251             ret_llvm_ty,
   6252             llvm_param_types.ptr,
   6253             @intCast(c_uint, param_count),
   6254             .False,
   6255         );
   6256         const asm_fn = llvm.getInlineAsm(
   6257             llvm_fn_ty,
   6258             rendered_template.items.ptr,
   6259             rendered_template.items.len,
   6260             llvm_constraints.items.ptr,
   6261             llvm_constraints.items.len,
   6262             llvm.Bool.fromBool(is_volatile),
   6263             .False,
   6264             .ATT,
   6265             .False,
   6266         );
   6267         const call = self.builder.buildCall(
   6268             llvm_fn_ty,
   6269             asm_fn,
   6270             llvm_param_values.ptr,
   6271             @intCast(c_uint, param_count),
   6272             .C,
   6273             .Auto,
   6274             "",
   6275         );
   6276         for (llvm_param_attrs[0..param_count]) |llvm_elem_ty, i| {
   6277             if (llvm_elem_ty) |llvm_ty| {
   6278                 llvm.setCallElemTypeAttr(call, i, llvm_ty);
   6279             }
   6280         }
   6281 
   6282         var ret_val = call;
   6283         llvm_ret_i = 0;
   6284         for (outputs) |output, i| {
   6285             if (llvm_ret_indirect[i]) continue;
   6286 
   6287             const output_value = if (return_count > 1) b: {
   6288                 break :b self.builder.buildExtractValue(call, @intCast(c_uint, llvm_ret_i), "");
   6289             } else call;
   6290 
   6291             if (output != .none) {
   6292                 const output_ptr = try self.resolveInst(output);
   6293                 const output_ptr_ty = self.air.typeOf(output);
   6294 
   6295                 const store_inst = self.builder.buildStore(output_value, output_ptr);
   6296                 store_inst.setAlignment(output_ptr_ty.ptrAlignment(target));
   6297             } else {
   6298                 ret_val = output_value;
   6299             }
   6300             llvm_ret_i += 1;
   6301         }
   6302 
   6303         return ret_val;
   6304     }
   6305 
   6306     fn airIsNonNull(
   6307         self: *FuncGen,
   6308         inst: Air.Inst.Index,
   6309         operand_is_ptr: bool,
   6310         pred: llvm.IntPredicate,
   6311     ) !?*llvm.Value {
   6312         if (self.liveness.isUnused(inst)) return null;
   6313 
   6314         const un_op = self.air.instructions.items(.data)[inst].un_op;
   6315         const operand = try self.resolveInst(un_op);
   6316         const operand_ty = self.air.typeOf(un_op);
   6317         const optional_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
   6318         const optional_llvm_ty = try self.dg.lowerType(optional_ty);
   6319         if (optional_ty.optionalReprIsPayload()) {
   6320             const loaded = if (operand_is_ptr)
   6321                 self.builder.buildLoad(optional_llvm_ty, operand, "")
   6322             else
   6323                 operand;
   6324             return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), "");
   6325         }
   6326 
   6327         comptime assert(optional_layout_version == 3);
   6328 
   6329         var buf: Type.Payload.ElemType = undefined;
   6330         const payload_ty = optional_ty.optionalChild(&buf);
   6331         if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
   6332             const loaded = if (operand_is_ptr)
   6333                 self.builder.buildLoad(optional_llvm_ty, operand, "")
   6334             else
   6335                 operand;
   6336             const llvm_i8 = self.dg.context.intType(8);
   6337             return self.builder.buildICmp(pred, loaded, llvm_i8.constNull(), "");
   6338         }
   6339 
   6340         const is_by_ref = operand_is_ptr or isByRef(optional_ty);
   6341         const non_null_bit = self.optIsNonNull(optional_llvm_ty, operand, is_by_ref);
   6342         if (pred == .EQ) {
   6343             return self.builder.buildNot(non_null_bit, "");
   6344         } else {
   6345             return non_null_bit;
   6346         }
   6347     }
   6348 
   6349     fn airIsErr(
   6350         self: *FuncGen,
   6351         inst: Air.Inst.Index,
   6352         op: llvm.IntPredicate,
   6353         operand_is_ptr: bool,
   6354     ) !?*llvm.Value {
   6355         if (self.liveness.isUnused(inst)) return null;
   6356 
   6357         const un_op = self.air.instructions.items(.data)[inst].un_op;
   6358         const operand = try self.resolveInst(un_op);
   6359         const operand_ty = self.air.typeOf(un_op);
   6360         const err_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
   6361         const payload_ty = err_union_ty.errorUnionPayload();
   6362         const err_set_ty = try self.dg.lowerType(Type.anyerror);
   6363         const zero = err_set_ty.constNull();
   6364 
   6365         if (err_union_ty.errorUnionSet().errorSetIsEmpty()) {
   6366             const llvm_i1 = self.context.intType(1);
   6367             switch (op) {
   6368                 .EQ => return llvm_i1.constInt(1, .False), // 0 == 0
   6369                 .NE => return llvm_i1.constInt(0, .False), // 0 != 0
   6370                 else => unreachable,
   6371             }
   6372         }
   6373 
   6374         if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
   6375             const loaded = if (operand_is_ptr)
   6376                 self.builder.buildLoad(try self.dg.lowerType(err_union_ty), operand, "")
   6377             else
   6378                 operand;
   6379             return self.builder.buildICmp(op, loaded, zero, "");
   6380         }
   6381 
   6382         const target = self.dg.module.getTarget();
   6383         const err_field_index = errUnionErrorOffset(payload_ty, target);
   6384 
   6385         if (operand_is_ptr or isByRef(err_union_ty)) {
   6386             const err_union_llvm_ty = try self.dg.lowerType(err_union_ty);
   6387             const err_field_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, err_field_index, "");
   6388             const loaded = self.builder.buildLoad(err_set_ty, err_field_ptr, "");
   6389             return self.builder.buildICmp(op, loaded, zero, "");
   6390         }
   6391 
   6392         const loaded = self.builder.buildExtractValue(operand, err_field_index, "");
   6393         return self.builder.buildICmp(op, loaded, zero, "");
   6394     }
   6395 
   6396     fn airOptionalPayloadPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   6397         if (self.liveness.isUnused(inst)) return null;
   6398 
   6399         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   6400         const operand = try self.resolveInst(ty_op.operand);
   6401         const optional_ty = self.air.typeOf(ty_op.operand).childType();
   6402         const result_ty = self.air.getRefType(ty_op.ty);
   6403         var buf: Type.Payload.ElemType = undefined;
   6404         const payload_ty = optional_ty.optionalChild(&buf);
   6405         if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
   6406             // We have a pointer to a zero-bit value and we need to return
   6407             // a pointer to a zero-bit value.
   6408 
   6409             // TODO once we update to LLVM 16 this bitcast won't be necessary.
   6410             const res_ptr_ty = try self.dg.lowerType(result_ty);
   6411             return self.builder.buildBitCast(operand, res_ptr_ty, "");
   6412         }
   6413         if (optional_ty.optionalReprIsPayload()) {
   6414             // The payload and the optional are the same value.
   6415             return operand;
   6416         }
   6417         const optional_llvm_ty = try self.dg.lowerType(optional_ty);
   6418         return self.builder.buildStructGEP(optional_llvm_ty, operand, 0, "");
   6419     }
   6420 
   6421     fn airOptionalPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   6422         comptime assert(optional_layout_version == 3);
   6423 
   6424         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   6425         const operand = try self.resolveInst(ty_op.operand);
   6426         const optional_ty = self.air.typeOf(ty_op.operand).childType();
   6427         const result_ty = self.air.getRefType(ty_op.ty);
   6428         var buf: Type.Payload.ElemType = undefined;
   6429         const payload_ty = optional_ty.optionalChild(&buf);
   6430         const non_null_bit = self.context.intType(8).constInt(1, .False);
   6431         if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
   6432             // We have a pointer to a i8. We need to set it to 1 and then return the same pointer.
   6433             _ = self.builder.buildStore(non_null_bit, operand);
   6434 
   6435             // TODO once we update to LLVM 16 this bitcast won't be necessary.
   6436             const res_ptr_ty = try self.dg.lowerType(result_ty);
   6437             return self.builder.buildBitCast(operand, res_ptr_ty, "");
   6438         }
   6439         if (optional_ty.optionalReprIsPayload()) {
   6440             // The payload and the optional are the same value.
   6441             // Setting to non-null will be done when the payload is set.
   6442             return operand;
   6443         }
   6444 
   6445         // First set the non-null bit.
   6446         const optional_llvm_ty = try self.dg.lowerType(optional_ty);
   6447         const non_null_ptr = self.builder.buildStructGEP(optional_llvm_ty, operand, 1, "");
   6448         // TODO set alignment on this store
   6449         _ = self.builder.buildStore(non_null_bit, non_null_ptr);
   6450 
   6451         // Then return the payload pointer (only if it's used).
   6452         if (self.liveness.isUnused(inst))
   6453             return null;
   6454 
   6455         return self.builder.buildStructGEP(optional_llvm_ty, operand, 0, "");
   6456     }
   6457 
   6458     fn airOptionalPayload(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   6459         if (self.liveness.isUnused(inst)) return null;
   6460 
   6461         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   6462         const operand = try self.resolveInst(ty_op.operand);
   6463         const optional_ty = self.air.typeOf(ty_op.operand);
   6464         const payload_ty = self.air.typeOfIndex(inst);
   6465         if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return null;
   6466 
   6467         if (optional_ty.optionalReprIsPayload()) {
   6468             // Payload value is the same as the optional value.
   6469             return operand;
   6470         }
   6471 
   6472         const opt_llvm_ty = try self.dg.lowerType(optional_ty);
   6473         return self.optPayloadHandle(opt_llvm_ty, operand, optional_ty);
   6474     }
   6475 
   6476     fn airErrUnionPayload(
   6477         self: *FuncGen,
   6478         inst: Air.Inst.Index,
   6479         operand_is_ptr: bool,
   6480     ) !?*llvm.Value {
   6481         if (self.liveness.isUnused(inst)) return null;
   6482 
   6483         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   6484         const operand = try self.resolveInst(ty_op.operand);
   6485         const operand_ty = self.air.typeOf(ty_op.operand);
   6486         const err_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
   6487         const result_ty = self.air.typeOfIndex(inst);
   6488         const payload_ty = if (operand_is_ptr) result_ty.childType() else result_ty;
   6489         const target = self.dg.module.getTarget();
   6490 
   6491         if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
   6492             if (!operand_is_ptr) return null;
   6493 
   6494             // TODO once we update to LLVM 14 this bitcast won't be necessary.
   6495             const res_ptr_ty = try self.dg.lowerType(result_ty);
   6496             return self.builder.buildBitCast(operand, res_ptr_ty, "");
   6497         }
   6498         const offset = errUnionPayloadOffset(payload_ty, target);
   6499         const err_union_llvm_ty = try self.dg.lowerType(err_union_ty);
   6500         if (operand_is_ptr or isByRef(payload_ty)) {
   6501             return self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, "");
   6502         } else if (isByRef(err_union_ty)) {
   6503             const payload_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, "");
   6504             if (isByRef(payload_ty)) {
   6505                 return payload_ptr;
   6506             }
   6507             const load_inst = self.builder.buildLoad(payload_ptr.getGEPResultElementType(), payload_ptr, "");
   6508             load_inst.setAlignment(payload_ty.abiAlignment(target));
   6509             return load_inst;
   6510         }
   6511         return self.builder.buildExtractValue(operand, offset, "");
   6512     }
   6513 
   6514     fn airErrUnionErr(
   6515         self: *FuncGen,
   6516         inst: Air.Inst.Index,
   6517         operand_is_ptr: bool,
   6518     ) !?*llvm.Value {
   6519         if (self.liveness.isUnused(inst))
   6520             return null;
   6521 
   6522         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   6523         const operand = try self.resolveInst(ty_op.operand);
   6524         const operand_ty = self.air.typeOf(ty_op.operand);
   6525         const err_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
   6526         if (err_union_ty.errorUnionSet().errorSetIsEmpty()) {
   6527             const err_llvm_ty = try self.dg.lowerType(Type.anyerror);
   6528             if (operand_is_ptr) {
   6529                 return self.builder.buildBitCast(operand, err_llvm_ty.pointerType(0), "");
   6530             } else {
   6531                 return err_llvm_ty.constInt(0, .False);
   6532             }
   6533         }
   6534 
   6535         const err_set_llvm_ty = try self.dg.lowerType(Type.anyerror);
   6536 
   6537         const payload_ty = err_union_ty.errorUnionPayload();
   6538         if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
   6539             if (!operand_is_ptr) return operand;
   6540             return self.builder.buildLoad(err_set_llvm_ty, operand, "");
   6541         }
   6542 
   6543         const target = self.dg.module.getTarget();
   6544         const offset = errUnionErrorOffset(payload_ty, target);
   6545 
   6546         if (operand_is_ptr or isByRef(err_union_ty)) {
   6547             const err_union_llvm_ty = try self.dg.lowerType(err_union_ty);
   6548             const err_field_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, "");
   6549             return self.builder.buildLoad(err_set_llvm_ty, err_field_ptr, "");
   6550         }
   6551 
   6552         return self.builder.buildExtractValue(operand, offset, "");
   6553     }
   6554 
   6555     fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   6556         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   6557         const operand = try self.resolveInst(ty_op.operand);
   6558         const err_union_ty = self.air.typeOf(ty_op.operand).childType();
   6559 
   6560         const payload_ty = err_union_ty.errorUnionPayload();
   6561         const non_error_val = try self.dg.lowerValue(.{ .ty = Type.anyerror, .val = Value.zero });
   6562         if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
   6563             _ = self.builder.buildStore(non_error_val, operand);
   6564             return operand;
   6565         }
   6566         const target = self.dg.module.getTarget();
   6567         const err_union_llvm_ty = try self.dg.lowerType(err_union_ty);
   6568         {
   6569             const error_offset = errUnionErrorOffset(payload_ty, target);
   6570             // First set the non-error value.
   6571             const non_null_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, error_offset, "");
   6572             const store_inst = self.builder.buildStore(non_error_val, non_null_ptr);
   6573             store_inst.setAlignment(Type.anyerror.abiAlignment(target));
   6574         }
   6575         // Then return the payload pointer (only if it is used).
   6576         if (self.liveness.isUnused(inst))
   6577             return null;
   6578 
   6579         const payload_offset = errUnionPayloadOffset(payload_ty, target);
   6580         return self.builder.buildStructGEP(err_union_llvm_ty, operand, payload_offset, "");
   6581     }
   6582 
   6583     fn airErrReturnTrace(self: *FuncGen, _: Air.Inst.Index) !?*llvm.Value {
   6584         return self.err_ret_trace.?;
   6585     }
   6586 
   6587     fn airSetErrReturnTrace(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   6588         const un_op = self.air.instructions.items(.data)[inst].un_op;
   6589         const operand = try self.resolveInst(un_op);
   6590         self.err_ret_trace = operand;
   6591         return null;
   6592     }
   6593 
   6594     fn airSaveErrReturnTraceIndex(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   6595         if (self.liveness.isUnused(inst)) return null;
   6596 
   6597         const target = self.dg.module.getTarget();
   6598 
   6599         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
   6600         //const struct_ty = try self.resolveInst(ty_pl.ty);
   6601         const struct_ty = self.air.getRefType(ty_pl.ty);
   6602         const field_index = ty_pl.payload;
   6603 
   6604         var ptr_ty_buf: Type.Payload.Pointer = undefined;
   6605         const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?;
   6606         const struct_llvm_ty = try self.dg.lowerType(struct_ty);
   6607         const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, self.err_ret_trace.?, llvm_field_index, "");
   6608         const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base);
   6609         return self.load(field_ptr, field_ptr_ty);
   6610     }
   6611 
   6612     fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   6613         if (self.liveness.isUnused(inst)) return null;
   6614 
   6615         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   6616         const payload_ty = self.air.typeOf(ty_op.operand);
   6617         const non_null_bit = self.context.intType(8).constInt(1, .False);
   6618         comptime assert(optional_layout_version == 3);
   6619         if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return non_null_bit;
   6620         const operand = try self.resolveInst(ty_op.operand);
   6621         const optional_ty = self.air.typeOfIndex(inst);
   6622         if (optional_ty.optionalReprIsPayload()) {
   6623             return operand;
   6624         }
   6625         const llvm_optional_ty = try self.dg.lowerType(optional_ty);
   6626         if (isByRef(optional_ty)) {
   6627             const target = self.dg.module.getTarget();
   6628             const optional_ptr = self.buildAlloca(llvm_optional_ty, optional_ty.abiAlignment(target));
   6629             const payload_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 0, "");
   6630             var ptr_ty_payload: Type.Payload.ElemType = .{
   6631                 .base = .{ .tag = .single_mut_pointer },
   6632                 .data = payload_ty,
   6633             };
   6634             const payload_ptr_ty = Type.initPayload(&ptr_ty_payload.base);
   6635             self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic);
   6636             const non_null_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 1, "");
   6637             _ = self.builder.buildStore(non_null_bit, non_null_ptr);
   6638             return optional_ptr;
   6639         }
   6640         const partial = self.builder.buildInsertValue(llvm_optional_ty.getUndef(), operand, 0, "");
   6641         return self.builder.buildInsertValue(partial, non_null_bit, 1, "");
   6642     }
   6643 
   6644     fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   6645         if (self.liveness.isUnused(inst)) return null;
   6646 
   6647         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   6648         const err_un_ty = self.air.typeOfIndex(inst);
   6649         const operand = try self.resolveInst(ty_op.operand);
   6650         const payload_ty = self.air.typeOf(ty_op.operand);
   6651         if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
   6652             return operand;
   6653         }
   6654         const ok_err_code = (try self.dg.lowerType(Type.anyerror)).constNull();
   6655         const err_un_llvm_ty = try self.dg.lowerType(err_un_ty);
   6656 
   6657         const target = self.dg.module.getTarget();
   6658         const payload_offset = errUnionPayloadOffset(payload_ty, target);
   6659         const error_offset = errUnionErrorOffset(payload_ty, target);
   6660         if (isByRef(err_un_ty)) {
   6661             const result_ptr = self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(target));
   6662             const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");
   6663             const store_inst = self.builder.buildStore(ok_err_code, err_ptr);
   6664             store_inst.setAlignment(Type.anyerror.abiAlignment(target));
   6665             const payload_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, payload_offset, "");
   6666             var ptr_ty_payload: Type.Payload.ElemType = .{
   6667                 .base = .{ .tag = .single_mut_pointer },
   6668                 .data = payload_ty,
   6669             };
   6670             const payload_ptr_ty = Type.initPayload(&ptr_ty_payload.base);
   6671             self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic);
   6672             return result_ptr;
   6673         }
   6674 
   6675         const partial = self.builder.buildInsertValue(err_un_llvm_ty.getUndef(), ok_err_code, error_offset, "");
   6676         return self.builder.buildInsertValue(partial, operand, payload_offset, "");
   6677     }
   6678 
   6679     fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   6680         if (self.liveness.isUnused(inst)) return null;
   6681 
   6682         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   6683         const err_un_ty = self.air.typeOfIndex(inst);
   6684         const payload_ty = err_un_ty.errorUnionPayload();
   6685         const operand = try self.resolveInst(ty_op.operand);
   6686         if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
   6687             return operand;
   6688         }
   6689         const err_un_llvm_ty = try self.dg.lowerType(err_un_ty);
   6690 
   6691         const target = self.dg.module.getTarget();
   6692         const payload_offset = errUnionPayloadOffset(payload_ty, target);
   6693         const error_offset = errUnionErrorOffset(payload_ty, target);
   6694         if (isByRef(err_un_ty)) {
   6695             const result_ptr = self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(target));
   6696             const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");
   6697             const store_inst = self.builder.buildStore(operand, err_ptr);
   6698             store_inst.setAlignment(Type.anyerror.abiAlignment(target));
   6699             const payload_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, payload_offset, "");
   6700             var ptr_ty_payload: Type.Payload.ElemType = .{
   6701                 .base = .{ .tag = .single_mut_pointer },
   6702                 .data = payload_ty,
   6703             };
   6704             const payload_ptr_ty = Type.initPayload(&ptr_ty_payload.base);
   6705             // TODO store undef to payload_ptr
   6706             _ = payload_ptr;
   6707             _ = payload_ptr_ty;
   6708             return result_ptr;
   6709         }
   6710 
   6711         const partial = self.builder.buildInsertValue(err_un_llvm_ty.getUndef(), operand, error_offset, "");
   6712         // TODO set payload bytes to undef
   6713         return partial;
   6714     }
   6715 
   6716     fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   6717         if (self.liveness.isUnused(inst)) return null;
   6718 
   6719         const pl_op = self.air.instructions.items(.data)[inst].pl_op;
   6720         const index = pl_op.payload;
   6721         const llvm_u32 = self.context.intType(32);
   6722         const llvm_fn = self.getIntrinsic("llvm.wasm.memory.size", &.{llvm_u32});
   6723         const args: [1]*llvm.Value = .{llvm_u32.constInt(index, .False)};
   6724         return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");
   6725     }
   6726 
   6727     fn airWasmMemoryGrow(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   6728         const pl_op = self.air.instructions.items(.data)[inst].pl_op;
   6729         const index = pl_op.payload;
   6730         const operand = try self.resolveInst(pl_op.operand);
   6731         const llvm_u32 = self.context.intType(32);
   6732         const llvm_fn = self.getIntrinsic("llvm.wasm.memory.grow", &.{llvm_u32});
   6733         const args: [2]*llvm.Value = .{
   6734             llvm_u32.constInt(index, .False),
   6735             operand,
   6736         };
   6737         return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");
   6738     }
   6739 
   6740     fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   6741         if (self.liveness.isUnused(inst)) return null;
   6742 
   6743         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   6744         const lhs = try self.resolveInst(bin_op.lhs);
   6745         const rhs = try self.resolveInst(bin_op.rhs);
   6746         const scalar_ty = self.air.typeOfIndex(inst).scalarType();
   6747 
   6748         if (scalar_ty.isAnyFloat()) return self.builder.buildMinNum(lhs, rhs, "");
   6749         if (scalar_ty.isSignedInt()) return self.builder.buildSMin(lhs, rhs, "");
   6750         return self.builder.buildUMin(lhs, rhs, "");
   6751     }
   6752 
   6753     fn airMax(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   6754         if (self.liveness.isUnused(inst)) return null;
   6755 
   6756         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   6757         const lhs = try self.resolveInst(bin_op.lhs);
   6758         const rhs = try self.resolveInst(bin_op.rhs);
   6759         const scalar_ty = self.air.typeOfIndex(inst).scalarType();
   6760 
   6761         if (scalar_ty.isAnyFloat()) return self.builder.buildMaxNum(lhs, rhs, "");
   6762         if (scalar_ty.isSignedInt()) return self.builder.buildSMax(lhs, rhs, "");
   6763         return self.builder.buildUMax(lhs, rhs, "");
   6764     }
   6765 
   6766     fn airSlice(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   6767         if (self.liveness.isUnused(inst)) return null;
   6768 
   6769         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
   6770         const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
   6771         const ptr = try self.resolveInst(bin_op.lhs);
   6772         const len = try self.resolveInst(bin_op.rhs);
   6773         const inst_ty = self.air.typeOfIndex(inst);
   6774         const llvm_slice_ty = try self.dg.lowerType(inst_ty);
   6775 
   6776         // In case of slicing a global, the result type looks something like `{ i8*, i64 }`
   6777         // but `ptr` is pointing to the global directly. If it's an array, we would want to
   6778         // do GEP(0,0), or we can just bitcast it to be correct, like we do here.
   6779         // This prevents an assertion failure.
   6780         var buf: Type.SlicePtrFieldTypeBuffer = undefined;
   6781         const ptr_ty = inst_ty.slicePtrFieldType(&buf);
   6782         const ptr_llvm_ty = try self.dg.lowerType(ptr_ty);
   6783         const casted_ptr = self.builder.buildBitCast(ptr, ptr_llvm_ty, "");
   6784         const partial = self.builder.buildInsertValue(llvm_slice_ty.getUndef(), casted_ptr, 0, "");
   6785         return self.builder.buildInsertValue(partial, len, 1, "");
   6786     }
   6787 
   6788     fn airAdd(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
   6789         if (self.liveness.isUnused(inst)) return null;
   6790         self.builder.setFastMath(want_fast_math);
   6791 
   6792         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   6793         const lhs = try self.resolveInst(bin_op.lhs);
   6794         const rhs = try self.resolveInst(bin_op.rhs);
   6795         const inst_ty = self.air.typeOfIndex(inst);
   6796         const scalar_ty = inst_ty.scalarType();
   6797 
   6798         if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.add, inst_ty, 2, .{ lhs, rhs });
   6799         if (scalar_ty.isSignedInt()) return self.builder.buildNSWAdd(lhs, rhs, "");
   6800         return self.builder.buildNUWAdd(lhs, rhs, "");
   6801     }
   6802 
   6803     fn airAddWrap(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
   6804         if (self.liveness.isUnused(inst)) return null;
   6805         self.builder.setFastMath(want_fast_math);
   6806 
   6807         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   6808         const lhs = try self.resolveInst(bin_op.lhs);
   6809         const rhs = try self.resolveInst(bin_op.rhs);
   6810 
   6811         return self.builder.buildAdd(lhs, rhs, "");
   6812     }
   6813 
   6814     fn airAddSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   6815         if (self.liveness.isUnused(inst)) return null;
   6816 
   6817         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   6818         const lhs = try self.resolveInst(bin_op.lhs);
   6819         const rhs = try self.resolveInst(bin_op.rhs);
   6820         const inst_ty = self.air.typeOfIndex(inst);
   6821         const scalar_ty = inst_ty.scalarType();
   6822 
   6823         if (scalar_ty.isAnyFloat()) return self.todo("saturating float add", .{});
   6824         if (scalar_ty.isSignedInt()) return self.builder.buildSAddSat(lhs, rhs, "");
   6825 
   6826         return self.builder.buildUAddSat(lhs, rhs, "");
   6827     }
   6828 
   6829     fn airSub(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
   6830         if (self.liveness.isUnused(inst)) return null;
   6831         self.builder.setFastMath(want_fast_math);
   6832 
   6833         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   6834         const lhs = try self.resolveInst(bin_op.lhs);
   6835         const rhs = try self.resolveInst(bin_op.rhs);
   6836         const inst_ty = self.air.typeOfIndex(inst);
   6837         const scalar_ty = inst_ty.scalarType();
   6838 
   6839         if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.sub, inst_ty, 2, .{ lhs, rhs });
   6840         if (scalar_ty.isSignedInt()) return self.builder.buildNSWSub(lhs, rhs, "");
   6841         return self.builder.buildNUWSub(lhs, rhs, "");
   6842     }
   6843 
   6844     fn airSubWrap(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
   6845         if (self.liveness.isUnused(inst)) return null;
   6846         self.builder.setFastMath(want_fast_math);
   6847 
   6848         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   6849         const lhs = try self.resolveInst(bin_op.lhs);
   6850         const rhs = try self.resolveInst(bin_op.rhs);
   6851 
   6852         return self.builder.buildSub(lhs, rhs, "");
   6853     }
   6854 
   6855     fn airSubSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   6856         if (self.liveness.isUnused(inst)) return null;
   6857 
   6858         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   6859         const lhs = try self.resolveInst(bin_op.lhs);
   6860         const rhs = try self.resolveInst(bin_op.rhs);
   6861         const inst_ty = self.air.typeOfIndex(inst);
   6862         const scalar_ty = inst_ty.scalarType();
   6863 
   6864         if (scalar_ty.isAnyFloat()) return self.todo("saturating float sub", .{});
   6865         if (scalar_ty.isSignedInt()) return self.builder.buildSSubSat(lhs, rhs, "");
   6866         return self.builder.buildUSubSat(lhs, rhs, "");
   6867     }
   6868 
   6869     fn airMul(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
   6870         if (self.liveness.isUnused(inst)) return null;
   6871         self.builder.setFastMath(want_fast_math);
   6872 
   6873         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   6874         const lhs = try self.resolveInst(bin_op.lhs);
   6875         const rhs = try self.resolveInst(bin_op.rhs);
   6876         const inst_ty = self.air.typeOfIndex(inst);
   6877         const scalar_ty = inst_ty.scalarType();
   6878 
   6879         if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.mul, inst_ty, 2, .{ lhs, rhs });
   6880         if (scalar_ty.isSignedInt()) return self.builder.buildNSWMul(lhs, rhs, "");
   6881         return self.builder.buildNUWMul(lhs, rhs, "");
   6882     }
   6883 
   6884     fn airMulWrap(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
   6885         if (self.liveness.isUnused(inst)) return null;
   6886         self.builder.setFastMath(want_fast_math);
   6887 
   6888         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   6889         const lhs = try self.resolveInst(bin_op.lhs);
   6890         const rhs = try self.resolveInst(bin_op.rhs);
   6891 
   6892         return self.builder.buildMul(lhs, rhs, "");
   6893     }
   6894 
   6895     fn airMulSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   6896         if (self.liveness.isUnused(inst)) return null;
   6897 
   6898         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   6899         const lhs = try self.resolveInst(bin_op.lhs);
   6900         const rhs = try self.resolveInst(bin_op.rhs);
   6901         const inst_ty = self.air.typeOfIndex(inst);
   6902         const scalar_ty = inst_ty.scalarType();
   6903 
   6904         if (scalar_ty.isAnyFloat()) return self.todo("saturating float mul", .{});
   6905         if (scalar_ty.isSignedInt()) return self.builder.buildSMulFixSat(lhs, rhs, "");
   6906         return self.builder.buildUMulFixSat(lhs, rhs, "");
   6907     }
   6908 
   6909     fn airDivFloat(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
   6910         if (self.liveness.isUnused(inst)) return null;
   6911         self.builder.setFastMath(want_fast_math);
   6912 
   6913         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   6914         const lhs = try self.resolveInst(bin_op.lhs);
   6915         const rhs = try self.resolveInst(bin_op.rhs);
   6916         const inst_ty = self.air.typeOfIndex(inst);
   6917 
   6918         return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });
   6919     }
   6920 
   6921     fn airDivTrunc(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
   6922         if (self.liveness.isUnused(inst)) return null;
   6923         self.builder.setFastMath(want_fast_math);
   6924 
   6925         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   6926         const lhs = try self.resolveInst(bin_op.lhs);
   6927         const rhs = try self.resolveInst(bin_op.rhs);
   6928         const inst_ty = self.air.typeOfIndex(inst);
   6929         const scalar_ty = inst_ty.scalarType();
   6930 
   6931         if (scalar_ty.isRuntimeFloat()) {
   6932             const result = try self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });
   6933             return self.buildFloatOp(.trunc, inst_ty, 1, .{result});
   6934         }
   6935         if (scalar_ty.isSignedInt()) return self.builder.buildSDiv(lhs, rhs, "");
   6936         return self.builder.buildUDiv(lhs, rhs, "");
   6937     }
   6938 
   6939     fn airDivFloor(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
   6940         if (self.liveness.isUnused(inst)) return null;
   6941         self.builder.setFastMath(want_fast_math);
   6942 
   6943         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   6944         const lhs = try self.resolveInst(bin_op.lhs);
   6945         const rhs = try self.resolveInst(bin_op.rhs);
   6946         const inst_ty = self.air.typeOfIndex(inst);
   6947         const scalar_ty = inst_ty.scalarType();
   6948 
   6949         if (scalar_ty.isRuntimeFloat()) {
   6950             const result = try self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });
   6951             return self.buildFloatOp(.floor, inst_ty, 1, .{result});
   6952         }
   6953         if (scalar_ty.isSignedInt()) {
   6954             // const d = @divTrunc(a, b);
   6955             // const r = @rem(a, b);
   6956             // return if (r == 0) d else d - ((a < 0) ^ (b < 0));
   6957             const result_llvm_ty = try self.dg.lowerType(inst_ty);
   6958             const zero = result_llvm_ty.constNull();
   6959             const div_trunc = self.builder.buildSDiv(lhs, rhs, "");
   6960             const rem = self.builder.buildSRem(lhs, rhs, "");
   6961             const rem_eq_0 = self.builder.buildICmp(.EQ, rem, zero, "");
   6962             const a_lt_0 = self.builder.buildICmp(.SLT, lhs, zero, "");
   6963             const b_lt_0 = self.builder.buildICmp(.SLT, rhs, zero, "");
   6964             const a_b_xor = self.builder.buildXor(a_lt_0, b_lt_0, "");
   6965             const a_b_xor_ext = self.builder.buildZExt(a_b_xor, div_trunc.typeOf(), "");
   6966             const d_sub_xor = self.builder.buildSub(div_trunc, a_b_xor_ext, "");
   6967             return self.builder.buildSelect(rem_eq_0, div_trunc, d_sub_xor, "");
   6968         }
   6969         return self.builder.buildUDiv(lhs, rhs, "");
   6970     }
   6971 
   6972     fn airDivExact(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
   6973         if (self.liveness.isUnused(inst)) return null;
   6974         self.builder.setFastMath(want_fast_math);
   6975 
   6976         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   6977         const lhs = try self.resolveInst(bin_op.lhs);
   6978         const rhs = try self.resolveInst(bin_op.rhs);
   6979         const inst_ty = self.air.typeOfIndex(inst);
   6980         const scalar_ty = inst_ty.scalarType();
   6981 
   6982         if (scalar_ty.isRuntimeFloat()) return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });
   6983         if (scalar_ty.isSignedInt()) return self.builder.buildExactSDiv(lhs, rhs, "");
   6984         return self.builder.buildExactUDiv(lhs, rhs, "");
   6985     }
   6986 
   6987     fn airRem(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
   6988         if (self.liveness.isUnused(inst)) return null;
   6989         self.builder.setFastMath(want_fast_math);
   6990 
   6991         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   6992         const lhs = try self.resolveInst(bin_op.lhs);
   6993         const rhs = try self.resolveInst(bin_op.rhs);
   6994         const inst_ty = self.air.typeOfIndex(inst);
   6995         const scalar_ty = inst_ty.scalarType();
   6996 
   6997         if (scalar_ty.isRuntimeFloat()) return self.buildFloatOp(.fmod, inst_ty, 2, .{ lhs, rhs });
   6998         if (scalar_ty.isSignedInt()) return self.builder.buildSRem(lhs, rhs, "");
   6999         return self.builder.buildURem(lhs, rhs, "");
   7000     }
   7001 
   7002     fn airMod(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
   7003         if (self.liveness.isUnused(inst)) return null;
   7004         self.builder.setFastMath(want_fast_math);
   7005 
   7006         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   7007         const lhs = try self.resolveInst(bin_op.lhs);
   7008         const rhs = try self.resolveInst(bin_op.rhs);
   7009         const inst_ty = self.air.typeOfIndex(inst);
   7010         const inst_llvm_ty = try self.dg.lowerType(inst_ty);
   7011         const scalar_ty = inst_ty.scalarType();
   7012 
   7013         if (scalar_ty.isRuntimeFloat()) {
   7014             const a = try self.buildFloatOp(.fmod, inst_ty, 2, .{ lhs, rhs });
   7015             const b = try self.buildFloatOp(.add, inst_ty, 2, .{ a, rhs });
   7016             const c = try self.buildFloatOp(.fmod, inst_ty, 2, .{ b, rhs });
   7017             const zero = inst_llvm_ty.constNull();
   7018             const ltz = try self.buildFloatCmp(.lt, inst_ty, .{ lhs, zero });
   7019             return self.builder.buildSelect(ltz, c, a, "");
   7020         }
   7021         if (scalar_ty.isSignedInt()) {
   7022             const a = self.builder.buildSRem(lhs, rhs, "");
   7023             const b = self.builder.buildNSWAdd(a, rhs, "");
   7024             const c = self.builder.buildSRem(b, rhs, "");
   7025             const zero = inst_llvm_ty.constNull();
   7026             const ltz = self.builder.buildICmp(.SLT, lhs, zero, "");
   7027             return self.builder.buildSelect(ltz, c, a, "");
   7028         }
   7029         return self.builder.buildURem(lhs, rhs, "");
   7030     }
   7031 
   7032     fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   7033         if (self.liveness.isUnused(inst)) return null;
   7034 
   7035         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
   7036         const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
   7037         const base_ptr = try self.resolveInst(bin_op.lhs);
   7038         const offset = try self.resolveInst(bin_op.rhs);
   7039         const ptr_ty = self.air.typeOf(bin_op.lhs);
   7040         const llvm_elem_ty = try self.dg.lowerPtrElemTy(ptr_ty.childType());
   7041         if (ptr_ty.ptrSize() == .One) {
   7042             // It's a pointer to an array, so according to LLVM we need an extra GEP index.
   7043             const indices: [2]*llvm.Value = .{
   7044                 self.context.intType(32).constNull(), offset,
   7045             };
   7046             return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
   7047         } else {
   7048             const indices: [1]*llvm.Value = .{offset};
   7049             return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
   7050         }
   7051     }
   7052 
   7053     fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   7054         if (self.liveness.isUnused(inst)) return null;
   7055 
   7056         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
   7057         const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
   7058         const base_ptr = try self.resolveInst(bin_op.lhs);
   7059         const offset = try self.resolveInst(bin_op.rhs);
   7060         const negative_offset = self.builder.buildNeg(offset, "");
   7061         const ptr_ty = self.air.typeOf(bin_op.lhs);
   7062         const llvm_elem_ty = try self.dg.lowerPtrElemTy(ptr_ty.childType());
   7063         if (ptr_ty.ptrSize() == .One) {
   7064             // It's a pointer to an array, so according to LLVM we need an extra GEP index.
   7065             const indices: [2]*llvm.Value = .{
   7066                 self.context.intType(32).constNull(), negative_offset,
   7067             };
   7068             return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
   7069         } else {
   7070             const indices: [1]*llvm.Value = .{negative_offset};
   7071             return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
   7072         }
   7073     }
   7074 
   7075     fn airOverflow(
   7076         self: *FuncGen,
   7077         inst: Air.Inst.Index,
   7078         signed_intrinsic: []const u8,
   7079         unsigned_intrinsic: []const u8,
   7080     ) !?*llvm.Value {
   7081         if (self.liveness.isUnused(inst))
   7082             return null;
   7083 
   7084         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
   7085         const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
   7086 
   7087         const lhs = try self.resolveInst(extra.lhs);
   7088         const rhs = try self.resolveInst(extra.rhs);
   7089 
   7090         const lhs_ty = self.air.typeOf(extra.lhs);
   7091         const scalar_ty = lhs_ty.scalarType();
   7092         const dest_ty = self.air.typeOfIndex(inst);
   7093 
   7094         const intrinsic_name = if (scalar_ty.isSignedInt()) signed_intrinsic else unsigned_intrinsic;
   7095 
   7096         const llvm_lhs_ty = try self.dg.lowerType(lhs_ty);
   7097         const llvm_dest_ty = try self.dg.lowerType(dest_ty);
   7098 
   7099         const tg = self.dg.module.getTarget();
   7100 
   7101         const llvm_fn = self.getIntrinsic(intrinsic_name, &.{llvm_lhs_ty});
   7102         const result_struct = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &[_]*llvm.Value{ lhs, rhs }, 2, .Fast, .Auto, "");
   7103 
   7104         const result = self.builder.buildExtractValue(result_struct, 0, "");
   7105         const overflow_bit = self.builder.buildExtractValue(result_struct, 1, "");
   7106 
   7107         var ty_buf: Type.Payload.Pointer = undefined;
   7108         const result_index = llvmFieldIndex(dest_ty, 0, tg, &ty_buf).?;
   7109         const overflow_index = llvmFieldIndex(dest_ty, 1, tg, &ty_buf).?;
   7110 
   7111         if (isByRef(dest_ty)) {
   7112             const target = self.dg.module.getTarget();
   7113             const result_alignment = dest_ty.abiAlignment(target);
   7114             const alloca_inst = self.buildAlloca(llvm_dest_ty, result_alignment);
   7115             {
   7116                 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, "");
   7117                 const store_inst = self.builder.buildStore(result, field_ptr);
   7118                 store_inst.setAlignment(result_alignment);
   7119             }
   7120             {
   7121                 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, overflow_index, "");
   7122                 const store_inst = self.builder.buildStore(overflow_bit, field_ptr);
   7123                 store_inst.setAlignment(1);
   7124             }
   7125 
   7126             return alloca_inst;
   7127         }
   7128 
   7129         const partial = self.builder.buildInsertValue(llvm_dest_ty.getUndef(), result, result_index, "");
   7130         return self.builder.buildInsertValue(partial, overflow_bit, overflow_index, "");
   7131     }
   7132 
   7133     fn buildElementwiseCall(
   7134         self: *FuncGen,
   7135         llvm_fn: *llvm.Value,
   7136         args_vectors: []const *llvm.Value,
   7137         result_vector: *llvm.Value,
   7138         vector_len: usize,
   7139     ) !*llvm.Value {
   7140         const args_len = @intCast(c_uint, args_vectors.len);
   7141         const llvm_i32 = self.context.intType(32);
   7142         assert(args_len <= 3);
   7143 
   7144         var i: usize = 0;
   7145         var result = result_vector;
   7146         while (i < vector_len) : (i += 1) {
   7147             const index_i32 = llvm_i32.constInt(i, .False);
   7148 
   7149             var args: [3]*llvm.Value = undefined;
   7150             for (args_vectors) |arg_vector, k| {
   7151                 args[k] = self.builder.buildExtractElement(arg_vector, index_i32, "");
   7152             }
   7153             const result_elem = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args_len, .C, .Auto, "");
   7154             result = self.builder.buildInsertElement(result, result_elem, index_i32, "");
   7155         }
   7156         return result;
   7157     }
   7158 
   7159     fn getLibcFunction(
   7160         self: *FuncGen,
   7161         fn_name: [:0]const u8,
   7162         param_types: []const *llvm.Type,
   7163         return_type: *llvm.Type,
   7164     ) *llvm.Value {
   7165         return self.dg.object.llvm_module.getNamedFunction(fn_name.ptr) orelse b: {
   7166             const alias = self.dg.object.llvm_module.getNamedGlobalAlias(fn_name.ptr, fn_name.len);
   7167             break :b if (alias) |a| a.getAliasee() else null;
   7168         } orelse b: {
   7169             const params_len = @intCast(c_uint, param_types.len);
   7170             const fn_type = llvm.functionType(return_type, param_types.ptr, params_len, .False);
   7171             const f = self.dg.object.llvm_module.addFunction(fn_name, fn_type);
   7172             break :b f;
   7173         };
   7174     }
   7175 
   7176     fn libcFloatPrefix(float_bits: u16) []const u8 {
   7177         return switch (float_bits) {
   7178             16, 80 => "__",
   7179             32, 64, 128 => "",
   7180             else => unreachable,
   7181         };
   7182     }
   7183 
   7184     fn libcFloatSuffix(float_bits: u16) []const u8 {
   7185         return switch (float_bits) {
   7186             16 => "h", // Non-standard
   7187             32 => "f",
   7188             64 => "",
   7189             80 => "x", // Non-standard
   7190             128 => "q", // Non-standard (mimics convention in GCC libquadmath)
   7191             else => unreachable,
   7192         };
   7193     }
   7194 
   7195     fn compilerRtFloatAbbrev(float_bits: u16) []const u8 {
   7196         return switch (float_bits) {
   7197             16 => "h",
   7198             32 => "s",
   7199             64 => "d",
   7200             80 => "x",
   7201             128 => "t",
   7202             else => unreachable,
   7203         };
   7204     }
   7205 
   7206     fn compilerRtIntAbbrev(bits: u16) []const u8 {
   7207         return switch (bits) {
   7208             16 => "h",
   7209             32 => "s",
   7210             64 => "d",
   7211             128 => "t",
   7212             else => "o", // Non-standard
   7213         };
   7214     }
   7215 
   7216     /// Creates a floating point comparison by lowering to the appropriate
   7217     /// hardware instruction or softfloat routine for the target
   7218     fn buildFloatCmp(
   7219         self: *FuncGen,
   7220         pred: math.CompareOperator,
   7221         ty: Type,
   7222         params: [2]*llvm.Value,
   7223     ) !*llvm.Value {
   7224         const target = self.dg.module.getTarget();
   7225         const scalar_ty = ty.scalarType();
   7226         const scalar_llvm_ty = try self.dg.lowerType(scalar_ty);
   7227 
   7228         if (intrinsicsAllowed(scalar_ty, target)) {
   7229             const llvm_predicate: llvm.RealPredicate = switch (pred) {
   7230                 .eq => .OEQ,
   7231                 .neq => .UNE,
   7232                 .lt => .OLT,
   7233                 .lte => .OLE,
   7234                 .gt => .OGT,
   7235                 .gte => .OGE,
   7236             };
   7237             return self.builder.buildFCmp(llvm_predicate, params[0], params[1], "");
   7238         }
   7239 
   7240         const float_bits = scalar_ty.floatBits(target);
   7241         const compiler_rt_float_abbrev = compilerRtFloatAbbrev(float_bits);
   7242         var fn_name_buf: [64]u8 = undefined;
   7243         const fn_base_name = switch (pred) {
   7244             .neq => "ne",
   7245             .eq => "eq",
   7246             .lt => "lt",
   7247             .lte => "le",
   7248             .gt => "gt",
   7249             .gte => "ge",
   7250         };
   7251         const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__{s}{s}f2", .{
   7252             fn_base_name, compiler_rt_float_abbrev,
   7253         }) catch unreachable;
   7254 
   7255         const param_types = [2]*llvm.Type{ scalar_llvm_ty, scalar_llvm_ty };
   7256         const llvm_i32 = self.context.intType(32);
   7257         const libc_fn = self.getLibcFunction(fn_name, param_types[0..], llvm_i32);
   7258 
   7259         const zero = llvm_i32.constInt(0, .False);
   7260         const int_pred: llvm.IntPredicate = switch (pred) {
   7261             .eq => .EQ,
   7262             .neq => .NE,
   7263             .lt => .SLT,
   7264             .lte => .SLE,
   7265             .gt => .SGT,
   7266             .gte => .SGE,
   7267         };
   7268 
   7269         if (ty.zigTypeTag() == .Vector) {
   7270             const vec_len = ty.vectorLen();
   7271             const vector_result_ty = llvm_i32.vectorType(vec_len);
   7272 
   7273             var result = vector_result_ty.getUndef();
   7274             result = try self.buildElementwiseCall(libc_fn, &params, result, vec_len);
   7275 
   7276             const zero_vector = self.builder.buildVectorSplat(vec_len, zero, "");
   7277             return self.builder.buildICmp(int_pred, result, zero_vector, "");
   7278         }
   7279 
   7280         const result = self.builder.buildCall(libc_fn.globalGetValueType(), libc_fn, &params, params.len, .C, .Auto, "");
   7281         return self.builder.buildICmp(int_pred, result, zero, "");
   7282     }
   7283 
   7284     const FloatOp = enum {
   7285         add,
   7286         ceil,
   7287         cos,
   7288         div,
   7289         exp,
   7290         exp2,
   7291         fabs,
   7292         floor,
   7293         fma,
   7294         fmax,
   7295         fmin,
   7296         fmod,
   7297         log,
   7298         log10,
   7299         log2,
   7300         mul,
   7301         neg,
   7302         round,
   7303         sin,
   7304         sqrt,
   7305         sub,
   7306         tan,
   7307         trunc,
   7308     };
   7309 
   7310     const FloatOpStrat = union(enum) {
   7311         intrinsic: []const u8,
   7312         libc: [:0]const u8,
   7313     };
   7314 
   7315     /// Creates a floating point operation (add, sub, fma, sqrt, exp, etc.)
   7316     /// by lowering to the appropriate hardware instruction or softfloat
   7317     /// routine for the target
   7318     fn buildFloatOp(
   7319         self: *FuncGen,
   7320         comptime op: FloatOp,
   7321         ty: Type,
   7322         comptime params_len: usize,
   7323         params: [params_len]*llvm.Value,
   7324     ) !*llvm.Value {
   7325         const target = self.dg.module.getTarget();
   7326         const scalar_ty = ty.scalarType();
   7327         const llvm_ty = try self.dg.lowerType(ty);
   7328         const scalar_llvm_ty = try self.dg.lowerType(scalar_ty);
   7329 
   7330         const intrinsics_allowed = op != .tan and intrinsicsAllowed(scalar_ty, target);
   7331         var fn_name_buf: [64]u8 = undefined;
   7332         const strat: FloatOpStrat = if (intrinsics_allowed) switch (op) {
   7333             // Some operations are dedicated LLVM instructions, not available as intrinsics
   7334             .neg => return self.builder.buildFNeg(params[0], ""),
   7335             .add => return self.builder.buildFAdd(params[0], params[1], ""),
   7336             .sub => return self.builder.buildFSub(params[0], params[1], ""),
   7337             .mul => return self.builder.buildFMul(params[0], params[1], ""),
   7338             .div => return self.builder.buildFDiv(params[0], params[1], ""),
   7339             .fmod => return self.builder.buildFRem(params[0], params[1], ""),
   7340             .fmax => return self.builder.buildMaxNum(params[0], params[1], ""),
   7341             .fmin => return self.builder.buildMinNum(params[0], params[1], ""),
   7342             else => .{ .intrinsic = "llvm." ++ @tagName(op) },
   7343         } else b: {
   7344             const float_bits = scalar_ty.floatBits(target);
   7345             break :b switch (op) {
   7346                 .neg => {
   7347                     // In this case we can generate a softfloat negation by XORing the
   7348                     // bits with a constant.
   7349                     const int_llvm_ty = self.dg.context.intType(float_bits);
   7350                     const one = int_llvm_ty.constInt(1, .False);
   7351                     const shift_amt = int_llvm_ty.constInt(float_bits - 1, .False);
   7352                     const sign_mask = one.constShl(shift_amt);
   7353                     const result = if (ty.zigTypeTag() == .Vector) blk: {
   7354                         const splat_sign_mask = self.builder.buildVectorSplat(ty.vectorLen(), sign_mask, "");
   7355                         const cast_ty = int_llvm_ty.vectorType(ty.vectorLen());
   7356                         const bitcasted_operand = self.builder.buildBitCast(params[0], cast_ty, "");
   7357                         break :blk self.builder.buildXor(bitcasted_operand, splat_sign_mask, "");
   7358                     } else blk: {
   7359                         const bitcasted_operand = self.builder.buildBitCast(params[0], int_llvm_ty, "");
   7360                         break :blk self.builder.buildXor(bitcasted_operand, sign_mask, "");
   7361                     };
   7362                     return self.builder.buildBitCast(result, llvm_ty, "");
   7363                 },
   7364                 .add, .sub, .div, .mul => FloatOpStrat{
   7365                     .libc = std.fmt.bufPrintZ(&fn_name_buf, "__{s}{s}f3", .{
   7366                         @tagName(op), compilerRtFloatAbbrev(float_bits),
   7367                     }) catch unreachable,
   7368                 },
   7369                 .ceil,
   7370                 .cos,
   7371                 .exp,
   7372                 .exp2,
   7373                 .fabs,
   7374                 .floor,
   7375                 .fma,
   7376                 .fmax,
   7377                 .fmin,
   7378                 .fmod,
   7379                 .log,
   7380                 .log10,
   7381                 .log2,
   7382                 .round,
   7383                 .sin,
   7384                 .sqrt,
   7385                 .tan,
   7386                 .trunc,
   7387                 => FloatOpStrat{
   7388                     .libc = std.fmt.bufPrintZ(&fn_name_buf, "{s}{s}{s}", .{
   7389                         libcFloatPrefix(float_bits), @tagName(op), libcFloatSuffix(float_bits),
   7390                     }) catch unreachable,
   7391                 },
   7392             };
   7393         };
   7394 
   7395         const llvm_fn: *llvm.Value = switch (strat) {
   7396             .intrinsic => |fn_name| self.getIntrinsic(fn_name, &.{llvm_ty}),
   7397             .libc => |fn_name| b: {
   7398                 const param_types = [3]*llvm.Type{ scalar_llvm_ty, scalar_llvm_ty, scalar_llvm_ty };
   7399                 const libc_fn = self.getLibcFunction(fn_name, param_types[0..params.len], scalar_llvm_ty);
   7400                 if (ty.zigTypeTag() == .Vector) {
   7401                     const result = llvm_ty.getUndef();
   7402                     return self.buildElementwiseCall(libc_fn, &params, result, ty.vectorLen());
   7403                 }
   7404 
   7405                 break :b libc_fn;
   7406             },
   7407         };
   7408         return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params_len, .C, .Auto, "");
   7409     }
   7410 
   7411     fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   7412         if (self.liveness.isUnused(inst)) return null;
   7413 
   7414         const pl_op = self.air.instructions.items(.data)[inst].pl_op;
   7415         const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
   7416 
   7417         const mulend1 = try self.resolveInst(extra.lhs);
   7418         const mulend2 = try self.resolveInst(extra.rhs);
   7419         const addend = try self.resolveInst(pl_op.operand);
   7420 
   7421         const ty = self.air.typeOfIndex(inst);
   7422         return self.buildFloatOp(.fma, ty, 3, .{ mulend1, mulend2, addend });
   7423     }
   7424 
   7425     fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   7426         if (self.liveness.isUnused(inst))
   7427             return null;
   7428 
   7429         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
   7430         const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
   7431 
   7432         const lhs = try self.resolveInst(extra.lhs);
   7433         const rhs = try self.resolveInst(extra.rhs);
   7434 
   7435         const lhs_ty = self.air.typeOf(extra.lhs);
   7436         const rhs_ty = self.air.typeOf(extra.rhs);
   7437         const lhs_scalar_ty = lhs_ty.scalarType();
   7438         const rhs_scalar_ty = rhs_ty.scalarType();
   7439 
   7440         const dest_ty = self.air.typeOfIndex(inst);
   7441         const llvm_dest_ty = try self.dg.lowerType(dest_ty);
   7442 
   7443         const tg = self.dg.module.getTarget();
   7444 
   7445         const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
   7446             self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_ty), "")
   7447         else
   7448             rhs;
   7449 
   7450         const result = self.builder.buildShl(lhs, casted_rhs, "");
   7451         const reconstructed = if (lhs_scalar_ty.isSignedInt())
   7452             self.builder.buildAShr(result, casted_rhs, "")
   7453         else
   7454             self.builder.buildLShr(result, casted_rhs, "");
   7455 
   7456         const overflow_bit = self.builder.buildICmp(.NE, lhs, reconstructed, "");
   7457 
   7458         var ty_buf: Type.Payload.Pointer = undefined;
   7459         const result_index = llvmFieldIndex(dest_ty, 0, tg, &ty_buf).?;
   7460         const overflow_index = llvmFieldIndex(dest_ty, 1, tg, &ty_buf).?;
   7461 
   7462         if (isByRef(dest_ty)) {
   7463             const target = self.dg.module.getTarget();
   7464             const result_alignment = dest_ty.abiAlignment(target);
   7465             const alloca_inst = self.buildAlloca(llvm_dest_ty, result_alignment);
   7466             {
   7467                 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, "");
   7468                 const store_inst = self.builder.buildStore(result, field_ptr);
   7469                 store_inst.setAlignment(result_alignment);
   7470             }
   7471             {
   7472                 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, overflow_index, "");
   7473                 const store_inst = self.builder.buildStore(overflow_bit, field_ptr);
   7474                 store_inst.setAlignment(1);
   7475             }
   7476 
   7477             return alloca_inst;
   7478         }
   7479 
   7480         const partial = self.builder.buildInsertValue(llvm_dest_ty.getUndef(), result, result_index, "");
   7481         return self.builder.buildInsertValue(partial, overflow_bit, overflow_index, "");
   7482     }
   7483 
   7484     fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   7485         if (self.liveness.isUnused(inst))
   7486             return null;
   7487         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   7488         const lhs = try self.resolveInst(bin_op.lhs);
   7489         const rhs = try self.resolveInst(bin_op.rhs);
   7490         return self.builder.buildAnd(lhs, rhs, "");
   7491     }
   7492 
   7493     fn airOr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   7494         if (self.liveness.isUnused(inst))
   7495             return null;
   7496         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   7497         const lhs = try self.resolveInst(bin_op.lhs);
   7498         const rhs = try self.resolveInst(bin_op.rhs);
   7499         return self.builder.buildOr(lhs, rhs, "");
   7500     }
   7501 
   7502     fn airXor(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   7503         if (self.liveness.isUnused(inst))
   7504             return null;
   7505         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   7506         const lhs = try self.resolveInst(bin_op.lhs);
   7507         const rhs = try self.resolveInst(bin_op.rhs);
   7508         return self.builder.buildXor(lhs, rhs, "");
   7509     }
   7510 
   7511     fn airShlExact(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   7512         if (self.liveness.isUnused(inst)) return null;
   7513 
   7514         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   7515 
   7516         const lhs = try self.resolveInst(bin_op.lhs);
   7517         const rhs = try self.resolveInst(bin_op.rhs);
   7518 
   7519         const lhs_ty = self.air.typeOf(bin_op.lhs);
   7520         const rhs_ty = self.air.typeOf(bin_op.rhs);
   7521         const lhs_scalar_ty = lhs_ty.scalarType();
   7522         const rhs_scalar_ty = rhs_ty.scalarType();
   7523 
   7524         const tg = self.dg.module.getTarget();
   7525 
   7526         const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
   7527             self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_ty), "")
   7528         else
   7529             rhs;
   7530         if (lhs_scalar_ty.isSignedInt()) return self.builder.buildNSWShl(lhs, casted_rhs, "");
   7531         return self.builder.buildNUWShl(lhs, casted_rhs, "");
   7532     }
   7533 
   7534     fn airShl(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   7535         if (self.liveness.isUnused(inst)) return null;
   7536 
   7537         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   7538 
   7539         const lhs = try self.resolveInst(bin_op.lhs);
   7540         const rhs = try self.resolveInst(bin_op.rhs);
   7541 
   7542         const lhs_type = self.air.typeOf(bin_op.lhs);
   7543         const rhs_type = self.air.typeOf(bin_op.rhs);
   7544         const lhs_scalar_ty = lhs_type.scalarType();
   7545         const rhs_scalar_ty = rhs_type.scalarType();
   7546 
   7547         const tg = self.dg.module.getTarget();
   7548 
   7549         const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
   7550             self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_type), "")
   7551         else
   7552             rhs;
   7553         return self.builder.buildShl(lhs, casted_rhs, "");
   7554     }
   7555 
   7556     fn airShlSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   7557         if (self.liveness.isUnused(inst)) return null;
   7558 
   7559         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   7560 
   7561         const lhs = try self.resolveInst(bin_op.lhs);
   7562         const rhs = try self.resolveInst(bin_op.rhs);
   7563 
   7564         const lhs_ty = self.air.typeOf(bin_op.lhs);
   7565         const rhs_ty = self.air.typeOf(bin_op.rhs);
   7566         const lhs_scalar_ty = lhs_ty.scalarType();
   7567         const rhs_scalar_ty = rhs_ty.scalarType();
   7568         const tg = self.dg.module.getTarget();
   7569         const lhs_bits = lhs_scalar_ty.bitSize(tg);
   7570 
   7571         const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_bits)
   7572             self.builder.buildZExt(rhs, lhs.typeOf(), "")
   7573         else
   7574             rhs;
   7575 
   7576         const result = if (lhs_scalar_ty.isSignedInt())
   7577             self.builder.buildSShlSat(lhs, casted_rhs, "")
   7578         else
   7579             self.builder.buildUShlSat(lhs, casted_rhs, "");
   7580 
   7581         // LLVM langref says "If b is (statically or dynamically) equal to or
   7582         // larger than the integer bit width of the arguments, the result is a
   7583         // poison value."
   7584         // However Zig semantics says that saturating shift left can never produce
   7585         // undefined; instead it saturates.
   7586         const lhs_scalar_llvm_ty = try self.dg.lowerType(lhs_scalar_ty);
   7587         const bits = lhs_scalar_llvm_ty.constInt(lhs_bits, .False);
   7588         const lhs_max = lhs_scalar_llvm_ty.constAllOnes();
   7589         if (rhs_ty.zigTypeTag() == .Vector) {
   7590             const vec_len = rhs_ty.vectorLen();
   7591             const bits_vec = self.builder.buildVectorSplat(vec_len, bits, "");
   7592             const lhs_max_vec = self.builder.buildVectorSplat(vec_len, lhs_max, "");
   7593             const in_range = self.builder.buildICmp(.ULT, rhs, bits_vec, "");
   7594             return self.builder.buildSelect(in_range, result, lhs_max_vec, "");
   7595         } else {
   7596             const in_range = self.builder.buildICmp(.ULT, rhs, bits, "");
   7597             return self.builder.buildSelect(in_range, result, lhs_max, "");
   7598         }
   7599     }
   7600 
   7601     fn airShr(self: *FuncGen, inst: Air.Inst.Index, is_exact: bool) !?*llvm.Value {
   7602         if (self.liveness.isUnused(inst)) return null;
   7603 
   7604         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   7605 
   7606         const lhs = try self.resolveInst(bin_op.lhs);
   7607         const rhs = try self.resolveInst(bin_op.rhs);
   7608 
   7609         const lhs_ty = self.air.typeOf(bin_op.lhs);
   7610         const rhs_ty = self.air.typeOf(bin_op.rhs);
   7611         const lhs_scalar_ty = lhs_ty.scalarType();
   7612         const rhs_scalar_ty = rhs_ty.scalarType();
   7613 
   7614         const tg = self.dg.module.getTarget();
   7615 
   7616         const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
   7617             self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_ty), "")
   7618         else
   7619             rhs;
   7620         const is_signed_int = lhs_scalar_ty.isSignedInt();
   7621 
   7622         if (is_exact) {
   7623             if (is_signed_int) {
   7624                 return self.builder.buildAShrExact(lhs, casted_rhs, "");
   7625             } else {
   7626                 return self.builder.buildLShrExact(lhs, casted_rhs, "");
   7627             }
   7628         } else {
   7629             if (is_signed_int) {
   7630                 return self.builder.buildAShr(lhs, casted_rhs, "");
   7631             } else {
   7632                 return self.builder.buildLShr(lhs, casted_rhs, "");
   7633             }
   7634         }
   7635     }
   7636 
   7637     fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   7638         if (self.liveness.isUnused(inst))
   7639             return null;
   7640 
   7641         const target = self.dg.module.getTarget();
   7642         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   7643         const dest_ty = self.air.typeOfIndex(inst);
   7644         const dest_info = dest_ty.intInfo(target);
   7645         const dest_llvm_ty = try self.dg.lowerType(dest_ty);
   7646         const operand = try self.resolveInst(ty_op.operand);
   7647         const operand_ty = self.air.typeOf(ty_op.operand);
   7648         const operand_info = operand_ty.intInfo(target);
   7649 
   7650         if (operand_info.bits < dest_info.bits) {
   7651             switch (operand_info.signedness) {
   7652                 .signed => return self.builder.buildSExt(operand, dest_llvm_ty, ""),
   7653                 .unsigned => return self.builder.buildZExt(operand, dest_llvm_ty, ""),
   7654             }
   7655         } else if (operand_info.bits > dest_info.bits) {
   7656             return self.builder.buildTrunc(operand, dest_llvm_ty, "");
   7657         } else {
   7658             return operand;
   7659         }
   7660     }
   7661 
   7662     fn airTrunc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   7663         if (self.liveness.isUnused(inst)) return null;
   7664 
   7665         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   7666         const operand = try self.resolveInst(ty_op.operand);
   7667         const dest_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
   7668         return self.builder.buildTrunc(operand, dest_llvm_ty, "");
   7669     }
   7670 
   7671     fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   7672         if (self.liveness.isUnused(inst))
   7673             return null;
   7674 
   7675         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   7676         const operand = try self.resolveInst(ty_op.operand);
   7677         const operand_ty = self.air.typeOf(ty_op.operand);
   7678         const dest_ty = self.air.typeOfIndex(inst);
   7679         const target = self.dg.module.getTarget();
   7680         const dest_bits = dest_ty.floatBits(target);
   7681         const src_bits = operand_ty.floatBits(target);
   7682 
   7683         if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) {
   7684             const dest_llvm_ty = try self.dg.lowerType(dest_ty);
   7685             return self.builder.buildFPTrunc(operand, dest_llvm_ty, "");
   7686         } else {
   7687             const operand_llvm_ty = try self.dg.lowerType(operand_ty);
   7688             const dest_llvm_ty = try self.dg.lowerType(dest_ty);
   7689 
   7690             var fn_name_buf: [64]u8 = undefined;
   7691             const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__trunc{s}f{s}f2", .{
   7692                 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
   7693             }) catch unreachable;
   7694 
   7695             const params = [1]*llvm.Value{operand};
   7696             const param_types = [1]*llvm.Type{operand_llvm_ty};
   7697             const llvm_fn = self.getLibcFunction(fn_name, &param_types, dest_llvm_ty);
   7698 
   7699             return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .C, .Auto, "");
   7700         }
   7701     }
   7702 
   7703     fn airFpext(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   7704         if (self.liveness.isUnused(inst))
   7705             return null;
   7706 
   7707         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   7708         const operand = try self.resolveInst(ty_op.operand);
   7709         const operand_ty = self.air.typeOf(ty_op.operand);
   7710         const dest_ty = self.air.typeOfIndex(inst);
   7711         const target = self.dg.module.getTarget();
   7712         const dest_bits = dest_ty.floatBits(target);
   7713         const src_bits = operand_ty.floatBits(target);
   7714 
   7715         if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) {
   7716             const dest_llvm_ty = try self.dg.lowerType(dest_ty);
   7717             return self.builder.buildFPExt(operand, dest_llvm_ty, "");
   7718         } else {
   7719             const operand_llvm_ty = try self.dg.lowerType(operand_ty);
   7720             const dest_llvm_ty = try self.dg.lowerType(dest_ty);
   7721 
   7722             var fn_name_buf: [64]u8 = undefined;
   7723             const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__extend{s}f{s}f2", .{
   7724                 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
   7725             }) catch unreachable;
   7726 
   7727             const params = [1]*llvm.Value{operand};
   7728             const param_types = [1]*llvm.Type{operand_llvm_ty};
   7729             const llvm_fn = self.getLibcFunction(fn_name, &param_types, dest_llvm_ty);
   7730 
   7731             return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .C, .Auto, "");
   7732         }
   7733     }
   7734 
   7735     fn airPtrToInt(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   7736         if (self.liveness.isUnused(inst))
   7737             return null;
   7738 
   7739         const un_op = self.air.instructions.items(.data)[inst].un_op;
   7740         const operand = try self.resolveInst(un_op);
   7741         const dest_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
   7742         return self.builder.buildPtrToInt(operand, dest_llvm_ty, "");
   7743     }
   7744 
   7745     fn airBitCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   7746         if (self.liveness.isUnused(inst)) return null;
   7747 
   7748         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   7749         const operand_ty = self.air.typeOf(ty_op.operand);
   7750         const inst_ty = self.air.typeOfIndex(inst);
   7751         const operand = try self.resolveInst(ty_op.operand);
   7752         const operand_is_ref = isByRef(operand_ty);
   7753         const result_is_ref = isByRef(inst_ty);
   7754         const llvm_dest_ty = try self.dg.lowerType(inst_ty);
   7755         const target = self.dg.module.getTarget();
   7756 
   7757         if (operand_is_ref and result_is_ref) {
   7758             // They are both pointers; just do a bitcast on the pointers :)
   7759             return self.builder.buildBitCast(operand, llvm_dest_ty.pointerType(0), "");
   7760         }
   7761 
   7762         if (operand_ty.zigTypeTag() == .Int and inst_ty.isPtrAtRuntime()) {
   7763             return self.builder.buildIntToPtr(operand, llvm_dest_ty, "");
   7764         }
   7765 
   7766         if (operand_ty.zigTypeTag() == .Vector and inst_ty.zigTypeTag() == .Array) {
   7767             const elem_ty = operand_ty.childType();
   7768             if (!result_is_ref) {
   7769                 return self.dg.todo("implement bitcast vector to non-ref array", .{});
   7770             }
   7771             const array_ptr = self.buildAlloca(llvm_dest_ty, null);
   7772             const bitcast_ok = elem_ty.bitSize(target) == elem_ty.abiSize(target) * 8;
   7773             if (bitcast_ok) {
   7774                 const llvm_vector_ty = try self.dg.lowerType(operand_ty);
   7775                 const casted_ptr = self.builder.buildBitCast(array_ptr, llvm_vector_ty.pointerType(0), "");
   7776                 const llvm_store = self.builder.buildStore(operand, casted_ptr);
   7777                 llvm_store.setAlignment(inst_ty.abiAlignment(target));
   7778             } else {
   7779                 // If the ABI size of the element type is not evenly divisible by size in bits;
   7780                 // a simple bitcast will not work, and we fall back to extractelement.
   7781                 const llvm_usize = try self.dg.lowerType(Type.usize);
   7782                 const llvm_u32 = self.context.intType(32);
   7783                 const zero = llvm_usize.constNull();
   7784                 const vector_len = operand_ty.arrayLen();
   7785                 var i: u64 = 0;
   7786                 while (i < vector_len) : (i += 1) {
   7787                     const index_usize = llvm_usize.constInt(i, .False);
   7788                     const index_u32 = llvm_u32.constInt(i, .False);
   7789                     const indexes: [2]*llvm.Value = .{ zero, index_usize };
   7790                     const elem_ptr = self.builder.buildInBoundsGEP(llvm_dest_ty, array_ptr, &indexes, indexes.len, "");
   7791                     const elem = self.builder.buildExtractElement(operand, index_u32, "");
   7792                     _ = self.builder.buildStore(elem, elem_ptr);
   7793                 }
   7794             }
   7795             return array_ptr;
   7796         } else if (operand_ty.zigTypeTag() == .Array and inst_ty.zigTypeTag() == .Vector) {
   7797             const elem_ty = operand_ty.childType();
   7798             const llvm_vector_ty = try self.dg.lowerType(inst_ty);
   7799             if (!operand_is_ref) {
   7800                 return self.dg.todo("implement bitcast non-ref array to vector", .{});
   7801             }
   7802 
   7803             const bitcast_ok = elem_ty.bitSize(target) == elem_ty.abiSize(target) * 8;
   7804             if (bitcast_ok) {
   7805                 const llvm_vector_ptr_ty = llvm_vector_ty.pointerType(0);
   7806                 const casted_ptr = self.builder.buildBitCast(operand, llvm_vector_ptr_ty, "");
   7807                 const vector = self.builder.buildLoad(llvm_vector_ty, casted_ptr, "");
   7808                 // The array is aligned to the element's alignment, while the vector might have a completely
   7809                 // different alignment. This means we need to enforce the alignment of this load.
   7810                 vector.setAlignment(elem_ty.abiAlignment(target));
   7811                 return vector;
   7812             } else {
   7813                 // If the ABI size of the element type is not evenly divisible by size in bits;
   7814                 // a simple bitcast will not work, and we fall back to extractelement.
   7815                 const array_llvm_ty = try self.dg.lowerType(operand_ty);
   7816                 const elem_llvm_ty = try self.dg.lowerType(elem_ty);
   7817                 const llvm_usize = try self.dg.lowerType(Type.usize);
   7818                 const llvm_u32 = self.context.intType(32);
   7819                 const zero = llvm_usize.constNull();
   7820                 const vector_len = operand_ty.arrayLen();
   7821                 var vector = llvm_vector_ty.getUndef();
   7822                 var i: u64 = 0;
   7823                 while (i < vector_len) : (i += 1) {
   7824                     const index_usize = llvm_usize.constInt(i, .False);
   7825                     const index_u32 = llvm_u32.constInt(i, .False);
   7826                     const indexes: [2]*llvm.Value = .{ zero, index_usize };
   7827                     const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, operand, &indexes, indexes.len, "");
   7828                     const elem = self.builder.buildLoad(elem_llvm_ty, elem_ptr, "");
   7829                     vector = self.builder.buildInsertElement(vector, elem, index_u32, "");
   7830                 }
   7831 
   7832                 return vector;
   7833             }
   7834         }
   7835 
   7836         if (operand_is_ref) {
   7837             // Bitcast the operand pointer, then load.
   7838             const casted_ptr = self.builder.buildBitCast(operand, llvm_dest_ty.pointerType(0), "");
   7839             const load_inst = self.builder.buildLoad(llvm_dest_ty, casted_ptr, "");
   7840             load_inst.setAlignment(operand_ty.abiAlignment(target));
   7841             return load_inst;
   7842         }
   7843 
   7844         if (result_is_ref) {
   7845             // Bitcast the result pointer, then store.
   7846             const alignment = @max(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target));
   7847             const result_ptr = self.buildAlloca(llvm_dest_ty, alignment);
   7848             const operand_llvm_ty = try self.dg.lowerType(operand_ty);
   7849             const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), "");
   7850             const store_inst = self.builder.buildStore(operand, casted_ptr);
   7851             store_inst.setAlignment(alignment);
   7852             return result_ptr;
   7853         }
   7854 
   7855         if (llvm_dest_ty.getTypeKind() == .Struct) {
   7856             // Both our operand and our result are values, not pointers,
   7857             // but LLVM won't let us bitcast struct values.
   7858             // Therefore, we store operand to bitcasted alloca, then load for result.
   7859             const alignment = @max(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target));
   7860             const result_ptr = self.buildAlloca(llvm_dest_ty, alignment);
   7861             const operand_llvm_ty = try self.dg.lowerType(operand_ty);
   7862             const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), "");
   7863             const store_inst = self.builder.buildStore(operand, casted_ptr);
   7864             store_inst.setAlignment(alignment);
   7865             const load_inst = self.builder.buildLoad(llvm_dest_ty, result_ptr, "");
   7866             load_inst.setAlignment(alignment);
   7867             return load_inst;
   7868         }
   7869 
   7870         return self.builder.buildBitCast(operand, llvm_dest_ty, "");
   7871     }
   7872 
   7873     fn airBoolToInt(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   7874         if (self.liveness.isUnused(inst))
   7875             return null;
   7876 
   7877         const un_op = self.air.instructions.items(.data)[inst].un_op;
   7878         const operand = try self.resolveInst(un_op);
   7879         return operand;
   7880     }
   7881 
   7882     fn airArg(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   7883         const arg_val = self.args[self.arg_index];
   7884         self.arg_index += 1;
   7885 
   7886         const inst_ty = self.air.typeOfIndex(inst);
   7887         if (self.dg.object.di_builder) |dib| {
   7888             if (needDbgVarWorkaround(self.dg)) {
   7889                 return arg_val;
   7890             }
   7891 
   7892             const src_index = self.getSrcArgIndex(self.arg_index - 1);
   7893             const func = self.dg.decl.getFunction().?;
   7894             const lbrace_line = self.dg.module.declPtr(func.owner_decl).src_line + func.lbrace_line + 1;
   7895             const lbrace_col = func.lbrace_column + 1;
   7896             const di_local_var = dib.createParameterVariable(
   7897                 self.di_scope.?,
   7898                 func.getParamName(self.dg.module, src_index).ptr, // TODO test 0 bit args
   7899                 self.di_file.?,
   7900                 lbrace_line,
   7901                 try self.dg.object.lowerDebugType(inst_ty, .full),
   7902                 true, // always preserve
   7903                 0, // flags
   7904                 self.arg_index, // includes +1 because 0 is return type
   7905             );
   7906 
   7907             const debug_loc = llvm.getDebugLoc(lbrace_line, lbrace_col, self.di_scope.?, null);
   7908             const insert_block = self.builder.getInsertBlock();
   7909             if (isByRef(inst_ty)) {
   7910                 _ = dib.insertDeclareAtEnd(arg_val, di_local_var, debug_loc, insert_block);
   7911             } else {
   7912                 _ = dib.insertDbgValueIntrinsicAtEnd(arg_val, di_local_var, debug_loc, insert_block);
   7913             }
   7914         }
   7915 
   7916         return arg_val;
   7917     }
   7918 
   7919     fn getSrcArgIndex(self: *FuncGen, runtime_index: u32) u32 {
   7920         const fn_info = self.dg.decl.ty.fnInfo();
   7921         var i: u32 = 0;
   7922         for (fn_info.param_types) |param_ty, src_index| {
   7923             if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue;
   7924             if (i == runtime_index) return @intCast(u32, src_index);
   7925             i += 1;
   7926         } else unreachable;
   7927     }
   7928 
   7929     fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   7930         if (self.liveness.isUnused(inst)) return null;
   7931         const ptr_ty = self.air.typeOfIndex(inst);
   7932         const pointee_type = ptr_ty.childType();
   7933         if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty);
   7934 
   7935         const pointee_llvm_ty = try self.dg.lowerType(pointee_type);
   7936         const target = self.dg.module.getTarget();
   7937         const alignment = ptr_ty.ptrAlignment(target);
   7938         return self.buildAlloca(pointee_llvm_ty, alignment);
   7939     }
   7940 
   7941     fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   7942         if (self.liveness.isUnused(inst)) return null;
   7943         const ptr_ty = self.air.typeOfIndex(inst);
   7944         const ret_ty = ptr_ty.childType();
   7945         if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty);
   7946         if (self.ret_ptr) |ret_ptr| return ret_ptr;
   7947         const ret_llvm_ty = try self.dg.lowerType(ret_ty);
   7948         const target = self.dg.module.getTarget();
   7949         return self.buildAlloca(ret_llvm_ty, ptr_ty.ptrAlignment(target));
   7950     }
   7951 
   7952     /// Use this instead of builder.buildAlloca, because this function makes sure to
   7953     /// put the alloca instruction at the top of the function!
   7954     fn buildAlloca(self: *FuncGen, llvm_ty: *llvm.Type, alignment: ?c_uint) *llvm.Value {
   7955         return buildAllocaInner(self.builder, self.llvm_func, self.di_scope != null, llvm_ty, alignment, self.dg.module.getTarget());
   7956     }
   7957 
   7958     fn airStore(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   7959         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   7960         const dest_ptr = try self.resolveInst(bin_op.lhs);
   7961         const ptr_ty = self.air.typeOf(bin_op.lhs);
   7962         const operand_ty = ptr_ty.childType();
   7963         if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return null;
   7964 
   7965         // TODO Sema should emit a different instruction when the store should
   7966         // possibly do the safety 0xaa bytes for undefined.
   7967         const val_is_undef = if (self.air.value(bin_op.rhs)) |val| val.isUndefDeep() else false;
   7968         if (val_is_undef) {
   7969             {
   7970                 // TODO let's handle this in AIR rather than by having each backend
   7971                 // check the optimization mode of the compilation because the plan is
   7972                 // to support setting the optimization mode at finer grained scopes
   7973                 // which happens in Sema. Codegen should not be aware of this logic.
   7974                 // I think this comment is basically the same as the other TODO comment just
   7975                 // above but I'm leaving them both here to make it look super messy and
   7976                 // thereby bait contributors (or let's be honest, probably myself) into
   7977                 // fixing this instead of letting it rot.
   7978                 const safety = switch (self.dg.module.comp.bin_file.options.optimize_mode) {
   7979                     .ReleaseSmall, .ReleaseFast => false,
   7980                     .Debug, .ReleaseSafe => true,
   7981                 };
   7982                 if (!safety) {
   7983                     return null;
   7984                 }
   7985             }
   7986             const target = self.dg.module.getTarget();
   7987             const operand_size = operand_ty.abiSize(target);
   7988             const u8_llvm_ty = self.context.intType(8);
   7989             const ptr_u8_llvm_ty = u8_llvm_ty.pointerType(0);
   7990             const dest_ptr_u8 = self.builder.buildBitCast(dest_ptr, ptr_u8_llvm_ty, "");
   7991             const fill_char = u8_llvm_ty.constInt(0xaa, .False);
   7992             const dest_ptr_align = ptr_ty.ptrAlignment(target);
   7993             const usize_llvm_ty = try self.dg.lowerType(Type.usize);
   7994             const len = usize_llvm_ty.constInt(operand_size, .False);
   7995             _ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr());
   7996             if (self.dg.module.comp.bin_file.options.valgrind) {
   7997                 self.valgrindMarkUndef(dest_ptr, len);
   7998             }
   7999         } else {
   8000             const src_operand = try self.resolveInst(bin_op.rhs);
   8001             self.store(dest_ptr, ptr_ty, src_operand, .NotAtomic);
   8002         }
   8003         return null;
   8004     }
   8005 
   8006     fn airLoad(
   8007         self: *FuncGen,
   8008         inst: Air.Inst.Index,
   8009         body: []const Air.Inst.Index,
   8010         body_i: usize,
   8011     ) !?*llvm.Value {
   8012         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   8013         const ptr_ty = self.air.typeOf(ty_op.operand);
   8014         elide: {
   8015             const ptr_info = ptr_ty.ptrInfo().data;
   8016             if (ptr_info.@"volatile") break :elide;
   8017             if (self.liveness.isUnused(inst)) return null;
   8018             if (!isByRef(ptr_info.pointee_type)) break :elide;
   8019 
   8020             // It would be valid to fall back to the code below here that simply calls
   8021             // load(). However, as an optimization, we want to avoid unnecessary copies
   8022             // of isByRef=true types. Here, we scan forward in the current block,
   8023             // looking to see if this load dies before any side effects occur.
   8024             // In such case, we can safely return the operand without making a copy.
   8025             for (body[body_i..]) |body_inst| {
   8026                 switch (self.liveness.categorizeOperand(self.air, body_inst, inst)) {
   8027                     .none => continue,
   8028                     .write, .noret, .complex => break :elide,
   8029                     .tomb => return try self.resolveInst(ty_op.operand),
   8030                 }
   8031             } else unreachable;
   8032         }
   8033         const ptr = try self.resolveInst(ty_op.operand);
   8034         return self.load(ptr, ptr_ty);
   8035     }
   8036 
   8037     fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   8038         _ = inst;
   8039         const llvm_fn = self.getIntrinsic("llvm.debugtrap", &.{});
   8040         _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, undefined, 0, .C, .Auto, "");
   8041         return null;
   8042     }
   8043 
   8044     fn airRetAddr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   8045         if (self.liveness.isUnused(inst)) return null;
   8046 
   8047         const llvm_usize = try self.dg.lowerType(Type.usize);
   8048         const target = self.dg.module.getTarget();
   8049         if (!target_util.supportsReturnAddress(target)) {
   8050             // https://github.com/ziglang/zig/issues/11946
   8051             return llvm_usize.constNull();
   8052         }
   8053 
   8054         const llvm_i32 = self.context.intType(32);
   8055         const llvm_fn = self.getIntrinsic("llvm.returnaddress", &.{});
   8056         const params = [_]*llvm.Value{llvm_i32.constNull()};
   8057         const ptr_val = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, "");
   8058         return self.builder.buildPtrToInt(ptr_val, llvm_usize, "");
   8059     }
   8060 
   8061     fn airFrameAddress(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   8062         if (self.liveness.isUnused(inst)) return null;
   8063 
   8064         const llvm_i32 = self.context.intType(32);
   8065         const llvm_fn_name = "llvm.frameaddress.p0";
   8066         const llvm_fn = self.dg.object.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {
   8067             const llvm_p0i8 = self.context.intType(8).pointerType(0);
   8068             const param_types = [_]*llvm.Type{llvm_i32};
   8069             const fn_type = llvm.functionType(llvm_p0i8, &param_types, param_types.len, .False);
   8070             break :blk self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type);
   8071         };
   8072 
   8073         const params = [_]*llvm.Value{llvm_i32.constNull()};
   8074         const ptr_val = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, "");
   8075         const llvm_usize = try self.dg.lowerType(Type.usize);
   8076         return self.builder.buildPtrToInt(ptr_val, llvm_usize, "");
   8077     }
   8078 
   8079     fn airFence(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   8080         const atomic_order = self.air.instructions.items(.data)[inst].fence;
   8081         const llvm_memory_order = toLlvmAtomicOrdering(atomic_order);
   8082         const single_threaded = llvm.Bool.fromBool(self.single_threaded);
   8083         _ = self.builder.buildFence(llvm_memory_order, single_threaded, "");
   8084         return null;
   8085     }
   8086 
   8087     fn airCmpxchg(self: *FuncGen, inst: Air.Inst.Index, is_weak: bool) !?*llvm.Value {
   8088         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
   8089         const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
   8090         var ptr = try self.resolveInst(extra.ptr);
   8091         var expected_value = try self.resolveInst(extra.expected_value);
   8092         var new_value = try self.resolveInst(extra.new_value);
   8093         const operand_ty = self.air.typeOf(extra.ptr).elemType();
   8094         const opt_abi_ty = self.dg.getAtomicAbiType(operand_ty, false);
   8095         if (opt_abi_ty) |abi_ty| {
   8096             // operand needs widening and truncating
   8097             ptr = self.builder.buildBitCast(ptr, abi_ty.pointerType(0), "");
   8098             if (operand_ty.isSignedInt()) {
   8099                 expected_value = self.builder.buildSExt(expected_value, abi_ty, "");
   8100                 new_value = self.builder.buildSExt(new_value, abi_ty, "");
   8101             } else {
   8102                 expected_value = self.builder.buildZExt(expected_value, abi_ty, "");
   8103                 new_value = self.builder.buildZExt(new_value, abi_ty, "");
   8104             }
   8105         }
   8106         const result = self.builder.buildAtomicCmpXchg(
   8107             ptr,
   8108             expected_value,
   8109             new_value,
   8110             toLlvmAtomicOrdering(extra.successOrder()),
   8111             toLlvmAtomicOrdering(extra.failureOrder()),
   8112             llvm.Bool.fromBool(self.single_threaded),
   8113         );
   8114         result.setWeak(llvm.Bool.fromBool(is_weak));
   8115 
   8116         const optional_ty = self.air.typeOfIndex(inst);
   8117 
   8118         var payload = self.builder.buildExtractValue(result, 0, "");
   8119         if (opt_abi_ty != null) {
   8120             payload = self.builder.buildTrunc(payload, try self.dg.lowerType(operand_ty), "");
   8121         }
   8122         const success_bit = self.builder.buildExtractValue(result, 1, "");
   8123 
   8124         if (optional_ty.optionalReprIsPayload()) {
   8125             return self.builder.buildSelect(success_bit, payload.typeOf().constNull(), payload, "");
   8126         }
   8127 
   8128         comptime assert(optional_layout_version == 3);
   8129 
   8130         const non_null_bit = self.builder.buildNot(success_bit, "");
   8131         return buildOptional(self, optional_ty, payload, non_null_bit);
   8132     }
   8133 
   8134     fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   8135         const pl_op = self.air.instructions.items(.data)[inst].pl_op;
   8136         const extra = self.air.extraData(Air.AtomicRmw, pl_op.payload).data;
   8137         const ptr = try self.resolveInst(pl_op.operand);
   8138         const ptr_ty = self.air.typeOf(pl_op.operand);
   8139         const operand_ty = ptr_ty.elemType();
   8140         const operand = try self.resolveInst(extra.operand);
   8141         const is_signed_int = operand_ty.isSignedInt();
   8142         const is_float = operand_ty.isRuntimeFloat();
   8143         const op = toLlvmAtomicRmwBinOp(extra.op(), is_signed_int, is_float);
   8144         const ordering = toLlvmAtomicOrdering(extra.ordering());
   8145         const single_threaded = llvm.Bool.fromBool(self.single_threaded);
   8146         const opt_abi_ty = self.dg.getAtomicAbiType(operand_ty, op == .Xchg);
   8147         if (opt_abi_ty) |abi_ty| {
   8148             // operand needs widening and truncating or bitcasting.
   8149             const casted_ptr = self.builder.buildBitCast(ptr, abi_ty.pointerType(0), "");
   8150             const casted_operand = if (is_float)
   8151                 self.builder.buildBitCast(operand, abi_ty, "")
   8152             else if (is_signed_int)
   8153                 self.builder.buildSExt(operand, abi_ty, "")
   8154             else
   8155                 self.builder.buildZExt(operand, abi_ty, "");
   8156 
   8157             const uncasted_result = self.builder.buildAtomicRmw(
   8158                 op,
   8159                 casted_ptr,
   8160                 casted_operand,
   8161                 ordering,
   8162                 single_threaded,
   8163             );
   8164             const operand_llvm_ty = try self.dg.lowerType(operand_ty);
   8165             if (is_float) {
   8166                 return self.builder.buildBitCast(uncasted_result, operand_llvm_ty, "");
   8167             } else {
   8168                 return self.builder.buildTrunc(uncasted_result, operand_llvm_ty, "");
   8169             }
   8170         }
   8171 
   8172         if (operand.typeOf().getTypeKind() != .Pointer) {
   8173             return self.builder.buildAtomicRmw(op, ptr, operand, ordering, single_threaded);
   8174         }
   8175 
   8176         // It's a pointer but we need to treat it as an int.
   8177         const usize_llvm_ty = try self.dg.lowerType(Type.usize);
   8178         const casted_ptr = self.builder.buildBitCast(ptr, usize_llvm_ty.pointerType(0), "");
   8179         const casted_operand = self.builder.buildPtrToInt(operand, usize_llvm_ty, "");
   8180         const uncasted_result = self.builder.buildAtomicRmw(
   8181             op,
   8182             casted_ptr,
   8183             casted_operand,
   8184             ordering,
   8185             single_threaded,
   8186         );
   8187         const operand_llvm_ty = try self.dg.lowerType(operand_ty);
   8188         return self.builder.buildIntToPtr(uncasted_result, operand_llvm_ty, "");
   8189     }
   8190 
   8191     fn airAtomicLoad(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   8192         const atomic_load = self.air.instructions.items(.data)[inst].atomic_load;
   8193         const ptr = try self.resolveInst(atomic_load.ptr);
   8194         const ptr_ty = self.air.typeOf(atomic_load.ptr);
   8195         const ptr_info = ptr_ty.ptrInfo().data;
   8196         if (!ptr_info.@"volatile" and self.liveness.isUnused(inst))
   8197             return null;
   8198         const elem_ty = ptr_info.pointee_type;
   8199         if (!elem_ty.hasRuntimeBitsIgnoreComptime())
   8200             return null;
   8201         const ordering = toLlvmAtomicOrdering(atomic_load.order);
   8202         const opt_abi_llvm_ty = self.dg.getAtomicAbiType(elem_ty, false);
   8203         const target = self.dg.module.getTarget();
   8204         const ptr_alignment = ptr_info.alignment(target);
   8205         const ptr_volatile = llvm.Bool.fromBool(ptr_info.@"volatile");
   8206         const elem_llvm_ty = try self.dg.lowerType(elem_ty);
   8207 
   8208         if (opt_abi_llvm_ty) |abi_llvm_ty| {
   8209             // operand needs widening and truncating
   8210             const casted_ptr = self.builder.buildBitCast(ptr, abi_llvm_ty.pointerType(0), "");
   8211             const load_inst = self.builder.buildLoad(abi_llvm_ty, casted_ptr, "");
   8212             load_inst.setAlignment(ptr_alignment);
   8213             load_inst.setVolatile(ptr_volatile);
   8214             load_inst.setOrdering(ordering);
   8215             return self.builder.buildTrunc(load_inst, elem_llvm_ty, "");
   8216         }
   8217         const load_inst = self.builder.buildLoad(elem_llvm_ty, ptr, "");
   8218         load_inst.setAlignment(ptr_alignment);
   8219         load_inst.setVolatile(ptr_volatile);
   8220         load_inst.setOrdering(ordering);
   8221         return load_inst;
   8222     }
   8223 
   8224     fn airAtomicStore(
   8225         self: *FuncGen,
   8226         inst: Air.Inst.Index,
   8227         ordering: llvm.AtomicOrdering,
   8228     ) !?*llvm.Value {
   8229         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   8230         const ptr_ty = self.air.typeOf(bin_op.lhs);
   8231         const operand_ty = ptr_ty.childType();
   8232         if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return null;
   8233         var ptr = try self.resolveInst(bin_op.lhs);
   8234         var element = try self.resolveInst(bin_op.rhs);
   8235         const opt_abi_ty = self.dg.getAtomicAbiType(operand_ty, false);
   8236 
   8237         if (opt_abi_ty) |abi_ty| {
   8238             // operand needs widening
   8239             ptr = self.builder.buildBitCast(ptr, abi_ty.pointerType(0), "");
   8240             if (operand_ty.isSignedInt()) {
   8241                 element = self.builder.buildSExt(element, abi_ty, "");
   8242             } else {
   8243                 element = self.builder.buildZExt(element, abi_ty, "");
   8244             }
   8245         }
   8246         self.store(ptr, ptr_ty, element, ordering);
   8247         return null;
   8248     }
   8249 
   8250     fn airMemset(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   8251         const pl_op = self.air.instructions.items(.data)[inst].pl_op;
   8252         const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
   8253         const dest_ptr = try self.resolveInst(pl_op.operand);
   8254         const ptr_ty = self.air.typeOf(pl_op.operand);
   8255         const value = try self.resolveInst(extra.lhs);
   8256         const val_is_undef = if (self.air.value(extra.lhs)) |val| val.isUndefDeep() else false;
   8257         const len = try self.resolveInst(extra.rhs);
   8258         const u8_llvm_ty = self.context.intType(8);
   8259         const ptr_u8_llvm_ty = u8_llvm_ty.pointerType(0);
   8260         const dest_ptr_u8 = self.builder.buildBitCast(dest_ptr, ptr_u8_llvm_ty, "");
   8261         const fill_char = if (val_is_undef) u8_llvm_ty.constInt(0xaa, .False) else value;
   8262         const target = self.dg.module.getTarget();
   8263         const dest_ptr_align = ptr_ty.ptrAlignment(target);
   8264         _ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr());
   8265 
   8266         if (val_is_undef and self.dg.module.comp.bin_file.options.valgrind) {
   8267             self.valgrindMarkUndef(dest_ptr_u8, len);
   8268         }
   8269         return null;
   8270     }
   8271 
   8272     fn airMemcpy(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   8273         const pl_op = self.air.instructions.items(.data)[inst].pl_op;
   8274         const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
   8275         const dest_ptr = try self.resolveInst(pl_op.operand);
   8276         const dest_ptr_ty = self.air.typeOf(pl_op.operand);
   8277         const src_ptr = try self.resolveInst(extra.lhs);
   8278         const src_ptr_ty = self.air.typeOf(extra.lhs);
   8279         const len = try self.resolveInst(extra.rhs);
   8280         const llvm_ptr_u8 = self.context.intType(8).pointerType(0);
   8281         const dest_ptr_u8 = self.builder.buildBitCast(dest_ptr, llvm_ptr_u8, "");
   8282         const src_ptr_u8 = self.builder.buildBitCast(src_ptr, llvm_ptr_u8, "");
   8283         const is_volatile = src_ptr_ty.isVolatilePtr() or dest_ptr_ty.isVolatilePtr();
   8284         const target = self.dg.module.getTarget();
   8285         _ = self.builder.buildMemCpy(
   8286             dest_ptr_u8,
   8287             dest_ptr_ty.ptrAlignment(target),
   8288             src_ptr_u8,
   8289             src_ptr_ty.ptrAlignment(target),
   8290             len,
   8291             is_volatile,
   8292         );
   8293         return null;
   8294     }
   8295 
   8296     fn airSetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   8297         const bin_op = self.air.instructions.items(.data)[inst].bin_op;
   8298         const un_ty = self.air.typeOf(bin_op.lhs).childType();
   8299         const target = self.dg.module.getTarget();
   8300         const layout = un_ty.unionGetLayout(target);
   8301         if (layout.tag_size == 0) return null;
   8302         const union_ptr = try self.resolveInst(bin_op.lhs);
   8303         const new_tag = try self.resolveInst(bin_op.rhs);
   8304         if (layout.payload_size == 0) {
   8305             // TODO alignment on this store
   8306             _ = self.builder.buildStore(new_tag, union_ptr);
   8307             return null;
   8308         }
   8309         const un_llvm_ty = try self.dg.lowerType(un_ty);
   8310         const tag_index = @boolToInt(layout.tag_align < layout.payload_align);
   8311         const tag_field_ptr = self.builder.buildStructGEP(un_llvm_ty, union_ptr, tag_index, "");
   8312         // TODO alignment on this store
   8313         _ = self.builder.buildStore(new_tag, tag_field_ptr);
   8314         return null;
   8315     }
   8316 
   8317     fn airGetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   8318         if (self.liveness.isUnused(inst)) return null;
   8319 
   8320         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   8321         const un_ty = self.air.typeOf(ty_op.operand);
   8322         const target = self.dg.module.getTarget();
   8323         const layout = un_ty.unionGetLayout(target);
   8324         if (layout.tag_size == 0) return null;
   8325         const union_handle = try self.resolveInst(ty_op.operand);
   8326         if (isByRef(un_ty)) {
   8327             const llvm_un_ty = try self.dg.lowerType(un_ty);
   8328             if (layout.payload_size == 0) {
   8329                 return self.builder.buildLoad(llvm_un_ty, union_handle, "");
   8330             }
   8331             const tag_index = @boolToInt(layout.tag_align < layout.payload_align);
   8332             const tag_field_ptr = self.builder.buildStructGEP(llvm_un_ty, union_handle, tag_index, "");
   8333             return self.builder.buildLoad(tag_field_ptr.getGEPResultElementType(), tag_field_ptr, "");
   8334         } else {
   8335             if (layout.payload_size == 0) {
   8336                 return union_handle;
   8337             }
   8338             const tag_index = @boolToInt(layout.tag_align < layout.payload_align);
   8339             return self.builder.buildExtractValue(union_handle, tag_index, "");
   8340         }
   8341     }
   8342 
   8343     fn airUnaryOp(self: *FuncGen, inst: Air.Inst.Index, comptime op: FloatOp) !?*llvm.Value {
   8344         if (self.liveness.isUnused(inst)) return null;
   8345 
   8346         const un_op = self.air.instructions.items(.data)[inst].un_op;
   8347         const operand = try self.resolveInst(un_op);
   8348         const operand_ty = self.air.typeOf(un_op);
   8349 
   8350         return self.buildFloatOp(op, operand_ty, 1, .{operand});
   8351     }
   8352 
   8353     fn airNeg(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
   8354         if (self.liveness.isUnused(inst)) return null;
   8355         self.builder.setFastMath(want_fast_math);
   8356 
   8357         const un_op = self.air.instructions.items(.data)[inst].un_op;
   8358         const operand = try self.resolveInst(un_op);
   8359         const operand_ty = self.air.typeOf(un_op);
   8360 
   8361         return self.buildFloatOp(.neg, operand_ty, 1, .{operand});
   8362     }
   8363 
   8364     fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value {
   8365         if (self.liveness.isUnused(inst)) return null;
   8366 
   8367         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   8368         const operand_ty = self.air.typeOf(ty_op.operand);
   8369         const operand = try self.resolveInst(ty_op.operand);
   8370 
   8371         const llvm_i1 = self.context.intType(1);
   8372         const operand_llvm_ty = try self.dg.lowerType(operand_ty);
   8373         const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty});
   8374 
   8375         const params = [_]*llvm.Value{ operand, llvm_i1.constNull() };
   8376         const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, "");
   8377         const result_ty = self.air.typeOfIndex(inst);
   8378         const result_llvm_ty = try self.dg.lowerType(result_ty);
   8379 
   8380         const target = self.dg.module.getTarget();
   8381         const bits = operand_ty.intInfo(target).bits;
   8382         const result_bits = result_ty.intInfo(target).bits;
   8383         if (bits > result_bits) {
   8384             return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, "");
   8385         } else if (bits < result_bits) {
   8386             return self.builder.buildZExt(wrong_size_result, result_llvm_ty, "");
   8387         } else {
   8388             return wrong_size_result;
   8389         }
   8390     }
   8391 
   8392     fn airBitOp(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value {
   8393         if (self.liveness.isUnused(inst)) return null;
   8394 
   8395         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   8396         const operand_ty = self.air.typeOf(ty_op.operand);
   8397         const operand = try self.resolveInst(ty_op.operand);
   8398 
   8399         const params = [_]*llvm.Value{operand};
   8400         const operand_llvm_ty = try self.dg.lowerType(operand_ty);
   8401         const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty});
   8402 
   8403         const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, "");
   8404         const result_ty = self.air.typeOfIndex(inst);
   8405         const result_llvm_ty = try self.dg.lowerType(result_ty);
   8406 
   8407         const target = self.dg.module.getTarget();
   8408         const bits = operand_ty.intInfo(target).bits;
   8409         const result_bits = result_ty.intInfo(target).bits;
   8410         if (bits > result_bits) {
   8411             return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, "");
   8412         } else if (bits < result_bits) {
   8413             return self.builder.buildZExt(wrong_size_result, result_llvm_ty, "");
   8414         } else {
   8415             return wrong_size_result;
   8416         }
   8417     }
   8418 
   8419     fn airByteSwap(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value {
   8420         if (self.liveness.isUnused(inst)) return null;
   8421 
   8422         const target = self.dg.module.getTarget();
   8423         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   8424         const operand_ty = self.air.typeOf(ty_op.operand);
   8425         var bits = operand_ty.intInfo(target).bits;
   8426         assert(bits % 8 == 0);
   8427 
   8428         var operand = try self.resolveInst(ty_op.operand);
   8429         var operand_llvm_ty = try self.dg.lowerType(operand_ty);
   8430 
   8431         if (bits % 16 == 8) {
   8432             // If not an even byte-multiple, we need zero-extend + shift-left 1 byte
   8433             // The truncated result at the end will be the correct bswap
   8434             const scalar_llvm_ty = self.context.intType(bits + 8);
   8435             if (operand_ty.zigTypeTag() == .Vector) {
   8436                 const vec_len = operand_ty.vectorLen();
   8437                 operand_llvm_ty = scalar_llvm_ty.vectorType(vec_len);
   8438 
   8439                 const shifts = try self.gpa.alloc(*llvm.Value, vec_len);
   8440                 defer self.gpa.free(shifts);
   8441 
   8442                 for (shifts) |*elem| {
   8443                     elem.* = scalar_llvm_ty.constInt(8, .False);
   8444                 }
   8445                 const shift_vec = llvm.constVector(shifts.ptr, vec_len);
   8446 
   8447                 const extended = self.builder.buildZExt(operand, operand_llvm_ty, "");
   8448                 operand = self.builder.buildShl(extended, shift_vec, "");
   8449             } else {
   8450                 const extended = self.builder.buildZExt(operand, scalar_llvm_ty, "");
   8451                 operand = self.builder.buildShl(extended, scalar_llvm_ty.constInt(8, .False), "");
   8452                 operand_llvm_ty = scalar_llvm_ty;
   8453             }
   8454             bits = bits + 8;
   8455         }
   8456 
   8457         const params = [_]*llvm.Value{operand};
   8458         const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty});
   8459 
   8460         const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, "");
   8461 
   8462         const result_ty = self.air.typeOfIndex(inst);
   8463         const result_llvm_ty = try self.dg.lowerType(result_ty);
   8464         const result_bits = result_ty.intInfo(target).bits;
   8465         if (bits > result_bits) {
   8466             return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, "");
   8467         } else if (bits < result_bits) {
   8468             return self.builder.buildZExt(wrong_size_result, result_llvm_ty, "");
   8469         } else {
   8470             return wrong_size_result;
   8471         }
   8472     }
   8473 
   8474     fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   8475         if (self.liveness.isUnused(inst)) return null;
   8476 
   8477         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   8478         const operand = try self.resolveInst(ty_op.operand);
   8479         const error_set_ty = self.air.getRefType(ty_op.ty);
   8480 
   8481         const names = error_set_ty.errorSetNames();
   8482         const valid_block = self.dg.context.appendBasicBlock(self.llvm_func, "Valid");
   8483         const invalid_block = self.dg.context.appendBasicBlock(self.llvm_func, "Invalid");
   8484         const end_block = self.context.appendBasicBlock(self.llvm_func, "End");
   8485         const switch_instr = self.builder.buildSwitch(operand, invalid_block, @intCast(c_uint, names.len));
   8486 
   8487         for (names) |name| {
   8488             const err_int = self.dg.module.global_error_set.get(name).?;
   8489             const this_tag_int_value = int: {
   8490                 var tag_val_payload: Value.Payload.U64 = .{
   8491                     .base = .{ .tag = .int_u64 },
   8492                     .data = err_int,
   8493                 };
   8494                 break :int try self.dg.lowerValue(.{
   8495                     .ty = Type.err_int,
   8496                     .val = Value.initPayload(&tag_val_payload.base),
   8497                 });
   8498             };
   8499             switch_instr.addCase(this_tag_int_value, valid_block);
   8500         }
   8501         self.builder.positionBuilderAtEnd(valid_block);
   8502         _ = self.builder.buildBr(end_block);
   8503 
   8504         self.builder.positionBuilderAtEnd(invalid_block);
   8505         _ = self.builder.buildBr(end_block);
   8506 
   8507         self.builder.positionBuilderAtEnd(end_block);
   8508 
   8509         const llvm_type = self.dg.context.intType(1);
   8510         const incoming_values: [2]*llvm.Value = .{
   8511             llvm_type.constInt(1, .False), llvm_type.constInt(0, .False),
   8512         };
   8513         const incoming_blocks: [2]*llvm.BasicBlock = .{
   8514             valid_block, invalid_block,
   8515         };
   8516         const phi_node = self.builder.buildPhi(llvm_type, "");
   8517         phi_node.addIncoming(&incoming_values, &incoming_blocks, 2);
   8518         return phi_node;
   8519     }
   8520 
   8521     fn airIsNamedEnumValue(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   8522         if (self.liveness.isUnused(inst)) return null;
   8523 
   8524         const un_op = self.air.instructions.items(.data)[inst].un_op;
   8525         const operand = try self.resolveInst(un_op);
   8526         const enum_ty = self.air.typeOf(un_op);
   8527 
   8528         const llvm_fn = try self.getIsNamedEnumValueFunction(enum_ty);
   8529         const params = [_]*llvm.Value{operand};
   8530         return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, "");
   8531     }
   8532 
   8533     fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !*llvm.Value {
   8534         const enum_decl = enum_ty.getOwnerDecl();
   8535 
   8536         // TODO: detect when the type changes and re-emit this function.
   8537         const gop = try self.dg.object.named_enum_map.getOrPut(self.dg.gpa, enum_decl);
   8538         if (gop.found_existing) return gop.value_ptr.*;
   8539         errdefer assert(self.dg.object.named_enum_map.remove(enum_decl));
   8540 
   8541         var arena_allocator = std.heap.ArenaAllocator.init(self.gpa);
   8542         defer arena_allocator.deinit();
   8543         const arena = arena_allocator.allocator();
   8544 
   8545         const mod = self.dg.module;
   8546         const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_is_named_enum_value_{s}", .{
   8547             try mod.declPtr(enum_decl).getFullyQualifiedName(mod),
   8548         });
   8549 
   8550         var int_tag_type_buffer: Type.Payload.Bits = undefined;
   8551         const int_tag_ty = enum_ty.intTagType(&int_tag_type_buffer);
   8552         const param_types = [_]*llvm.Type{try self.dg.lowerType(int_tag_ty)};
   8553 
   8554         const llvm_ret_ty = try self.dg.lowerType(Type.bool);
   8555         const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False);
   8556         const fn_val = self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type);
   8557         fn_val.setLinkage(.Internal);
   8558         fn_val.setFunctionCallConv(.Fast);
   8559         self.dg.addCommonFnAttributes(fn_val);
   8560         gop.value_ptr.* = fn_val;
   8561 
   8562         const prev_block = self.builder.getInsertBlock();
   8563         const prev_debug_location = self.builder.getCurrentDebugLocation2();
   8564         defer {
   8565             self.builder.positionBuilderAtEnd(prev_block);
   8566             if (self.di_scope != null) {
   8567                 self.builder.setCurrentDebugLocation2(prev_debug_location);
   8568             }
   8569         }
   8570 
   8571         const entry_block = self.dg.context.appendBasicBlock(fn_val, "Entry");
   8572         self.builder.positionBuilderAtEnd(entry_block);
   8573         self.builder.clearCurrentDebugLocation();
   8574 
   8575         const fields = enum_ty.enumFields();
   8576         const named_block = self.dg.context.appendBasicBlock(fn_val, "Named");
   8577         const unnamed_block = self.dg.context.appendBasicBlock(fn_val, "Unnamed");
   8578         const tag_int_value = fn_val.getParam(0);
   8579         const switch_instr = self.builder.buildSwitch(tag_int_value, unnamed_block, @intCast(c_uint, fields.count()));
   8580 
   8581         for (fields.keys()) |_, field_index| {
   8582             const this_tag_int_value = int: {
   8583                 var tag_val_payload: Value.Payload.U32 = .{
   8584                     .base = .{ .tag = .enum_field_index },
   8585                     .data = @intCast(u32, field_index),
   8586                 };
   8587                 break :int try self.dg.lowerValue(.{
   8588                     .ty = enum_ty,
   8589                     .val = Value.initPayload(&tag_val_payload.base),
   8590                 });
   8591             };
   8592             switch_instr.addCase(this_tag_int_value, named_block);
   8593         }
   8594         self.builder.positionBuilderAtEnd(named_block);
   8595         _ = self.builder.buildRet(self.dg.context.intType(1).constInt(1, .False));
   8596 
   8597         self.builder.positionBuilderAtEnd(unnamed_block);
   8598         _ = self.builder.buildRet(self.dg.context.intType(1).constInt(0, .False));
   8599         return fn_val;
   8600     }
   8601 
   8602     fn airTagName(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   8603         if (self.liveness.isUnused(inst)) return null;
   8604 
   8605         const un_op = self.air.instructions.items(.data)[inst].un_op;
   8606         const operand = try self.resolveInst(un_op);
   8607         const enum_ty = self.air.typeOf(un_op);
   8608 
   8609         const llvm_fn = try self.getEnumTagNameFunction(enum_ty);
   8610         const params = [_]*llvm.Value{operand};
   8611         return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, "");
   8612     }
   8613 
   8614     fn getEnumTagNameFunction(self: *FuncGen, enum_ty: Type) !*llvm.Value {
   8615         const enum_decl = enum_ty.getOwnerDecl();
   8616 
   8617         // TODO: detect when the type changes and re-emit this function.
   8618         const gop = try self.dg.object.decl_map.getOrPut(self.dg.gpa, enum_decl);
   8619         if (gop.found_existing) return gop.value_ptr.*;
   8620         errdefer assert(self.dg.object.decl_map.remove(enum_decl));
   8621 
   8622         var arena_allocator = std.heap.ArenaAllocator.init(self.gpa);
   8623         defer arena_allocator.deinit();
   8624         const arena = arena_allocator.allocator();
   8625 
   8626         const mod = self.dg.module;
   8627         const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{s}", .{
   8628             try mod.declPtr(enum_decl).getFullyQualifiedName(mod),
   8629         });
   8630 
   8631         const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
   8632         const llvm_ret_ty = try self.dg.lowerType(slice_ty);
   8633         const usize_llvm_ty = try self.dg.lowerType(Type.usize);
   8634         const target = self.dg.module.getTarget();
   8635         const slice_alignment = slice_ty.abiAlignment(target);
   8636 
   8637         var int_tag_type_buffer: Type.Payload.Bits = undefined;
   8638         const int_tag_ty = enum_ty.intTagType(&int_tag_type_buffer);
   8639         const param_types = [_]*llvm.Type{try self.dg.lowerType(int_tag_ty)};
   8640 
   8641         const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False);
   8642         const fn_val = self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type);
   8643         fn_val.setLinkage(.Internal);
   8644         fn_val.setFunctionCallConv(.Fast);
   8645         self.dg.addCommonFnAttributes(fn_val);
   8646         gop.value_ptr.* = fn_val;
   8647 
   8648         const prev_block = self.builder.getInsertBlock();
   8649         const prev_debug_location = self.builder.getCurrentDebugLocation2();
   8650         defer {
   8651             self.builder.positionBuilderAtEnd(prev_block);
   8652             if (self.di_scope != null) {
   8653                 self.builder.setCurrentDebugLocation2(prev_debug_location);
   8654             }
   8655         }
   8656 
   8657         const entry_block = self.dg.context.appendBasicBlock(fn_val, "Entry");
   8658         self.builder.positionBuilderAtEnd(entry_block);
   8659         self.builder.clearCurrentDebugLocation();
   8660 
   8661         const fields = enum_ty.enumFields();
   8662         const bad_value_block = self.dg.context.appendBasicBlock(fn_val, "BadValue");
   8663         const tag_int_value = fn_val.getParam(0);
   8664         const switch_instr = self.builder.buildSwitch(tag_int_value, bad_value_block, @intCast(c_uint, fields.count()));
   8665 
   8666         const array_ptr_indices = [_]*llvm.Value{
   8667             usize_llvm_ty.constNull(), usize_llvm_ty.constNull(),
   8668         };
   8669 
   8670         for (fields.keys()) |name, field_index| {
   8671             const str_init = self.dg.context.constString(name.ptr, @intCast(c_uint, name.len), .False);
   8672             const str_init_llvm_ty = str_init.typeOf();
   8673             const str_global = self.dg.object.llvm_module.addGlobal(str_init_llvm_ty, "");
   8674             str_global.setInitializer(str_init);
   8675             str_global.setLinkage(.Private);
   8676             str_global.setGlobalConstant(.True);
   8677             str_global.setUnnamedAddr(.True);
   8678             str_global.setAlignment(1);
   8679 
   8680             const slice_fields = [_]*llvm.Value{
   8681                 str_init_llvm_ty.constInBoundsGEP(str_global, &array_ptr_indices, array_ptr_indices.len),
   8682                 usize_llvm_ty.constInt(name.len, .False),
   8683             };
   8684             const slice_init = llvm_ret_ty.constNamedStruct(&slice_fields, slice_fields.len);
   8685             const slice_global = self.dg.object.llvm_module.addGlobal(slice_init.typeOf(), "");
   8686             slice_global.setInitializer(slice_init);
   8687             slice_global.setLinkage(.Private);
   8688             slice_global.setGlobalConstant(.True);
   8689             slice_global.setUnnamedAddr(.True);
   8690             slice_global.setAlignment(slice_alignment);
   8691 
   8692             const return_block = self.dg.context.appendBasicBlock(fn_val, "Name");
   8693             const this_tag_int_value = int: {
   8694                 var tag_val_payload: Value.Payload.U32 = .{
   8695                     .base = .{ .tag = .enum_field_index },
   8696                     .data = @intCast(u32, field_index),
   8697                 };
   8698                 break :int try self.dg.lowerValue(.{
   8699                     .ty = enum_ty,
   8700                     .val = Value.initPayload(&tag_val_payload.base),
   8701                 });
   8702             };
   8703             switch_instr.addCase(this_tag_int_value, return_block);
   8704 
   8705             self.builder.positionBuilderAtEnd(return_block);
   8706             const loaded = self.builder.buildLoad(llvm_ret_ty, slice_global, "");
   8707             loaded.setAlignment(slice_alignment);
   8708             _ = self.builder.buildRet(loaded);
   8709         }
   8710 
   8711         self.builder.positionBuilderAtEnd(bad_value_block);
   8712         _ = self.builder.buildUnreachable();
   8713         return fn_val;
   8714     }
   8715 
   8716     fn getCmpLtErrorsLenFunction(self: *FuncGen) !*llvm.Value {
   8717         if (self.dg.object.llvm_module.getNamedFunction(lt_errors_fn_name)) |llvm_fn| {
   8718             return llvm_fn;
   8719         }
   8720 
   8721         // Function signature: fn (anyerror) bool
   8722 
   8723         const ret_llvm_ty = try self.dg.lowerType(Type.bool);
   8724         const anyerror_llvm_ty = try self.dg.lowerType(Type.anyerror);
   8725         const param_types = [_]*llvm.Type{anyerror_llvm_ty};
   8726 
   8727         const fn_type = llvm.functionType(ret_llvm_ty, &param_types, param_types.len, .False);
   8728         const llvm_fn = self.dg.object.llvm_module.addFunction(lt_errors_fn_name, fn_type);
   8729         llvm_fn.setLinkage(.Internal);
   8730         llvm_fn.setFunctionCallConv(.Fast);
   8731         self.dg.addCommonFnAttributes(llvm_fn);
   8732         return llvm_fn;
   8733     }
   8734 
   8735     fn airErrorName(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   8736         if (self.liveness.isUnused(inst)) return null;
   8737 
   8738         const un_op = self.air.instructions.items(.data)[inst].un_op;
   8739         const operand = try self.resolveInst(un_op);
   8740         const slice_ty = self.air.typeOfIndex(inst);
   8741         const slice_llvm_ty = try self.dg.lowerType(slice_ty);
   8742 
   8743         const error_name_table_ptr = try self.getErrorNameTable();
   8744         const ptr_slice_llvm_ty = slice_llvm_ty.pointerType(0);
   8745         const error_name_table = self.builder.buildLoad(ptr_slice_llvm_ty, error_name_table_ptr, "");
   8746         const indices = [_]*llvm.Value{operand};
   8747         const error_name_ptr = self.builder.buildInBoundsGEP(slice_llvm_ty, error_name_table, &indices, indices.len, "");
   8748         return self.builder.buildLoad(slice_llvm_ty, error_name_ptr, "");
   8749     }
   8750 
   8751     fn airSplat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   8752         if (self.liveness.isUnused(inst)) return null;
   8753 
   8754         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   8755         const scalar = try self.resolveInst(ty_op.operand);
   8756         const vector_ty = self.air.typeOfIndex(inst);
   8757         const len = vector_ty.vectorLen();
   8758         return self.builder.buildVectorSplat(len, scalar, "");
   8759     }
   8760 
   8761     fn airSelect(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   8762         if (self.liveness.isUnused(inst)) return null;
   8763 
   8764         const pl_op = self.air.instructions.items(.data)[inst].pl_op;
   8765         const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
   8766         const pred = try self.resolveInst(pl_op.operand);
   8767         const a = try self.resolveInst(extra.lhs);
   8768         const b = try self.resolveInst(extra.rhs);
   8769 
   8770         return self.builder.buildSelect(pred, a, b, "");
   8771     }
   8772 
   8773     fn airShuffle(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   8774         if (self.liveness.isUnused(inst)) return null;
   8775 
   8776         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
   8777         const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data;
   8778         const a = try self.resolveInst(extra.a);
   8779         const b = try self.resolveInst(extra.b);
   8780         const mask = self.air.values[extra.mask];
   8781         const mask_len = extra.mask_len;
   8782         const a_len = self.air.typeOf(extra.a).vectorLen();
   8783 
   8784         // LLVM uses integers larger than the length of the first array to
   8785         // index into the second array. This was deemed unnecessarily fragile
   8786         // when changing code, so Zig uses negative numbers to index the
   8787         // second vector. These start at -1 and go down, and are easiest to use
   8788         // with the ~ operator. Here we convert between the two formats.
   8789         const values = try self.gpa.alloc(*llvm.Value, mask_len);
   8790         defer self.gpa.free(values);
   8791 
   8792         const llvm_i32 = self.context.intType(32);
   8793 
   8794         for (values) |*val, i| {
   8795             var buf: Value.ElemValueBuffer = undefined;
   8796             const elem = mask.elemValueBuffer(self.dg.module, i, &buf);
   8797             if (elem.isUndef()) {
   8798                 val.* = llvm_i32.getUndef();
   8799             } else {
   8800                 const int = elem.toSignedInt();
   8801                 const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int + a_len);
   8802                 val.* = llvm_i32.constInt(unsigned, .False);
   8803             }
   8804         }
   8805 
   8806         const llvm_mask_value = llvm.constVector(values.ptr, mask_len);
   8807         return self.builder.buildShuffleVector(a, b, llvm_mask_value, "");
   8808     }
   8809 
   8810     /// Reduce a vector by repeatedly applying `llvm_fn` to produce an accumulated result.
   8811     ///
   8812     /// Equivalent to:
   8813     ///   reduce: {
   8814     ///     var i: usize = 0;
   8815     ///     var accum: T = init;
   8816     ///     while (i < vec.len) : (i += 1) {
   8817     ///       accum = llvm_fn(accum, vec[i]);
   8818     ///     }
   8819     ///     break :reduce accum;
   8820     ///   }
   8821     ///
   8822     fn buildReducedCall(
   8823         self: *FuncGen,
   8824         llvm_fn: *llvm.Value,
   8825         operand_vector: *llvm.Value,
   8826         vector_len: usize,
   8827         accum_init: *llvm.Value,
   8828     ) !*llvm.Value {
   8829         const llvm_usize_ty = try self.dg.lowerType(Type.usize);
   8830         const llvm_vector_len = llvm_usize_ty.constInt(vector_len, .False);
   8831         const llvm_result_ty = accum_init.typeOf();
   8832 
   8833         // Allocate and initialize our mutable variables
   8834         const i_ptr = self.buildAlloca(llvm_usize_ty, null);
   8835         _ = self.builder.buildStore(llvm_usize_ty.constInt(0, .False), i_ptr);
   8836         const accum_ptr = self.buildAlloca(llvm_result_ty, null);
   8837         _ = self.builder.buildStore(accum_init, accum_ptr);
   8838 
   8839         // Setup the loop
   8840         const loop = self.context.appendBasicBlock(self.llvm_func, "ReduceLoop");
   8841         const loop_exit = self.context.appendBasicBlock(self.llvm_func, "AfterReduce");
   8842         _ = self.builder.buildBr(loop);
   8843         {
   8844             self.builder.positionBuilderAtEnd(loop);
   8845 
   8846             // while (i < vec.len)
   8847             const i = self.builder.buildLoad(llvm_usize_ty, i_ptr, "");
   8848             const cond = self.builder.buildICmp(.ULT, i, llvm_vector_len, "");
   8849             const loop_then = self.context.appendBasicBlock(self.llvm_func, "ReduceLoopThen");
   8850 
   8851             _ = self.builder.buildCondBr(cond, loop_then, loop_exit);
   8852 
   8853             {
   8854                 self.builder.positionBuilderAtEnd(loop_then);
   8855 
   8856                 // accum = f(accum, vec[i]);
   8857                 const accum = self.builder.buildLoad(llvm_result_ty, accum_ptr, "");
   8858                 const element = self.builder.buildExtractElement(operand_vector, i, "");
   8859                 const params = [2]*llvm.Value{ accum, element };
   8860                 const new_accum = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .C, .Auto, "");
   8861                 _ = self.builder.buildStore(new_accum, accum_ptr);
   8862 
   8863                 // i += 1
   8864                 const new_i = self.builder.buildAdd(i, llvm_usize_ty.constInt(1, .False), "");
   8865                 _ = self.builder.buildStore(new_i, i_ptr);
   8866                 _ = self.builder.buildBr(loop);
   8867             }
   8868         }
   8869 
   8870         self.builder.positionBuilderAtEnd(loop_exit);
   8871         return self.builder.buildLoad(llvm_result_ty, accum_ptr, "");
   8872     }
   8873 
   8874     fn airReduce(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
   8875         if (self.liveness.isUnused(inst)) return null;
   8876         self.builder.setFastMath(want_fast_math);
   8877         const target = self.dg.module.getTarget();
   8878 
   8879         const reduce = self.air.instructions.items(.data)[inst].reduce;
   8880         var operand = try self.resolveInst(reduce.operand);
   8881         const operand_ty = self.air.typeOf(reduce.operand);
   8882         const scalar_ty = self.air.typeOfIndex(inst);
   8883 
   8884         // TODO handle the fast math setting
   8885 
   8886         switch (reduce.operation) {
   8887             .And => return self.builder.buildAndReduce(operand),
   8888             .Or => return self.builder.buildOrReduce(operand),
   8889             .Xor => return self.builder.buildXorReduce(operand),
   8890             .Min => switch (scalar_ty.zigTypeTag()) {
   8891                 .Int => return self.builder.buildIntMinReduce(operand, scalar_ty.isSignedInt()),
   8892                 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
   8893                     return self.builder.buildFPMinReduce(operand);
   8894                 },
   8895                 else => unreachable,
   8896             },
   8897             .Max => switch (scalar_ty.zigTypeTag()) {
   8898                 .Int => return self.builder.buildIntMaxReduce(operand, scalar_ty.isSignedInt()),
   8899                 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
   8900                     return self.builder.buildFPMaxReduce(operand);
   8901                 },
   8902                 else => unreachable,
   8903             },
   8904             .Add => switch (scalar_ty.zigTypeTag()) {
   8905                 .Int => return self.builder.buildAddReduce(operand),
   8906                 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
   8907                     const scalar_llvm_ty = try self.dg.lowerType(scalar_ty);
   8908                     const neutral_value = scalar_llvm_ty.constReal(-0.0);
   8909                     return self.builder.buildFPAddReduce(neutral_value, operand);
   8910                 },
   8911                 else => unreachable,
   8912             },
   8913             .Mul => switch (scalar_ty.zigTypeTag()) {
   8914                 .Int => return self.builder.buildMulReduce(operand),
   8915                 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
   8916                     const scalar_llvm_ty = try self.dg.lowerType(scalar_ty);
   8917                     const neutral_value = scalar_llvm_ty.constReal(1.0);
   8918                     return self.builder.buildFPMulReduce(neutral_value, operand);
   8919                 },
   8920                 else => unreachable,
   8921             },
   8922         }
   8923 
   8924         // Reduction could not be performed with intrinsics.
   8925         // Use a manual loop over a softfloat call instead.
   8926         var fn_name_buf: [64]u8 = undefined;
   8927         const float_bits = scalar_ty.floatBits(target);
   8928         const fn_name = switch (reduce.operation) {
   8929             .Min => std.fmt.bufPrintZ(&fn_name_buf, "{s}fmin{s}", .{
   8930                 libcFloatPrefix(float_bits), libcFloatSuffix(float_bits),
   8931             }) catch unreachable,
   8932             .Max => std.fmt.bufPrintZ(&fn_name_buf, "{s}fmax{s}", .{
   8933                 libcFloatPrefix(float_bits), libcFloatSuffix(float_bits),
   8934             }) catch unreachable,
   8935             .Add => std.fmt.bufPrintZ(&fn_name_buf, "__add{s}f3", .{
   8936                 compilerRtFloatAbbrev(float_bits),
   8937             }) catch unreachable,
   8938             .Mul => std.fmt.bufPrintZ(&fn_name_buf, "__mul{s}f3", .{
   8939                 compilerRtFloatAbbrev(float_bits),
   8940             }) catch unreachable,
   8941             else => unreachable,
   8942         };
   8943         var init_value_payload = Value.Payload.Float_32{
   8944             .data = switch (reduce.operation) {
   8945                 .Min => std.math.nan(f32),
   8946                 .Max => std.math.nan(f32),
   8947                 .Add => -0.0,
   8948                 .Mul => 1.0,
   8949                 else => unreachable,
   8950             },
   8951         };
   8952 
   8953         const param_llvm_ty = try self.dg.lowerType(scalar_ty);
   8954         const param_types = [2]*llvm.Type{ param_llvm_ty, param_llvm_ty };
   8955         const libc_fn = self.getLibcFunction(fn_name, &param_types, param_llvm_ty);
   8956         const init_value = try self.dg.lowerValue(.{
   8957             .ty = scalar_ty,
   8958             .val = Value.initPayload(&init_value_payload.base),
   8959         });
   8960         return self.buildReducedCall(libc_fn, operand, operand_ty.vectorLen(), init_value);
   8961     }
   8962 
   8963     fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   8964         if (self.liveness.isUnused(inst)) return null;
   8965 
   8966         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
   8967         const result_ty = self.air.typeOfIndex(inst);
   8968         const len = @intCast(usize, result_ty.arrayLen());
   8969         const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
   8970         const llvm_result_ty = try self.dg.lowerType(result_ty);
   8971         const target = self.dg.module.getTarget();
   8972 
   8973         switch (result_ty.zigTypeTag()) {
   8974             .Vector => {
   8975                 const llvm_u32 = self.context.intType(32);
   8976 
   8977                 var vector = llvm_result_ty.getUndef();
   8978                 for (elements) |elem, i| {
   8979                     const index_u32 = llvm_u32.constInt(i, .False);
   8980                     const llvm_elem = try self.resolveInst(elem);
   8981                     vector = self.builder.buildInsertElement(vector, llvm_elem, index_u32, "");
   8982                 }
   8983                 return vector;
   8984             },
   8985             .Struct => {
   8986                 if (result_ty.containerLayout() == .Packed) {
   8987                     const struct_obj = result_ty.castTag(.@"struct").?.data;
   8988                     const big_bits = struct_obj.backing_int_ty.bitSize(target);
   8989                     const int_llvm_ty = self.dg.context.intType(@intCast(c_uint, big_bits));
   8990                     const fields = struct_obj.fields.values();
   8991                     comptime assert(Type.packed_struct_layout_version == 2);
   8992                     var running_int: *llvm.Value = int_llvm_ty.constNull();
   8993                     var running_bits: u16 = 0;
   8994                     for (elements) |elem, i| {
   8995                         const field = fields[i];
   8996                         if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue;
   8997 
   8998                         const non_int_val = try self.resolveInst(elem);
   8999                         const ty_bit_size = @intCast(u16, field.ty.bitSize(target));
   9000                         const small_int_ty = self.dg.context.intType(ty_bit_size);
   9001                         const small_int_val = if (field.ty.isPtrAtRuntime())
   9002                             self.builder.buildPtrToInt(non_int_val, small_int_ty, "")
   9003                         else
   9004                             self.builder.buildBitCast(non_int_val, small_int_ty, "");
   9005                         const shift_rhs = int_llvm_ty.constInt(running_bits, .False);
   9006                         // If the field is as large as the entire packed struct, this
   9007                         // zext would go from, e.g. i16 to i16. This is legal with
   9008                         // constZExtOrBitCast but not legal with constZExt.
   9009                         const extended_int_val = self.builder.buildZExtOrBitCast(small_int_val, int_llvm_ty, "");
   9010                         const shifted = self.builder.buildShl(extended_int_val, shift_rhs, "");
   9011                         running_int = self.builder.buildOr(running_int, shifted, "");
   9012                         running_bits += ty_bit_size;
   9013                     }
   9014                     return running_int;
   9015                 }
   9016 
   9017                 var ptr_ty_buf: Type.Payload.Pointer = undefined;
   9018 
   9019                 if (isByRef(result_ty)) {
   9020                     const llvm_u32 = self.context.intType(32);
   9021                     // TODO in debug builds init to undef so that the padding will be 0xaa
   9022                     // even if we fully populate the fields.
   9023                     const alloca_inst = self.buildAlloca(llvm_result_ty, result_ty.abiAlignment(target));
   9024 
   9025                     var indices: [2]*llvm.Value = .{ llvm_u32.constNull(), undefined };
   9026                     for (elements) |elem, i| {
   9027                         if (result_ty.structFieldValueComptime(i) != null) continue;
   9028 
   9029                         const llvm_elem = try self.resolveInst(elem);
   9030                         const llvm_i = llvmFieldIndex(result_ty, i, target, &ptr_ty_buf).?;
   9031                         indices[1] = llvm_u32.constInt(llvm_i, .False);
   9032                         const field_ptr = self.builder.buildInBoundsGEP(llvm_result_ty, alloca_inst, &indices, indices.len, "");
   9033                         var field_ptr_payload: Type.Payload.Pointer = .{
   9034                             .data = .{
   9035                                 .pointee_type = self.air.typeOf(elem),
   9036                                 .@"align" = result_ty.structFieldAlign(i, target),
   9037                                 .@"addrspace" = .generic,
   9038                             },
   9039                         };
   9040                         const field_ptr_ty = Type.initPayload(&field_ptr_payload.base);
   9041                         self.store(field_ptr, field_ptr_ty, llvm_elem, .NotAtomic);
   9042                     }
   9043 
   9044                     return alloca_inst;
   9045                 } else {
   9046                     var result = llvm_result_ty.getUndef();
   9047                     for (elements) |elem, i| {
   9048                         if (result_ty.structFieldValueComptime(i) != null) continue;
   9049 
   9050                         const llvm_elem = try self.resolveInst(elem);
   9051                         const llvm_i = llvmFieldIndex(result_ty, i, target, &ptr_ty_buf).?;
   9052                         result = self.builder.buildInsertValue(result, llvm_elem, llvm_i, "");
   9053                     }
   9054                     return result;
   9055                 }
   9056             },
   9057             .Array => {
   9058                 assert(isByRef(result_ty));
   9059 
   9060                 const llvm_usize = try self.dg.lowerType(Type.usize);
   9061                 const alloca_inst = self.buildAlloca(llvm_result_ty, result_ty.abiAlignment(target));
   9062 
   9063                 const array_info = result_ty.arrayInfo();
   9064                 var elem_ptr_payload: Type.Payload.Pointer = .{
   9065                     .data = .{
   9066                         .pointee_type = array_info.elem_type,
   9067                         .@"addrspace" = .generic,
   9068                     },
   9069                 };
   9070                 const elem_ptr_ty = Type.initPayload(&elem_ptr_payload.base);
   9071 
   9072                 for (elements) |elem, i| {
   9073                     const indices: [2]*llvm.Value = .{
   9074                         llvm_usize.constNull(),
   9075                         llvm_usize.constInt(@intCast(c_uint, i), .False),
   9076                     };
   9077                     const elem_ptr = self.builder.buildInBoundsGEP(llvm_result_ty, alloca_inst, &indices, indices.len, "");
   9078                     const llvm_elem = try self.resolveInst(elem);
   9079                     self.store(elem_ptr, elem_ptr_ty, llvm_elem, .NotAtomic);
   9080                 }
   9081                 if (array_info.sentinel) |sent_val| {
   9082                     const indices: [2]*llvm.Value = .{
   9083                         llvm_usize.constNull(),
   9084                         llvm_usize.constInt(@intCast(c_uint, array_info.len), .False),
   9085                     };
   9086                     const elem_ptr = self.builder.buildInBoundsGEP(llvm_result_ty, alloca_inst, &indices, indices.len, "");
   9087                     const llvm_elem = try self.resolveValue(.{
   9088                         .ty = array_info.elem_type,
   9089                         .val = sent_val,
   9090                     });
   9091 
   9092                     self.store(elem_ptr, elem_ptr_ty, llvm_elem, .NotAtomic);
   9093                 }
   9094 
   9095                 return alloca_inst;
   9096             },
   9097             else => unreachable,
   9098         }
   9099     }
   9100 
   9101     fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   9102         if (self.liveness.isUnused(inst)) return null;
   9103 
   9104         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
   9105         const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
   9106         const union_ty = self.air.typeOfIndex(inst);
   9107         const union_llvm_ty = try self.dg.lowerType(union_ty);
   9108         const target = self.dg.module.getTarget();
   9109         const layout = union_ty.unionGetLayout(target);
   9110         const union_obj = union_ty.cast(Type.Payload.Union).?.data;
   9111         const tag_int = blk: {
   9112             const tag_ty = union_ty.unionTagTypeHypothetical();
   9113             const union_field_name = union_obj.fields.keys()[extra.field_index];
   9114             const enum_field_index = tag_ty.enumFieldIndex(union_field_name).?;
   9115             var tag_val_payload: Value.Payload.U32 = .{
   9116                 .base = .{ .tag = .enum_field_index },
   9117                 .data = @intCast(u32, enum_field_index),
   9118             };
   9119             const tag_val = Value.initPayload(&tag_val_payload.base);
   9120             var int_payload: Value.Payload.U64 = undefined;
   9121             const tag_int_val = tag_val.enumToInt(tag_ty, &int_payload);
   9122             break :blk tag_int_val.toUnsignedInt(target);
   9123         };
   9124         if (layout.payload_size == 0) {
   9125             if (layout.tag_size == 0) {
   9126                 return null;
   9127             }
   9128             assert(!isByRef(union_ty));
   9129             return union_llvm_ty.constInt(tag_int, .False);
   9130         }
   9131         assert(isByRef(union_ty));
   9132         // The llvm type of the alloca will be the named LLVM union type, and will not
   9133         // necessarily match the format that we need, depending on which tag is active. We
   9134         // must construct the correct unnamed struct type here and bitcast, in order to
   9135         // then set the fields appropriately.
   9136         const result_ptr = self.buildAlloca(union_llvm_ty, null);
   9137         const llvm_payload = try self.resolveInst(extra.init);
   9138         assert(union_obj.haveFieldTypes());
   9139         const field = union_obj.fields.values()[extra.field_index];
   9140         const field_llvm_ty = try self.dg.lowerType(field.ty);
   9141         const field_size = field.ty.abiSize(target);
   9142         const field_align = field.normalAlignment(target);
   9143 
   9144         const llvm_union_ty = t: {
   9145             const payload = p: {
   9146                 if (!field.ty.hasRuntimeBitsIgnoreComptime()) {
   9147                     const padding_len = @intCast(c_uint, layout.payload_size);
   9148                     break :p self.context.intType(8).arrayType(padding_len);
   9149                 }
   9150                 if (field_size == layout.payload_size) {
   9151                     break :p field_llvm_ty;
   9152                 }
   9153                 const padding_len = @intCast(c_uint, layout.payload_size - field_size);
   9154                 const fields: [2]*llvm.Type = .{
   9155                     field_llvm_ty, self.context.intType(8).arrayType(padding_len),
   9156                 };
   9157                 break :p self.context.structType(&fields, fields.len, .True);
   9158             };
   9159             if (layout.tag_size == 0) {
   9160                 const fields: [1]*llvm.Type = .{payload};
   9161                 break :t self.context.structType(&fields, fields.len, .False);
   9162             }
   9163             const tag_llvm_ty = try self.dg.lowerType(union_obj.tag_ty);
   9164             var fields: [3]*llvm.Type = undefined;
   9165             var fields_len: c_uint = 2;
   9166             if (layout.tag_align >= layout.payload_align) {
   9167                 fields = .{ tag_llvm_ty, payload, undefined };
   9168             } else {
   9169                 fields = .{ payload, tag_llvm_ty, undefined };
   9170             }
   9171             if (layout.padding != 0) {
   9172                 fields[2] = self.context.intType(8).arrayType(layout.padding);
   9173                 fields_len = 3;
   9174             }
   9175             break :t self.context.structType(&fields, fields_len, .False);
   9176         };
   9177 
   9178         const casted_ptr = self.builder.buildBitCast(result_ptr, llvm_union_ty.pointerType(0), "");
   9179 
   9180         // Now we follow the layout as expressed above with GEP instructions to set the
   9181         // tag and the payload.
   9182         const index_type = self.context.intType(32);
   9183 
   9184         var field_ptr_payload: Type.Payload.Pointer = .{
   9185             .data = .{
   9186                 .pointee_type = field.ty,
   9187                 .@"align" = field_align,
   9188                 .@"addrspace" = .generic,
   9189             },
   9190         };
   9191         const field_ptr_ty = Type.initPayload(&field_ptr_payload.base);
   9192         if (layout.tag_size == 0) {
   9193             const indices: [3]*llvm.Value = .{
   9194                 index_type.constNull(),
   9195                 index_type.constNull(),
   9196                 index_type.constNull(),
   9197             };
   9198             const len: c_uint = if (field_size == layout.payload_size) 2 else 3;
   9199             const field_ptr = self.builder.buildInBoundsGEP(llvm_union_ty, casted_ptr, &indices, len, "");
   9200             self.store(field_ptr, field_ptr_ty, llvm_payload, .NotAtomic);
   9201             return result_ptr;
   9202         }
   9203 
   9204         {
   9205             const indices: [3]*llvm.Value = .{
   9206                 index_type.constNull(),
   9207                 index_type.constInt(@boolToInt(layout.tag_align >= layout.payload_align), .False),
   9208                 index_type.constNull(),
   9209             };
   9210             const len: c_uint = if (field_size == layout.payload_size) 2 else 3;
   9211             const field_ptr = self.builder.buildInBoundsGEP(llvm_union_ty, casted_ptr, &indices, len, "");
   9212             self.store(field_ptr, field_ptr_ty, llvm_payload, .NotAtomic);
   9213         }
   9214         {
   9215             const indices: [2]*llvm.Value = .{
   9216                 index_type.constNull(),
   9217                 index_type.constInt(@boolToInt(layout.tag_align < layout.payload_align), .False),
   9218             };
   9219             const field_ptr = self.builder.buildInBoundsGEP(llvm_union_ty, casted_ptr, &indices, indices.len, "");
   9220             const tag_llvm_ty = try self.dg.lowerType(union_obj.tag_ty);
   9221             const llvm_tag = tag_llvm_ty.constInt(tag_int, .False);
   9222             const store_inst = self.builder.buildStore(llvm_tag, field_ptr);
   9223             store_inst.setAlignment(union_obj.tag_ty.abiAlignment(target));
   9224         }
   9225 
   9226         return result_ptr;
   9227     }
   9228 
   9229     fn airPrefetch(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   9230         const prefetch = self.air.instructions.items(.data)[inst].prefetch;
   9231 
   9232         comptime assert(@enumToInt(std.builtin.PrefetchOptions.Rw.read) == 0);
   9233         comptime assert(@enumToInt(std.builtin.PrefetchOptions.Rw.write) == 1);
   9234 
   9235         // TODO these two asserts should be able to be comptime because the type is a u2
   9236         assert(prefetch.locality >= 0);
   9237         assert(prefetch.locality <= 3);
   9238 
   9239         comptime assert(@enumToInt(std.builtin.PrefetchOptions.Cache.instruction) == 0);
   9240         comptime assert(@enumToInt(std.builtin.PrefetchOptions.Cache.data) == 1);
   9241 
   9242         // LLVM fails during codegen of instruction cache prefetchs for these architectures.
   9243         // This is an LLVM bug as the prefetch intrinsic should be a noop if not supported
   9244         // by the target.
   9245         // To work around this, don't emit llvm.prefetch in this case.
   9246         // See https://bugs.llvm.org/show_bug.cgi?id=21037
   9247         const target = self.dg.module.getTarget();
   9248         switch (prefetch.cache) {
   9249             .instruction => switch (target.cpu.arch) {
   9250                 .x86_64,
   9251                 .i386,
   9252                 .powerpc,
   9253                 .powerpcle,
   9254                 .powerpc64,
   9255                 .powerpc64le,
   9256                 => return null,
   9257                 .arm, .armeb, .thumb, .thumbeb => {
   9258                     switch (prefetch.rw) {
   9259                         .write => return null,
   9260                         else => {},
   9261                     }
   9262                 },
   9263                 else => {},
   9264             },
   9265             .data => {},
   9266         }
   9267 
   9268         const llvm_u8 = self.context.intType(8);
   9269         const llvm_ptr_u8 = llvm_u8.pointerType(0);
   9270         const llvm_u32 = self.context.intType(32);
   9271 
   9272         const llvm_fn_name = "llvm.prefetch.p0";
   9273         const fn_val = self.dg.object.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {
   9274             // declare void @llvm.prefetch(i8*, i32, i32, i32)
   9275             const llvm_void = self.context.voidType();
   9276             const param_types = [_]*llvm.Type{
   9277                 llvm_ptr_u8, llvm_u32, llvm_u32, llvm_u32,
   9278             };
   9279             const fn_type = llvm.functionType(llvm_void, &param_types, param_types.len, .False);
   9280             break :blk self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type);
   9281         };
   9282 
   9283         const ptr = try self.resolveInst(prefetch.ptr);
   9284         const ptr_u8 = self.builder.buildBitCast(ptr, llvm_ptr_u8, "");
   9285 
   9286         const params = [_]*llvm.Value{
   9287             ptr_u8,
   9288             llvm_u32.constInt(@enumToInt(prefetch.rw), .False),
   9289             llvm_u32.constInt(prefetch.locality, .False),
   9290             llvm_u32.constInt(@enumToInt(prefetch.cache), .False),
   9291         };
   9292         _ = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, "");
   9293         return null;
   9294     }
   9295 
   9296     fn airAddrSpaceCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
   9297         if (self.liveness.isUnused(inst)) return null;
   9298 
   9299         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
   9300         const inst_ty = self.air.typeOfIndex(inst);
   9301         const operand = try self.resolveInst(ty_op.operand);
   9302 
   9303         const llvm_dest_ty = try self.dg.lowerType(inst_ty);
   9304         return self.builder.buildAddrSpaceCast(operand, llvm_dest_ty, "");
   9305     }
   9306 
   9307     fn getErrorNameTable(self: *FuncGen) !*llvm.Value {
   9308         if (self.dg.object.error_name_table) |table| {
   9309             return table;
   9310         }
   9311 
   9312         const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
   9313         const slice_alignment = slice_ty.abiAlignment(self.dg.module.getTarget());
   9314         const llvm_slice_ty = try self.dg.lowerType(slice_ty);
   9315         const llvm_slice_ptr_ty = llvm_slice_ty.pointerType(0); // TODO: Address space
   9316 
   9317         const error_name_table_global = self.dg.object.llvm_module.addGlobal(llvm_slice_ptr_ty, "__zig_err_name_table");
   9318         error_name_table_global.setInitializer(llvm_slice_ptr_ty.getUndef());
   9319         error_name_table_global.setLinkage(.Private);
   9320         error_name_table_global.setGlobalConstant(.True);
   9321         error_name_table_global.setUnnamedAddr(.True);
   9322         error_name_table_global.setAlignment(slice_alignment);
   9323 
   9324         self.dg.object.error_name_table = error_name_table_global;
   9325         return error_name_table_global;
   9326     }
   9327 
   9328     /// Assumes the optional is not pointer-like and payload has bits.
   9329     fn optIsNonNull(
   9330         self: *FuncGen,
   9331         opt_llvm_ty: *llvm.Type,
   9332         opt_handle: *llvm.Value,
   9333         is_by_ref: bool,
   9334     ) *llvm.Value {
   9335         const non_null_llvm_ty = self.context.intType(8);
   9336         const field = b: {
   9337             if (is_by_ref) {
   9338                 const field_ptr = self.builder.buildStructGEP(opt_llvm_ty, opt_handle, 1, "");
   9339                 break :b self.builder.buildLoad(non_null_llvm_ty, field_ptr, "");
   9340             }
   9341             break :b self.builder.buildExtractValue(opt_handle, 1, "");
   9342         };
   9343         comptime assert(optional_layout_version == 3);
   9344 
   9345         return self.builder.buildICmp(.NE, field, non_null_llvm_ty.constInt(0, .False), "");
   9346     }
   9347 
   9348     /// Assumes the optional is not pointer-like and payload has bits.
   9349     fn optPayloadHandle(
   9350         fg: *FuncGen,
   9351         opt_llvm_ty: *llvm.Type,
   9352         opt_handle: *llvm.Value,
   9353         opt_ty: Type,
   9354     ) !*llvm.Value {
   9355         var buf: Type.Payload.ElemType = undefined;
   9356         const payload_ty = opt_ty.optionalChild(&buf);
   9357 
   9358         if (isByRef(opt_ty)) {
   9359             // We have a pointer and we need to return a pointer to the first field.
   9360             const payload_ptr = fg.builder.buildStructGEP(opt_llvm_ty, opt_handle, 0, "");
   9361 
   9362             if (isByRef(payload_ty)) {
   9363                 return payload_ptr;
   9364             }
   9365             const target = fg.dg.module.getTarget();
   9366             const payload_alignment = payload_ty.abiAlignment(target);
   9367             const payload_llvm_ty = try fg.dg.lowerType(payload_ty);
   9368             const load_inst = fg.builder.buildLoad(payload_llvm_ty, payload_ptr, "");
   9369             load_inst.setAlignment(payload_alignment);
   9370             return load_inst;
   9371         }
   9372 
   9373         assert(!isByRef(payload_ty));
   9374         return fg.builder.buildExtractValue(opt_handle, 0, "");
   9375     }
   9376 
   9377     fn buildOptional(
   9378         self: *FuncGen,
   9379         optional_ty: Type,
   9380         payload: *llvm.Value,
   9381         non_null_bit: *llvm.Value,
   9382     ) !?*llvm.Value {
   9383         const optional_llvm_ty = try self.dg.lowerType(optional_ty);
   9384         const non_null_field = self.builder.buildZExt(non_null_bit, self.dg.context.intType(8), "");
   9385 
   9386         if (isByRef(optional_ty)) {
   9387             const target = self.dg.module.getTarget();
   9388             const payload_alignment = optional_ty.abiAlignment(target);
   9389             const alloca_inst = self.buildAlloca(optional_llvm_ty, payload_alignment);
   9390 
   9391             {
   9392                 const field_ptr = self.builder.buildStructGEP(optional_llvm_ty, alloca_inst, 0, "");
   9393                 const store_inst = self.builder.buildStore(payload, field_ptr);
   9394                 store_inst.setAlignment(payload_alignment);
   9395             }
   9396             {
   9397                 const field_ptr = self.builder.buildStructGEP(optional_llvm_ty, alloca_inst, 1, "");
   9398                 const store_inst = self.builder.buildStore(non_null_field, field_ptr);
   9399                 store_inst.setAlignment(1);
   9400             }
   9401 
   9402             return alloca_inst;
   9403         }
   9404 
   9405         const partial = self.builder.buildInsertValue(optional_llvm_ty.getUndef(), payload, 0, "");
   9406         return self.builder.buildInsertValue(partial, non_null_field, 1, "");
   9407     }
   9408 
   9409     fn fieldPtr(
   9410         self: *FuncGen,
   9411         inst: Air.Inst.Index,
   9412         struct_ptr: *llvm.Value,
   9413         struct_ptr_ty: Type,
   9414         field_index: u32,
   9415     ) !?*llvm.Value {
   9416         if (self.liveness.isUnused(inst)) return null;
   9417 
   9418         const target = self.dg.object.target;
   9419         const struct_ty = struct_ptr_ty.childType();
   9420         switch (struct_ty.zigTypeTag()) {
   9421             .Struct => switch (struct_ty.containerLayout()) {
   9422                 .Packed => {
   9423                     const result_ty = self.air.typeOfIndex(inst);
   9424                     const result_ty_info = result_ty.ptrInfo().data;
   9425                     const result_llvm_ty = try self.dg.lowerType(result_ty);
   9426 
   9427                     if (result_ty_info.host_size != 0) {
   9428                         // From LLVM's perspective, a pointer to a packed struct and a pointer
   9429                         // to a field of a packed struct are the same. The difference is in the
   9430                         // Zig pointer type which provides information for how to mask and shift
   9431                         // out the relevant bits when accessing the pointee.
   9432                         // Here we perform a bitcast because we want to use the host_size
   9433                         // as the llvm pointer element type.
   9434                         return self.builder.buildBitCast(struct_ptr, result_llvm_ty, "");
   9435                     }
   9436 
   9437                     // We have a pointer to a packed struct field that happens to be byte-aligned.
   9438                     // Offset our operand pointer by the correct number of bytes.
   9439                     const byte_offset = struct_ty.packedStructFieldByteOffset(field_index, target);
   9440                     if (byte_offset == 0) {
   9441                         return self.builder.buildBitCast(struct_ptr, result_llvm_ty, "");
   9442                     }
   9443                     const byte_llvm_ty = self.context.intType(8);
   9444                     const ptr_as_bytes = self.builder.buildBitCast(struct_ptr, byte_llvm_ty.pointerType(0), "");
   9445                     const llvm_usize = try self.dg.lowerType(Type.usize);
   9446                     const llvm_index = llvm_usize.constInt(byte_offset, .False);
   9447                     const indices: [1]*llvm.Value = .{llvm_index};
   9448                     const new_ptr = self.builder.buildInBoundsGEP(byte_llvm_ty, ptr_as_bytes, &indices, indices.len, "");
   9449                     return self.builder.buildBitCast(new_ptr, result_llvm_ty, "");
   9450                 },
   9451                 else => {
   9452                     const struct_llvm_ty = try self.dg.lowerPtrElemTy(struct_ty);
   9453 
   9454                     var ty_buf: Type.Payload.Pointer = undefined;
   9455                     if (llvmFieldIndex(struct_ty, field_index, target, &ty_buf)) |llvm_field_index| {
   9456                         return self.builder.buildStructGEP(struct_llvm_ty, struct_ptr, llvm_field_index, "");
   9457                     } else {
   9458                         // If we found no index then this means this is a zero sized field at the
   9459                         // end of the struct. Treat our struct pointer as an array of two and get
   9460                         // the index to the element at index `1` to get a pointer to the end of
   9461                         // the struct.
   9462                         const llvm_usize = try self.dg.lowerType(Type.usize);
   9463                         const llvm_index = llvm_usize.constInt(1, .False);
   9464                         const indices: [1]*llvm.Value = .{llvm_index};
   9465                         return self.builder.buildInBoundsGEP(struct_llvm_ty, struct_ptr, &indices, indices.len, "");
   9466                     }
   9467                 },
   9468             },
   9469             .Union => return self.unionFieldPtr(inst, struct_ptr, struct_ty),
   9470             else => unreachable,
   9471         }
   9472     }
   9473 
   9474     fn unionFieldPtr(
   9475         self: *FuncGen,
   9476         inst: Air.Inst.Index,
   9477         union_ptr: *llvm.Value,
   9478         union_ty: Type,
   9479     ) !?*llvm.Value {
   9480         const target = self.dg.module.getTarget();
   9481         const layout = union_ty.unionGetLayout(target);
   9482         const result_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
   9483         if (layout.payload_size == 0) {
   9484             return self.builder.buildBitCast(union_ptr, result_llvm_ty, "");
   9485         }
   9486         const payload_index = @boolToInt(layout.tag_align >= layout.payload_align);
   9487         const union_llvm_ty = try self.dg.lowerType(union_ty);
   9488         const union_field_ptr = self.builder.buildStructGEP(union_llvm_ty, union_ptr, payload_index, "");
   9489         return self.builder.buildBitCast(union_field_ptr, result_llvm_ty, "");
   9490     }
   9491 
   9492     fn getIntrinsic(self: *FuncGen, name: []const u8, types: []const *llvm.Type) *llvm.Value {
   9493         const id = llvm.lookupIntrinsicID(name.ptr, name.len);
   9494         assert(id != 0);
   9495         return self.llvmModule().getIntrinsicDeclaration(id, types.ptr, types.len);
   9496     }
   9497 
   9498     /// This function always performs a copy. For isByRef=true types, it creates a new
   9499     /// alloca and copies the value into it, then returns the alloca instruction.
   9500     /// For isByRef=false types, it creates a load instruction and returns it.
   9501     fn load(self: *FuncGen, ptr: *llvm.Value, ptr_ty: Type) !?*llvm.Value {
   9502         const info = ptr_ty.ptrInfo().data;
   9503         if (!info.pointee_type.hasRuntimeBitsIgnoreComptime()) return null;
   9504 
   9505         const target = self.dg.module.getTarget();
   9506         const ptr_alignment = info.alignment(target);
   9507         const ptr_volatile = llvm.Bool.fromBool(ptr_ty.isVolatilePtr());
   9508         if (info.host_size == 0) {
   9509             const elem_llvm_ty = try self.dg.lowerType(info.pointee_type);
   9510             if (isByRef(info.pointee_type)) {
   9511                 const result_align = info.pointee_type.abiAlignment(target);
   9512                 const max_align = @max(result_align, ptr_alignment);
   9513                 const result_ptr = self.buildAlloca(elem_llvm_ty, max_align);
   9514                 const llvm_ptr_u8 = self.context.intType(8).pointerType(0);
   9515                 const llvm_usize = self.context.intType(Type.usize.intInfo(target).bits);
   9516                 const size_bytes = info.pointee_type.abiSize(target);
   9517                 _ = self.builder.buildMemCpy(
   9518                     self.builder.buildBitCast(result_ptr, llvm_ptr_u8, ""),
   9519                     max_align,
   9520                     self.builder.buildBitCast(ptr, llvm_ptr_u8, ""),
   9521                     max_align,
   9522                     llvm_usize.constInt(size_bytes, .False),
   9523                     info.@"volatile",
   9524                 );
   9525                 return result_ptr;
   9526             }
   9527             const llvm_inst = self.builder.buildLoad(elem_llvm_ty, ptr, "");
   9528             llvm_inst.setAlignment(ptr_alignment);
   9529             llvm_inst.setVolatile(ptr_volatile);
   9530             return llvm_inst;
   9531         }
   9532 
   9533         const int_elem_ty = self.context.intType(info.host_size * 8);
   9534         const int_ptr = self.builder.buildBitCast(ptr, int_elem_ty.pointerType(0), "");
   9535         const containing_int = self.builder.buildLoad(int_elem_ty, int_ptr, "");
   9536         containing_int.setAlignment(ptr_alignment);
   9537         containing_int.setVolatile(ptr_volatile);
   9538 
   9539         const elem_bits = @intCast(c_uint, ptr_ty.elemType().bitSize(target));
   9540         const shift_amt = containing_int.typeOf().constInt(info.bit_offset, .False);
   9541         const shifted_value = self.builder.buildLShr(containing_int, shift_amt, "");
   9542         const elem_llvm_ty = try self.dg.lowerType(info.pointee_type);
   9543 
   9544         if (isByRef(info.pointee_type)) {
   9545             const result_align = info.pointee_type.abiAlignment(target);
   9546             const result_ptr = self.buildAlloca(elem_llvm_ty, result_align);
   9547 
   9548             const same_size_int = self.context.intType(elem_bits);
   9549             const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
   9550             const bitcasted_ptr = self.builder.buildBitCast(result_ptr, same_size_int.pointerType(0), "");
   9551             const store_inst = self.builder.buildStore(truncated_int, bitcasted_ptr);
   9552             store_inst.setAlignment(result_align);
   9553             return result_ptr;
   9554         }
   9555 
   9556         if (info.pointee_type.zigTypeTag() == .Float) {
   9557             const same_size_int = self.context.intType(elem_bits);
   9558             const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
   9559             return self.builder.buildBitCast(truncated_int, elem_llvm_ty, "");
   9560         }
   9561 
   9562         if (info.pointee_type.isPtrAtRuntime()) {
   9563             const same_size_int = self.context.intType(elem_bits);
   9564             const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
   9565             return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, "");
   9566         }
   9567 
   9568         return self.builder.buildTrunc(shifted_value, elem_llvm_ty, "");
   9569     }
   9570 
   9571     fn store(
   9572         self: *FuncGen,
   9573         ptr: *llvm.Value,
   9574         ptr_ty: Type,
   9575         elem: *llvm.Value,
   9576         ordering: llvm.AtomicOrdering,
   9577     ) void {
   9578         const info = ptr_ty.ptrInfo().data;
   9579         const elem_ty = info.pointee_type;
   9580         if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
   9581             return;
   9582         }
   9583         const target = self.dg.module.getTarget();
   9584         const ptr_alignment = ptr_ty.ptrAlignment(target);
   9585         const ptr_volatile = llvm.Bool.fromBool(info.@"volatile");
   9586         if (info.host_size != 0) {
   9587             const int_elem_ty = self.context.intType(info.host_size * 8);
   9588             const int_ptr = self.builder.buildBitCast(ptr, int_elem_ty.pointerType(0), "");
   9589             const containing_int = self.builder.buildLoad(int_elem_ty, int_ptr, "");
   9590             assert(ordering == .NotAtomic);
   9591             containing_int.setAlignment(ptr_alignment);
   9592             containing_int.setVolatile(ptr_volatile);
   9593             const elem_bits = @intCast(c_uint, ptr_ty.elemType().bitSize(target));
   9594             const containing_int_ty = containing_int.typeOf();
   9595             const shift_amt = containing_int_ty.constInt(info.bit_offset, .False);
   9596             // Convert to equally-sized integer type in order to perform the bit
   9597             // operations on the value to store
   9598             const value_bits_type = self.context.intType(elem_bits);
   9599             const value_bits = if (elem_ty.isPtrAtRuntime())
   9600                 self.builder.buildPtrToInt(elem, value_bits_type, "")
   9601             else
   9602                 self.builder.buildBitCast(elem, value_bits_type, "");
   9603 
   9604             var mask_val = value_bits_type.constAllOnes();
   9605             mask_val = mask_val.constZExt(containing_int_ty);
   9606             mask_val = mask_val.constShl(shift_amt);
   9607             mask_val = mask_val.constNot();
   9608 
   9609             const anded_containing_int = self.builder.buildAnd(containing_int, mask_val, "");
   9610             const extended_value = self.builder.buildZExt(value_bits, containing_int_ty, "");
   9611             const shifted_value = self.builder.buildShl(extended_value, shift_amt, "");
   9612             const ored_value = self.builder.buildOr(shifted_value, anded_containing_int, "");
   9613 
   9614             const store_inst = self.builder.buildStore(ored_value, int_ptr);
   9615             assert(ordering == .NotAtomic);
   9616             store_inst.setAlignment(ptr_alignment);
   9617             store_inst.setVolatile(ptr_volatile);
   9618             return;
   9619         }
   9620         if (!isByRef(elem_ty)) {
   9621             const store_inst = self.builder.buildStore(elem, ptr);
   9622             store_inst.setOrdering(ordering);
   9623             store_inst.setAlignment(ptr_alignment);
   9624             store_inst.setVolatile(ptr_volatile);
   9625             return;
   9626         }
   9627         assert(ordering == .NotAtomic);
   9628         const llvm_ptr_u8 = self.context.intType(8).pointerType(0);
   9629         const size_bytes = elem_ty.abiSize(target);
   9630         _ = self.builder.buildMemCpy(
   9631             self.builder.buildBitCast(ptr, llvm_ptr_u8, ""),
   9632             ptr_alignment,
   9633             self.builder.buildBitCast(elem, llvm_ptr_u8, ""),
   9634             elem_ty.abiAlignment(target),
   9635             self.context.intType(Type.usize.intInfo(target).bits).constInt(size_bytes, .False),
   9636             info.@"volatile",
   9637         );
   9638     }
   9639 
   9640     fn valgrindMarkUndef(fg: *FuncGen, ptr: *llvm.Value, len: *llvm.Value) void {
   9641         const VG_USERREQ__MAKE_MEM_UNDEFINED = 1296236545;
   9642         const target = fg.dg.module.getTarget();
   9643         const usize_llvm_ty = fg.context.intType(target.cpu.arch.ptrBitWidth());
   9644         const zero = usize_llvm_ty.constInt(0, .False);
   9645         const req = usize_llvm_ty.constInt(VG_USERREQ__MAKE_MEM_UNDEFINED, .False);
   9646         const ptr_as_usize = fg.builder.buildPtrToInt(ptr, usize_llvm_ty, "");
   9647         _ = valgrindClientRequest(fg, zero, req, ptr_as_usize, len, zero, zero, zero);
   9648     }
   9649 
   9650     fn valgrindClientRequest(
   9651         fg: *FuncGen,
   9652         default_value: *llvm.Value,
   9653         request: *llvm.Value,
   9654         a1: *llvm.Value,
   9655         a2: *llvm.Value,
   9656         a3: *llvm.Value,
   9657         a4: *llvm.Value,
   9658         a5: *llvm.Value,
   9659     ) *llvm.Value {
   9660         const target = fg.dg.module.getTarget();
   9661         if (!target_util.hasValgrindSupport(target)) return default_value;
   9662 
   9663         const usize_llvm_ty = fg.context.intType(target.cpu.arch.ptrBitWidth());
   9664         const usize_alignment = @intCast(c_uint, Type.usize.abiSize(target));
   9665 
   9666         switch (target.cpu.arch) {
   9667             .x86_64 => {
   9668                 const array_llvm_ty = usize_llvm_ty.arrayType(6);
   9669                 const array_ptr = fg.valgrind_client_request_array orelse a: {
   9670                     const array_ptr = fg.buildAlloca(array_llvm_ty, usize_alignment);
   9671                     fg.valgrind_client_request_array = array_ptr;
   9672                     break :a array_ptr;
   9673                 };
   9674                 const array_elements = [_]*llvm.Value{ request, a1, a2, a3, a4, a5 };
   9675                 const zero = usize_llvm_ty.constInt(0, .False);
   9676                 for (array_elements) |elem, i| {
   9677                     const indexes = [_]*llvm.Value{
   9678                         zero, usize_llvm_ty.constInt(@intCast(c_uint, i), .False),
   9679                     };
   9680                     const elem_ptr = fg.builder.buildInBoundsGEP(array_llvm_ty, array_ptr, &indexes, indexes.len, "");
   9681                     const store_inst = fg.builder.buildStore(elem, elem_ptr);
   9682                     store_inst.setAlignment(usize_alignment);
   9683                 }
   9684 
   9685                 const asm_template =
   9686                     \\rolq $$3,  %rdi ; rolq $$13, %rdi
   9687                     \\rolq $$61, %rdi ; rolq $$51, %rdi
   9688                     \\xchgq %rbx,%rbx
   9689                 ;
   9690 
   9691                 const asm_constraints = "={rdx},{rax},0,~{cc},~{memory}";
   9692 
   9693                 const array_ptr_as_usize = fg.builder.buildPtrToInt(array_ptr, usize_llvm_ty, "");
   9694                 const args = [_]*llvm.Value{ array_ptr_as_usize, default_value };
   9695                 const param_types = [_]*llvm.Type{ usize_llvm_ty, usize_llvm_ty };
   9696                 const fn_llvm_ty = llvm.functionType(usize_llvm_ty, &param_types, args.len, .False);
   9697                 const asm_fn = llvm.getInlineAsm(
   9698                     fn_llvm_ty,
   9699                     asm_template,
   9700                     asm_template.len,
   9701                     asm_constraints,
   9702                     asm_constraints.len,
   9703                     .True, // has side effects
   9704                     .False, // alignstack
   9705                     .ATT,
   9706                     .False,
   9707                 );
   9708 
   9709                 const call = fg.builder.buildCall(
   9710                     fn_llvm_ty,
   9711                     asm_fn,
   9712                     &args,
   9713                     args.len,
   9714                     .C,
   9715                     .Auto,
   9716                     "",
   9717                 );
   9718                 return call;
   9719             },
   9720             else => unreachable,
   9721         }
   9722     }
   9723 };
   9724 
   9725 fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void {
   9726     switch (arch) {
   9727         .aarch64, .aarch64_be, .aarch64_32 => {
   9728             llvm.LLVMInitializeAArch64Target();
   9729             llvm.LLVMInitializeAArch64TargetInfo();
   9730             llvm.LLVMInitializeAArch64TargetMC();
   9731             llvm.LLVMInitializeAArch64AsmPrinter();
   9732             llvm.LLVMInitializeAArch64AsmParser();
   9733         },
   9734         .amdgcn => {
   9735             llvm.LLVMInitializeAMDGPUTarget();
   9736             llvm.LLVMInitializeAMDGPUTargetInfo();
   9737             llvm.LLVMInitializeAMDGPUTargetMC();
   9738             llvm.LLVMInitializeAMDGPUAsmPrinter();
   9739             llvm.LLVMInitializeAMDGPUAsmParser();
   9740         },
   9741         .thumb, .thumbeb, .arm, .armeb => {
   9742             llvm.LLVMInitializeARMTarget();
   9743             llvm.LLVMInitializeARMTargetInfo();
   9744             llvm.LLVMInitializeARMTargetMC();
   9745             llvm.LLVMInitializeARMAsmPrinter();
   9746             llvm.LLVMInitializeARMAsmParser();
   9747         },
   9748         .avr => {
   9749             llvm.LLVMInitializeAVRTarget();
   9750             llvm.LLVMInitializeAVRTargetInfo();
   9751             llvm.LLVMInitializeAVRTargetMC();
   9752             llvm.LLVMInitializeAVRAsmPrinter();
   9753             llvm.LLVMInitializeAVRAsmParser();
   9754         },
   9755         .bpfel, .bpfeb => {
   9756             llvm.LLVMInitializeBPFTarget();
   9757             llvm.LLVMInitializeBPFTargetInfo();
   9758             llvm.LLVMInitializeBPFTargetMC();
   9759             llvm.LLVMInitializeBPFAsmPrinter();
   9760             llvm.LLVMInitializeBPFAsmParser();
   9761         },
   9762         .hexagon => {
   9763             llvm.LLVMInitializeHexagonTarget();
   9764             llvm.LLVMInitializeHexagonTargetInfo();
   9765             llvm.LLVMInitializeHexagonTargetMC();
   9766             llvm.LLVMInitializeHexagonAsmPrinter();
   9767             llvm.LLVMInitializeHexagonAsmParser();
   9768         },
   9769         .lanai => {
   9770             llvm.LLVMInitializeLanaiTarget();
   9771             llvm.LLVMInitializeLanaiTargetInfo();
   9772             llvm.LLVMInitializeLanaiTargetMC();
   9773             llvm.LLVMInitializeLanaiAsmPrinter();
   9774             llvm.LLVMInitializeLanaiAsmParser();
   9775         },
   9776         .mips, .mipsel, .mips64, .mips64el => {
   9777             llvm.LLVMInitializeMipsTarget();
   9778             llvm.LLVMInitializeMipsTargetInfo();
   9779             llvm.LLVMInitializeMipsTargetMC();
   9780             llvm.LLVMInitializeMipsAsmPrinter();
   9781             llvm.LLVMInitializeMipsAsmParser();
   9782         },
   9783         .msp430 => {
   9784             llvm.LLVMInitializeMSP430Target();
   9785             llvm.LLVMInitializeMSP430TargetInfo();
   9786             llvm.LLVMInitializeMSP430TargetMC();
   9787             llvm.LLVMInitializeMSP430AsmPrinter();
   9788             llvm.LLVMInitializeMSP430AsmParser();
   9789         },
   9790         .nvptx, .nvptx64 => {
   9791             llvm.LLVMInitializeNVPTXTarget();
   9792             llvm.LLVMInitializeNVPTXTargetInfo();
   9793             llvm.LLVMInitializeNVPTXTargetMC();
   9794             llvm.LLVMInitializeNVPTXAsmPrinter();
   9795             // There is no LLVMInitializeNVPTXAsmParser function available.
   9796         },
   9797         .powerpc, .powerpcle, .powerpc64, .powerpc64le => {
   9798             llvm.LLVMInitializePowerPCTarget();
   9799             llvm.LLVMInitializePowerPCTargetInfo();
   9800             llvm.LLVMInitializePowerPCTargetMC();
   9801             llvm.LLVMInitializePowerPCAsmPrinter();
   9802             llvm.LLVMInitializePowerPCAsmParser();
   9803         },
   9804         .riscv32, .riscv64 => {
   9805             llvm.LLVMInitializeRISCVTarget();
   9806             llvm.LLVMInitializeRISCVTargetInfo();
   9807             llvm.LLVMInitializeRISCVTargetMC();
   9808             llvm.LLVMInitializeRISCVAsmPrinter();
   9809             llvm.LLVMInitializeRISCVAsmParser();
   9810         },
   9811         .sparc, .sparc64, .sparcel => {
   9812             llvm.LLVMInitializeSparcTarget();
   9813             llvm.LLVMInitializeSparcTargetInfo();
   9814             llvm.LLVMInitializeSparcTargetMC();
   9815             llvm.LLVMInitializeSparcAsmPrinter();
   9816             llvm.LLVMInitializeSparcAsmParser();
   9817         },
   9818         .s390x => {
   9819             llvm.LLVMInitializeSystemZTarget();
   9820             llvm.LLVMInitializeSystemZTargetInfo();
   9821             llvm.LLVMInitializeSystemZTargetMC();
   9822             llvm.LLVMInitializeSystemZAsmPrinter();
   9823             llvm.LLVMInitializeSystemZAsmParser();
   9824         },
   9825         .wasm32, .wasm64 => {
   9826             llvm.LLVMInitializeWebAssemblyTarget();
   9827             llvm.LLVMInitializeWebAssemblyTargetInfo();
   9828             llvm.LLVMInitializeWebAssemblyTargetMC();
   9829             llvm.LLVMInitializeWebAssemblyAsmPrinter();
   9830             llvm.LLVMInitializeWebAssemblyAsmParser();
   9831         },
   9832         .i386, .x86_64 => {
   9833             llvm.LLVMInitializeX86Target();
   9834             llvm.LLVMInitializeX86TargetInfo();
   9835             llvm.LLVMInitializeX86TargetMC();
   9836             llvm.LLVMInitializeX86AsmPrinter();
   9837             llvm.LLVMInitializeX86AsmParser();
   9838         },
   9839         .xcore => {
   9840             llvm.LLVMInitializeXCoreTarget();
   9841             llvm.LLVMInitializeXCoreTargetInfo();
   9842             llvm.LLVMInitializeXCoreTargetMC();
   9843             llvm.LLVMInitializeXCoreAsmPrinter();
   9844             // There is no LLVMInitializeXCoreAsmParser function.
   9845         },
   9846         .m68k => {
   9847             if (build_options.llvm_has_m68k) {
   9848                 llvm.LLVMInitializeM68kTarget();
   9849                 llvm.LLVMInitializeM68kTargetInfo();
   9850                 llvm.LLVMInitializeM68kTargetMC();
   9851                 llvm.LLVMInitializeM68kAsmPrinter();
   9852                 llvm.LLVMInitializeM68kAsmParser();
   9853             }
   9854         },
   9855         .csky => {
   9856             if (build_options.llvm_has_csky) {
   9857                 llvm.LLVMInitializeCSKYTarget();
   9858                 llvm.LLVMInitializeCSKYTargetInfo();
   9859                 llvm.LLVMInitializeCSKYTargetMC();
   9860                 // There is no LLVMInitializeCSKYAsmPrinter function.
   9861                 llvm.LLVMInitializeCSKYAsmParser();
   9862             }
   9863         },
   9864         .ve => {
   9865             llvm.LLVMInitializeVETarget();
   9866             llvm.LLVMInitializeVETargetInfo();
   9867             llvm.LLVMInitializeVETargetMC();
   9868             llvm.LLVMInitializeVEAsmPrinter();
   9869             llvm.LLVMInitializeVEAsmParser();
   9870         },
   9871         .arc => {
   9872             if (build_options.llvm_has_arc) {
   9873                 llvm.LLVMInitializeARCTarget();
   9874                 llvm.LLVMInitializeARCTargetInfo();
   9875                 llvm.LLVMInitializeARCTargetMC();
   9876                 llvm.LLVMInitializeARCAsmPrinter();
   9877                 // There is no LLVMInitializeARCAsmParser function.
   9878             }
   9879         },
   9880 
   9881         // LLVM backends that have no initialization functions.
   9882         .tce,
   9883         .tcele,
   9884         .r600,
   9885         .le32,
   9886         .le64,
   9887         .amdil,
   9888         .amdil64,
   9889         .hsail,
   9890         .hsail64,
   9891         .shave,
   9892         .spir,
   9893         .spir64,
   9894         .kalimba,
   9895         .renderscript32,
   9896         .renderscript64,
   9897         .dxil,
   9898         .loongarch32,
   9899         .loongarch64,
   9900         => {},
   9901 
   9902         .spu_2 => unreachable, // LLVM does not support this backend
   9903         .spirv32 => unreachable, // LLVM does not support this backend
   9904         .spirv64 => unreachable, // LLVM does not support this backend
   9905     }
   9906 }
   9907 
   9908 fn toLlvmAtomicOrdering(atomic_order: std.builtin.AtomicOrder) llvm.AtomicOrdering {
   9909     return switch (atomic_order) {
   9910         .Unordered => .Unordered,
   9911         .Monotonic => .Monotonic,
   9912         .Acquire => .Acquire,
   9913         .Release => .Release,
   9914         .AcqRel => .AcquireRelease,
   9915         .SeqCst => .SequentiallyConsistent,
   9916     };
   9917 }
   9918 
   9919 fn toLlvmAtomicRmwBinOp(
   9920     op: std.builtin.AtomicRmwOp,
   9921     is_signed: bool,
   9922     is_float: bool,
   9923 ) llvm.AtomicRMWBinOp {
   9924     return switch (op) {
   9925         .Xchg => .Xchg,
   9926         .Add => if (is_float) llvm.AtomicRMWBinOp.FAdd else return .Add,
   9927         .Sub => if (is_float) llvm.AtomicRMWBinOp.FSub else return .Sub,
   9928         .And => .And,
   9929         .Nand => .Nand,
   9930         .Or => .Or,
   9931         .Xor => .Xor,
   9932         .Max => if (is_signed) llvm.AtomicRMWBinOp.Max else return .UMax,
   9933         .Min => if (is_signed) llvm.AtomicRMWBinOp.Min else return .UMin,
   9934     };
   9935 }
   9936 
   9937 fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.CallConv {
   9938     return switch (cc) {
   9939         .Unspecified, .Inline, .Async => .Fast,
   9940         .C, .Naked => .C,
   9941         .Stdcall => .X86_StdCall,
   9942         .Fastcall => .X86_FastCall,
   9943         .Vectorcall => return switch (target.cpu.arch) {
   9944             .i386, .x86_64 => .X86_VectorCall,
   9945             .aarch64, .aarch64_be, .aarch64_32 => .AArch64_VectorCall,
   9946             else => unreachable,
   9947         },
   9948         .Thiscall => .X86_ThisCall,
   9949         .APCS => .ARM_APCS,
   9950         .AAPCS => .ARM_AAPCS,
   9951         .AAPCSVFP => .ARM_AAPCS_VFP,
   9952         .Interrupt => return switch (target.cpu.arch) {
   9953             .i386, .x86_64 => .X86_INTR,
   9954             .avr => .AVR_INTR,
   9955             .msp430 => .MSP430_INTR,
   9956             else => unreachable,
   9957         },
   9958         .Signal => .AVR_SIGNAL,
   9959         .SysV => .X86_64_SysV,
   9960         .Win64 => .Win64,
   9961         .PtxKernel => return switch (target.cpu.arch) {
   9962             .nvptx, .nvptx64 => .PTX_Kernel,
   9963             else => unreachable,
   9964         },
   9965         .AmdgpuKernel => return switch (target.cpu.arch) {
   9966             .amdgcn => .AMDGPU_KERNEL,
   9967             else => unreachable,
   9968         },
   9969     };
   9970 }
   9971 
   9972 /// Convert a zig-address space to an llvm address space.
   9973 fn toLlvmAddressSpace(address_space: std.builtin.AddressSpace, target: std.Target) c_uint {
   9974     return switch (target.cpu.arch) {
   9975         .i386, .x86_64 => switch (address_space) {
   9976             .generic => llvm.address_space.default,
   9977             .gs => llvm.address_space.x86.gs,
   9978             .fs => llvm.address_space.x86.fs,
   9979             .ss => llvm.address_space.x86.ss,
   9980             else => unreachable,
   9981         },
   9982         .nvptx, .nvptx64 => switch (address_space) {
   9983             .generic => llvm.address_space.default,
   9984             .global => llvm.address_space.nvptx.global,
   9985             .constant => llvm.address_space.nvptx.constant,
   9986             .param => llvm.address_space.nvptx.param,
   9987             .shared => llvm.address_space.nvptx.shared,
   9988             .local => llvm.address_space.nvptx.local,
   9989             else => unreachable,
   9990         },
   9991         .amdgcn => switch (address_space) {
   9992             .generic => llvm.address_space.amdgpu.flat,
   9993             .global => llvm.address_space.amdgpu.global,
   9994             .constant => llvm.address_space.amdgpu.constant,
   9995             .shared => llvm.address_space.amdgpu.local,
   9996             .local => llvm.address_space.amdgpu.private,
   9997             else => unreachable,
   9998         },
   9999         else => switch (address_space) {
  10000             .generic => llvm.address_space.default,
  10001             else => unreachable,
  10002         },
  10003     };
  10004 }
  10005 
  10006 /// On some targets, local values that are in the generic address space must be generated into a
  10007 /// different address, space and then cast back to the generic address space.
  10008 /// For example, on GPUs local variable declarations must be generated into the local address space.
  10009 /// This function returns the address space local values should be generated into.
  10010 fn llvmAllocaAddressSpace(target: std.Target) c_uint {
  10011     return switch (target.cpu.arch) {
  10012         // On amdgcn, locals should be generated into the private address space.
  10013         // To make Zig not impossible to use, these are then converted to addresses in the
  10014         // generic address space and treates as regular pointers. This is the way that HIP also does it.
  10015         .amdgcn => llvm.address_space.amdgpu.private,
  10016         else => llvm.address_space.default,
  10017     };
  10018 }
  10019 
  10020 /// On some targets, global values that are in the generic address space must be generated into a
  10021 /// different address space, and then cast back to the generic address space.
  10022 fn llvmDefaultGlobalAddressSpace(target: std.Target) c_uint {
  10023     return switch (target.cpu.arch) {
  10024         // On amdgcn, globals must be explicitly allocated and uploaded so that the program can access
  10025         // them.
  10026         .amdgcn => llvm.address_space.amdgpu.global,
  10027         else => llvm.address_space.default,
  10028     };
  10029 }
  10030 
  10031 /// Return the actual address space that a value should be stored in if its a global address space.
  10032 /// When a value is placed in the resulting address space, it needs to be cast back into wanted_address_space.
  10033 fn toLlvmGlobalAddressSpace(wanted_address_space: std.builtin.AddressSpace, target: std.Target) c_uint {
  10034     return switch (wanted_address_space) {
  10035         .generic => llvmDefaultGlobalAddressSpace(target),
  10036         else => |as| toLlvmAddressSpace(as, target),
  10037     };
  10038 }
  10039 
  10040 /// Take into account 0 bit fields and padding. Returns null if an llvm
  10041 /// field could not be found.
  10042 /// This only happens if you want the field index of a zero sized field at
  10043 /// the end of the struct.
  10044 fn llvmFieldIndex(
  10045     ty: Type,
  10046     field_index: usize,
  10047     target: std.Target,
  10048     ptr_pl_buf: *Type.Payload.Pointer,
  10049 ) ?c_uint {
  10050     // Detects where we inserted extra padding fields so that we can skip
  10051     // over them in this function.
  10052     comptime assert(struct_layout_version == 2);
  10053     var offset: u64 = 0;
  10054     var big_align: u32 = 0;
  10055 
  10056     if (ty.isTupleOrAnonStruct()) {
  10057         const tuple = ty.tupleFields();
  10058         var llvm_field_index: c_uint = 0;
  10059         for (tuple.types) |field_ty, i| {
  10060             if (tuple.values[i].tag() != .unreachable_value) continue;
  10061 
  10062             const field_align = field_ty.abiAlignment(target);
  10063             big_align = @max(big_align, field_align);
  10064             const prev_offset = offset;
  10065             offset = std.mem.alignForwardGeneric(u64, offset, field_align);
  10066 
  10067             const padding_len = offset - prev_offset;
  10068             if (padding_len > 0) {
  10069                 llvm_field_index += 1;
  10070             }
  10071 
  10072             if (field_index == i) {
  10073                 ptr_pl_buf.* = .{
  10074                     .data = .{
  10075                         .pointee_type = field_ty,
  10076                         .@"align" = field_align,
  10077                         .@"addrspace" = .generic,
  10078                     },
  10079                 };
  10080                 return llvm_field_index;
  10081             }
  10082 
  10083             llvm_field_index += 1;
  10084             offset += field_ty.abiSize(target);
  10085         }
  10086         return null;
  10087     }
  10088     const layout = ty.containerLayout();
  10089     assert(layout != .Packed);
  10090 
  10091     var llvm_field_index: c_uint = 0;
  10092     for (ty.structFields().values()) |field, i| {
  10093         if (field.is_comptime or !field.ty.hasRuntimeBits()) continue;
  10094 
  10095         const field_align = field.alignment(target, layout);
  10096         big_align = @max(big_align, field_align);
  10097         const prev_offset = offset;
  10098         offset = std.mem.alignForwardGeneric(u64, offset, field_align);
  10099 
  10100         const padding_len = offset - prev_offset;
  10101         if (padding_len > 0) {
  10102             llvm_field_index += 1;
  10103         }
  10104 
  10105         if (field_index == i) {
  10106             ptr_pl_buf.* = .{
  10107                 .data = .{
  10108                     .pointee_type = field.ty,
  10109                     .@"align" = field_align,
  10110                     .@"addrspace" = .generic,
  10111                 },
  10112             };
  10113             return llvm_field_index;
  10114         }
  10115 
  10116         llvm_field_index += 1;
  10117         offset += field.ty.abiSize(target);
  10118     } else {
  10119         // We did not find an llvm field that corresponds to this zig field.
  10120         return null;
  10121     }
  10122 }
  10123 
  10124 fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool {
  10125     if (!fn_info.return_type.hasRuntimeBitsIgnoreComptime()) return false;
  10126 
  10127     switch (fn_info.cc) {
  10128         .Unspecified, .Inline => return isByRef(fn_info.return_type),
  10129         .C => switch (target.cpu.arch) {
  10130             .mips, .mipsel => return false,
  10131             .x86_64 => switch (target.os.tag) {
  10132                 .windows => return x86_64_abi.classifyWindows(fn_info.return_type, target) == .memory,
  10133                 else => return x86_64_abi.classifySystemV(fn_info.return_type, target, .ret)[0] == .memory,
  10134             },
  10135             .wasm32 => return wasm_c_abi.classifyType(fn_info.return_type, target)[0] == .indirect,
  10136             .aarch64, .aarch64_be => return aarch64_c_abi.classifyType(fn_info.return_type, target) == .memory,
  10137             .arm, .armeb => switch (arm_c_abi.classifyType(fn_info.return_type, target, .ret)) {
  10138                 .memory, .i64_array => return true,
  10139                 .i32_array => |size| return size != 1,
  10140                 .byval => return false,
  10141             },
  10142             .riscv32, .riscv64 => return riscv_c_abi.classifyType(fn_info.return_type, target) == .memory,
  10143             else => return false, // TODO investigate C ABI for other architectures
  10144         },
  10145         else => return false,
  10146     }
  10147 }
  10148 
  10149 /// In order to support the C calling convention, some return types need to be lowered
  10150 /// completely differently in the function prototype to honor the C ABI, and then
  10151 /// be effectively bitcasted to the actual return type.
  10152 fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type {
  10153     if (!fn_info.return_type.hasRuntimeBitsIgnoreComptime()) {
  10154         // If the return type is an error set or an error union, then we make this
  10155         // anyerror return type instead, so that it can be coerced into a function
  10156         // pointer type which has anyerror as the return type.
  10157         if (fn_info.return_type.isError()) {
  10158             return dg.lowerType(Type.anyerror);
  10159         } else {
  10160             return dg.context.voidType();
  10161         }
  10162     }
  10163     const target = dg.module.getTarget();
  10164     switch (fn_info.cc) {
  10165         .Unspecified, .Inline => {
  10166             if (isByRef(fn_info.return_type)) {
  10167                 return dg.context.voidType();
  10168             } else {
  10169                 return dg.lowerType(fn_info.return_type);
  10170             }
  10171         },
  10172         .C => {
  10173             const is_scalar = isScalar(fn_info.return_type);
  10174             switch (target.cpu.arch) {
  10175                 .mips, .mipsel => return dg.lowerType(fn_info.return_type),
  10176                 .x86_64 => switch (target.os.tag) {
  10177                     .windows => switch (x86_64_abi.classifyWindows(fn_info.return_type, target)) {
  10178                         .integer => {
  10179                             if (is_scalar) {
  10180                                 return dg.lowerType(fn_info.return_type);
  10181                             } else {
  10182                                 const abi_size = fn_info.return_type.abiSize(target);
  10183                                 return dg.context.intType(@intCast(c_uint, abi_size * 8));
  10184                             }
  10185                         },
  10186                         .win_i128 => return dg.context.intType(64).vectorType(2),
  10187                         .memory => return dg.context.voidType(),
  10188                         .sse => return dg.lowerType(fn_info.return_type),
  10189                         else => unreachable,
  10190                     },
  10191                     else => {
  10192                         if (is_scalar) {
  10193                             return dg.lowerType(fn_info.return_type);
  10194                         }
  10195                         const classes = x86_64_abi.classifySystemV(fn_info.return_type, target, .ret);
  10196                         if (classes[0] == .memory) {
  10197                             return dg.context.voidType();
  10198                         }
  10199                         var llvm_types_buffer: [8]*llvm.Type = undefined;
  10200                         var llvm_types_index: u32 = 0;
  10201                         for (classes) |class| {
  10202                             switch (class) {
  10203                                 .integer => {
  10204                                     llvm_types_buffer[llvm_types_index] = dg.context.intType(64);
  10205                                     llvm_types_index += 1;
  10206                                 },
  10207                                 .sse => {
  10208                                     llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
  10209                                     llvm_types_index += 1;
  10210                                 },
  10211                                 .sseup => {
  10212                                     llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
  10213                                     llvm_types_index += 1;
  10214                                 },
  10215                                 .x87 => {
  10216                                     llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();
  10217                                     llvm_types_index += 1;
  10218                                 },
  10219                                 .x87up => {
  10220                                     llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();
  10221                                     llvm_types_index += 1;
  10222                                 },
  10223                                 .complex_x87 => {
  10224                                     @panic("TODO");
  10225                                 },
  10226                                 .memory => unreachable, // handled above
  10227                                 .win_i128 => unreachable, // windows only
  10228                                 .none => break,
  10229                             }
  10230                         }
  10231                         if (classes[0] == .integer and classes[1] == .none) {
  10232                             const abi_size = fn_info.return_type.abiSize(target);
  10233                             return dg.context.intType(@intCast(c_uint, abi_size * 8));
  10234                         }
  10235                         return dg.context.structType(&llvm_types_buffer, llvm_types_index, .False);
  10236                     },
  10237                 },
  10238                 .wasm32 => {
  10239                     if (is_scalar) {
  10240                         return dg.lowerType(fn_info.return_type);
  10241                     }
  10242                     const classes = wasm_c_abi.classifyType(fn_info.return_type, target);
  10243                     if (classes[0] == .indirect or classes[0] == .none) {
  10244                         return dg.context.voidType();
  10245                     }
  10246 
  10247                     assert(classes[0] == .direct and classes[1] == .none);
  10248                     const scalar_type = wasm_c_abi.scalarType(fn_info.return_type, target);
  10249                     const abi_size = scalar_type.abiSize(target);
  10250                     return dg.context.intType(@intCast(c_uint, abi_size * 8));
  10251                 },
  10252                 .aarch64, .aarch64_be => {
  10253                     switch (aarch64_c_abi.classifyType(fn_info.return_type, target)) {
  10254                         .memory => return dg.context.voidType(),
  10255                         .float_array => return dg.lowerType(fn_info.return_type),
  10256                         .byval => return dg.lowerType(fn_info.return_type),
  10257                         .integer => {
  10258                             const bit_size = fn_info.return_type.bitSize(target);
  10259                             return dg.context.intType(@intCast(c_uint, bit_size));
  10260                         },
  10261                         .double_integer => return dg.context.intType(64).arrayType(2),
  10262                     }
  10263                 },
  10264                 .arm, .armeb => {
  10265                     switch (arm_c_abi.classifyType(fn_info.return_type, target, .ret)) {
  10266                         .memory, .i64_array => return dg.context.voidType(),
  10267                         .i32_array => |len| if (len == 1) {
  10268                             return dg.context.intType(32);
  10269                         } else {
  10270                             return dg.context.voidType();
  10271                         },
  10272                         .byval => return dg.lowerType(fn_info.return_type),
  10273                     }
  10274                 },
  10275                 .riscv32, .riscv64 => {
  10276                     switch (riscv_c_abi.classifyType(fn_info.return_type, target)) {
  10277                         .memory => return dg.context.voidType(),
  10278                         .integer => {
  10279                             const bit_size = fn_info.return_type.bitSize(target);
  10280                             return dg.context.intType(@intCast(c_uint, bit_size));
  10281                         },
  10282                         .double_integer => {
  10283                             var llvm_types_buffer: [2]*llvm.Type = .{
  10284                                 dg.context.intType(64),
  10285                                 dg.context.intType(64),
  10286                             };
  10287                             return dg.context.structType(&llvm_types_buffer, 2, .False);
  10288                         },
  10289                         .byval => return dg.lowerType(fn_info.return_type),
  10290                     }
  10291                 },
  10292                 // TODO investigate C ABI for other architectures
  10293                 else => return dg.lowerType(fn_info.return_type),
  10294             }
  10295         },
  10296         else => return dg.lowerType(fn_info.return_type),
  10297     }
  10298 }
  10299 
  10300 const ParamTypeIterator = struct {
  10301     dg: *DeclGen,
  10302     fn_info: Type.Payload.Function.Data,
  10303     zig_index: u32,
  10304     llvm_index: u32,
  10305     target: std.Target,
  10306     llvm_types_len: u32,
  10307     llvm_types_buffer: [8]u16,
  10308     byval_attr: bool,
  10309 
  10310     const Lowering = union(enum) {
  10311         no_bits,
  10312         byval,
  10313         byref,
  10314         abi_sized_int,
  10315         multiple_llvm_ints,
  10316         multiple_llvm_float,
  10317         slice,
  10318         as_u16,
  10319         float_array: u8,
  10320         i32_array: u8,
  10321         i64_array: u8,
  10322     };
  10323 
  10324     pub fn next(it: *ParamTypeIterator) ?Lowering {
  10325         if (it.zig_index >= it.fn_info.param_types.len) return null;
  10326         const ty = it.fn_info.param_types[it.zig_index];
  10327         it.byval_attr = false;
  10328         return nextInner(it, ty);
  10329     }
  10330 
  10331     /// `airCall` uses this instead of `next` so that it can take into account variadic functions.
  10332     pub fn nextCall(it: *ParamTypeIterator, fg: *FuncGen, args: []const Air.Inst.Ref) ?Lowering {
  10333         if (it.zig_index >= it.fn_info.param_types.len) {
  10334             if (it.zig_index >= args.len) {
  10335                 return null;
  10336             } else {
  10337                 return nextInner(it, fg.air.typeOf(args[it.zig_index]));
  10338             }
  10339         } else {
  10340             return nextInner(it, it.fn_info.param_types[it.zig_index]);
  10341         }
  10342     }
  10343 
  10344     fn nextInner(it: *ParamTypeIterator, ty: Type) ?Lowering {
  10345         if (!ty.hasRuntimeBitsIgnoreComptime()) {
  10346             it.zig_index += 1;
  10347             return .no_bits;
  10348         }
  10349 
  10350         switch (it.fn_info.cc) {
  10351             .Unspecified, .Inline => {
  10352                 it.zig_index += 1;
  10353                 it.llvm_index += 1;
  10354                 if (ty.isSlice()) {
  10355                     return .slice;
  10356                 } else if (isByRef(ty)) {
  10357                     return .byref;
  10358                 } else {
  10359                     return .byval;
  10360                 }
  10361             },
  10362             .Async => {
  10363                 @panic("TODO implement async function lowering in the LLVM backend");
  10364             },
  10365             .C => {
  10366                 const is_scalar = isScalar(ty);
  10367                 switch (it.target.cpu.arch) {
  10368                     .mips, .mipsel => {
  10369                         it.zig_index += 1;
  10370                         it.llvm_index += 1;
  10371                         return .byval;
  10372                     },
  10373                     .x86_64 => switch (it.target.os.tag) {
  10374                         .windows => switch (x86_64_abi.classifyWindows(ty, it.target)) {
  10375                             .integer => {
  10376                                 if (is_scalar) {
  10377                                     it.zig_index += 1;
  10378                                     it.llvm_index += 1;
  10379                                     return .byval;
  10380                                 } else {
  10381                                     it.zig_index += 1;
  10382                                     it.llvm_index += 1;
  10383                                     return .abi_sized_int;
  10384                                 }
  10385                             },
  10386                             .win_i128 => {
  10387                                 it.zig_index += 1;
  10388                                 it.llvm_index += 1;
  10389                                 return .byref;
  10390                             },
  10391                             .memory => {
  10392                                 it.zig_index += 1;
  10393                                 it.llvm_index += 1;
  10394                                 it.byval_attr = true;
  10395                                 return .byref;
  10396                             },
  10397                             .sse => {
  10398                                 it.zig_index += 1;
  10399                                 it.llvm_index += 1;
  10400                                 return .byval;
  10401                             },
  10402                             else => unreachable,
  10403                         },
  10404                         else => {
  10405                             const classes = x86_64_abi.classifySystemV(ty, it.target, .arg);
  10406                             if (classes[0] == .memory) {
  10407                                 it.zig_index += 1;
  10408                                 it.llvm_index += 1;
  10409                                 it.byval_attr = true;
  10410                                 return .byref;
  10411                             }
  10412                             if (is_scalar) {
  10413                                 it.zig_index += 1;
  10414                                 it.llvm_index += 1;
  10415                                 return .byval;
  10416                             }
  10417                             var llvm_types_buffer: [8]u16 = undefined;
  10418                             var llvm_types_index: u32 = 0;
  10419                             for (classes) |class| {
  10420                                 switch (class) {
  10421                                     .integer => {
  10422                                         llvm_types_buffer[llvm_types_index] = 64;
  10423                                         llvm_types_index += 1;
  10424                                     },
  10425                                     .sse => {
  10426                                         llvm_types_buffer[llvm_types_index] = 64;
  10427                                         llvm_types_index += 1;
  10428                                     },
  10429                                     .sseup => {
  10430                                         llvm_types_buffer[llvm_types_index] = 64;
  10431                                         llvm_types_index += 1;
  10432                                     },
  10433                                     .x87 => {
  10434                                         llvm_types_buffer[llvm_types_index] = 80;
  10435                                         llvm_types_index += 1;
  10436                                     },
  10437                                     .x87up => {
  10438                                         llvm_types_buffer[llvm_types_index] = 80;
  10439                                         llvm_types_index += 1;
  10440                                     },
  10441                                     .complex_x87 => {
  10442                                         @panic("TODO");
  10443                                     },
  10444                                     .memory => unreachable, // handled above
  10445                                     .win_i128 => unreachable, // windows only
  10446                                     .none => break,
  10447                                 }
  10448                             }
  10449                             if (classes[0] == .integer and classes[1] == .none) {
  10450                                 it.zig_index += 1;
  10451                                 it.llvm_index += 1;
  10452                                 return .abi_sized_int;
  10453                             }
  10454                             it.llvm_types_buffer = llvm_types_buffer;
  10455                             it.llvm_types_len = llvm_types_index;
  10456                             it.llvm_index += llvm_types_index;
  10457                             it.zig_index += 1;
  10458                             return if (classes[0] == .integer) .multiple_llvm_ints else .multiple_llvm_float;
  10459                         },
  10460                     },
  10461                     .wasm32 => {
  10462                         it.zig_index += 1;
  10463                         it.llvm_index += 1;
  10464                         if (is_scalar) {
  10465                             return .byval;
  10466                         }
  10467                         const classes = wasm_c_abi.classifyType(ty, it.target);
  10468                         if (classes[0] == .indirect) {
  10469                             return .byref;
  10470                         }
  10471                         return .abi_sized_int;
  10472                     },
  10473                     .aarch64, .aarch64_be => {
  10474                         it.zig_index += 1;
  10475                         it.llvm_index += 1;
  10476                         switch (aarch64_c_abi.classifyType(ty, it.target)) {
  10477                             .memory => return .byref,
  10478                             .float_array => |len| return Lowering{ .float_array = len },
  10479                             .byval => return .byval,
  10480                             .integer => {
  10481                                 it.llvm_types_len = 1;
  10482                                 it.llvm_types_buffer[0] = 64;
  10483                                 return .multiple_llvm_ints;
  10484                             },
  10485                             .double_integer => return Lowering{ .i64_array = 2 },
  10486                         }
  10487                     },
  10488                     .arm, .armeb => {
  10489                         it.zig_index += 1;
  10490                         it.llvm_index += 1;
  10491                         switch (arm_c_abi.classifyType(ty, it.target, .arg)) {
  10492                             .memory => {
  10493                                 it.byval_attr = true;
  10494                                 return .byref;
  10495                             },
  10496                             .byval => return .byval,
  10497                             .i32_array => |size| return Lowering{ .i32_array = size },
  10498                             .i64_array => |size| return Lowering{ .i64_array = size },
  10499                         }
  10500                     },
  10501                     .riscv32, .riscv64 => {
  10502                         it.zig_index += 1;
  10503                         it.llvm_index += 1;
  10504                         if (ty.tag() == .f16) {
  10505                             return .as_u16;
  10506                         }
  10507                         switch (riscv_c_abi.classifyType(ty, it.target)) {
  10508                             .memory => {
  10509                                 return .byref;
  10510                             },
  10511                             .byval => return .byval,
  10512                             .integer => return .abi_sized_int,
  10513                             .double_integer => return Lowering{ .i64_array = 2 },
  10514                         }
  10515                     },
  10516                     // TODO investigate C ABI for other architectures
  10517                     else => {
  10518                         it.zig_index += 1;
  10519                         it.llvm_index += 1;
  10520                         return .byval;
  10521                     },
  10522                 }
  10523             },
  10524             else => {
  10525                 it.zig_index += 1;
  10526                 it.llvm_index += 1;
  10527                 return .byval;
  10528             },
  10529         }
  10530     }
  10531 };
  10532 
  10533 fn iterateParamTypes(dg: *DeclGen, fn_info: Type.Payload.Function.Data) ParamTypeIterator {
  10534     return .{
  10535         .dg = dg,
  10536         .fn_info = fn_info,
  10537         .zig_index = 0,
  10538         .llvm_index = 0,
  10539         .target = dg.module.getTarget(),
  10540         .llvm_types_buffer = undefined,
  10541         .llvm_types_len = 0,
  10542         .byval_attr = false,
  10543     };
  10544 }
  10545 
  10546 fn ccAbiPromoteInt(
  10547     cc: std.builtin.CallingConvention,
  10548     target: std.Target,
  10549     ty: Type,
  10550 ) ?std.builtin.Signedness {
  10551     switch (cc) {
  10552         .Unspecified, .Inline, .Async => return null,
  10553         else => {},
  10554     }
  10555     const int_info = switch (ty.zigTypeTag()) {
  10556         .Bool => Type.@"u1".intInfo(target),
  10557         .Int, .Enum, .ErrorSet => ty.intInfo(target),
  10558         else => return null,
  10559     };
  10560     if (int_info.bits <= 16) return int_info.signedness;
  10561     switch (target.cpu.arch) {
  10562         .riscv64 => {
  10563             if (int_info.bits == 32) {
  10564                 // LLVM always signextends 32 bit ints, unsure if bug.
  10565                 return .signed;
  10566             }
  10567             if (int_info.bits < 64) {
  10568                 return int_info.signedness;
  10569             }
  10570         },
  10571         .sparc64,
  10572         .powerpc64,
  10573         .powerpc64le,
  10574         => {
  10575             if (int_info.bits < 64) {
  10576                 return int_info.signedness;
  10577             }
  10578         },
  10579         else => {},
  10580     }
  10581     return null;
  10582 }
  10583 
  10584 /// This is the one source of truth for whether a type is passed around as an LLVM pointer,
  10585 /// or as an LLVM value.
  10586 fn isByRef(ty: Type) bool {
  10587     // For tuples and structs, if there are more than this many non-void
  10588     // fields, then we make it byref, otherwise byval.
  10589     const max_fields_byval = 0;
  10590 
  10591     switch (ty.zigTypeTag()) {
  10592         .Type,
  10593         .ComptimeInt,
  10594         .ComptimeFloat,
  10595         .EnumLiteral,
  10596         .Undefined,
  10597         .Null,
  10598         .BoundFn,
  10599         .Opaque,
  10600         => unreachable,
  10601 
  10602         .NoReturn,
  10603         .Void,
  10604         .Bool,
  10605         .Int,
  10606         .Float,
  10607         .Pointer,
  10608         .ErrorSet,
  10609         .Fn,
  10610         .Enum,
  10611         .Vector,
  10612         .AnyFrame,
  10613         => return false,
  10614 
  10615         .Array, .Frame => return ty.hasRuntimeBits(),
  10616         .Struct => {
  10617             // Packed structs are represented to LLVM as integers.
  10618             if (ty.containerLayout() == .Packed) return false;
  10619             if (ty.isTupleOrAnonStruct()) {
  10620                 const tuple = ty.tupleFields();
  10621                 var count: usize = 0;
  10622                 for (tuple.values) |field_val, i| {
  10623                     if (field_val.tag() != .unreachable_value) continue;
  10624 
  10625                     count += 1;
  10626                     if (count > max_fields_byval) return true;
  10627                     if (isByRef(tuple.types[i])) return true;
  10628                 }
  10629                 return false;
  10630             }
  10631             var count: usize = 0;
  10632             const fields = ty.structFields();
  10633             for (fields.values()) |field| {
  10634                 if (field.is_comptime or !field.ty.hasRuntimeBits()) continue;
  10635 
  10636                 count += 1;
  10637                 if (count > max_fields_byval) return true;
  10638                 if (isByRef(field.ty)) return true;
  10639             }
  10640             return false;
  10641         },
  10642         .Union => return ty.hasRuntimeBits(),
  10643         .ErrorUnion => {
  10644             const payload_ty = ty.errorUnionPayload();
  10645             if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
  10646                 return false;
  10647             }
  10648             return true;
  10649         },
  10650         .Optional => {
  10651             var buf: Type.Payload.ElemType = undefined;
  10652             const payload_ty = ty.optionalChild(&buf);
  10653             if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
  10654                 return false;
  10655             }
  10656             if (ty.optionalReprIsPayload()) {
  10657                 return false;
  10658             }
  10659             return true;
  10660         },
  10661     }
  10662 }
  10663 
  10664 fn isScalar(ty: Type) bool {
  10665     return switch (ty.zigTypeTag()) {
  10666         .Void,
  10667         .Bool,
  10668         .NoReturn,
  10669         .Int,
  10670         .Float,
  10671         .Pointer,
  10672         .Optional,
  10673         .ErrorSet,
  10674         .Enum,
  10675         .AnyFrame,
  10676         .Vector,
  10677         => true,
  10678 
  10679         .Struct => ty.containerLayout() == .Packed,
  10680         .Union => ty.containerLayout() == .Packed,
  10681         else => false,
  10682     };
  10683 }
  10684 
  10685 /// This function returns true if we expect LLVM to lower x86_fp80 correctly
  10686 /// and false if we expect LLVM to crash if it counters an x86_fp80 type.
  10687 fn backendSupportsF80(target: std.Target) bool {
  10688     return switch (target.cpu.arch) {
  10689         .x86_64, .i386 => !std.Target.x86.featureSetHas(target.cpu.features, .soft_float),
  10690         else => false,
  10691     };
  10692 }
  10693 
  10694 /// This function returns true if we expect LLVM to lower f16 correctly
  10695 /// and false if we expect LLVM to crash if it counters an f16 type or
  10696 /// if it produces miscompilations.
  10697 fn backendSupportsF16(target: std.Target) bool {
  10698     return switch (target.cpu.arch) {
  10699         .powerpc,
  10700         .powerpcle,
  10701         .powerpc64,
  10702         .powerpc64le,
  10703         .wasm32,
  10704         .wasm64,
  10705         .mips,
  10706         .mipsel,
  10707         .mips64,
  10708         .mips64el,
  10709         => false,
  10710         else => true,
  10711     };
  10712 }
  10713 
  10714 /// This function returns true if we expect LLVM to lower f128 correctly,
  10715 /// and false if we expect LLVm to crash if it encounters and f128 type
  10716 /// or if it produces miscompilations.
  10717 fn backendSupportsF128(target: std.Target) bool {
  10718     return switch (target.cpu.arch) {
  10719         .amdgcn => false,
  10720         else => true,
  10721     };
  10722 }
  10723 
  10724 /// LLVM does not support all relevant intrinsics for all targets, so we
  10725 /// may need to manually generate a libc call
  10726 fn intrinsicsAllowed(scalar_ty: Type, target: std.Target) bool {
  10727     return switch (scalar_ty.tag()) {
  10728         .f16 => backendSupportsF16(target),
  10729         .f80 => target.longDoubleIs(f80) and backendSupportsF80(target),
  10730         .f128 => target.longDoubleIs(f128) and backendSupportsF128(target),
  10731         else => true,
  10732     };
  10733 }
  10734 
  10735 /// We need to insert extra padding if LLVM's isn't enough.
  10736 /// However we don't want to ever call LLVMABIAlignmentOfType or
  10737 /// LLVMABISizeOfType because these functions will trip assertions
  10738 /// when using them for self-referential types. So our strategy is
  10739 /// to use non-packed llvm structs but to emit all padding explicitly.
  10740 /// We can do this because for all types, Zig ABI alignment >= LLVM ABI
  10741 /// alignment.
  10742 const struct_layout_version = 2;
  10743 
  10744 // TODO: Restore the non_null field to i1 once
  10745 //       https://github.com/llvm/llvm-project/issues/56585/ is fixed
  10746 const optional_layout_version = 3;
  10747 
  10748 /// We use the least significant bit of the pointer address to tell us
  10749 /// whether the type is fully resolved. Types that are only fwd declared
  10750 /// have the LSB flipped to a 1.
  10751 const AnnotatedDITypePtr = enum(usize) {
  10752     _,
  10753 
  10754     fn initFwd(di_type: *llvm.DIType) AnnotatedDITypePtr {
  10755         const addr = @ptrToInt(di_type);
  10756         assert(@truncate(u1, addr) == 0);
  10757         return @intToEnum(AnnotatedDITypePtr, addr | 1);
  10758     }
  10759 
  10760     fn initFull(di_type: *llvm.DIType) AnnotatedDITypePtr {
  10761         const addr = @ptrToInt(di_type);
  10762         return @intToEnum(AnnotatedDITypePtr, addr);
  10763     }
  10764 
  10765     fn init(di_type: *llvm.DIType, resolve: Object.DebugResolveStatus) AnnotatedDITypePtr {
  10766         const addr = @ptrToInt(di_type);
  10767         const bit = @boolToInt(resolve == .fwd);
  10768         return @intToEnum(AnnotatedDITypePtr, addr | bit);
  10769     }
  10770 
  10771     fn toDIType(self: AnnotatedDITypePtr) *llvm.DIType {
  10772         const fixed_addr = @enumToInt(self) & ~@as(usize, 1);
  10773         return @intToPtr(*llvm.DIType, fixed_addr);
  10774     }
  10775 
  10776     fn isFwdOnly(self: AnnotatedDITypePtr) bool {
  10777         return @truncate(u1, @enumToInt(self)) != 0;
  10778     }
  10779 };
  10780 
  10781 const lt_errors_fn_name = "__zig_lt_errors_len";
  10782 
  10783 /// Without this workaround, LLVM crashes with "unknown codeview register H1"
  10784 /// https://github.com/llvm/llvm-project/issues/56484
  10785 fn needDbgVarWorkaround(dg: *DeclGen) bool {
  10786     const target = dg.module.getTarget();
  10787     if (target.os.tag == .windows and target.cpu.arch == .aarch64) {
  10788         return true;
  10789     }
  10790     return false;
  10791 }
  10792 
  10793 fn compilerRtIntBits(bits: u16) u16 {
  10794     inline for (.{ 32, 64, 128 }) |b| {
  10795         if (bits <= b) {
  10796             return b;
  10797         }
  10798     }
  10799     return bits;
  10800 }
  10801 
  10802 fn buildAllocaInner(
  10803     builder: *llvm.Builder,
  10804     llvm_func: *llvm.Value,
  10805     di_scope_non_null: bool,
  10806     llvm_ty: *llvm.Type,
  10807     maybe_alignment: ?c_uint,
  10808     target: std.Target,
  10809 ) *llvm.Value {
  10810     const address_space = llvmAllocaAddressSpace(target);
  10811 
  10812     const alloca = blk: {
  10813         const prev_block = builder.getInsertBlock();
  10814         const prev_debug_location = builder.getCurrentDebugLocation2();
  10815         defer {
  10816             builder.positionBuilderAtEnd(prev_block);
  10817             if (di_scope_non_null) {
  10818                 builder.setCurrentDebugLocation2(prev_debug_location);
  10819             }
  10820         }
  10821 
  10822         const entry_block = llvm_func.getFirstBasicBlock().?;
  10823         if (entry_block.getFirstInstruction()) |first_inst| {
  10824             builder.positionBuilder(entry_block, first_inst);
  10825         } else {
  10826             builder.positionBuilderAtEnd(entry_block);
  10827         }
  10828         builder.clearCurrentDebugLocation();
  10829 
  10830         break :blk builder.buildAllocaInAddressSpace(llvm_ty, address_space, "");
  10831     };
  10832 
  10833     if (maybe_alignment) |alignment| {
  10834         alloca.setAlignment(alignment);
  10835     }
  10836 
  10837     // The pointer returned from this function should have the generic address space,
  10838     // if this isn't the case then cast it to the generic address space.
  10839     if (address_space != llvm.address_space.default) {
  10840         return builder.buildAddrSpaceCast(alloca, llvm_ty.pointerType(llvm.address_space.default), "");
  10841     }
  10842 
  10843     return alloca;
  10844 }
  10845 
  10846 fn errUnionPayloadOffset(payload_ty: Type, target: std.Target) u1 {
  10847     return @boolToInt(Type.anyerror.abiAlignment(target) > payload_ty.abiAlignment(target));
  10848 }
  10849 
  10850 fn errUnionErrorOffset(payload_ty: Type, target: std.Target) u1 {
  10851     return @boolToInt(Type.anyerror.abiAlignment(target) <= payload_ty.abiAlignment(target));
  10852 }
  10853 
  10854 /// Returns true for asm constraint (e.g. "=*m", "=r") if it accepts a memory location
  10855 ///
  10856 /// See also TargetInfo::validateOutputConstraint, AArch64TargetInfo::validateAsmConstraint, etc. in Clang
  10857 fn constraintAllowsMemory(constraint: []const u8) bool {
  10858     // TODO: This implementation is woefully incomplete.
  10859     for (constraint) |byte| {
  10860         switch (byte) {
  10861             '=', '*', ',', '&' => {},
  10862             'm', 'o', 'X', 'g' => return true,
  10863             else => {},
  10864         }
  10865     } else return false;
  10866 }
  10867 
  10868 /// Returns true for asm constraint (e.g. "=*m", "=r") if it accepts a register
  10869 ///
  10870 /// See also TargetInfo::validateOutputConstraint, AArch64TargetInfo::validateAsmConstraint, etc. in Clang
  10871 fn constraintAllowsRegister(constraint: []const u8) bool {
  10872     // TODO: This implementation is woefully incomplete.
  10873     for (constraint) |byte| {
  10874         switch (byte) {
  10875             '=', '*', ',', '&' => {},
  10876             'm', 'o' => {},
  10877             else => return true,
  10878         }
  10879     } else return false;
  10880 }