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, ¶m_types, dest_llvm_ty); 5504 const params = [1]*llvm.Value{extended}; 5505 5506 return self.builder.buildCall(libc_fn.globalGetValueType(), libc_fn, ¶ms, 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, ¶m_types, libc_ret_ty); 5559 const params = [1]*llvm.Value{operand}; 5560 5561 var result = self.builder.buildCall(libc_fn.globalGetValueType(), libc_fn, ¶ms, 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, ¶ms, 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, ¶ms, 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, ¶ms, result, ty.vectorLen()); 7403 } 7404 7405 break :b libc_fn; 7406 }, 7407 }; 7408 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, ¶ms, 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, ¶m_types, dest_llvm_ty); 7698 7699 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, ¶ms, 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, ¶m_types, dest_llvm_ty); 7730 7731 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, ¶ms, 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, ¶ms, 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, ¶m_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, ¶ms, 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, ¶ms, 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, ¶ms, 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, ¶ms, 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, ¶ms, 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, ¶m_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, ¶ms, 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, ¶m_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, ¶m_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, ¶ms, 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, ¶m_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, ¶m_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, ¶ms, 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, ¶m_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 }