authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-07-20 12:55:03-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-07-20 12:55:03-07:00
log3f15010abe5c5efaed16799fcb94c9f84117bdde
treef1892ab71f40a4473c35783ac88d86e4290dc0e5
parent3bada8e3ce9ba72f57c6fbed100c76fd40ba0d15
parent4d31d4d875f32ed49c56151ca053a614b3ae343c
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #16430 from jacobly0/llvm-builder

llvm: begin the journey of independence from llvm

11 files changed, 12542 insertions(+), 3975 deletions(-)

lib/std/target.zig+39-4
......@@ -1357,8 +1357,6 @@ pub const Target = struct {
13571357 }
13581358 };
13591359
1360 pub const stack_align = 16;
1361
13621360 pub fn zigTriple(self: Target, allocator: mem.Allocator) ![]u8 {
13631361 return std.zig.CrossTarget.fromTarget(self).zigTriple(allocator);
13641362 }
......@@ -1833,7 +1831,7 @@ pub const Target = struct {
18331831 };
18341832 }
18351833
1836 pub fn ptrBitWidth(target: std.Target) u16 {
1834 pub fn ptrBitWidth(target: Target) u16 {
18371835 switch (target.abi) {
18381836 .gnux32, .muslx32, .gnuabin32, .gnuilp32 => return 32,
18391837 .gnuabi64 => return 64,
......@@ -1910,6 +1908,43 @@ pub const Target = struct {
19101908 }
19111909 }
19121910
1911 pub fn stackAlignment(target: Target) u16 {
1912 return switch (target.cpu.arch) {
1913 .amdgcn => 4,
1914 .x86 => switch (target.os.tag) {
1915 .windows => 4,
1916 else => 16,
1917 },
1918 .arm,
1919 .armeb,
1920 .thumb,
1921 .thumbeb,
1922 .mips,
1923 .mipsel,
1924 .sparc,
1925 .sparcel,
1926 => 8,
1927 .aarch64,
1928 .aarch64_be,
1929 .aarch64_32,
1930 .bpfeb,
1931 .bpfel,
1932 .mips64,
1933 .mips64el,
1934 .powerpc64,
1935 .powerpc64le,
1936 .riscv32,
1937 .riscv64,
1938 .sparc64,
1939 .x86_64,
1940 .ve,
1941 .wasm32,
1942 .wasm64,
1943 => 16,
1944 else => @divExact(target.ptrBitWidth(), 8),
1945 };
1946 }
1947
19131948 /// Default signedness of `char` for the native C compiler for this target
19141949 /// Note that char signedness is implementation-defined and many compilers provide
19151950 /// an option to override the default signedness e.g. GCC's -funsigned-char / -fsigned-char
......@@ -2428,7 +2463,7 @@ pub const Target = struct {
24282463 else => {},
24292464 },
24302465 .avr => switch (c_type) {
2431 .int, .uint, .long, .ulong, .float, .longdouble => return 1,
2466 .char, .int, .uint, .long, .ulong, .float, .longdouble => return 1,
24322467 .short, .ushort => return 2,
24332468 .double => return 4,
24342469 .longlong, .ulonglong => return 8,
lib/test_runner.zig+1-1
......@@ -136,7 +136,7 @@ fn mainTerminal() void {
136136 const have_tty = progress.terminal != null and
137137 (progress.supports_ansi_escape_codes or progress.is_windows_terminal);
138138
139 var async_frame_buffer: []align(std.Target.stack_align) u8 = undefined;
139 var async_frame_buffer: []align(builtin.target.stackAlignment()) u8 = undefined;
140140 // TODO this is on the next line (using `undefined` above) because otherwise zig incorrectly
141141 // ignores the alignment of the slice.
142142 async_frame_buffer = &[_]u8{};
src/Compilation.zig+5-1
......@@ -538,6 +538,7 @@ pub const InitOptions = struct {
538538 want_lto: ?bool = null,
539539 want_unwind_tables: ?bool = null,
540540 use_llvm: ?bool = null,
541 use_lib_llvm: ?bool = null,
541542 use_lld: ?bool = null,
542543 use_clang: ?bool = null,
543544 single_threaded: ?bool = null,
......@@ -753,7 +754,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
753754 const root_name = try arena.dupeZ(u8, options.root_name);
754755
755756 // Make a decision on whether to use LLVM or our own backend.
756 const use_llvm = build_options.have_llvm and blk: {
757 const use_lib_llvm = options.use_lib_llvm orelse build_options.have_llvm;
758 const use_llvm = blk: {
757759 if (options.use_llvm) |explicit|
758760 break :blk explicit;
759761
......@@ -1161,6 +1163,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
11611163 hash.add(valgrind);
11621164 hash.add(single_threaded);
11631165 hash.add(use_llvm);
1166 hash.add(use_lib_llvm);
11641167 hash.add(dll_export_fns);
11651168 hash.add(options.is_test);
11661169 hash.add(options.test_evented_io);
......@@ -1444,6 +1447,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
14441447 .optimize_mode = options.optimize_mode,
14451448 .use_lld = use_lld,
14461449 .use_llvm = use_llvm,
1450 .use_lib_llvm = use_lib_llvm,
14471451 .link_libc = link_libc,
14481452 .link_libcpp = link_libcpp,
14491453 .link_libunwind = link_libunwind,
src/Module.zig+4-8
......@@ -835,10 +835,6 @@ pub const Decl = struct {
835835 assert(decl.has_tv);
836836 return @as(u32, @intCast(decl.alignment.toByteUnitsOptional() orelse decl.ty.abiAlignment(mod)));
837837 }
838
839 pub fn intern(decl: *Decl, mod: *Module) Allocator.Error!void {
840 decl.val = (try decl.val.intern(decl.ty, mod)).toValue();
841 }
842838};
843839
844840/// This state is attached to every Decl when Module emit_h is non-null.
......@@ -4204,7 +4200,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
42044200 try wip_captures.finalize();
42054201 for (comptime_mutable_decls.items) |decl_index| {
42064202 const decl = mod.declPtr(decl_index);
4207 try decl.intern(mod);
4203 _ = try decl.internValue(mod);
42084204 }
42094205 new_decl.analysis = .complete;
42104206 } else |err| switch (err) {
......@@ -4315,7 +4311,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
43154311 try wip_captures.finalize();
43164312 for (comptime_mutable_decls.items) |ct_decl_index| {
43174313 const ct_decl = mod.declPtr(ct_decl_index);
4318 try ct_decl.intern(mod);
4314 _ = try ct_decl.internValue(mod);
43194315 }
43204316 const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = 0 };
43214317 const section_src: LazySrcLoc = .{ .node_offset_var_decl_section = 0 };
......@@ -5362,7 +5358,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
53625358 try wip_captures.finalize();
53635359 for (comptime_mutable_decls.items) |ct_decl_index| {
53645360 const ct_decl = mod.declPtr(ct_decl_index);
5365 try ct_decl.intern(mod);
5361 _ = try ct_decl.internValue(mod);
53665362 }
53675363
53685364 // Copy the block into place and mark that as the main block.
......@@ -6369,7 +6365,7 @@ pub fn markDeclAlive(mod: *Module, decl: *Decl) Allocator.Error!void {
63696365 if (decl.alive) return;
63706366 decl.alive = true;
63716367
6372 try decl.intern(mod);
6368 _ = try decl.internValue(mod);
63736369
63746370 // This is the first time we are marking this Decl alive. We must
63756371 // therefore recurse into its value and mark any Decl it references
src/Sema.zig+4-4
......@@ -3899,7 +3899,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
38993899 try mod.declareDeclDependency(sema.owner_decl_index, decl_index);
39003900
39013901 const decl = mod.declPtr(decl_index);
3902 if (iac.is_const) try decl.intern(mod);
3902 if (iac.is_const) _ = try decl.internValue(mod);
39033903 const final_elem_ty = decl.ty;
39043904 const final_ptr_ty = try mod.ptrType(.{
39053905 .child = final_elem_ty.toIntern(),
......@@ -33577,7 +33577,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
3357733577 try wip_captures.finalize();
3357833578 for (comptime_mutable_decls.items) |ct_decl_index| {
3357933579 const ct_decl = mod.declPtr(ct_decl_index);
33580 try ct_decl.intern(mod);
33580 _ = try ct_decl.internValue(mod);
3358133581 }
3358233582 } else {
3358333583 if (fields_bit_sum > std.math.maxInt(u16)) {
......@@ -34645,7 +34645,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3464534645 try wip_captures.finalize();
3464634646 for (comptime_mutable_decls.items) |ct_decl_index| {
3464734647 const ct_decl = mod.declPtr(ct_decl_index);
34648 try ct_decl.intern(mod);
34648 _ = try ct_decl.internValue(mod);
3464934649 }
3465034650
3465134651 struct_obj.have_field_inits = true;
......@@ -34744,7 +34744,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
3474434744 try wip_captures.finalize();
3474534745 for (comptime_mutable_decls.items) |ct_decl_index| {
3474634746 const ct_decl = mod.declPtr(ct_decl_index);
34747 try ct_decl.intern(mod);
34747 _ = try ct_decl.internValue(mod);
3474834748 }
3474934749
3475034750 try union_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len);
src/codegen/llvm.zig+4363-3861
......@@ -7,7 +7,11 @@ const math = std.math;
77const native_endian = builtin.cpu.arch.endian();
88const DW = std.dwarf;
99
10const llvm = @import("llvm/bindings.zig");
10const Builder = @import("llvm/Builder.zig");
11const llvm = if (build_options.have_llvm or true)
12 @import("llvm/bindings.zig")
13else
14 @compileError("LLVM unavailable");
1115const link = @import("../link.zig");
1216const Compilation = @import("../Compilation.zig");
1317const build_options = @import("build_options");
......@@ -34,7 +38,7 @@ const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev;
3438
3539const Error = error{ OutOfMemory, CodegenFail };
3640
37pub fn targetTriple(allocator: Allocator, target: std.Target) ![:0]u8 {
41pub fn targetTriple(allocator: Allocator, target: std.Target) ![]const u8 {
3842 var llvm_triple = std.ArrayList(u8).init(allocator);
3943 defer llvm_triple.deinit();
4044
......@@ -207,7 +211,7 @@ pub fn targetTriple(allocator: Allocator, target: std.Target) ![:0]u8 {
207211 };
208212 try llvm_triple.appendSlice(llvm_abi);
209213
210 return llvm_triple.toOwnedSliceSentinel(0);
214 return llvm_triple.toOwnedSlice();
211215}
212216
213217pub fn targetOs(os_tag: std.Target.Os.Tag) llvm.OSType {
......@@ -327,17 +331,363 @@ pub fn supportsTailCall(target: std.Target) bool {
327331 }
328332}
329333
330/// TODO can this be done with simpler logic / different API binding?
331fn deleteLlvmGlobal(llvm_global: *llvm.Value) void {
332 if (llvm_global.globalGetValueType().getTypeKind() == .Function) {
333 llvm_global.deleteFunction();
334 return;
334const DataLayoutBuilder = struct {
335 target: std.Target,
336
337 pub fn format(
338 self: DataLayoutBuilder,
339 comptime _: []const u8,
340 _: std.fmt.FormatOptions,
341 writer: anytype,
342 ) @TypeOf(writer).Error!void {
343 const is_aarch64_windows = self.target.cpu.arch == .aarch64 and self.target.os.tag == .windows;
344 try writer.writeByte(switch (self.target.cpu.arch.endian()) {
345 .Little => 'e',
346 .Big => 'E',
347 });
348 switch (self.target.cpu.arch) {
349 .amdgcn,
350 .nvptx,
351 .nvptx64,
352 => {},
353 .avr => try writer.writeAll("-P1"),
354 else => try writer.print("-m:{c}", .{@as(u8, switch (self.target.cpu.arch) {
355 .mips, .mipsel => 'm', // Mips mangling: Private symbols get a $ prefix.
356 else => switch (self.target.ofmt) {
357 .elf => 'e', // ELF mangling: Private symbols get a `.L` prefix.
358 //.goff => 'l', // GOFF mangling: Private symbols get a `@` prefix.
359 .macho => 'o', // Mach-O mangling: Private symbols get `L` prefix.
360 // Other symbols get a `_` prefix.
361 .coff => switch (self.target.os.tag) {
362 .windows => switch (self.target.cpu.arch) {
363 .x86 => 'x', // Windows x86 COFF mangling: Private symbols get the usual
364 // prefix. Regular C symbols get a `_` prefix. Functions with `__stdcall`,
365 //`__fastcall`, and `__vectorcall` have custom mangling that appends `@N`
366 // where N is the number of bytes used to pass parameters. C++ symbols
367 // starting with `?` are not mangled in any way.
368 else => 'w', // Windows COFF mangling: Similar to x, except that normal C
369 // symbols do not receive a `_` prefix.
370 },
371 else => 'e',
372 },
373 //.xcoff => 'a', // XCOFF mangling: Private symbols get a `L..` prefix.
374 else => 'e',
375 },
376 })}),
377 }
378 var any_non_integral = false;
379 const ptr_bit_width = self.target.ptrBitWidth();
380 var default_info = struct { size: u16, abi: u16, pref: u16, idx: u16 }{
381 .size = 64,
382 .abi = 64,
383 .pref = 64,
384 .idx = 64,
385 };
386 const addr_space_info = llvmAddrSpaceInfo(self.target);
387 for (addr_space_info, 0..) |info, i| {
388 assert((info.llvm == .default) == (i == 0));
389 if (info.non_integral) {
390 assert(info.llvm != .default);
391 any_non_integral = true;
392 }
393 const size = info.size orelse ptr_bit_width;
394 const abi = info.abi orelse ptr_bit_width;
395 const pref = info.pref orelse abi;
396 const idx = info.idx orelse size;
397 const matches_default =
398 size == default_info.size and
399 abi == default_info.abi and
400 pref == default_info.pref and
401 idx == default_info.idx;
402 if (info.llvm == .default) default_info = .{
403 .size = size,
404 .abi = abi,
405 .pref = pref,
406 .idx = idx,
407 };
408 if (self.target.cpu.arch == .aarch64_32) continue;
409 if (!info.force_in_data_layout and matches_default and
410 self.target.cpu.arch != .riscv64 and !is_aarch64_windows and
411 self.target.cpu.arch != .bpfeb and self.target.cpu.arch != .bpfel) continue;
412 try writer.writeAll("-p");
413 if (info.llvm != .default) try writer.print("{d}", .{@intFromEnum(info.llvm)});
414 try writer.print(":{d}:{d}", .{ size, abi });
415 if (pref != abi or idx != size or self.target.cpu.arch == .hexagon) {
416 try writer.print(":{d}", .{pref});
417 if (idx != size) try writer.print(":{d}", .{idx});
418 }
419 }
420 if (self.target.cpu.arch.isARM() or self.target.cpu.arch.isThumb())
421 try writer.writeAll("-Fi8"); // for thumb interwork
422 if (self.target.cpu.arch != .hexagon) {
423 if (self.target.cpu.arch == .s390x) try self.typeAlignment(.integer, 1, 8, 8, false, writer);
424 try self.typeAlignment(.integer, 8, 8, 8, false, writer);
425 try self.typeAlignment(.integer, 16, 16, 16, false, writer);
426 try self.typeAlignment(.integer, 32, if (is_aarch64_windows) 0 else 32, 32, false, writer);
427 try self.typeAlignment(.integer, 64, 32, 64, false, writer);
428 try self.typeAlignment(.integer, 128, 32, 64, false, writer);
429 if (backendSupportsF16(self.target)) try self.typeAlignment(.float, 16, 16, 16, false, writer);
430 try self.typeAlignment(.float, 32, 32, 32, false, writer);
431 try self.typeAlignment(.float, 64, 64, 64, false, writer);
432 if (backendSupportsF80(self.target)) try self.typeAlignment(.float, 80, 0, 0, false, writer);
433 try self.typeAlignment(.float, 128, 128, 128, false, writer);
434 }
435 switch (self.target.cpu.arch) {
436 .amdgcn => {
437 try self.typeAlignment(.vector, 16, 16, 16, false, writer);
438 try self.typeAlignment(.vector, 24, 32, 32, false, writer);
439 try self.typeAlignment(.vector, 32, 32, 32, false, writer);
440 try self.typeAlignment(.vector, 48, 64, 64, false, writer);
441 try self.typeAlignment(.vector, 96, 128, 128, false, writer);
442 try self.typeAlignment(.vector, 192, 256, 256, false, writer);
443 try self.typeAlignment(.vector, 256, 256, 256, false, writer);
444 try self.typeAlignment(.vector, 512, 512, 512, false, writer);
445 try self.typeAlignment(.vector, 1024, 1024, 1024, false, writer);
446 try self.typeAlignment(.vector, 2048, 2048, 2048, false, writer);
447 },
448 .ve => {},
449 else => {
450 try self.typeAlignment(.vector, 16, 32, 32, false, writer);
451 try self.typeAlignment(.vector, 32, 32, 32, false, writer);
452 try self.typeAlignment(.vector, 64, 64, 64, false, writer);
453 try self.typeAlignment(.vector, 128, 128, 128, true, writer);
454 },
455 }
456 if (self.target.os.tag != .windows and self.target.cpu.arch != .avr)
457 try self.typeAlignment(.aggregate, 0, 0, 64, false, writer);
458 for (@as([]const u24, switch (self.target.cpu.arch) {
459 .avr => &.{8},
460 .msp430 => &.{ 8, 16 },
461 .arm,
462 .armeb,
463 .mips,
464 .mipsel,
465 .powerpc,
466 .powerpcle,
467 .riscv32,
468 .sparc,
469 .sparcel,
470 .thumb,
471 .thumbeb,
472 => &.{32},
473 .aarch64,
474 .aarch64_be,
475 .aarch64_32,
476 .amdgcn,
477 .bpfeb,
478 .bpfel,
479 .mips64,
480 .mips64el,
481 .powerpc64,
482 .powerpc64le,
483 .riscv64,
484 .s390x,
485 .sparc64,
486 .ve,
487 .wasm32,
488 .wasm64,
489 => &.{ 32, 64 },
490 .hexagon => &.{ 16, 32 },
491 .x86 => &.{ 8, 16, 32 },
492 .nvptx,
493 .nvptx64,
494 => &.{ 16, 32, 64 },
495 .x86_64 => &.{ 8, 16, 32, 64 },
496 else => &.{},
497 }), 0..) |natural, index| switch (index) {
498 0 => try writer.print("-n{d}", .{natural}),
499 else => try writer.print(":{d}", .{natural}),
500 };
501 if (self.target.cpu.arch == .hexagon) {
502 try self.typeAlignment(.integer, 64, 64, 64, true, writer);
503 try self.typeAlignment(.integer, 32, 32, 32, true, writer);
504 try self.typeAlignment(.integer, 16, 16, 16, true, writer);
505 try self.typeAlignment(.integer, 1, 8, 8, true, writer);
506 try self.typeAlignment(.float, 32, 32, 32, true, writer);
507 try self.typeAlignment(.float, 64, 64, 64, true, writer);
508 }
509 if (self.target.os.tag == .windows or self.target.cpu.arch == .avr)
510 try self.typeAlignment(.aggregate, 0, 0, 64, false, writer);
511 const stack_abi = self.target.stackAlignment() * 8;
512 if (self.target.os.tag == .windows or self.target.cpu.arch == .msp430 or
513 stack_abi != ptr_bit_width)
514 try writer.print("-S{d}", .{stack_abi});
515 switch (self.target.cpu.arch) {
516 .hexagon, .ve => {
517 try self.typeAlignment(.vector, 32, 128, 128, true, writer);
518 try self.typeAlignment(.vector, 64, 128, 128, true, writer);
519 try self.typeAlignment(.vector, 128, 128, 128, true, writer);
520 },
521 else => {},
522 }
523 if (self.target.cpu.arch != .amdgcn) {
524 try self.typeAlignment(.vector, 256, 128, 128, true, writer);
525 try self.typeAlignment(.vector, 512, 128, 128, true, writer);
526 try self.typeAlignment(.vector, 1024, 128, 128, true, writer);
527 try self.typeAlignment(.vector, 2048, 128, 128, true, writer);
528 try self.typeAlignment(.vector, 4096, 128, 128, true, writer);
529 try self.typeAlignment(.vector, 8192, 128, 128, true, writer);
530 try self.typeAlignment(.vector, 16384, 128, 128, true, writer);
531 }
532 const alloca_addr_space = llvmAllocaAddressSpace(self.target);
533 if (alloca_addr_space != .default) try writer.print("-A{d}", .{@intFromEnum(alloca_addr_space)});
534 const global_addr_space = llvmDefaultGlobalAddressSpace(self.target);
535 if (global_addr_space != .default) try writer.print("-G{d}", .{@intFromEnum(global_addr_space)});
536 if (any_non_integral) {
537 try writer.writeAll("-ni");
538 for (addr_space_info) |info| if (info.non_integral)
539 try writer.print(":{d}", .{@intFromEnum(info.llvm)});
540 }
541 }
542
543 fn typeAlignment(
544 self: DataLayoutBuilder,
545 kind: enum { integer, vector, float, aggregate },
546 size: u24,
547 default_abi: u24,
548 default_pref: u24,
549 default_force_pref: bool,
550 writer: anytype,
551 ) @TypeOf(writer).Error!void {
552 var abi = default_abi;
553 var pref = default_pref;
554 var force_abi = false;
555 var force_pref = default_force_pref;
556 if (kind == .float and size == 80) {
557 abi = 128;
558 pref = 128;
559 }
560 for (@as([]const std.Target.CType, switch (kind) {
561 .integer => &.{ .char, .short, .int, .long, .longlong },
562 .float => &.{ .float, .double, .longdouble },
563 .vector, .aggregate => &.{},
564 })) |cty| {
565 if (self.target.c_type_bit_size(cty) != size) continue;
566 abi = self.target.c_type_alignment(cty) * 8;
567 pref = self.target.c_type_preferred_alignment(cty) * 8;
568 break;
569 }
570 switch (kind) {
571 .integer => {
572 if (self.target.ptrBitWidth() <= 16 and size >= 128) return;
573 abi = @min(abi, self.target.maxIntAlignment() * 8);
574 switch (self.target.os.tag) {
575 .linux => switch (self.target.cpu.arch) {
576 .aarch64,
577 .aarch64_be,
578 .aarch64_32,
579 .mips,
580 .mipsel,
581 => pref = @max(pref, 32),
582 else => {},
583 },
584 else => {},
585 }
586 switch (self.target.cpu.arch) {
587 .aarch64,
588 .aarch64_be,
589 .aarch64_32,
590 .bpfeb,
591 .bpfel,
592 .nvptx,
593 .nvptx64,
594 .riscv64,
595 => if (size == 128) {
596 abi = size;
597 pref = size;
598 },
599 .hexagon => force_abi = true,
600 .mips64,
601 .mips64el,
602 => if (size <= 32) {
603 pref = 32;
604 },
605 .s390x => if (size <= 16) {
606 pref = 16;
607 },
608 .ve => if (size == 64) {
609 abi = size;
610 pref = size;
611 },
612 else => {},
613 }
614 },
615 .vector => if (self.target.cpu.arch.isARM() or self.target.cpu.arch.isThumb()) {
616 switch (size) {
617 128 => abi = 64,
618 else => {},
619 }
620 } else if ((self.target.cpu.arch.isPPC64() and (size == 256 or size == 512)) or
621 (self.target.cpu.arch.isNvptx() and (size == 16 or size == 32)))
622 {
623 force_abi = true;
624 abi = size;
625 pref = size;
626 } else if (self.target.cpu.arch == .amdgcn and size <= 2048) {
627 force_abi = true;
628 } else if (self.target.cpu.arch == .hexagon and
629 ((size >= 32 and size <= 64) or (size >= 512 and size <= 2048)))
630 {
631 abi = size;
632 pref = size;
633 force_pref = true;
634 } else if (self.target.cpu.arch == .s390x and size == 128) {
635 abi = 64;
636 pref = 64;
637 force_pref = false;
638 } else if (self.target.cpu.arch == .ve and (size >= 64 and size <= 16384)) {
639 abi = 64;
640 pref = 64;
641 force_abi = true;
642 force_pref = true;
643 },
644 .float => switch (self.target.cpu.arch) {
645 .avr, .msp430, .sparc64 => if (size != 32 and size != 64) return,
646 .hexagon => if (size == 32 or size == 64) {
647 force_abi = true;
648 },
649 .aarch64_32 => if (size == 128) {
650 abi = size;
651 pref = size;
652 },
653 .ve => if (size == 64) {
654 abi = size;
655 pref = size;
656 },
657 else => {},
658 },
659 .aggregate => if (self.target.os.tag == .windows or
660 self.target.cpu.arch.isARM() or self.target.cpu.arch.isThumb())
661 {
662 pref = @min(pref, self.target.ptrBitWidth());
663 } else if (self.target.cpu.arch == .hexagon) {
664 abi = 0;
665 pref = 0;
666 } else if (self.target.cpu.arch == .s390x) {
667 abi = 8;
668 pref = 16;
669 } else if (self.target.cpu.arch == .msp430) {
670 abi = 8;
671 pref = 8;
672 },
673 }
674 if (kind != .vector and self.target.cpu.arch == .avr) {
675 force_abi = true;
676 abi = 8;
677 pref = 8;
678 }
679 if (!force_abi and abi == default_abi and pref == default_pref) return;
680 try writer.print("-{c}", .{@tagName(kind)[0]});
681 if (size != 0) try writer.print("{d}", .{size});
682 try writer.print(":{d}", .{abi});
683 if (pref != abi or force_pref) try writer.print(":{d}", .{pref});
335684 }
336 return llvm_global.deleteGlobal();
337}
685};
338686
339687pub const Object = struct {
340688 gpa: Allocator,
689 builder: Builder,
690
341691 module: *Module,
342692 llvm_module: *llvm.Module,
343693 di_builder: ?*llvm.DIBuilder,
......@@ -347,7 +697,6 @@ pub const Object = struct {
347697 /// - *Module.Decl (Non-Fn) => *DIGlobalVariable
348698 di_map: std.AutoHashMapUnmanaged(*const anyopaque, *llvm.DINode),
349699 di_compile_unit: ?*llvm.DICompileUnit,
350 context: *llvm.Context,
351700 target_machine: *llvm.TargetMachine,
352701 target_data: *llvm.TargetData,
353702 target: std.Target,
......@@ -359,9 +708,9 @@ pub const Object = struct {
359708 /// version of the name and incorrectly get function not found in the llvm module.
360709 /// * it works for functions not all globals.
361710 /// Therefore, this table keeps track of the mapping.
362 decl_map: std.AutoHashMapUnmanaged(Module.Decl.Index, *llvm.Value),
711 decl_map: std.AutoHashMapUnmanaged(Module.Decl.Index, Builder.Global.Index),
363712 /// Serves the same purpose as `decl_map` but only used for the `is_named_enum_value` instruction.
364 named_enum_map: std.AutoHashMapUnmanaged(Module.Decl.Index, *llvm.Value),
713 named_enum_map: std.AutoHashMapUnmanaged(Module.Decl.Index, Builder.Function.Index),
365714 /// Maps Zig types to LLVM types. The table memory is backed by the GPA of
366715 /// the compiler.
367716 /// TODO when InternPool garbage collection is implemented, this map needs
......@@ -371,16 +720,16 @@ pub const Object = struct {
371720 /// The LLVM global table which holds the names corresponding to Zig errors.
372721 /// Note that the values are not added until flushModule, when all errors in
373722 /// the compilation are known.
374 error_name_table: ?*llvm.Value,
723 error_name_table: Builder.Variable.Index,
375724 /// This map is usually very close to empty. It tracks only the cases when a
376725 /// second extern Decl could not be emitted with the correct name due to a
377726 /// name collision.
378727 extern_collisions: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void),
379728
380729 /// Memoizes a null `?usize` value.
381 null_opt_addr: ?*llvm.Value,
730 null_opt_usize: Builder.Constant,
382731
383 pub const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, *llvm.Type);
732 pub const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, Builder.Type);
384733
385734 /// This is an ArrayHashMap as opposed to a HashMap because in `flushModule` we
386735 /// want to iterate over it while adding entries to it.
......@@ -394,138 +743,137 @@ pub const Object = struct {
394743 }
395744
396745 pub fn init(gpa: Allocator, options: link.Options) !Object {
397 const context = llvm.Context.create();
398 errdefer context.dispose();
399
400 initializeLLVMTarget(options.target.cpu.arch);
401
402 const llvm_module = llvm.Module.createWithName(options.root_name.ptr, context);
403 errdefer llvm_module.dispose();
404
405746 const llvm_target_triple = try targetTriple(gpa, options.target);
406747 defer gpa.free(llvm_target_triple);
407748
408 var error_message: [*:0]const u8 = undefined;
409 var target: *llvm.Target = undefined;
410 if (llvm.Target.getFromTriple(llvm_target_triple.ptr, &target, &error_message).toBool()) {
411 defer llvm.disposeMessage(error_message);
412
413 log.err("LLVM failed to parse '{s}': {s}", .{ llvm_target_triple, error_message });
414 return error.InvalidLlvmTriple;
415 }
749 var builder = try Builder.init(.{
750 .allocator = gpa,
751 .use_lib_llvm = options.use_lib_llvm,
752 .strip = options.strip,
753 .name = options.root_name,
754 .target = options.target,
755 .triple = llvm_target_triple,
756 });
757 errdefer builder.deinit();
758
759 var target_machine: *llvm.TargetMachine = undefined;
760 var target_data: *llvm.TargetData = undefined;
761 if (builder.useLibLlvm()) {
762 if (!options.strip) {
763 switch (options.target.ofmt) {
764 .coff => builder.llvm.module.?.addModuleCodeViewFlag(),
765 else => builder.llvm.module.?.addModuleDebugInfoFlag(options.dwarf_format == std.dwarf.Format.@"64"),
766 }
767 builder.llvm.di_builder = builder.llvm.module.?.createDIBuilder(true);
768
769 // Don't use the version string here; LLVM misparses it when it
770 // includes the git revision.
771 const producer = try builder.fmt("zig {d}.{d}.{d}", .{
772 build_options.semver.major,
773 build_options.semver.minor,
774 build_options.semver.patch,
775 });
416776
417 llvm_module.setTarget(llvm_target_triple.ptr);
418 var opt_di_builder: ?*llvm.DIBuilder = null;
419 errdefer if (opt_di_builder) |di_builder| di_builder.dispose();
777 // We fully resolve all paths at this point to avoid lack of source line info in stack
778 // traces or lack of debugging information which, if relative paths were used, would
779 // be very location dependent.
780 // TODO: the only concern I have with this is WASI as either host or target, should
781 // we leave the paths as relative then?
782 var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
783 const compile_unit_dir = blk: {
784 const path = d: {
785 const mod = options.module orelse break :d ".";
786 break :d mod.root_pkg.root_src_directory.path orelse ".";
787 };
788 if (std.fs.path.isAbsolute(path)) break :blk path;
789 break :blk std.os.realpath(path, &buf) catch path; // If realpath fails, fallback to whatever path was
790 };
791 const compile_unit_dir_z = try builder.gpa.dupeZ(u8, compile_unit_dir);
792 defer builder.gpa.free(compile_unit_dir_z);
793
794 builder.llvm.di_compile_unit = builder.llvm.di_builder.?.createCompileUnit(
795 DW.LANG.C99,
796 builder.llvm.di_builder.?.createFile(options.root_name, compile_unit_dir_z),
797 producer.toSlice(&builder).?,
798 options.optimize_mode != .Debug,
799 "", // flags
800 0, // runtime version
801 "", // split name
802 0, // dwo id
803 true, // emit debug info
804 );
805 }
420806
421 var di_compile_unit: ?*llvm.DICompileUnit = null;
807 const opt_level: llvm.CodeGenOptLevel = if (options.optimize_mode == .Debug)
808 .None
809 else
810 .Aggressive;
422811
423 if (!options.strip) {
424 switch (options.target.ofmt) {
425 .coff => llvm_module.addModuleCodeViewFlag(),
426 else => llvm_module.addModuleDebugInfoFlag(options.dwarf_format == std.dwarf.Format.@"64"),
427 }
428 const di_builder = llvm_module.createDIBuilder(true);
429 opt_di_builder = di_builder;
430
431 // Don't use the version string here; LLVM misparses it when it
432 // includes the git revision.
433 const producer = try std.fmt.allocPrintZ(gpa, "zig {d}.{d}.{d}", .{
434 build_options.semver.major,
435 build_options.semver.minor,
436 build_options.semver.patch,
437 });
438 defer gpa.free(producer);
439
440 // We fully resolve all paths at this point to avoid lack of source line info in stack
441 // traces or lack of debugging information which, if relative paths were used, would
442 // be very location dependent.
443 // TODO: the only concern I have with this is WASI as either host or target, should
444 // we leave the paths as relative then?
445 var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
446 const compile_unit_dir = blk: {
447 const path = d: {
448 const mod = options.module orelse break :d ".";
449 break :d mod.root_pkg.root_src_directory.path orelse ".";
450 };
451 if (std.fs.path.isAbsolute(path)) break :blk path;
452 break :blk std.os.realpath(path, &buf) catch path; // If realpath fails, fallback to whatever path was
812 const reloc_mode: llvm.RelocMode = if (options.pic)
813 .PIC
814 else if (options.link_mode == .Dynamic)
815 llvm.RelocMode.DynamicNoPIC
816 else
817 .Static;
818
819 const code_model: llvm.CodeModel = switch (options.machine_code_model) {
820 .default => .Default,
821 .tiny => .Tiny,
822 .small => .Small,
823 .kernel => .Kernel,
824 .medium => .Medium,
825 .large => .Large,
453826 };
454 const compile_unit_dir_z = try gpa.dupeZ(u8, compile_unit_dir);
455 defer gpa.free(compile_unit_dir_z);
456
457 di_compile_unit = di_builder.createCompileUnit(
458 DW.LANG.C99,
459 di_builder.createFile(options.root_name, compile_unit_dir_z),
460 producer,
461 options.optimize_mode != .Debug,
462 "", // flags
463 0, // runtime version
464 "", // split name
465 0, // dwo id
466 true, // emit debug info
467 );
468 }
469
470 const opt_level: llvm.CodeGenOptLevel = if (options.optimize_mode == .Debug)
471 .None
472 else
473 .Aggressive;
474827
475 const reloc_mode: llvm.RelocMode = if (options.pic)
476 .PIC
477 else if (options.link_mode == .Dynamic)
478 llvm.RelocMode.DynamicNoPIC
479 else
480 .Static;
481
482 const code_model: llvm.CodeModel = switch (options.machine_code_model) {
483 .default => .Default,
484 .tiny => .Tiny,
485 .small => .Small,
486 .kernel => .Kernel,
487 .medium => .Medium,
488 .large => .Large,
489 };
828 // TODO handle float ABI better- it should depend on the ABI portion of std.Target
829 const float_abi: llvm.ABIType = .Default;
830
831 target_machine = llvm.TargetMachine.create(
832 builder.llvm.target.?,
833 builder.target_triple.toSlice(&builder).?,
834 if (options.target.cpu.model.llvm_name) |s| s.ptr else null,
835 options.llvm_cpu_features,
836 opt_level,
837 reloc_mode,
838 code_model,
839 options.function_sections,
840 float_abi,
841 if (target_util.llvmMachineAbi(options.target)) |s| s.ptr else null,
842 );
843 errdefer target_machine.dispose();
490844
491 // TODO handle float ABI better- it should depend on the ABI portion of std.Target
492 const float_abi: llvm.ABIType = .Default;
493
494 const target_machine = llvm.TargetMachine.create(
495 target,
496 llvm_target_triple.ptr,
497 if (options.target.cpu.model.llvm_name) |s| s.ptr else null,
498 options.llvm_cpu_features,
499 opt_level,
500 reloc_mode,
501 code_model,
502 options.function_sections,
503 float_abi,
504 if (target_util.llvmMachineAbi(options.target)) |s| s.ptr else null,
505 );
506 errdefer target_machine.dispose();
845 target_data = target_machine.createTargetDataLayout();
846 errdefer target_data.dispose();
507847
508 const target_data = target_machine.createTargetDataLayout();
509 errdefer target_data.dispose();
848 builder.llvm.module.?.setModuleDataLayout(target_data);
510849
511 llvm_module.setModuleDataLayout(target_data);
850 if (options.pic) builder.llvm.module.?.setModulePICLevel();
851 if (options.pie) builder.llvm.module.?.setModulePIELevel();
852 if (code_model != .Default) builder.llvm.module.?.setModuleCodeModel(code_model);
512853
513 if (options.pic) llvm_module.setModulePICLevel();
514 if (options.pie) llvm_module.setModulePIELevel();
515 if (code_model != .Default) llvm_module.setModuleCodeModel(code_model);
854 if (options.opt_bisect_limit >= 0) {
855 builder.llvm.context.setOptBisectLimit(std.math.lossyCast(c_int, options.opt_bisect_limit));
856 }
516857
517 if (options.opt_bisect_limit >= 0) {
518 context.setOptBisectLimit(std.math.lossyCast(c_int, options.opt_bisect_limit));
858 builder.data_layout = try builder.fmt("{}", .{DataLayoutBuilder{ .target = options.target }});
859 if (std.debug.runtime_safety) {
860 const rep = target_data.stringRep();
861 defer llvm.disposeMessage(rep);
862 std.testing.expectEqualStrings(
863 std.mem.span(rep),
864 builder.data_layout.toSlice(&builder).?,
865 ) catch unreachable;
866 }
519867 }
520868
521 return Object{
869 return .{
522870 .gpa = gpa,
871 .builder = builder,
523872 .module = options.module.?,
524 .llvm_module = llvm_module,
873 .llvm_module = builder.llvm.module.?,
525874 .di_map = .{},
526 .di_builder = opt_di_builder,
527 .di_compile_unit = di_compile_unit,
528 .context = context,
875 .di_builder = builder.llvm.di_builder,
876 .di_compile_unit = builder.llvm.di_compile_unit,
529877 .target_machine = target_machine,
530878 .target_data = target_data,
531879 .target = options.target,
......@@ -533,22 +881,17 @@ pub const Object = struct {
533881 .named_enum_map = .{},
534882 .type_map = .{},
535883 .di_type_map = .{},
536 .error_name_table = null,
884 .error_name_table = .none,
537885 .extern_collisions = .{},
538 .null_opt_addr = null,
886 .null_opt_usize = .no_init,
539887 };
540888 }
541889
542890 pub fn deinit(self: *Object, gpa: Allocator) void {
543 if (self.di_builder) |dib| {
544 dib.dispose();
545 self.di_map.deinit(gpa);
546 self.di_type_map.deinit(gpa);
547 }
891 self.di_map.deinit(gpa);
892 self.di_type_map.deinit(gpa);
548893 self.target_data.dispose();
549894 self.target_machine.dispose();
550 self.llvm_module.dispose();
551 self.context.dispose();
552895 self.decl_map.deinit(gpa);
553896 self.named_enum_map.deinit(gpa);
554897 self.type_map.deinit(gpa);
......@@ -572,85 +915,108 @@ pub const Object = struct {
572915 return slice.ptr;
573916 }
574917
575 fn genErrorNameTable(o: *Object) !void {
918 fn genErrorNameTable(o: *Object) Allocator.Error!void {
576919 // If o.error_name_table is null, there was no instruction that actually referenced the error table.
577 const error_name_table_ptr_global = o.error_name_table orelse return;
920 const error_name_table_ptr_global = o.error_name_table;
921 if (error_name_table_ptr_global == .none) return;
578922
579923 const mod = o.module;
580 const target = mod.getTarget();
581
582 const llvm_ptr_ty = o.context.pointerType(0); // TODO: Address space
583 const llvm_usize_ty = o.context.intType(target.ptrBitWidth());
584 const type_fields = [_]*llvm.Type{
585 llvm_ptr_ty,
586 llvm_usize_ty,
587 };
588 const llvm_slice_ty = o.context.structType(&type_fields, type_fields.len, .False);
589 const slice_ty = Type.slice_const_u8_sentinel_0;
590 const slice_alignment = slice_ty.abiAlignment(mod);
591924
592925 const error_name_list = mod.global_error_set.keys();
593 const llvm_errors = try mod.gpa.alloc(*llvm.Value, error_name_list.len);
926 const llvm_errors = try mod.gpa.alloc(Builder.Constant, error_name_list.len);
594927 defer mod.gpa.free(llvm_errors);
595928
596 llvm_errors[0] = llvm_slice_ty.getUndef();
929 // TODO: Address space
930 const slice_ty = Type.slice_const_u8_sentinel_0;
931 const slice_alignment = slice_ty.abiAlignment(mod);
932 const llvm_usize_ty = try o.lowerType(Type.usize);
933 const llvm_slice_ty = try o.lowerType(slice_ty);
934 const llvm_table_ty = try o.builder.arrayType(error_name_list.len, llvm_slice_ty);
935
936 llvm_errors[0] = try o.builder.undefConst(llvm_slice_ty);
597937 for (llvm_errors[1..], error_name_list[1..]) |*llvm_error, name_nts| {
598 const name = mod.intern_pool.stringToSlice(name_nts);
599 const str_init = o.context.constString(name.ptr, @as(c_uint, @intCast(name.len)), .False);
600 const str_global = o.llvm_module.addGlobal(str_init.typeOf(), "");
601 str_global.setInitializer(str_init);
602 str_global.setLinkage(.Private);
603 str_global.setGlobalConstant(.True);
604 str_global.setUnnamedAddr(.True);
605 str_global.setAlignment(1);
606
607 const slice_fields = [_]*llvm.Value{
608 str_global,
609 llvm_usize_ty.constInt(name.len, .False),
938 const name = try o.builder.string(mod.intern_pool.stringToSlice(name_nts));
939 const str_init = try o.builder.stringNullConst(name);
940 const str_ty = str_init.typeOf(&o.builder);
941 const str_llvm_global = o.llvm_module.addGlobal(str_ty.toLlvm(&o.builder), "");
942 str_llvm_global.setInitializer(str_init.toLlvm(&o.builder));
943 str_llvm_global.setLinkage(.Private);
944 str_llvm_global.setGlobalConstant(.True);
945 str_llvm_global.setUnnamedAddr(.True);
946 str_llvm_global.setAlignment(1);
947
948 var str_global = Builder.Global{
949 .linkage = .private,
950 .unnamed_addr = .unnamed_addr,
951 .type = str_ty,
952 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
610953 };
611 llvm_error.* = llvm_slice_ty.constNamedStruct(&slice_fields, slice_fields.len);
612 }
954 var str_variable = Builder.Variable{
955 .global = @enumFromInt(o.builder.globals.count()),
956 .mutability = .constant,
957 .init = str_init,
958 .alignment = comptime Builder.Alignment.fromByteUnits(1),
959 };
960 try o.builder.llvm.globals.append(o.gpa, str_llvm_global);
961 const global_index = try o.builder.addGlobal(.empty, str_global);
962 try o.builder.variables.append(o.gpa, str_variable);
613963
614 const error_name_table_init = llvm_slice_ty.constArray(llvm_errors.ptr, @as(c_uint, @intCast(error_name_list.len)));
964 llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{
965 global_index.toConst(),
966 try o.builder.intConst(llvm_usize_ty, name.toSlice(&o.builder).?.len),
967 });
968 }
615969
616 const error_name_table_global = o.llvm_module.addGlobal(error_name_table_init.typeOf(), "");
617 error_name_table_global.setInitializer(error_name_table_init);
970 const error_name_table_init = try o.builder.arrayConst(llvm_table_ty, llvm_errors);
971 const error_name_table_global = o.llvm_module.addGlobal(llvm_table_ty.toLlvm(&o.builder), "");
972 error_name_table_global.setInitializer(error_name_table_init.toLlvm(&o.builder));
618973 error_name_table_global.setLinkage(.Private);
619974 error_name_table_global.setGlobalConstant(.True);
620975 error_name_table_global.setUnnamedAddr(.True);
621976 error_name_table_global.setAlignment(slice_alignment); // TODO: Dont hardcode
622977
978 var global = Builder.Global{
979 .linkage = .private,
980 .unnamed_addr = .unnamed_addr,
981 .type = llvm_table_ty,
982 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
983 };
984 var variable = Builder.Variable{
985 .global = @enumFromInt(o.builder.globals.count()),
986 .mutability = .constant,
987 .init = error_name_table_init,
988 .alignment = Builder.Alignment.fromByteUnits(slice_alignment),
989 };
990 try o.builder.llvm.globals.append(o.gpa, error_name_table_global);
991 _ = try o.builder.addGlobal(.empty, global);
992 try o.builder.variables.append(o.gpa, variable);
993
623994 const error_name_table_ptr = error_name_table_global;
624 error_name_table_ptr_global.setInitializer(error_name_table_ptr);
995 error_name_table_ptr_global.ptr(&o.builder).init = variable.global.toConst();
996 error_name_table_ptr_global.toLlvm(&o.builder).setInitializer(error_name_table_ptr);
625997 }
626998
627 fn genCmpLtErrorsLenFunction(object: *Object) !void {
999 fn genCmpLtErrorsLenFunction(o: *Object) !void {
6281000 // If there is no such function in the module, it means the source code does not need it.
629 const llvm_fn = object.llvm_module.getNamedFunction(lt_errors_fn_name) orelse return;
630 const mod = object.module;
1001 const name = o.builder.stringIfExists(lt_errors_fn_name) orelse return;
1002 const llvm_fn = o.builder.getGlobal(name) orelse return;
1003 const mod = o.module;
6311004 const errors_len = mod.global_error_set.count();
6321005
633 // Delete previous implementation. We replace it with every flush() because the
634 // total number of errors may have changed.
635 while (llvm_fn.getFirstBasicBlock()) |bb| {
636 bb.deleteBasicBlock();
637 }
638
639 const builder = object.context.createBuilder();
640
641 const entry_block = object.context.appendBasicBlock(llvm_fn, "Entry");
642 builder.positionBuilderAtEnd(entry_block);
643 builder.clearCurrentDebugLocation();
1006 var wip = try Builder.WipFunction.init(&o.builder, llvm_fn.ptrConst(&o.builder).kind.function);
1007 defer wip.deinit();
1008 wip.cursor = .{ .block = try wip.block(0, "Entry") };
6441009
6451010 // Example source of the following LLVM IR:
6461011 // fn __zig_lt_errors_len(index: u16) bool {
6471012 // return index < total_errors_len;
6481013 // }
6491014
650 const lhs = llvm_fn.getParam(0);
651 const rhs = lhs.typeOf().constInt(errors_len, .False);
652 const is_lt = builder.buildICmp(.ULT, lhs, rhs, "");
653 _ = builder.buildRet(is_lt);
1015 const lhs = wip.arg(0);
1016 const rhs = try o.builder.intValue(Builder.Type.err_int, errors_len);
1017 const is_lt = try wip.icmp(.ult, lhs, rhs, "");
1018 _ = try wip.ret(is_lt);
1019 try wip.finish();
6541020 }
6551021
6561022 fn genModuleLevelAssembly(object: *Object) !void {
......@@ -671,34 +1037,28 @@ pub const Object = struct {
6711037
6721038 // This map has externs with incorrect symbol names.
6731039 for (object.extern_collisions.keys()) |decl_index| {
674 const entry = object.decl_map.getEntry(decl_index) orelse continue;
675 const llvm_global = entry.value_ptr.*;
1040 const global = object.decl_map.get(decl_index) orelse continue;
6761041 // Same logic as below but for externs instead of exports.
677 const decl = mod.declPtr(decl_index);
678 const other_global = object.getLlvmGlobal(mod.intern_pool.stringToSlice(decl.name)) orelse continue;
679 if (other_global == llvm_global) continue;
1042 const decl_name = object.builder.stringIfExists(mod.intern_pool.stringToSlice(mod.declPtr(decl_index).name)) orelse continue;
1043 const other_global = object.builder.getGlobal(decl_name) orelse continue;
1044 if (other_global.eql(global, &object.builder)) continue;
6801045
681 llvm_global.replaceAllUsesWith(other_global);
682 deleteLlvmGlobal(llvm_global);
683 entry.value_ptr.* = other_global;
1046 try global.replace(other_global, &object.builder);
6841047 }
6851048 object.extern_collisions.clearRetainingCapacity();
6861049
687 const export_keys = mod.decl_exports.keys();
688 for (mod.decl_exports.values(), 0..) |export_list, i| {
689 const decl_index = export_keys[i];
690 const llvm_global = object.decl_map.get(decl_index) orelse continue;
1050 for (mod.decl_exports.keys(), mod.decl_exports.values()) |decl_index, export_list| {
1051 const global = object.decl_map.get(decl_index) orelse continue;
6911052 for (export_list.items) |exp| {
6921053 // Detect if the LLVM global has already been created as an extern. In such
6931054 // case, we need to replace all uses of it with this exported global.
694 const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
1055 const exp_name = object.builder.stringIfExists(mod.intern_pool.stringToSlice(exp.opts.name)) orelse continue;
6951056
696 const other_global = object.getLlvmGlobal(exp_name.ptr) orelse continue;
697 if (other_global == llvm_global) continue;
1057 const other_global = object.builder.getGlobal(exp_name) orelse continue;
1058 if (other_global.eql(global, &object.builder)) continue;
6981059
699 other_global.replaceAllUsesWith(llvm_global);
700 llvm_global.takeName(other_global);
701 deleteLlvmGlobal(other_global);
1060 try global.takeName(other_global, &object.builder);
1061 try other_global.replace(global, &object.builder);
7021062 // Problem: now we need to replace in the decl_map that
7031063 // the extern decl index points to this new global. However we don't
7041064 // know the decl index.
......@@ -744,20 +1104,9 @@ pub const Object = struct {
7441104
7451105 if (comp.verbose_llvm_ir) |path| {
7461106 if (std.mem.eql(u8, path, "-")) {
747 self.llvm_module.dump();
1107 self.builder.dump();
7481108 } else {
749 const path_z = try comp.gpa.dupeZ(u8, path);
750 defer comp.gpa.free(path_z);
751
752 var error_message: [*:0]const u8 = undefined;
753
754 if (self.llvm_module.printModuleToFile(path_z, &error_message).toBool()) {
755 defer llvm.disposeMessage(error_message);
756
757 log.err("dump LLVM module failed ir={s}: {s}", .{
758 path, error_message,
759 });
760 }
1109 _ = try self.builder.printToFile(path);
7611110 }
7621111 }
7631112
......@@ -884,7 +1233,9 @@ pub const Object = struct {
8841233 .err_msg = null,
8851234 };
8861235
887 const llvm_func = try o.resolveLlvmFunction(decl_index);
1236 const function = try o.resolveLlvmFunction(decl_index);
1237 const global = function.ptrConst(&o.builder).global;
1238 const llvm_func = global.toLlvm(&o.builder);
8881239
8891240 if (func.analysis(ip).is_noinline) {
8901241 o.addFnAttr(llvm_func, "noinline");
......@@ -921,24 +1272,27 @@ pub const Object = struct {
9211272 o.addFnAttrString(llvm_func, "no-stack-arg-probe", "");
9221273 }
9231274
924 if (ip.stringToSliceUnwrap(decl.@"linksection")) |section|
1275 if (ip.stringToSliceUnwrap(decl.@"linksection")) |section| {
1276 function.ptr(&o.builder).section = try o.builder.string(section);
9251277 llvm_func.setSection(section);
926
927 // Remove all the basic blocks of a function in order to start over, generating
928 // LLVM IR from an empty function body.
929 while (llvm_func.getFirstBasicBlock()) |bb| {
930 bb.deleteBasicBlock();
9311278 }
9321279
933 const builder = o.context.createBuilder();
1280 var deinit_wip = true;
1281 var wip = try Builder.WipFunction.init(&o.builder, function);
1282 defer if (deinit_wip) wip.deinit();
1283 wip.cursor = .{ .block = try wip.block(0, "Entry") };
9341284
935 const entry_block = o.context.appendBasicBlock(llvm_func, "Entry");
936 builder.positionBuilderAtEnd(entry_block);
1285 const builder = wip.llvm.builder;
1286 var llvm_arg_i: u32 = 0;
9371287
9381288 // This gets the LLVM values from the function and stores them in `dg.args`.
9391289 const fn_info = mod.typeToFunc(decl.ty).?;
9401290 const sret = firstParamSRet(fn_info, mod);
941 const ret_ptr = if (sret) llvm_func.getParam(0) else null;
1291 const ret_ptr: Builder.Value = if (sret) param: {
1292 const param = wip.arg(llvm_arg_i);
1293 llvm_arg_i += 1;
1294 break :param param;
1295 } else .none;
9421296 const gpa = o.gpa;
9431297
9441298 if (ccAbiPromoteInt(fn_info.cc, mod, fn_info.return_type.toType())) |s| switch (s) {
......@@ -949,207 +1303,183 @@ pub const Object = struct {
9491303 const err_return_tracing = fn_info.return_type.toType().isError(mod) and
9501304 mod.comp.bin_file.options.error_return_tracing;
9511305
952 const err_ret_trace = if (err_return_tracing)
953 llvm_func.getParam(@intFromBool(ret_ptr != null))
954 else
955 null;
1306 const err_ret_trace: Builder.Value = if (err_return_tracing) param: {
1307 const param = wip.arg(llvm_arg_i);
1308 llvm_arg_i += 1;
1309 break :param param;
1310 } else .none;
9561311
9571312 // This is the list of args we will use that correspond directly to the AIR arg
9581313 // instructions. Depending on the calling convention, this list is not necessarily
9591314 // a bijection with the actual LLVM parameters of the function.
960 var args = std.ArrayList(*llvm.Value).init(gpa);
961 defer args.deinit();
1315 var args: std.ArrayListUnmanaged(Builder.Value) = .{};
1316 defer args.deinit(gpa);
9621317
9631318 {
964 var llvm_arg_i = @as(c_uint, @intFromBool(ret_ptr != null)) + @intFromBool(err_return_tracing);
9651319 var it = iterateParamTypes(o, fn_info);
966 while (it.next()) |lowering| switch (lowering) {
967 .no_bits => continue,
968 .byval => {
969 assert(!it.byval_attr);
970 const param_index = it.zig_index - 1;
971 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
972 const param = llvm_func.getParam(llvm_arg_i);
973 try args.ensureUnusedCapacity(1);
974
975 if (isByRef(param_ty, mod)) {
976 const alignment = param_ty.abiAlignment(mod);
977 const param_llvm_ty = param.typeOf();
978 const arg_ptr = buildAllocaInner(o.context, builder, llvm_func, false, param_llvm_ty, alignment, target);
979 const store_inst = builder.buildStore(param, arg_ptr);
980 store_inst.setAlignment(alignment);
981 args.appendAssumeCapacity(arg_ptr);
982 } else {
983 args.appendAssumeCapacity(param);
984
985 o.addByValParamAttrs(llvm_func, param_ty, param_index, fn_info, llvm_arg_i);
986 }
987 llvm_arg_i += 1;
988 },
989 .byref => {
990 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
991 const param_llvm_ty = try o.lowerType(param_ty);
992 const param = llvm_func.getParam(llvm_arg_i);
993 const alignment = param_ty.abiAlignment(mod);
994
995 o.addByRefParamAttrs(llvm_func, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty);
996 llvm_arg_i += 1;
997
998 try args.ensureUnusedCapacity(1);
999
1000 if (isByRef(param_ty, mod)) {
1001 args.appendAssumeCapacity(param);
1002 } else {
1003 const load_inst = builder.buildLoad(param_llvm_ty, param, "");
1004 load_inst.setAlignment(alignment);
1005 args.appendAssumeCapacity(load_inst);
1006 }
1007 },
1008 .byref_mut => {
1009 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1010 const param_llvm_ty = try o.lowerType(param_ty);
1011 const param = llvm_func.getParam(llvm_arg_i);
1012 const alignment = param_ty.abiAlignment(mod);
1013
1014 o.addArgAttr(llvm_func, llvm_arg_i, "noundef");
1015 llvm_arg_i += 1;
1016
1017 try args.ensureUnusedCapacity(1);
1320 while (try it.next()) |lowering| {
1321 try args.ensureUnusedCapacity(gpa, 1);
1322
1323 switch (lowering) {
1324 .no_bits => continue,
1325 .byval => {
1326 assert(!it.byval_attr);
1327 const param_index = it.zig_index - 1;
1328 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
1329 const param = wip.arg(llvm_arg_i);
1330
1331 if (isByRef(param_ty, mod)) {
1332 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1333 const param_llvm_ty = param.typeOfWip(&wip);
1334 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
1335 _ = try wip.store(.normal, param, arg_ptr, alignment);
1336 args.appendAssumeCapacity(arg_ptr);
1337 } else {
1338 args.appendAssumeCapacity(param);
10181339
1019 if (isByRef(param_ty, mod)) {
1020 args.appendAssumeCapacity(param);
1021 } else {
1022 const load_inst = builder.buildLoad(param_llvm_ty, param, "");
1023 load_inst.setAlignment(alignment);
1024 args.appendAssumeCapacity(load_inst);
1025 }
1026 },
1027 .abi_sized_int => {
1028 assert(!it.byval_attr);
1029 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1030 const param = llvm_func.getParam(llvm_arg_i);
1031 llvm_arg_i += 1;
1340 o.addByValParamAttrs(llvm_func, param_ty, param_index, fn_info, @intCast(llvm_arg_i));
1341 }
1342 llvm_arg_i += 1;
1343 },
1344 .byref => {
1345 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1346 const param_llvm_ty = try o.lowerType(param_ty);
1347 const param = wip.arg(llvm_arg_i);
1348 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
10321349
1033 const param_llvm_ty = try o.lowerType(param_ty);
1034 const abi_size = @as(c_uint, @intCast(param_ty.abiSize(mod)));
1035 const int_llvm_ty = o.context.intType(abi_size * 8);
1036 const alignment = @max(
1037 param_ty.abiAlignment(mod),
1038 o.target_data.abiAlignmentOfType(int_llvm_ty),
1039 );
1040 const arg_ptr = buildAllocaInner(o.context, builder, llvm_func, false, param_llvm_ty, alignment, target);
1041 const store_inst = builder.buildStore(param, arg_ptr);
1042 store_inst.setAlignment(alignment);
1350 o.addByRefParamAttrs(llvm_func, @intCast(llvm_arg_i), @intCast(alignment.toByteUnits() orelse 0), it.byval_attr, param_llvm_ty);
1351 llvm_arg_i += 1;
10431352
1044 try args.ensureUnusedCapacity(1);
1353 if (isByRef(param_ty, mod)) {
1354 args.appendAssumeCapacity(param);
1355 } else {
1356 args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, ""));
1357 }
1358 },
1359 .byref_mut => {
1360 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1361 const param_llvm_ty = try o.lowerType(param_ty);
1362 const param = wip.arg(llvm_arg_i);
1363 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
10451364
1046 if (isByRef(param_ty, mod)) {
1047 args.appendAssumeCapacity(arg_ptr);
1048 } else {
1049 const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");
1050 load_inst.setAlignment(alignment);
1051 args.appendAssumeCapacity(load_inst);
1052 }
1053 },
1054 .slice => {
1055 assert(!it.byval_attr);
1056 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1057 const ptr_info = param_ty.ptrInfo(mod);
1365 o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "noundef");
1366 llvm_arg_i += 1;
10581367
1059 if (math.cast(u5, it.zig_index - 1)) |i| {
1060 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
1061 o.addArgAttr(llvm_func, llvm_arg_i, "noalias");
1368 if (isByRef(param_ty, mod)) {
1369 args.appendAssumeCapacity(param);
1370 } else {
1371 args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, ""));
10621372 }
1063 }
1064 if (param_ty.zigTypeTag(mod) != .Optional) {
1065 o.addArgAttr(llvm_func, llvm_arg_i, "nonnull");
1066 }
1067 if (ptr_info.flags.is_const) {
1068 o.addArgAttr(llvm_func, llvm_arg_i, "readonly");
1069 }
1070 const elem_align = ptr_info.flags.alignment.toByteUnitsOptional() orelse
1071 @max(ptr_info.child.toType().abiAlignment(mod), 1);
1072 o.addArgAttrInt(llvm_func, llvm_arg_i, "align", elem_align);
1073 const ptr_param = llvm_func.getParam(llvm_arg_i);
1074 llvm_arg_i += 1;
1075 const len_param = llvm_func.getParam(llvm_arg_i);
1076 llvm_arg_i += 1;
1077
1078 const slice_llvm_ty = try o.lowerType(param_ty);
1079 const partial = builder.buildInsertValue(slice_llvm_ty.getUndef(), ptr_param, 0, "");
1080 const aggregate = builder.buildInsertValue(partial, len_param, 1, "");
1081 try args.append(aggregate);
1082 },
1083 .multiple_llvm_types => {
1084 assert(!it.byval_attr);
1085 const field_types = it.llvm_types_buffer[0..it.llvm_types_len];
1086 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1087 const param_llvm_ty = try o.lowerType(param_ty);
1088 const param_alignment = param_ty.abiAlignment(mod);
1089 const arg_ptr = buildAllocaInner(o.context, builder, llvm_func, false, param_llvm_ty, param_alignment, target);
1090 const llvm_ty = o.context.structType(field_types.ptr, @as(c_uint, @intCast(field_types.len)), .False);
1091 for (field_types, 0..) |_, field_i_usize| {
1092 const field_i = @as(c_uint, @intCast(field_i_usize));
1093 const param = llvm_func.getParam(llvm_arg_i);
1373 },
1374 .abi_sized_int => {
1375 assert(!it.byval_attr);
1376 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1377 const param = wip.arg(llvm_arg_i);
10941378 llvm_arg_i += 1;
1095 const field_ptr = builder.buildStructGEP(llvm_ty, arg_ptr, field_i, "");
1096 const store_inst = builder.buildStore(param, field_ptr);
1097 store_inst.setAlignment(target.ptrBitWidth() / 8);
1098 }
10991379
1100 const is_by_ref = isByRef(param_ty, mod);
1101 const loaded = if (is_by_ref) arg_ptr else l: {
1102 const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");
1103 load_inst.setAlignment(param_alignment);
1104 break :l load_inst;
1105 };
1106 try args.append(loaded);
1107 },
1108 .as_u16 => {
1109 assert(!it.byval_attr);
1110 const param = llvm_func.getParam(llvm_arg_i);
1111 llvm_arg_i += 1;
1112 const casted = builder.buildBitCast(param, o.context.halfType(), "");
1113 try args.ensureUnusedCapacity(1);
1114 args.appendAssumeCapacity(casted);
1115 },
1116 .float_array => {
1117 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1118 const param_llvm_ty = try o.lowerType(param_ty);
1119 const param = llvm_func.getParam(llvm_arg_i);
1120 llvm_arg_i += 1;
1380 const param_llvm_ty = try o.lowerType(param_ty);
1381 const int_llvm_ty = try o.builder.intType(@intCast(param_ty.abiSize(mod) * 8));
1382 const alignment = Builder.Alignment.fromByteUnits(@max(
1383 param_ty.abiAlignment(mod),
1384 o.target_data.abiAlignmentOfType(int_llvm_ty.toLlvm(&o.builder)),
1385 ));
1386 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
1387 _ = try wip.store(.normal, param, arg_ptr, alignment);
1388
1389 args.appendAssumeCapacity(if (isByRef(param_ty, mod))
1390 arg_ptr
1391 else
1392 try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));
1393 },
1394 .slice => {
1395 assert(!it.byval_attr);
1396 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1397 const ptr_info = param_ty.ptrInfo(mod);
1398
1399 if (math.cast(u5, it.zig_index - 1)) |i| {
1400 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
1401 o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "noalias");
1402 }
1403 }
1404 if (param_ty.zigTypeTag(mod) != .Optional) {
1405 o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "nonnull");
1406 }
1407 if (ptr_info.flags.is_const) {
1408 o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "readonly");
1409 }
1410 const elem_align = ptr_info.flags.alignment.toByteUnitsOptional() orelse
1411 @max(ptr_info.child.toType().abiAlignment(mod), 1);
1412 o.addArgAttrInt(llvm_func, @intCast(llvm_arg_i), "align", elem_align);
1413 const ptr_param = wip.arg(llvm_arg_i + 0);
1414 const len_param = wip.arg(llvm_arg_i + 1);
1415 llvm_arg_i += 2;
1416
1417 const slice_llvm_ty = try o.lowerType(param_ty);
1418 args.appendAssumeCapacity(
1419 try wip.buildAggregate(slice_llvm_ty, &.{ ptr_param, len_param }, ""),
1420 );
1421 },
1422 .multiple_llvm_types => {
1423 assert(!it.byval_attr);
1424 const field_types = it.types_buffer[0..it.types_len];
1425 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1426 const param_llvm_ty = try o.lowerType(param_ty);
1427 const param_alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1428 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, param_alignment, target);
1429 const llvm_ty = try o.builder.structType(.normal, field_types);
1430 for (0..field_types.len) |field_i| {
1431 const param = wip.arg(llvm_arg_i);
1432 llvm_arg_i += 1;
1433 const field_ptr = try wip.gepStruct(llvm_ty, arg_ptr, field_i, "");
1434 const alignment =
1435 Builder.Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
1436 _ = try wip.store(.normal, param, field_ptr, alignment);
1437 }
11211438
1122 const alignment = param_ty.abiAlignment(mod);
1123 const arg_ptr = buildAllocaInner(o.context, builder, llvm_func, false, param_llvm_ty, alignment, target);
1124 _ = builder.buildStore(param, arg_ptr);
1439 const is_by_ref = isByRef(param_ty, mod);
1440 args.appendAssumeCapacity(if (is_by_ref)
1441 arg_ptr
1442 else
1443 try wip.load(.normal, param_llvm_ty, arg_ptr, param_alignment, ""));
1444 },
1445 .as_u16 => {
1446 assert(!it.byval_attr);
1447 const param = wip.arg(llvm_arg_i);
1448 llvm_arg_i += 1;
1449 args.appendAssumeCapacity(try wip.cast(.bitcast, param, .half, ""));
1450 },
1451 .float_array => {
1452 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1453 const param_llvm_ty = try o.lowerType(param_ty);
1454 const param = wip.arg(llvm_arg_i);
1455 llvm_arg_i += 1;
11251456
1126 if (isByRef(param_ty, mod)) {
1127 try args.append(arg_ptr);
1128 } else {
1129 const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");
1130 load_inst.setAlignment(alignment);
1131 try args.append(load_inst);
1132 }
1133 },
1134 .i32_array, .i64_array => {
1135 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1136 const param_llvm_ty = try o.lowerType(param_ty);
1137 const param = llvm_func.getParam(llvm_arg_i);
1138 llvm_arg_i += 1;
1457 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1458 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
1459 _ = try wip.store(.normal, param, arg_ptr, alignment);
11391460
1140 const alignment = param_ty.abiAlignment(mod);
1141 const arg_ptr = buildAllocaInner(o.context, builder, llvm_func, false, param_llvm_ty, alignment, target);
1142 _ = builder.buildStore(param, arg_ptr);
1461 args.appendAssumeCapacity(if (isByRef(param_ty, mod))
1462 arg_ptr
1463 else
1464 try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));
1465 },
1466 .i32_array, .i64_array => {
1467 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1468 const param_llvm_ty = try o.lowerType(param_ty);
1469 const param = wip.arg(llvm_arg_i);
1470 llvm_arg_i += 1;
11431471
1144 if (isByRef(param_ty, mod)) {
1145 try args.append(arg_ptr);
1146 } else {
1147 const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");
1148 load_inst.setAlignment(alignment);
1149 try args.append(load_inst);
1150 }
1151 },
1152 };
1472 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1473 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
1474 _ = try wip.store(.normal, param, arg_ptr, alignment);
1475
1476 args.appendAssumeCapacity(if (isByRef(param_ty, mod))
1477 arg_ptr
1478 else
1479 try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));
1480 },
1481 }
1482 }
11531483 }
11541484
11551485 var di_file: ?*llvm.DIFile = null;
......@@ -1191,16 +1521,15 @@ pub const Object = struct {
11911521 .gpa = gpa,
11921522 .air = air,
11931523 .liveness = liveness,
1194 .context = o.context,
11951524 .dg = &dg,
1525 .wip = wip,
11961526 .builder = builder,
11971527 .ret_ptr = ret_ptr,
11981528 .args = args.items,
11991529 .arg_index = 0,
12001530 .func_inst_table = .{},
1201 .llvm_func = llvm_func,
12021531 .blocks = .{},
1203 .single_threaded = mod.comp.bin_file.options.single_threaded,
1532 .sync_scope = if (mod.comp.bin_file.options.single_threaded) .singlethread else .system,
12041533 .di_scope = di_scope,
12051534 .di_file = di_file,
12061535 .base_line = dg.decl.src_line,
......@@ -1209,6 +1538,7 @@ pub const Object = struct {
12091538 .err_ret_trace = err_ret_trace,
12101539 };
12111540 defer fg.deinit();
1541 deinit_wip = false;
12121542
12131543 fg.genBody(air.getMainBody()) catch |err| switch (err) {
12141544 error.CodegenFail => {
......@@ -1220,6 +1550,8 @@ pub const Object = struct {
12201550 else => |e| return e,
12211551 };
12221552
1553 try fg.wip.finish();
1554
12231555 try o.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index));
12241556 }
12251557
......@@ -1243,14 +1575,6 @@ pub const Object = struct {
12431575 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
12441576 }
12451577
1246 /// TODO replace this with a call to `Module::getNamedValue`. This will require adding
1247 /// a new wrapper in zig_llvm.h/zig_llvm.cpp.
1248 fn getLlvmGlobal(o: Object, name: [*:0]const u8) ?*llvm.Value {
1249 if (o.llvm_module.getNamedFunction(name)) |x| return x;
1250 if (o.llvm_module.getNamedGlobal(name)) |x| return x;
1251 return null;
1252 }
1253
12541578 pub fn updateDeclExports(
12551579 self: *Object,
12561580 mod: *Module,
......@@ -1260,93 +1584,133 @@ pub const Object = struct {
12601584 const gpa = mod.gpa;
12611585 // If the module does not already have the function, we ignore this function call
12621586 // because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`.
1263 const llvm_global = self.decl_map.get(decl_index) orelse return;
1587 const global = self.decl_map.get(decl_index) orelse return;
1588 const llvm_global = global.toLlvm(&self.builder);
12641589 const decl = mod.declPtr(decl_index);
12651590 if (decl.isExtern(mod)) {
1266 var free_decl_name = false;
12671591 const decl_name = decl_name: {
12681592 const decl_name = mod.intern_pool.stringToSlice(decl.name);
12691593
12701594 if (mod.getTarget().isWasm() and try decl.isFunction(mod)) {
12711595 if (mod.intern_pool.stringToSliceUnwrap(decl.getOwnedExternFunc(mod).?.lib_name)) |lib_name| {
12721596 if (!std.mem.eql(u8, lib_name, "c")) {
1273 free_decl_name = true;
1274 break :decl_name try std.fmt.allocPrintZ(gpa, "{s}|{s}", .{
1275 decl_name, lib_name,
1276 });
1597 break :decl_name try self.builder.fmt("{s}|{s}", .{ decl_name, lib_name });
12771598 }
12781599 }
12791600 }
12801601
1281 break :decl_name decl_name;
1602 break :decl_name try self.builder.string(decl_name);
12821603 };
1283 defer if (free_decl_name) gpa.free(decl_name);
12841604
1285 llvm_global.setValueName(decl_name);
1286 if (self.getLlvmGlobal(decl_name)) |other_global| {
1287 if (other_global != llvm_global) {
1605 if (self.builder.getGlobal(decl_name)) |other_global| {
1606 if (other_global.toLlvm(&self.builder) != llvm_global) {
12881607 try self.extern_collisions.put(gpa, decl_index, {});
12891608 }
12901609 }
1610
1611 try global.rename(decl_name, &self.builder);
1612 global.ptr(&self.builder).unnamed_addr = .default;
12911613 llvm_global.setUnnamedAddr(.False);
1614 global.ptr(&self.builder).linkage = .external;
12921615 llvm_global.setLinkage(.External);
1293 if (mod.wantDllExports()) llvm_global.setDLLStorageClass(.Default);
1616 if (mod.wantDllExports()) {
1617 global.ptr(&self.builder).dll_storage_class = .default;
1618 llvm_global.setDLLStorageClass(.Default);
1619 }
12941620 if (self.di_map.get(decl)) |di_node| {
1621 const decl_name_slice = decl_name.toSlice(&self.builder).?;
12951622 if (try decl.isFunction(mod)) {
1296 const di_func = @as(*llvm.DISubprogram, @ptrCast(di_node));
1297 const linkage_name = llvm.MDString.get(self.context, decl_name.ptr, decl_name.len);
1623 const di_func: *llvm.DISubprogram = @ptrCast(di_node);
1624 const linkage_name = llvm.MDString.get(self.builder.llvm.context, decl_name_slice.ptr, decl_name_slice.len);
12981625 di_func.replaceLinkageName(linkage_name);
12991626 } else {
1300 const di_global = @as(*llvm.DIGlobalVariable, @ptrCast(di_node));
1301 const linkage_name = llvm.MDString.get(self.context, decl_name.ptr, decl_name.len);
1627 const di_global: *llvm.DIGlobalVariable = @ptrCast(di_node);
1628 const linkage_name = llvm.MDString.get(self.builder.llvm.context, decl_name_slice.ptr, decl_name_slice.len);
13021629 di_global.replaceLinkageName(linkage_name);
13031630 }
13041631 }
1305 if (decl.val.getVariable(mod)) |variable| {
1306 if (variable.is_threadlocal) {
1632 if (decl.val.getVariable(mod)) |decl_var| {
1633 if (decl_var.is_threadlocal) {
1634 global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local =
1635 .generaldynamic;
13071636 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
13081637 } else {
1638 global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local =
1639 .default;
13091640 llvm_global.setThreadLocalMode(.NotThreadLocal);
13101641 }
1311 if (variable.is_weak_linkage) {
1642 if (decl_var.is_weak_linkage) {
1643 global.ptr(&self.builder).linkage = .extern_weak;
13121644 llvm_global.setLinkage(.ExternalWeak);
13131645 }
13141646 }
1647 global.ptr(&self.builder).updateAttributes();
13151648 } else if (exports.len != 0) {
1316 const exp_name = mod.intern_pool.stringToSlice(exports[0].opts.name);
1317 llvm_global.setValueName2(exp_name.ptr, exp_name.len);
1649 const exp_name = try self.builder.string(mod.intern_pool.stringToSlice(exports[0].opts.name));
1650 try global.rename(exp_name, &self.builder);
1651 global.ptr(&self.builder).unnamed_addr = .default;
13181652 llvm_global.setUnnamedAddr(.False);
1319 if (mod.wantDllExports()) llvm_global.setDLLStorageClass(.DLLExport);
1653 if (mod.wantDllExports()) {
1654 global.ptr(&self.builder).dll_storage_class = .dllexport;
1655 llvm_global.setDLLStorageClass(.DLLExport);
1656 }
13201657 if (self.di_map.get(decl)) |di_node| {
1658 const exp_name_slice = exp_name.toSlice(&self.builder).?;
13211659 if (try decl.isFunction(mod)) {
1322 const di_func = @as(*llvm.DISubprogram, @ptrCast(di_node));
1323 const linkage_name = llvm.MDString.get(self.context, exp_name.ptr, exp_name.len);
1660 const di_func: *llvm.DISubprogram = @ptrCast(di_node);
1661 const linkage_name = llvm.MDString.get(self.builder.llvm.context, exp_name_slice.ptr, exp_name_slice.len);
13241662 di_func.replaceLinkageName(linkage_name);
13251663 } else {
1326 const di_global = @as(*llvm.DIGlobalVariable, @ptrCast(di_node));
1327 const linkage_name = llvm.MDString.get(self.context, exp_name.ptr, exp_name.len);
1664 const di_global: *llvm.DIGlobalVariable = @ptrCast(di_node);
1665 const linkage_name = llvm.MDString.get(self.builder.llvm.context, exp_name_slice.ptr, exp_name_slice.len);
13281666 di_global.replaceLinkageName(linkage_name);
13291667 }
13301668 }
13311669 switch (exports[0].opts.linkage) {
13321670 .Internal => unreachable,
1333 .Strong => llvm_global.setLinkage(.External),
1334 .Weak => llvm_global.setLinkage(.WeakODR),
1335 .LinkOnce => llvm_global.setLinkage(.LinkOnceODR),
1671 .Strong => {
1672 global.ptr(&self.builder).linkage = .external;
1673 llvm_global.setLinkage(.External);
1674 },
1675 .Weak => {
1676 global.ptr(&self.builder).linkage = .weak_odr;
1677 llvm_global.setLinkage(.WeakODR);
1678 },
1679 .LinkOnce => {
1680 global.ptr(&self.builder).linkage = .linkonce_odr;
1681 llvm_global.setLinkage(.LinkOnceODR);
1682 },
13361683 }
13371684 switch (exports[0].opts.visibility) {
1338 .default => llvm_global.setVisibility(.Default),
1339 .hidden => llvm_global.setVisibility(.Hidden),
1340 .protected => llvm_global.setVisibility(.Protected),
1685 .default => {
1686 global.ptr(&self.builder).visibility = .default;
1687 llvm_global.setVisibility(.Default);
1688 },
1689 .hidden => {
1690 global.ptr(&self.builder).visibility = .hidden;
1691 llvm_global.setVisibility(.Hidden);
1692 },
1693 .protected => {
1694 global.ptr(&self.builder).visibility = .protected;
1695 llvm_global.setVisibility(.Protected);
1696 },
13411697 }
13421698 if (mod.intern_pool.stringToSliceUnwrap(exports[0].opts.section)) |section| {
1699 switch (global.ptrConst(&self.builder).kind) {
1700 inline .variable, .function => |impl_index| impl_index.ptr(&self.builder).section =
1701 try self.builder.string(section),
1702 else => unreachable,
1703 }
13431704 llvm_global.setSection(section);
13441705 }
1345 if (decl.val.getVariable(mod)) |variable| {
1346 if (variable.is_threadlocal) {
1706 if (decl.val.getVariable(mod)) |decl_var| {
1707 if (decl_var.is_threadlocal) {
1708 global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local =
1709 .generaldynamic;
13471710 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
13481711 }
13491712 }
1713 global.ptr(&self.builder).updateAttributes();
13501714
13511715 // If a Decl is exported more than one time (which is rare),
13521716 // we add aliases for all but the first export.
......@@ -1361,7 +1725,7 @@ pub const Object = struct {
13611725 alias.setAliasee(llvm_global);
13621726 } else {
13631727 _ = self.llvm_module.addAlias(
1364 llvm_global.globalGetValueType(),
1728 global.ptrConst(&self.builder).type.toLlvm(&self.builder),
13651729 0,
13661730 llvm_global,
13671731 exp_name_z,
......@@ -1369,32 +1733,42 @@ pub const Object = struct {
13691733 }
13701734 }
13711735 } else {
1372 const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
1373 llvm_global.setValueName2(fqn.ptr, fqn.len);
1736 const fqn = try self.builder.string(mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)));
1737 try global.rename(fqn, &self.builder);
1738 global.ptr(&self.builder).linkage = .internal;
13741739 llvm_global.setLinkage(.Internal);
1375 if (mod.wantDllExports()) llvm_global.setDLLStorageClass(.Default);
1740 if (mod.wantDllExports()) {
1741 global.ptr(&self.builder).dll_storage_class = .default;
1742 llvm_global.setDLLStorageClass(.Default);
1743 }
1744 global.ptr(&self.builder).unnamed_addr = .unnamed_addr;
13761745 llvm_global.setUnnamedAddr(.True);
1377 if (decl.val.getVariable(mod)) |variable| {
1746 if (decl.val.getVariable(mod)) |decl_var| {
13781747 const single_threaded = mod.comp.bin_file.options.single_threaded;
1379 if (variable.is_threadlocal and !single_threaded) {
1748 if (decl_var.is_threadlocal and !single_threaded) {
1749 global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local =
1750 .generaldynamic;
13801751 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
13811752 } else {
1753 global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local =
1754 .default;
13821755 llvm_global.setThreadLocalMode(.NotThreadLocal);
13831756 }
13841757 }
1758 global.ptr(&self.builder).updateAttributes();
13851759 }
13861760 }
13871761
13881762 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();
1763 const global = self.decl_map.get(decl_index) orelse return;
1764 global.toLlvm(&self.builder).deleteGlobal();
13911765 }
13921766
13931767 fn getDIFile(o: *Object, gpa: Allocator, file: *const Module.File) !*llvm.DIFile {
13941768 const gop = try o.di_map.getOrPut(gpa, file);
13951769 errdefer assert(o.di_map.remove(file));
13961770 if (gop.found_existing) {
1397 return @as(*llvm.DIFile, @ptrCast(gop.value_ptr.*));
1771 return @ptrCast(gop.value_ptr.*);
13981772 }
13991773 const dir_path_z = d: {
14001774 var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
......@@ -1542,7 +1916,7 @@ pub const Object = struct {
15421916 ty.abiSize(mod) * 8,
15431917 ty.abiAlignment(mod) * 8,
15441918 enumerators.ptr,
1545 @as(c_int, @intCast(enumerators.len)),
1919 @intCast(enumerators.len),
15461920 try o.lowerDebugType(int_ty, .full),
15471921 "",
15481922 );
......@@ -1717,7 +2091,7 @@ pub const Object = struct {
17172091 ty.abiSize(mod) * 8,
17182092 ty.abiAlignment(mod) * 8,
17192093 try o.lowerDebugType(ty.childType(mod), .full),
1720 @as(i64, @intCast(ty.arrayLen(mod))),
2094 @intCast(ty.arrayLen(mod)),
17212095 );
17222096 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
17232097 try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(array_di_ty));
......@@ -2022,7 +2396,7 @@ pub const Object = struct {
20222396 0, // flags
20232397 null, // derived from
20242398 di_fields.items.ptr,
2025 @as(c_int, @intCast(di_fields.items.len)),
2399 @intCast(di_fields.items.len),
20262400 0, // run time lang
20272401 null, // vtable holder
20282402 "", // unique id
......@@ -2109,7 +2483,7 @@ pub const Object = struct {
21092483 0, // flags
21102484 null, // derived from
21112485 di_fields.items.ptr,
2112 @as(c_int, @intCast(di_fields.items.len)),
2486 @intCast(di_fields.items.len),
21132487 0, // run time lang
21142488 null, // vtable holder
21152489 "", // unique id
......@@ -2221,7 +2595,7 @@ pub const Object = struct {
22212595 ty.abiAlignment(mod) * 8, // align in bits
22222596 0, // flags
22232597 di_fields.items.ptr,
2224 @as(c_int, @intCast(di_fields.items.len)),
2598 @intCast(di_fields.items.len),
22252599 0, // run time lang
22262600 "", // unique id
22272601 );
......@@ -2334,7 +2708,7 @@ pub const Object = struct {
23342708
23352709 const fn_di_ty = dib.createSubroutineType(
23362710 param_di_types.items.ptr,
2337 @as(c_int, @intCast(param_di_types.items.len)),
2711 @intCast(param_di_types.items.len),
23382712 0,
23392713 );
23402714 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
......@@ -2420,52 +2794,16 @@ pub const Object = struct {
24202794 return buffer.toOwnedSliceSentinel(0);
24212795 }
24222796
2423 fn getNullOptAddr(o: *Object) !*llvm.Value {
2424 if (o.null_opt_addr) |global| return global;
2425
2426 const mod = o.module;
2427 const target = mod.getTarget();
2428 const ty = try mod.intern(.{ .opt_type = .usize_type });
2429 const null_opt_usize = try mod.intern(.{ .opt = .{
2430 .ty = ty,
2431 .val = .none,
2432 } });
2433
2434 const llvm_init = try o.lowerValue(.{
2435 .ty = ty.toType(),
2436 .val = null_opt_usize.toValue(),
2437 });
2438 const llvm_wanted_addrspace = toLlvmAddressSpace(.generic, target);
2439 const llvm_actual_addrspace = toLlvmGlobalAddressSpace(.generic, target);
2440 const global = o.llvm_module.addGlobalInAddressSpace(
2441 llvm_init.typeOf(),
2442 "",
2443 llvm_actual_addrspace,
2444 );
2445 global.setLinkage(.Internal);
2446 global.setUnnamedAddr(.True);
2447 global.setAlignment(ty.toType().abiAlignment(mod));
2448 global.setInitializer(llvm_init);
2449
2450 const addrspace_casted_global = if (llvm_wanted_addrspace != llvm_actual_addrspace)
2451 global.constAddrSpaceCast(o.context.pointerType(llvm_wanted_addrspace))
2452 else
2453 global;
2454
2455 o.null_opt_addr = addrspace_casted_global;
2456 return addrspace_casted_global;
2457 }
2458
24592797 /// If the llvm function does not exist, create it.
24602798 /// Note that this can be called before the function's semantic analysis has
24612799 /// completed, so if any attributes rely on that, they must be done in updateFunc, not here.
2462 fn resolveLlvmFunction(o: *Object, decl_index: Module.Decl.Index) !*llvm.Value {
2800 fn resolveLlvmFunction(o: *Object, decl_index: Module.Decl.Index) Allocator.Error!Builder.Function.Index {
24632801 const mod = o.module;
24642802 const gpa = o.gpa;
24652803 const decl = mod.declPtr(decl_index);
24662804 const zig_fn_type = decl.ty;
24672805 const gop = try o.decl_map.getOrPut(gpa, decl_index);
2468 if (gop.found_existing) return gop.value_ptr.*;
2806 if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.function;
24692807
24702808 assert(decl.has_tv);
24712809 const fn_info = mod.typeToFunc(zig_fn_type).?;
......@@ -2474,16 +2812,25 @@ pub const Object = struct {
24742812
24752813 const fn_type = try o.lowerType(zig_fn_type);
24762814
2477 const fqn = try decl.getFullyQualifiedName(mod);
24782815 const ip = &mod.intern_pool;
2816 const fqn = try o.builder.string(ip.stringToSlice(try decl.getFullyQualifiedName(mod)));
24792817
24802818 const llvm_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);
2481 const llvm_fn = o.llvm_module.addFunctionInAddressSpace(ip.stringToSlice(fqn), fn_type, llvm_addrspace);
2482 gop.value_ptr.* = llvm_fn;
2819 const llvm_fn = o.llvm_module.addFunctionInAddressSpace(fqn.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder), @intFromEnum(llvm_addrspace));
2820
2821 var global = Builder.Global{
2822 .type = fn_type,
2823 .kind = .{ .function = @enumFromInt(o.builder.functions.items.len) },
2824 };
2825 var function = Builder.Function{
2826 .global = @enumFromInt(o.builder.globals.count()),
2827 };
24832828
24842829 const is_extern = decl.isExtern(mod);
24852830 if (!is_extern) {
2831 global.linkage = .internal;
24862832 llvm_fn.setLinkage(.Internal);
2833 global.unnamed_addr = .unnamed_addr;
24872834 llvm_fn.setUnnamedAddr(.True);
24882835 } else {
24892836 if (target.isWasm()) {
......@@ -2500,7 +2847,7 @@ pub const Object = struct {
25002847 o.addArgAttr(llvm_fn, 0, "nonnull"); // Sret pointers must not be address 0
25012848 o.addArgAttr(llvm_fn, 0, "noalias");
25022849
2503 const raw_llvm_ret_ty = try o.lowerType(fn_info.return_type.toType());
2850 const raw_llvm_ret_ty = (try o.lowerType(fn_info.return_type.toType())).toLlvm(&o.builder);
25042851 llvm_fn.addSretAttr(raw_llvm_ret_ty);
25052852 }
25062853
......@@ -2528,7 +2875,8 @@ pub const Object = struct {
25282875 }
25292876
25302877 if (fn_info.alignment.toByteUnitsOptional()) |a| {
2531 llvm_fn.setAlignment(@as(c_uint, @intCast(a)));
2878 function.alignment = Builder.Alignment.fromByteUnits(a);
2879 llvm_fn.setAlignment(@intCast(a));
25322880 }
25332881
25342882 // Function attributes that are independent of analysis results of the function body.
......@@ -2544,7 +2892,7 @@ pub const Object = struct {
25442892 var it = iterateParamTypes(o, fn_info);
25452893 it.llvm_index += @intFromBool(sret);
25462894 it.llvm_index += @intFromBool(err_return_tracing);
2547 while (it.next()) |lowering| switch (lowering) {
2895 while (try it.next()) |lowering| switch (lowering) {
25482896 .byval => {
25492897 const param_index = it.zig_index - 1;
25502898 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
......@@ -2576,7 +2924,10 @@ pub const Object = struct {
25762924 };
25772925 }
25782926
2579 return llvm_fn;
2927 try o.builder.llvm.globals.append(o.gpa, llvm_fn);
2928 gop.value_ptr.* = try o.builder.addGlobal(fqn, global);
2929 try o.builder.functions.append(o.gpa, function);
2930 return global.kind.function;
25802931 }
25812932
25822933 fn addCommonFnAttributes(o: *Object, llvm_fn: *llvm.Value) void {
......@@ -2622,65 +2973,80 @@ pub const Object = struct {
26222973 }
26232974 }
26242975
2625 fn resolveGlobalDecl(o: *Object, decl_index: Module.Decl.Index) Error!*llvm.Value {
2976 fn resolveGlobalDecl(o: *Object, decl_index: Module.Decl.Index) Allocator.Error!Builder.Variable.Index {
26262977 const gop = try o.decl_map.getOrPut(o.gpa, decl_index);
2627 if (gop.found_existing) return gop.value_ptr.*;
2978 if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.variable;
26282979 errdefer assert(o.decl_map.remove(decl_index));
26292980
26302981 const mod = o.module;
26312982 const decl = mod.declPtr(decl_index);
2632 const fqn = try decl.getFullyQualifiedName(mod);
2983 const fqn = try o.builder.string(mod.intern_pool.stringToSlice(
2984 try decl.getFullyQualifiedName(mod),
2985 ));
26332986
26342987 const target = mod.getTarget();
26352988
2636 const llvm_type = try o.lowerType(decl.ty);
2637 const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);
2989 var global = Builder.Global{
2990 .addr_space = toLlvmGlobalAddressSpace(decl.@"addrspace", target),
2991 .type = try o.lowerType(decl.ty),
2992 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
2993 };
2994 var variable = Builder.Variable{
2995 .global = @enumFromInt(o.builder.globals.count()),
2996 };
26382997
2998 const is_extern = decl.isExtern(mod);
2999 const name = if (is_extern)
3000 try o.builder.string(mod.intern_pool.stringToSlice(decl.name))
3001 else
3002 fqn;
26393003 const llvm_global = o.llvm_module.addGlobalInAddressSpace(
2640 llvm_type,
2641 mod.intern_pool.stringToSlice(fqn),
2642 llvm_actual_addrspace,
3004 global.type.toLlvm(&o.builder),
3005 fqn.toSlice(&o.builder).?,
3006 @intFromEnum(global.addr_space),
26433007 );
2644 gop.value_ptr.* = llvm_global;
26453008
26463009 // This is needed for declarations created by `@extern`.
2647 if (decl.isExtern(mod)) {
2648 llvm_global.setValueName(mod.intern_pool.stringToSlice(decl.name));
3010 if (is_extern) {
3011 global.unnamed_addr = .default;
26493012 llvm_global.setUnnamedAddr(.False);
3013 global.linkage = .external;
26503014 llvm_global.setLinkage(.External);
2651 if (decl.val.getVariable(mod)) |variable| {
3015 if (decl.val.getVariable(mod)) |decl_var| {
26523016 const single_threaded = mod.comp.bin_file.options.single_threaded;
2653 if (variable.is_threadlocal and !single_threaded) {
3017 if (decl_var.is_threadlocal and !single_threaded) {
3018 variable.thread_local = .generaldynamic;
26543019 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
26553020 } else {
3021 variable.thread_local = .default;
26563022 llvm_global.setThreadLocalMode(.NotThreadLocal);
26573023 }
2658 if (variable.is_weak_linkage) llvm_global.setLinkage(.ExternalWeak);
3024 if (decl_var.is_weak_linkage) {
3025 global.linkage = .extern_weak;
3026 llvm_global.setLinkage(.ExternalWeak);
3027 }
26593028 }
26603029 } else {
3030 global.linkage = .internal;
26613031 llvm_global.setLinkage(.Internal);
3032 global.unnamed_addr = .unnamed_addr;
26623033 llvm_global.setUnnamedAddr(.True);
26633034 }
26643035
2665 return llvm_global;
2666 }
2667
2668 fn isUnnamedType(o: *Object, ty: Type, val: *llvm.Value) bool {
2669 // Once `lowerType` succeeds, successive calls to it with the same Zig type
2670 // are guaranteed to succeed. So if a call to `lowerType` fails here it means
2671 // it is the first time lowering the type, which means the value can't possible
2672 // have that type.
2673 const llvm_ty = o.lowerType(ty) catch return true;
2674 return val.typeOf() != llvm_ty;
3036 try o.builder.llvm.globals.append(o.gpa, llvm_global);
3037 gop.value_ptr.* = try o.builder.addGlobal(name, global);
3038 try o.builder.variables.append(o.gpa, variable);
3039 return global.kind.variable;
26753040 }
26763041
2677 fn lowerType(o: *Object, t: Type) Allocator.Error!*llvm.Type {
2678 const llvm_ty = try lowerTypeInner(o, t);
3042 fn lowerType(o: *Object, t: Type) Allocator.Error!Builder.Type {
3043 const ty = try o.lowerTypeInner(t);
26793044 const mod = o.module;
26803045 if (std.debug.runtime_safety and false) check: {
3046 const llvm_ty = ty.toLlvm(&o.builder);
26813047 if (t.zigTypeTag(mod) == .Opaque) break :check;
26823048 if (!t.hasRuntimeBits(mod)) break :check;
2683 if (!llvm_ty.isSized().toBool()) break :check;
3049 if (!try ty.isSized(&o.builder)) break :check;
26843050
26853051 const zig_size = t.abiSize(mod);
26863052 const llvm_size = o.target_data.abiSizeOfType(llvm_ty);
......@@ -2690,456 +3056,511 @@ pub const Object = struct {
26903056 });
26913057 }
26923058 }
2693 return llvm_ty;
3059 return ty;
26943060 }
26953061
2696 fn lowerTypeInner(o: *Object, t: Type) Allocator.Error!*llvm.Type {
2697 const gpa = o.gpa;
3062 fn lowerTypeInner(o: *Object, t: Type) Allocator.Error!Builder.Type {
26983063 const mod = o.module;
26993064 const target = mod.getTarget();
2700 switch (t.zigTypeTag(mod)) {
2701 .Void, .NoReturn => return o.context.voidType(),
2702 .Int => {
2703 const info = t.intInfo(mod);
2704 assert(info.bits != 0);
2705 return o.context.intType(info.bits);
2706 },
2707 .Enum => {
2708 const int_ty = t.intTagType(mod);
2709 const bit_count = int_ty.intInfo(mod).bits;
2710 assert(bit_count != 0);
2711 return o.context.intType(bit_count);
2712 },
2713 .Float => switch (t.floatBits(target)) {
2714 16 => return if (backendSupportsF16(target)) o.context.halfType() else o.context.intType(16),
2715 32 => return o.context.floatType(),
2716 64 => return o.context.doubleType(),
2717 80 => return if (backendSupportsF80(target)) o.context.x86FP80Type() else o.context.intType(80),
2718 128 => return o.context.fp128Type(),
3065 return switch (t.toIntern()) {
3066 .u0_type, .i0_type => unreachable,
3067 inline .u1_type,
3068 .u8_type,
3069 .i8_type,
3070 .u16_type,
3071 .i16_type,
3072 .u29_type,
3073 .u32_type,
3074 .i32_type,
3075 .u64_type,
3076 .i64_type,
3077 .u80_type,
3078 .u128_type,
3079 .i128_type,
3080 => |tag| @field(Builder.Type, "i" ++ @tagName(tag)[1 .. @tagName(tag).len - "_type".len]),
3081 .usize_type, .isize_type => try o.builder.intType(target.ptrBitWidth()),
3082 inline .c_char_type,
3083 .c_short_type,
3084 .c_ushort_type,
3085 .c_int_type,
3086 .c_uint_type,
3087 .c_long_type,
3088 .c_ulong_type,
3089 .c_longlong_type,
3090 .c_ulonglong_type,
3091 => |tag| try o.builder.intType(target.c_type_bit_size(
3092 @field(std.Target.CType, @tagName(tag)["c_".len .. @tagName(tag).len - "_type".len]),
3093 )),
3094 .c_longdouble_type,
3095 .f16_type,
3096 .f32_type,
3097 .f64_type,
3098 .f80_type,
3099 .f128_type,
3100 => switch (t.floatBits(target)) {
3101 16 => if (backendSupportsF16(target)) .half else .i16,
3102 32 => .float,
3103 64 => .double,
3104 80 => if (backendSupportsF80(target)) .x86_fp80 else .i80,
3105 128 => .fp128,
27193106 else => unreachable,
27203107 },
2721 .Bool => return o.context.intType(1),
2722 .Pointer => {
2723 if (t.isSlice(mod)) {
2724 const ptr_type = t.slicePtrFieldType(mod);
2725
2726 const fields: [2]*llvm.Type = .{
2727 try o.lowerType(ptr_type),
2728 try o.lowerType(Type.usize),
3108 .anyopaque_type => unreachable,
3109 .bool_type => .i1,
3110 .void_type => .void,
3111 .type_type => unreachable,
3112 .anyerror_type => Builder.Type.err_int,
3113 .comptime_int_type,
3114 .comptime_float_type,
3115 .noreturn_type,
3116 => unreachable,
3117 .anyframe_type => @panic("TODO implement lowerType for AnyFrame types"),
3118 .null_type,
3119 .undefined_type,
3120 .enum_literal_type,
3121 .atomic_order_type,
3122 .atomic_rmw_op_type,
3123 .calling_convention_type,
3124 .address_space_type,
3125 .float_mode_type,
3126 .reduce_op_type,
3127 .call_modifier_type,
3128 .prefetch_options_type,
3129 .export_options_type,
3130 .extern_options_type,
3131 .type_info_type,
3132 => unreachable,
3133 .manyptr_u8_type,
3134 .manyptr_const_u8_type,
3135 .manyptr_const_u8_sentinel_0_type,
3136 .single_const_pointer_to_comptime_int_type,
3137 => .ptr,
3138 .slice_const_u8_type,
3139 .slice_const_u8_sentinel_0_type,
3140 => try o.builder.structType(.normal, &.{ .ptr, try o.lowerType(Type.usize) }),
3141 .optional_noreturn_type => unreachable,
3142 .anyerror_void_error_union_type,
3143 .adhoc_inferred_error_set_type,
3144 => Builder.Type.err_int,
3145 .generic_poison_type,
3146 .empty_struct_type,
3147 => unreachable,
3148 // values, not types
3149 .undef,
3150 .zero,
3151 .zero_usize,
3152 .zero_u8,
3153 .one,
3154 .one_usize,
3155 .one_u8,
3156 .four_u8,
3157 .negative_one,
3158 .calling_convention_c,
3159 .calling_convention_inline,
3160 .void_value,
3161 .unreachable_value,
3162 .null_value,
3163 .bool_true,
3164 .bool_false,
3165 .empty_struct,
3166 .generic_poison,
3167 .var_args_param_type,
3168 .none,
3169 => unreachable,
3170 else => switch (mod.intern_pool.indexToKey(t.toIntern())) {
3171 .int_type => |int_type| try o.builder.intType(int_type.bits),
3172 .ptr_type => |ptr_type| type: {
3173 const ptr_ty = try o.builder.ptrType(
3174 toLlvmAddressSpace(ptr_type.flags.address_space, target),
3175 );
3176 break :type switch (ptr_type.flags.size) {
3177 .One, .Many, .C => ptr_ty,
3178 .Slice => try o.builder.structType(.normal, &.{
3179 ptr_ty,
3180 try o.lowerType(Type.usize),
3181 }),
27293182 };
2730 return o.context.structType(&fields, fields.len, .False);
2731 }
2732 const ptr_info = t.ptrInfo(mod);
2733 const llvm_addrspace = toLlvmAddressSpace(ptr_info.flags.address_space, target);
2734 return o.context.pointerType(llvm_addrspace);
2735 },
2736 .Opaque => {
2737 if (t.toIntern() == .anyopaque_type) return o.context.intType(8);
2738
2739 const gop = try o.type_map.getOrPut(gpa, t.toIntern());
2740 if (gop.found_existing) return gop.value_ptr.*;
2741
2742 const opaque_type = mod.intern_pool.indexToKey(t.toIntern()).opaque_type;
2743 const name = mod.intern_pool.stringToSlice(try mod.opaqueFullyQualifiedName(opaque_type));
2744
2745 const llvm_struct_ty = o.context.structCreateNamed(name);
2746 gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls
2747 return llvm_struct_ty;
2748 },
2749 .Array => {
2750 const elem_ty = t.childType(mod);
2751 if (std.debug.runtime_safety) assert((try elem_ty.onePossibleValue(mod)) == null);
2752 const elem_llvm_ty = try o.lowerType(elem_ty);
2753 const total_len = t.arrayLen(mod) + @intFromBool(t.sentinel(mod) != null);
2754 return elem_llvm_ty.arrayType(@as(c_uint, @intCast(total_len)));
2755 },
2756 .Vector => {
2757 const elem_type = try o.lowerType(t.childType(mod));
2758 return elem_type.vectorType(t.vectorLen(mod));
2759 },
2760 .Optional => {
2761 const child_ty = t.optionalChild(mod);
2762 if (!child_ty.hasRuntimeBitsIgnoreComptime(mod)) {
2763 return o.context.intType(8);
2764 }
2765 const payload_llvm_ty = try o.lowerType(child_ty);
2766 if (t.optionalReprIsPayload(mod)) {
2767 return payload_llvm_ty;
2768 }
2769
2770 comptime assert(optional_layout_version == 3);
2771 var fields_buf: [3]*llvm.Type = .{
2772 payload_llvm_ty, o.context.intType(8), undefined,
2773 };
2774 const offset = child_ty.abiSize(mod) + 1;
2775 const abi_size = t.abiSize(mod);
2776 const padding = @as(c_uint, @intCast(abi_size - offset));
2777 if (padding == 0) {
2778 return o.context.structType(&fields_buf, 2, .False);
2779 }
2780 fields_buf[2] = o.context.intType(8).arrayType(padding);
2781 return o.context.structType(&fields_buf, 3, .False);
2782 },
2783 .ErrorUnion => {
2784 const payload_ty = t.errorUnionPayload(mod);
2785 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
2786 return try o.lowerType(Type.anyerror);
2787 }
2788 const llvm_error_type = try o.lowerType(Type.anyerror);
2789 const llvm_payload_type = try o.lowerType(payload_ty);
2790
2791 const payload_align = payload_ty.abiAlignment(mod);
2792 const error_align = Type.anyerror.abiAlignment(mod);
2793
2794 const payload_size = payload_ty.abiSize(mod);
2795 const error_size = Type.anyerror.abiSize(mod);
2796
2797 var fields_buf: [3]*llvm.Type = undefined;
2798 if (error_align > payload_align) {
2799 fields_buf[0] = llvm_error_type;
2800 fields_buf[1] = llvm_payload_type;
2801 const payload_end =
2802 std.mem.alignForward(u64, error_size, payload_align) +
2803 payload_size;
2804 const abi_size = std.mem.alignForward(u64, payload_end, error_align);
2805 const padding = @as(c_uint, @intCast(abi_size - payload_end));
2806 if (padding == 0) {
2807 return o.context.structType(&fields_buf, 2, .False);
3183 },
3184 .array_type => |array_type| o.builder.arrayType(
3185 array_type.len + @intFromBool(array_type.sentinel != .none),
3186 try o.lowerType(array_type.child.toType()),
3187 ),
3188 .vector_type => |vector_type| o.builder.vectorType(
3189 .normal,
3190 vector_type.len,
3191 try o.lowerType(vector_type.child.toType()),
3192 ),
3193 .opt_type => |child_ty| {
3194 if (!child_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) return .i8;
3195
3196 const payload_ty = try o.lowerType(child_ty.toType());
3197 if (t.optionalReprIsPayload(mod)) return payload_ty;
3198
3199 comptime assert(optional_layout_version == 3);
3200 var fields: [3]Builder.Type = .{ payload_ty, .i8, undefined };
3201 var fields_len: usize = 2;
3202 const offset = child_ty.toType().abiSize(mod) + 1;
3203 const abi_size = t.abiSize(mod);
3204 const padding_len = abi_size - offset;
3205 if (padding_len > 0) {
3206 fields[2] = try o.builder.arrayType(padding_len, .i8);
3207 fields_len = 3;
28083208 }
2809 fields_buf[2] = o.context.intType(8).arrayType(padding);
2810 return o.context.structType(&fields_buf, 3, .False);
2811 } else {
2812 fields_buf[0] = llvm_payload_type;
2813 fields_buf[1] = llvm_error_type;
2814 const error_end =
2815 std.mem.alignForward(u64, payload_size, error_align) +
2816 error_size;
2817 const abi_size = std.mem.alignForward(u64, error_end, payload_align);
2818 const padding = @as(c_uint, @intCast(abi_size - error_end));
2819 if (padding == 0) {
2820 return o.context.structType(&fields_buf, 2, .False);
3209 return o.builder.structType(.normal, fields[0..fields_len]);
3210 },
3211 .anyframe_type => @panic("TODO implement lowerType for AnyFrame types"),
3212 .error_union_type => |error_union_type| {
3213 const error_type = Builder.Type.err_int;
3214 if (!error_union_type.payload_type.toType().hasRuntimeBitsIgnoreComptime(mod))
3215 return error_type;
3216 const payload_type = try o.lowerType(error_union_type.payload_type.toType());
3217
3218 const payload_align = error_union_type.payload_type.toType().abiAlignment(mod);
3219 const error_align = Type.err_int.abiAlignment(mod);
3220
3221 const payload_size = error_union_type.payload_type.toType().abiSize(mod);
3222 const error_size = Type.err_int.abiSize(mod);
3223
3224 var fields: [3]Builder.Type = undefined;
3225 var fields_len: usize = 2;
3226 const padding_len = if (error_align > payload_align) pad: {
3227 fields[0] = error_type;
3228 fields[1] = payload_type;
3229 const payload_end =
3230 std.mem.alignForward(u64, error_size, payload_align) +
3231 payload_size;
3232 const abi_size = std.mem.alignForward(u64, payload_end, error_align);
3233 break :pad abi_size - payload_end;
3234 } else pad: {
3235 fields[0] = payload_type;
3236 fields[1] = error_type;
3237 const error_end =
3238 std.mem.alignForward(u64, payload_size, error_align) +
3239 error_size;
3240 const abi_size = std.mem.alignForward(u64, error_end, payload_align);
3241 break :pad abi_size - error_end;
3242 };
3243 if (padding_len > 0) {
3244 fields[2] = try o.builder.arrayType(padding_len, .i8);
3245 fields_len = 3;
28213246 }
2822 fields_buf[2] = o.context.intType(8).arrayType(padding);
2823 return o.context.structType(&fields_buf, 3, .False);
2824 }
2825 },
2826 .ErrorSet => return o.context.intType(16),
2827 .Struct => {
2828 const gop = try o.type_map.getOrPut(gpa, t.toIntern());
2829 if (gop.found_existing) return gop.value_ptr.*;
2830
2831 const struct_type = switch (mod.intern_pool.indexToKey(t.toIntern())) {
2832 .anon_struct_type => |tuple| {
2833 const llvm_struct_ty = o.context.structCreateNamed("");
2834 gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls
3247 return o.builder.structType(.normal, fields[0..fields_len]);
3248 },
3249 .simple_type => unreachable,
3250 .struct_type => |struct_type| {
3251 const gop = try o.type_map.getOrPut(o.gpa, t.toIntern());
3252 if (gop.found_existing) return gop.value_ptr.*;
28353253
2836 var llvm_field_types: std.ArrayListUnmanaged(*llvm.Type) = .{};
2837 defer llvm_field_types.deinit(gpa);
3254 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3255 if (struct_obj.layout == .Packed) {
3256 assert(struct_obj.haveLayout());
3257 const int_ty = try o.lowerType(struct_obj.backing_int_ty);
3258 gop.value_ptr.* = int_ty;
3259 return int_ty;
3260 }
28383261
2839 try llvm_field_types.ensureUnusedCapacity(gpa, tuple.types.len);
3262 const name = try o.builder.string(mod.intern_pool.stringToSlice(
3263 try struct_obj.getFullyQualifiedName(mod),
3264 ));
3265 const ty = try o.builder.opaqueType(name);
3266 gop.value_ptr.* = ty; // must be done before any recursive calls
28403267
2841 comptime assert(struct_layout_version == 2);
2842 var offset: u64 = 0;
2843 var big_align: u32 = 0;
3268 assert(struct_obj.haveFieldTypes());
28443269
2845 for (tuple.types, tuple.values) |field_ty, field_val| {
2846 if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue;
3270 var llvm_field_types = std.ArrayListUnmanaged(Builder.Type){};
3271 defer llvm_field_types.deinit(o.gpa);
3272 try llvm_field_types.ensureUnusedCapacity(o.gpa, struct_obj.fields.count());
28473273
2848 const field_align = field_ty.toType().abiAlignment(mod);
2849 big_align = @max(big_align, field_align);
2850 const prev_offset = offset;
2851 offset = std.mem.alignForward(u64, offset, field_align);
2852
2853 const padding_len = offset - prev_offset;
2854 if (padding_len > 0) {
2855 const llvm_array_ty = o.context.intType(8).arrayType(@as(c_uint, @intCast(padding_len)));
2856 try llvm_field_types.append(gpa, llvm_array_ty);
2857 }
2858 const field_llvm_ty = try o.lowerType(field_ty.toType());
2859 try llvm_field_types.append(gpa, field_llvm_ty);
3274 comptime assert(struct_layout_version == 2);
3275 var offset: u64 = 0;
3276 var big_align: u32 = 1;
3277 var struct_kind: Builder.Type.Structure.Kind = .normal;
28603278
2861 offset += field_ty.toType().abiSize(mod);
2862 }
2863 {
2864 const prev_offset = offset;
2865 offset = std.mem.alignForward(u64, offset, big_align);
2866 const padding_len = offset - prev_offset;
2867 if (padding_len > 0) {
2868 const llvm_array_ty = o.context.intType(8).arrayType(@as(c_uint, @intCast(padding_len)));
2869 try llvm_field_types.append(gpa, llvm_array_ty);
2870 }
2871 }
3279 var it = struct_obj.runtimeFieldIterator(mod);
3280 while (it.next()) |field_and_index| {
3281 const field = field_and_index.field;
3282 const field_align = field.alignment(mod, struct_obj.layout);
3283 const field_ty_align = field.ty.abiAlignment(mod);
3284 if (field_align < field_ty_align) struct_kind = .@"packed";
3285 big_align = @max(big_align, field_align);
3286 const prev_offset = offset;
3287 offset = std.mem.alignForward(u64, offset, field_align);
28723288
2873 llvm_struct_ty.structSetBody(
2874 llvm_field_types.items.ptr,
2875 @as(c_uint, @intCast(llvm_field_types.items.len)),
2876 .False,
3289 const padding_len = offset - prev_offset;
3290 if (padding_len > 0) try llvm_field_types.append(
3291 o.gpa,
3292 try o.builder.arrayType(padding_len, .i8),
28773293 );
3294 try llvm_field_types.append(o.gpa, try o.lowerType(field.ty));
28783295
2879 return llvm_struct_ty;
2880 },
2881 .struct_type => |struct_type| struct_type,
2882 else => unreachable,
2883 };
2884
2885 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
2886
2887 if (struct_obj.layout == .Packed) {
2888 assert(struct_obj.haveLayout());
2889 const int_llvm_ty = try o.lowerType(struct_obj.backing_int_ty);
2890 gop.value_ptr.* = int_llvm_ty;
2891 return int_llvm_ty;
2892 }
2893
2894 const name = mod.intern_pool.stringToSlice(try struct_obj.getFullyQualifiedName(mod));
3296 offset += field.ty.abiSize(mod);
3297 }
3298 {
3299 const prev_offset = offset;
3300 offset = std.mem.alignForward(u64, offset, big_align);
3301 const padding_len = offset - prev_offset;
3302 if (padding_len > 0) try llvm_field_types.append(
3303 o.gpa,
3304 try o.builder.arrayType(padding_len, .i8),
3305 );
3306 }
28953307
2896 const llvm_struct_ty = o.context.structCreateNamed(name);
2897 gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls
3308 try o.builder.namedTypeSetBody(
3309 ty,
3310 try o.builder.structType(struct_kind, llvm_field_types.items),
3311 );
3312 return ty;
3313 },
3314 .anon_struct_type => |anon_struct_type| {
3315 var llvm_field_types: std.ArrayListUnmanaged(Builder.Type) = .{};
3316 defer llvm_field_types.deinit(o.gpa);
3317 try llvm_field_types.ensureUnusedCapacity(o.gpa, anon_struct_type.types.len);
28983318
2899 assert(struct_obj.haveFieldTypes());
3319 comptime assert(struct_layout_version == 2);
3320 var offset: u64 = 0;
3321 var big_align: u32 = 0;
29003322
2901 var llvm_field_types: std.ArrayListUnmanaged(*llvm.Type) = .{};
2902 defer llvm_field_types.deinit(gpa);
3323 for (anon_struct_type.types, anon_struct_type.values) |field_ty, field_val| {
3324 if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue;
29033325
2904 try llvm_field_types.ensureUnusedCapacity(gpa, struct_obj.fields.count());
3326 const field_align = field_ty.toType().abiAlignment(mod);
3327 big_align = @max(big_align, field_align);
3328 const prev_offset = offset;
3329 offset = std.mem.alignForward(u64, offset, field_align);
29053330
2906 comptime assert(struct_layout_version == 2);
2907 var offset: u64 = 0;
2908 var big_align: u32 = 1;
2909 var any_underaligned_fields = false;
3331 const padding_len = offset - prev_offset;
3332 if (padding_len > 0) try llvm_field_types.append(
3333 o.gpa,
3334 try o.builder.arrayType(padding_len, .i8),
3335 );
3336 try llvm_field_types.append(o.gpa, try o.lowerType(field_ty.toType()));
29103337
2911 var it = struct_obj.runtimeFieldIterator(mod);
2912 while (it.next()) |field_and_index| {
2913 const field = field_and_index.field;
2914 const field_align = field.alignment(mod, struct_obj.layout);
2915 const field_ty_align = field.ty.abiAlignment(mod);
2916 any_underaligned_fields = any_underaligned_fields or
2917 field_align < field_ty_align;
2918 big_align = @max(big_align, field_align);
2919 const prev_offset = offset;
2920 offset = std.mem.alignForward(u64, offset, field_align);
2921
2922 const padding_len = offset - prev_offset;
2923 if (padding_len > 0) {
2924 const llvm_array_ty = o.context.intType(8).arrayType(@as(c_uint, @intCast(padding_len)));
2925 try llvm_field_types.append(gpa, llvm_array_ty);
3338 offset += field_ty.toType().abiSize(mod);
29263339 }
2927 const field_llvm_ty = try o.lowerType(field.ty);
2928 try llvm_field_types.append(gpa, field_llvm_ty);
2929
2930 offset += field.ty.abiSize(mod);
2931 }
2932 {
2933 const prev_offset = offset;
2934 offset = std.mem.alignForward(u64, offset, big_align);
2935 const padding_len = offset - prev_offset;
2936 if (padding_len > 0) {
2937 const llvm_array_ty = o.context.intType(8).arrayType(@as(c_uint, @intCast(padding_len)));
2938 try llvm_field_types.append(gpa, llvm_array_ty);
3340 {
3341 const prev_offset = offset;
3342 offset = std.mem.alignForward(u64, offset, big_align);
3343 const padding_len = offset - prev_offset;
3344 if (padding_len > 0) try llvm_field_types.append(
3345 o.gpa,
3346 try o.builder.arrayType(padding_len, .i8),
3347 );
29393348 }
2940 }
2941
2942 llvm_struct_ty.structSetBody(
2943 llvm_field_types.items.ptr,
2944 @as(c_uint, @intCast(llvm_field_types.items.len)),
2945 llvm.Bool.fromBool(any_underaligned_fields),
2946 );
2947
2948 return llvm_struct_ty;
2949 },
2950 .Union => {
2951 const gop = try o.type_map.getOrPut(gpa, t.toIntern());
2952 if (gop.found_existing) return gop.value_ptr.*;
3349 return o.builder.structType(.normal, llvm_field_types.items);
3350 },
3351 .union_type => |union_type| {
3352 const gop = try o.type_map.getOrPut(o.gpa, t.toIntern());
3353 if (gop.found_existing) return gop.value_ptr.*;
29533354
2954 const layout = t.unionGetLayout(mod);
2955 const union_obj = mod.typeToUnion(t).?;
3355 const union_obj = mod.unionPtr(union_type.index);
3356 const layout = union_obj.getLayout(mod, union_type.hasTag());
29563357
2957 if (union_obj.layout == .Packed) {
2958 const bitsize = @as(c_uint, @intCast(t.bitSize(mod)));
2959 const int_llvm_ty = o.context.intType(bitsize);
2960 gop.value_ptr.* = int_llvm_ty;
2961 return int_llvm_ty;
2962 }
2963
2964 if (layout.payload_size == 0) {
2965 const enum_tag_llvm_ty = try o.lowerType(union_obj.tag_ty);
2966 gop.value_ptr.* = enum_tag_llvm_ty;
2967 return enum_tag_llvm_ty;
2968 }
3358 if (union_obj.layout == .Packed) {
3359 const int_ty = try o.builder.intType(@intCast(t.bitSize(mod)));
3360 gop.value_ptr.* = int_ty;
3361 return int_ty;
3362 }
29693363
2970 const name = mod.intern_pool.stringToSlice(try union_obj.getFullyQualifiedName(mod));
3364 if (layout.payload_size == 0) {
3365 const enum_tag_ty = try o.lowerType(union_obj.tag_ty);
3366 gop.value_ptr.* = enum_tag_ty;
3367 return enum_tag_ty;
3368 }
29713369
2972 const llvm_union_ty = o.context.structCreateNamed(name);
2973 gop.value_ptr.* = llvm_union_ty; // must be done before any recursive calls
3370 const name = try o.builder.string(mod.intern_pool.stringToSlice(
3371 try union_obj.getFullyQualifiedName(mod),
3372 ));
3373 const ty = try o.builder.opaqueType(name);
3374 gop.value_ptr.* = ty; // must be done before any recursive calls
29743375
2975 const aligned_field = union_obj.fields.values()[layout.most_aligned_field];
2976 const llvm_aligned_field_ty = try o.lowerType(aligned_field.ty);
3376 const aligned_field = union_obj.fields.values()[layout.most_aligned_field];
3377 const aligned_field_ty = try o.lowerType(aligned_field.ty);
29773378
2978 const llvm_payload_ty = t: {
2979 if (layout.most_aligned_field_size == layout.payload_size) {
2980 break :t llvm_aligned_field_ty;
2981 }
2982 const padding_len = if (layout.tag_size == 0)
2983 @as(c_uint, @intCast(layout.abi_size - layout.most_aligned_field_size))
2984 else
2985 @as(c_uint, @intCast(layout.payload_size - layout.most_aligned_field_size));
2986 const fields: [2]*llvm.Type = .{
2987 llvm_aligned_field_ty,
2988 o.context.intType(8).arrayType(padding_len),
3379 const payload_ty = ty: {
3380 if (layout.most_aligned_field_size == layout.payload_size) {
3381 break :ty aligned_field_ty;
3382 }
3383 const padding_len = if (layout.tag_size == 0)
3384 layout.abi_size - layout.most_aligned_field_size
3385 else
3386 layout.payload_size - layout.most_aligned_field_size;
3387 break :ty try o.builder.structType(.@"packed", &.{
3388 aligned_field_ty,
3389 try o.builder.arrayType(padding_len, .i8),
3390 });
29893391 };
2990 break :t o.context.structType(&fields, fields.len, .True);
2991 };
29923392
2993 if (layout.tag_size == 0) {
2994 var llvm_fields: [1]*llvm.Type = .{llvm_payload_ty};
2995 llvm_union_ty.structSetBody(&llvm_fields, llvm_fields.len, .False);
2996 return llvm_union_ty;
2997 }
2998 const enum_tag_llvm_ty = try o.lowerType(union_obj.tag_ty);
3393 if (layout.tag_size == 0) {
3394 try o.builder.namedTypeSetBody(
3395 ty,
3396 try o.builder.structType(.normal, &.{payload_ty}),
3397 );
3398 return ty;
3399 }
3400 const enum_tag_ty = try o.lowerType(union_obj.tag_ty);
29993401
3000 // Put the tag before or after the payload depending on which one's
3001 // alignment is greater.
3002 var llvm_fields: [3]*llvm.Type = undefined;
3003 var llvm_fields_len: c_uint = 2;
3402 // Put the tag before or after the payload depending on which one's
3403 // alignment is greater.
3404 var llvm_fields: [3]Builder.Type = undefined;
3405 var llvm_fields_len: usize = 2;
30043406
3005 if (layout.tag_align >= layout.payload_align) {
3006 llvm_fields = .{ enum_tag_llvm_ty, llvm_payload_ty, undefined };
3007 } else {
3008 llvm_fields = .{ llvm_payload_ty, enum_tag_llvm_ty, undefined };
3009 }
3407 if (layout.tag_align >= layout.payload_align) {
3408 llvm_fields = .{ enum_tag_ty, payload_ty, .none };
3409 } else {
3410 llvm_fields = .{ payload_ty, enum_tag_ty, .none };
3411 }
30103412
3011 // Insert padding to make the LLVM struct ABI size match the Zig union ABI size.
3012 if (layout.padding != 0) {
3013 llvm_fields[2] = o.context.intType(8).arrayType(layout.padding);
3014 llvm_fields_len = 3;
3015 }
3413 // Insert padding to make the LLVM struct ABI size match the Zig union ABI size.
3414 if (layout.padding != 0) {
3415 llvm_fields[llvm_fields_len] = try o.builder.arrayType(layout.padding, .i8);
3416 llvm_fields_len += 1;
3417 }
30163418
3017 llvm_union_ty.structSetBody(&llvm_fields, llvm_fields_len, .False);
3018 return llvm_union_ty;
3419 try o.builder.namedTypeSetBody(
3420 ty,
3421 try o.builder.structType(.normal, llvm_fields[0..llvm_fields_len]),
3422 );
3423 return ty;
3424 },
3425 .opaque_type => |opaque_type| {
3426 const gop = try o.type_map.getOrPut(o.gpa, t.toIntern());
3427 if (!gop.found_existing) {
3428 const name = try o.builder.string(mod.intern_pool.stringToSlice(
3429 try mod.opaqueFullyQualifiedName(opaque_type),
3430 ));
3431 gop.value_ptr.* = try o.builder.opaqueType(name);
3432 }
3433 return gop.value_ptr.*;
3434 },
3435 .enum_type => |enum_type| try o.lowerType(enum_type.tag_ty.toType()),
3436 .func_type => |func_type| try o.lowerTypeFn(func_type),
3437 .error_set_type, .inferred_error_set_type => Builder.Type.err_int,
3438 // values, not types
3439 .undef,
3440 .runtime_value,
3441 .simple_value,
3442 .variable,
3443 .extern_func,
3444 .func,
3445 .int,
3446 .err,
3447 .error_union,
3448 .enum_literal,
3449 .enum_tag,
3450 .empty_enum_value,
3451 .float,
3452 .ptr,
3453 .opt,
3454 .aggregate,
3455 .un,
3456 // memoization, not types
3457 .memoized_call,
3458 => unreachable,
30193459 },
3020 .Fn => return lowerTypeFn(o, t),
3021 .ComptimeInt => unreachable,
3022 .ComptimeFloat => unreachable,
3023 .Type => unreachable,
3024 .Undefined => unreachable,
3025 .Null => unreachable,
3026 .EnumLiteral => unreachable,
3460 };
3461 }
30273462
3028 .Frame => @panic("TODO implement llvmType for Frame types"),
3029 .AnyFrame => @panic("TODO implement llvmType for AnyFrame types"),
3030 }
3463 /// Use this instead of lowerType when you want to handle correctly the case of elem_ty
3464 /// being a zero bit type, but it should still be lowered as an i8 in such case.
3465 /// There are other similar cases handled here as well.
3466 fn lowerPtrElemTy(o: *Object, elem_ty: Type) Allocator.Error!Builder.Type {
3467 const mod = o.module;
3468 const lower_elem_ty = switch (elem_ty.zigTypeTag(mod)) {
3469 .Opaque => true,
3470 .Fn => !mod.typeToFunc(elem_ty).?.is_generic,
3471 .Array => elem_ty.childType(mod).hasRuntimeBitsIgnoreComptime(mod),
3472 else => elem_ty.hasRuntimeBitsIgnoreComptime(mod),
3473 };
3474 return if (lower_elem_ty) try o.lowerType(elem_ty) else .i8;
30313475 }
30323476
3033 fn lowerTypeFn(o: *Object, fn_ty: Type) Allocator.Error!*llvm.Type {
3477 fn lowerTypeFn(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type {
30343478 const mod = o.module;
30353479 const ip = &mod.intern_pool;
3036 const fn_info = mod.typeToFunc(fn_ty).?;
3037 const llvm_ret_ty = try lowerFnRetTy(o, fn_info);
3480 const target = mod.getTarget();
3481 const ret_ty = try lowerFnRetTy(o, fn_info);
30383482
3039 var llvm_params = std.ArrayList(*llvm.Type).init(o.gpa);
3040 defer llvm_params.deinit();
3483 var llvm_params = std.ArrayListUnmanaged(Builder.Type){};
3484 defer llvm_params.deinit(o.gpa);
30413485
30423486 if (firstParamSRet(fn_info, mod)) {
3043 try llvm_params.append(o.context.pointerType(0));
3487 try llvm_params.append(o.gpa, .ptr);
30443488 }
30453489
30463490 if (fn_info.return_type.toType().isError(mod) and
30473491 mod.comp.bin_file.options.error_return_tracing)
30483492 {
30493493 const ptr_ty = try mod.singleMutPtrType(try o.getStackTraceType());
3050 try llvm_params.append(try o.lowerType(ptr_ty));
3494 try llvm_params.append(o.gpa, try o.lowerType(ptr_ty));
30513495 }
30523496
30533497 var it = iterateParamTypes(o, fn_info);
3054 while (it.next()) |lowering| switch (lowering) {
3498 while (try it.next()) |lowering| switch (lowering) {
30553499 .no_bits => continue,
30563500 .byval => {
30573501 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
3058 try llvm_params.append(try o.lowerType(param_ty));
3502 try llvm_params.append(o.gpa, try o.lowerType(param_ty));
30593503 },
30603504 .byref, .byref_mut => {
3061 try llvm_params.append(o.context.pointerType(0));
3505 try llvm_params.append(o.gpa, .ptr);
30623506 },
30633507 .abi_sized_int => {
30643508 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
3065 const abi_size = @as(c_uint, @intCast(param_ty.abiSize(mod)));
3066 try llvm_params.append(o.context.intType(abi_size * 8));
3509 try llvm_params.append(o.gpa, try o.builder.intType(
3510 @intCast(param_ty.abiSize(mod) * 8),
3511 ));
30673512 },
30683513 .slice => {
30693514 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
3070 const ptr_ty = if (param_ty.zigTypeTag(mod) == .Optional)
3071 param_ty.optionalChild(mod).slicePtrFieldType(mod)
3072 else
3073 param_ty.slicePtrFieldType(mod);
3074 const ptr_llvm_ty = try o.lowerType(ptr_ty);
3075 const len_llvm_ty = try o.lowerType(Type.usize);
3076
3077 try llvm_params.ensureUnusedCapacity(2);
3078 llvm_params.appendAssumeCapacity(ptr_llvm_ty);
3079 llvm_params.appendAssumeCapacity(len_llvm_ty);
3515 try llvm_params.appendSlice(o.gpa, &.{
3516 try o.builder.ptrType(toLlvmAddressSpace(param_ty.ptrAddressSpace(mod), target)),
3517 try o.lowerType(Type.usize),
3518 });
30803519 },
30813520 .multiple_llvm_types => {
3082 try llvm_params.appendSlice(it.llvm_types_buffer[0..it.llvm_types_len]);
3521 try llvm_params.appendSlice(o.gpa, it.types_buffer[0..it.types_len]);
30833522 },
30843523 .as_u16 => {
3085 try llvm_params.append(o.context.intType(16));
3524 try llvm_params.append(o.gpa, .i16);
30863525 },
30873526 .float_array => |count| {
30883527 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
30893528 const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(param_ty, mod).?);
3090 const field_count = @as(c_uint, @intCast(count));
3091 const arr_ty = float_ty.arrayType(field_count);
3092 try llvm_params.append(arr_ty);
3529 try llvm_params.append(o.gpa, try o.builder.arrayType(count, float_ty));
30933530 },
30943531 .i32_array, .i64_array => |arr_len| {
3095 const elem_size: u8 = if (lowering == .i32_array) 32 else 64;
3096 const arr_ty = o.context.intType(elem_size).arrayType(arr_len);
3097 try llvm_params.append(arr_ty);
3532 try llvm_params.append(o.gpa, try o.builder.arrayType(arr_len, switch (lowering) {
3533 .i32_array => .i32,
3534 .i64_array => .i64,
3535 else => unreachable,
3536 }));
30983537 },
30993538 };
31003539
3101 return llvm.functionType(
3102 llvm_ret_ty,
3103 llvm_params.items.ptr,
3104 @as(c_uint, @intCast(llvm_params.items.len)),
3105 llvm.Bool.fromBool(fn_info.is_var_args),
3540 return o.builder.fnType(
3541 ret_ty,
3542 llvm_params.items,
3543 if (fn_info.is_var_args) .vararg else .normal,
31063544 );
31073545 }
31083546
3109 /// Use this instead of lowerType when you want to handle correctly the case of elem_ty
3110 /// being a zero bit type, but it should still be lowered as an i8 in such case.
3111 /// There are other similar cases handled here as well.
3112 fn lowerPtrElemTy(o: *Object, elem_ty: Type) Allocator.Error!*llvm.Type {
3547 fn lowerValue(o: *Object, arg_val: InternPool.Index) Error!Builder.Constant {
31133548 const mod = o.module;
3114 const lower_elem_ty = switch (elem_ty.zigTypeTag(mod)) {
3115 .Opaque => true,
3116 .Fn => !mod.typeToFunc(elem_ty).?.is_generic,
3117 .Array => elem_ty.childType(mod).hasRuntimeBitsIgnoreComptime(mod),
3118 else => elem_ty.hasRuntimeBitsIgnoreComptime(mod),
3119 };
3120 const llvm_elem_ty = if (lower_elem_ty)
3121 try o.lowerType(elem_ty)
3122 else
3123 o.context.intType(8);
3124
3125 return llvm_elem_ty;
3126 }
3127
3128 fn lowerValue(o: *Object, arg_tv: TypedValue) Error!*llvm.Value {
3129 const mod = o.module;
3130 const gpa = o.gpa;
31313549 const target = mod.getTarget();
3132 var tv = arg_tv;
3133 switch (mod.intern_pool.indexToKey(tv.val.toIntern())) {
3134 .runtime_value => |rt| tv.val = rt.val.toValue(),
3550
3551 var val = arg_val.toValue();
3552 const arg_val_key = mod.intern_pool.indexToKey(arg_val);
3553 switch (arg_val_key) {
3554 .runtime_value => |rt| val = rt.val.toValue(),
31353555 else => {},
31363556 }
3137 if (tv.val.isUndefDeep(mod)) {
3138 const llvm_type = try o.lowerType(tv.ty);
3139 return llvm_type.getUndef();
3557 if (val.isUndefDeep(mod)) {
3558 return o.builder.undefConst(try o.lowerType(arg_val_key.typeOf().toType()));
31403559 }
31413560
3142 switch (mod.intern_pool.indexToKey(tv.val.toIntern())) {
3561 const val_key = mod.intern_pool.indexToKey(val.toIntern());
3562 const ty = val_key.typeOf().toType();
3563 return switch (val_key) {
31433564 .int_type,
31443565 .ptr_type,
31453566 .array_type,
......@@ -3167,10 +3588,8 @@ pub const Object = struct {
31673588 .@"unreachable",
31683589 .generic_poison,
31693590 => unreachable, // non-runtime values
3170 .false, .true => {
3171 const llvm_type = try o.lowerType(tv.ty);
3172 return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull();
3173 },
3591 .false => .false,
3592 .true => .true,
31743593 },
31753594 .variable,
31763595 .enum_literal,
......@@ -3180,309 +3599,276 @@ pub const Object = struct {
31803599 const fn_decl_index = extern_func.decl;
31813600 const fn_decl = mod.declPtr(fn_decl_index);
31823601 try mod.markDeclAlive(fn_decl);
3183 return o.resolveLlvmFunction(fn_decl_index);
3602 const function_index = try o.resolveLlvmFunction(fn_decl_index);
3603 return function_index.ptrConst(&o.builder).global.toConst();
31843604 },
31853605 .func => |func| {
31863606 const fn_decl_index = func.owner_decl;
31873607 const fn_decl = mod.declPtr(fn_decl_index);
31883608 try mod.markDeclAlive(fn_decl);
3189 return o.resolveLlvmFunction(fn_decl_index);
3609 const function_index = try o.resolveLlvmFunction(fn_decl_index);
3610 return function_index.ptrConst(&o.builder).global.toConst();
31903611 },
31913612 .int => {
31923613 var bigint_space: Value.BigIntSpace = undefined;
3193 const bigint = tv.val.toBigInt(&bigint_space, mod);
3194 return lowerBigInt(o, tv.ty, bigint);
3614 const bigint = val.toBigInt(&bigint_space, mod);
3615 return lowerBigInt(o, ty, bigint);
31953616 },
31963617 .err => |err| {
3197 const llvm_ty = try o.lowerType(Type.anyerror);
31983618 const int = try mod.getErrorValue(err.name);
3199 return llvm_ty.constInt(int, .False);
3619 const llvm_int = try o.builder.intConst(Builder.Type.err_int, int);
3620 return llvm_int;
32003621 },
32013622 .error_union => |error_union| {
3202 const err_tv: TypedValue = switch (error_union.val) {
3203 .err_name => |err_name| .{
3204 .ty = tv.ty.errorUnionSet(mod),
3205 .val = (try mod.intern(.{ .err = .{
3206 .ty = tv.ty.errorUnionSet(mod).toIntern(),
3207 .name = err_name,
3208 } })).toValue(),
3209 },
3210 .payload => .{
3211 .ty = Type.err_int,
3212 .val = try mod.intValue(Type.err_int, 0),
3213 },
3623 const err_val = switch (error_union.val) {
3624 .err_name => |err_name| try mod.intern(.{ .err = .{
3625 .ty = ty.errorUnionSet(mod).toIntern(),
3626 .name = err_name,
3627 } }),
3628 .payload => (try mod.intValue(Type.err_int, 0)).toIntern(),
32143629 };
3215 const payload_type = tv.ty.errorUnionPayload(mod);
3630 const payload_type = ty.errorUnionPayload(mod);
32163631 if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) {
32173632 // We use the error type directly as the type.
3218 return o.lowerValue(err_tv);
3633 return o.lowerValue(err_val);
32193634 }
32203635
32213636 const payload_align = payload_type.abiAlignment(mod);
3222 const error_align = err_tv.ty.abiAlignment(mod);
3223 const llvm_error_value = try o.lowerValue(err_tv);
3224 const llvm_payload_value = try o.lowerValue(.{
3225 .ty = payload_type,
3226 .val = switch (error_union.val) {
3227 .err_name => try mod.intern(.{ .undef = payload_type.toIntern() }),
3228 .payload => |payload| payload,
3229 }.toValue(),
3637 const error_align = Type.err_int.abiAlignment(mod);
3638 const llvm_error_value = try o.lowerValue(err_val);
3639 const llvm_payload_value = try o.lowerValue(switch (error_union.val) {
3640 .err_name => try mod.intern(.{ .undef = payload_type.toIntern() }),
3641 .payload => |payload| payload,
32303642 });
3231 var fields_buf: [3]*llvm.Value = undefined;
3232
3233 const llvm_ty = try o.lowerType(tv.ty);
3234 const llvm_field_count = llvm_ty.countStructElementTypes();
3235 if (llvm_field_count > 2) {
3236 assert(llvm_field_count == 3);
3237 fields_buf[2] = llvm_ty.structGetTypeAtIndex(2).getUndef();
3238 }
32393643
3644 var fields: [3]Builder.Type = undefined;
3645 var vals: [3]Builder.Constant = undefined;
32403646 if (error_align > payload_align) {
3241 fields_buf[0] = llvm_error_value;
3242 fields_buf[1] = llvm_payload_value;
3243 return o.context.constStruct(&fields_buf, llvm_field_count, .False);
3647 vals[0] = llvm_error_value;
3648 vals[1] = llvm_payload_value;
32443649 } else {
3245 fields_buf[0] = llvm_payload_value;
3246 fields_buf[1] = llvm_error_value;
3247 return o.context.constStruct(&fields_buf, llvm_field_count, .False);
3650 vals[0] = llvm_payload_value;
3651 vals[1] = llvm_error_value;
32483652 }
3249 },
3250 .enum_tag => {
3251 const int_val = try tv.intFromEnum(mod);
3252
3253 var bigint_space: Value.BigIntSpace = undefined;
3254 const bigint = int_val.toBigInt(&bigint_space, mod);
3255
3256 const int_info = tv.ty.intInfo(mod);
3257 const llvm_type = o.context.intType(int_info.bits);
3258
3259 const unsigned_val = v: {
3260 if (bigint.limbs.len == 1) {
3261 break :v llvm_type.constInt(bigint.limbs[0], .False);
3262 }
3263 if (@sizeOf(usize) == @sizeOf(u64)) {
3264 break :v llvm_type.constIntOfArbitraryPrecision(
3265 @as(c_uint, @intCast(bigint.limbs.len)),
3266 bigint.limbs.ptr,
3267 );
3268 }
3269 @panic("TODO implement bigint to llvm int for 32-bit compiler builds");
3270 };
3271 if (!bigint.positive) {
3272 return llvm.constNeg(unsigned_val);
3653 fields[0] = vals[0].typeOf(&o.builder);
3654 fields[1] = vals[1].typeOf(&o.builder);
3655
3656 const llvm_ty = try o.lowerType(ty);
3657 const llvm_ty_fields = llvm_ty.structFields(&o.builder);
3658 if (llvm_ty_fields.len > 2) {
3659 assert(llvm_ty_fields.len == 3);
3660 fields[2] = llvm_ty_fields[2];
3661 vals[2] = try o.builder.undefConst(fields[2]);
32733662 }
3274 return unsigned_val;
3663 return o.builder.structConst(try o.builder.structType(
3664 llvm_ty.structKind(&o.builder),
3665 fields[0..llvm_ty_fields.len],
3666 ), vals[0..llvm_ty_fields.len]);
32753667 },
3276 .float => {
3277 const llvm_ty = try o.lowerType(tv.ty);
3278 switch (tv.ty.floatBits(target)) {
3279 16 => {
3280 const repr = @as(u16, @bitCast(tv.val.toFloat(f16, mod)));
3281 const llvm_i16 = o.context.intType(16);
3282 const int = llvm_i16.constInt(repr, .False);
3283 return int.constBitCast(llvm_ty);
3284 },
3285 32 => {
3286 const repr = @as(u32, @bitCast(tv.val.toFloat(f32, mod)));
3287 const llvm_i32 = o.context.intType(32);
3288 const int = llvm_i32.constInt(repr, .False);
3289 return int.constBitCast(llvm_ty);
3290 },
3291 64 => {
3292 const repr = @as(u64, @bitCast(tv.val.toFloat(f64, mod)));
3293 const llvm_i64 = o.context.intType(64);
3294 const int = llvm_i64.constInt(repr, .False);
3295 return int.constBitCast(llvm_ty);
3296 },
3297 80 => {
3298 const float = tv.val.toFloat(f80, mod);
3299 const repr = std.math.break_f80(float);
3300 const llvm_i80 = o.context.intType(80);
3301 var x = llvm_i80.constInt(repr.exp, .False);
3302 x = x.constShl(llvm_i80.constInt(64, .False));
3303 x = x.constOr(llvm_i80.constInt(repr.fraction, .False));
3304 if (backendSupportsF80(target)) {
3305 return x.constBitCast(llvm_ty);
3306 } else {
3307 return x;
3308 }
3309 },
3310 128 => {
3311 var buf: [2]u64 = @as([2]u64, @bitCast(tv.val.toFloat(f128, mod)));
3312 // LLVM seems to require that the lower half of the f128 be placed first
3313 // in the buffer.
3314 if (native_endian == .Big) {
3315 std.mem.swap(u64, &buf[0], &buf[1]);
3316 }
3317 const int = o.context.intType(128).constIntOfArbitraryPrecision(buf.len, &buf);
3318 return int.constBitCast(llvm_ty);
3319 },
3320 else => unreachable,
3321 }
3668 .enum_tag => |enum_tag| o.lowerValue(enum_tag.int),
3669 .float => switch (ty.floatBits(target)) {
3670 16 => if (backendSupportsF16(target))
3671 try o.builder.halfConst(val.toFloat(f16, mod))
3672 else
3673 try o.builder.intConst(.i16, @as(i16, @bitCast(val.toFloat(f16, mod)))),
3674 32 => try o.builder.floatConst(val.toFloat(f32, mod)),
3675 64 => try o.builder.doubleConst(val.toFloat(f64, mod)),
3676 80 => if (backendSupportsF80(target))
3677 try o.builder.x86_fp80Const(val.toFloat(f80, mod))
3678 else
3679 try o.builder.intConst(.i80, @as(i80, @bitCast(val.toFloat(f80, mod)))),
3680 128 => try o.builder.fp128Const(val.toFloat(f128, mod)),
3681 else => unreachable,
33223682 },
33233683 .ptr => |ptr| {
3324 const ptr_tv: TypedValue = switch (ptr.len) {
3325 .none => tv,
3326 else => .{ .ty = tv.ty.slicePtrFieldType(mod), .val = tv.val.slicePtr(mod) },
3684 const ptr_ty = switch (ptr.len) {
3685 .none => ty,
3686 else => ty.slicePtrFieldType(mod),
33273687 };
3328 const llvm_ptr_val = switch (ptr.addr) {
3329 .decl => |decl| try o.lowerDeclRefValue(ptr_tv, decl),
3330 .mut_decl => |mut_decl| try o.lowerDeclRefValue(ptr_tv, mut_decl.decl),
3331 .int => |int| try o.lowerIntAsPtr(int.toValue()),
3688 const ptr_val = switch (ptr.addr) {
3689 .decl => |decl| try o.lowerDeclRefValue(ptr_ty, decl),
3690 .mut_decl => |mut_decl| try o.lowerDeclRefValue(ptr_ty, mut_decl.decl),
3691 .int => |int| try o.lowerIntAsPtr(int),
33323692 .eu_payload,
33333693 .opt_payload,
33343694 .elem,
33353695 .field,
3336 => try o.lowerParentPtr(ptr_tv.val, ptr_tv.ty.ptrInfo(mod).packed_offset.bit_offset % 8 == 0),
3696 => try o.lowerParentPtr(val, ty.ptrInfo(mod).packed_offset.bit_offset % 8 == 0),
33373697 .comptime_field => unreachable,
33383698 };
33393699 switch (ptr.len) {
3340 .none => return llvm_ptr_val,
3341 else => {
3342 const fields: [2]*llvm.Value = .{
3343 llvm_ptr_val,
3344 try o.lowerValue(.{ .ty = Type.usize, .val = ptr.len.toValue() }),
3345 };
3346 return o.context.constStruct(&fields, fields.len, .False);
3347 },
3700 .none => return ptr_val,
3701 else => return o.builder.structConst(try o.lowerType(ty), &.{
3702 ptr_val, try o.lowerValue(ptr.len),
3703 }),
33483704 }
33493705 },
33503706 .opt => |opt| {
33513707 comptime assert(optional_layout_version == 3);
3352 const payload_ty = tv.ty.optionalChild(mod);
3708 const payload_ty = ty.optionalChild(mod);
33533709
3354 const llvm_i8 = o.context.intType(8);
3355 const non_null_bit = switch (opt.val) {
3356 .none => llvm_i8.constNull(),
3357 else => llvm_i8.constInt(1, .False),
3358 };
3710 const non_null_bit = try o.builder.intConst(.i8, @intFromBool(opt.val != .none));
33593711 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
33603712 return non_null_bit;
33613713 }
3362 const llvm_ty = try o.lowerType(tv.ty);
3363 if (tv.ty.optionalReprIsPayload(mod)) return switch (opt.val) {
3364 .none => llvm_ty.constNull(),
3365 else => |payload| o.lowerValue(.{ .ty = payload_ty, .val = payload.toValue() }),
3714 const llvm_ty = try o.lowerType(ty);
3715 if (ty.optionalReprIsPayload(mod)) return switch (opt.val) {
3716 .none => switch (llvm_ty.tag(&o.builder)) {
3717 .integer => try o.builder.intConst(llvm_ty, 0),
3718 .pointer => try o.builder.nullConst(llvm_ty),
3719 .structure => try o.builder.zeroInitConst(llvm_ty),
3720 else => unreachable,
3721 },
3722 else => |payload| try o.lowerValue(payload),
33663723 };
33673724 assert(payload_ty.zigTypeTag(mod) != .Fn);
33683725
3369 const llvm_field_count = llvm_ty.countStructElementTypes();
3370 var fields_buf: [3]*llvm.Value = undefined;
3371 fields_buf[0] = try o.lowerValue(.{
3372 .ty = payload_ty,
3373 .val = switch (opt.val) {
3374 .none => try mod.intern(.{ .undef = payload_ty.toIntern() }),
3375 else => |payload| payload,
3376 }.toValue(),
3726 var fields: [3]Builder.Type = undefined;
3727 var vals: [3]Builder.Constant = undefined;
3728 vals[0] = try o.lowerValue(switch (opt.val) {
3729 .none => try mod.intern(.{ .undef = payload_ty.toIntern() }),
3730 else => |payload| payload,
33773731 });
3378 fields_buf[1] = non_null_bit;
3379 if (llvm_field_count > 2) {
3380 assert(llvm_field_count == 3);
3381 fields_buf[2] = llvm_ty.structGetTypeAtIndex(2).getUndef();
3732 vals[1] = non_null_bit;
3733 fields[0] = vals[0].typeOf(&o.builder);
3734 fields[1] = vals[1].typeOf(&o.builder);
3735
3736 const llvm_ty_fields = llvm_ty.structFields(&o.builder);
3737 if (llvm_ty_fields.len > 2) {
3738 assert(llvm_ty_fields.len == 3);
3739 fields[2] = llvm_ty_fields[2];
3740 vals[2] = try o.builder.undefConst(fields[2]);
33823741 }
3383 return o.context.constStruct(&fields_buf, llvm_field_count, .False);
3742 return o.builder.structConst(try o.builder.structType(
3743 llvm_ty.structKind(&o.builder),
3744 fields[0..llvm_ty_fields.len],
3745 ), vals[0..llvm_ty_fields.len]);
33843746 },
3385 .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(tv.ty.toIntern())) {
3386 .array_type => switch (aggregate.storage) {
3387 .bytes => |bytes| return o.context.constString(
3388 bytes.ptr,
3389 @as(c_uint, @intCast(tv.ty.arrayLenIncludingSentinel(mod))),
3390 .True, // Don't null terminate. Bytes has the sentinel, if any.
3391 ),
3392 .elems => |elem_vals| {
3393 const elem_ty = tv.ty.childType(mod);
3394 const llvm_elems = try gpa.alloc(*llvm.Value, elem_vals.len);
3395 defer gpa.free(llvm_elems);
3747 .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(ty.toIntern())) {
3748 .array_type => |array_type| switch (aggregate.storage) {
3749 .bytes => |bytes| try o.builder.stringConst(try o.builder.string(bytes)),
3750 .elems => |elems| {
3751 const array_ty = try o.lowerType(ty);
3752 const elem_ty = array_ty.childType(&o.builder);
3753 assert(elems.len == array_ty.aggregateLen(&o.builder));
3754
3755 const ExpectedContents = extern struct {
3756 vals: [Builder.expected_fields_len]Builder.Constant,
3757 fields: [Builder.expected_fields_len]Builder.Type,
3758 };
3759 var stack align(@max(
3760 @alignOf(std.heap.StackFallbackAllocator(0)),
3761 @alignOf(ExpectedContents),
3762 )) = std.heap.stackFallback(@sizeOf(ExpectedContents), o.gpa);
3763 const allocator = stack.get();
3764 const vals = try allocator.alloc(Builder.Constant, elems.len);
3765 defer allocator.free(vals);
3766 const fields = try allocator.alloc(Builder.Type, elems.len);
3767 defer allocator.free(fields);
3768
33963769 var need_unnamed = false;
3397 for (elem_vals, 0..) |elem_val, i| {
3398 llvm_elems[i] = try o.lowerValue(.{ .ty = elem_ty, .val = elem_val.toValue() });
3399 need_unnamed = need_unnamed or o.isUnnamedType(elem_ty, llvm_elems[i]);
3400 }
3401 if (need_unnamed) {
3402 return o.context.constStruct(
3403 llvm_elems.ptr,
3404 @as(c_uint, @intCast(llvm_elems.len)),
3405 .True,
3406 );
3407 } else {
3408 const llvm_elem_ty = try o.lowerType(elem_ty);
3409 return llvm_elem_ty.constArray(
3410 llvm_elems.ptr,
3411 @as(c_uint, @intCast(llvm_elems.len)),
3412 );
3770 for (vals, fields, elems) |*result_val, *result_field, elem| {
3771 result_val.* = try o.lowerValue(elem);
3772 result_field.* = result_val.typeOf(&o.builder);
3773 if (result_field.* != elem_ty) need_unnamed = true;
34133774 }
3775 return if (need_unnamed) try o.builder.structConst(
3776 try o.builder.structType(.normal, fields),
3777 vals,
3778 ) else try o.builder.arrayConst(array_ty, vals);
34143779 },
3415 .repeated_elem => |val| {
3416 const elem_ty = tv.ty.childType(mod);
3417 const sentinel = tv.ty.sentinel(mod);
3418 const len = @as(usize, @intCast(tv.ty.arrayLen(mod)));
3419 const len_including_sent = len + @intFromBool(sentinel != null);
3420 const llvm_elems = try gpa.alloc(*llvm.Value, len_including_sent);
3421 defer gpa.free(llvm_elems);
3780 .repeated_elem => |elem| {
3781 const len: usize = @intCast(array_type.len);
3782 const len_including_sentinel: usize =
3783 @intCast(len + @intFromBool(array_type.sentinel != .none));
3784 const array_ty = try o.lowerType(ty);
3785 const elem_ty = array_ty.childType(&o.builder);
3786
3787 const ExpectedContents = extern struct {
3788 vals: [Builder.expected_fields_len]Builder.Constant,
3789 fields: [Builder.expected_fields_len]Builder.Type,
3790 };
3791 var stack align(@max(
3792 @alignOf(std.heap.StackFallbackAllocator(0)),
3793 @alignOf(ExpectedContents),
3794 )) = std.heap.stackFallback(@sizeOf(ExpectedContents), o.gpa);
3795 const allocator = stack.get();
3796 const vals = try allocator.alloc(Builder.Constant, len_including_sentinel);
3797 defer allocator.free(vals);
3798 const fields = try allocator.alloc(Builder.Type, len_including_sentinel);
3799 defer allocator.free(fields);
34223800
34233801 var need_unnamed = false;
3424 if (len != 0) {
3425 for (llvm_elems[0..len]) |*elem| {
3426 elem.* = try o.lowerValue(.{ .ty = elem_ty, .val = val.toValue() });
3427 }
3428 need_unnamed = need_unnamed or o.isUnnamedType(elem_ty, llvm_elems[0]);
3429 }
3430
3431 if (sentinel) |sent| {
3432 llvm_elems[len] = try o.lowerValue(.{ .ty = elem_ty, .val = sent });
3433 need_unnamed = need_unnamed or o.isUnnamedType(elem_ty, llvm_elems[len]);
3802 @memset(vals[0..len], try o.lowerValue(elem));
3803 @memset(fields[0..len], vals[0].typeOf(&o.builder));
3804 if (fields[0] != elem_ty) need_unnamed = true;
3805
3806 if (array_type.sentinel != .none) {
3807 vals[len] = try o.lowerValue(array_type.sentinel);
3808 fields[len] = vals[len].typeOf(&o.builder);
3809 if (fields[len] != elem_ty) need_unnamed = true;
34343810 }
34353811
3436 if (need_unnamed) {
3437 return o.context.constStruct(
3438 llvm_elems.ptr,
3439 @as(c_uint, @intCast(llvm_elems.len)),
3440 .True,
3441 );
3442 } else {
3443 const llvm_elem_ty = try o.lowerType(elem_ty);
3444 return llvm_elem_ty.constArray(
3445 llvm_elems.ptr,
3446 @as(c_uint, @intCast(llvm_elems.len)),
3447 );
3448 }
3812 return if (need_unnamed) try o.builder.structConst(
3813 try o.builder.structType(.@"packed", fields),
3814 vals,
3815 ) else try o.builder.arrayConst(array_ty, vals);
34493816 },
34503817 },
34513818 .vector_type => |vector_type| {
3452 const elem_ty = vector_type.child.toType();
3453 const llvm_elems = try gpa.alloc(*llvm.Value, vector_type.len);
3454 defer gpa.free(llvm_elems);
3455 const llvm_i8 = o.context.intType(8);
3456 for (llvm_elems, 0..) |*llvm_elem, i| {
3457 llvm_elem.* = switch (aggregate.storage) {
3458 .bytes => |bytes| llvm_i8.constInt(bytes[i], .False),
3459 .elems => |elems| try o.lowerValue(.{
3460 .ty = elem_ty,
3461 .val = elems[i].toValue(),
3462 }),
3463 .repeated_elem => |elem| try o.lowerValue(.{
3464 .ty = elem_ty,
3465 .val = elem.toValue(),
3466 }),
3467 };
3819 const vector_ty = try o.lowerType(ty);
3820 switch (aggregate.storage) {
3821 .bytes, .elems => {
3822 const ExpectedContents = [Builder.expected_fields_len]Builder.Constant;
3823 var stack align(@max(
3824 @alignOf(std.heap.StackFallbackAllocator(0)),
3825 @alignOf(ExpectedContents),
3826 )) = std.heap.stackFallback(@sizeOf(ExpectedContents), o.gpa);
3827 const allocator = stack.get();
3828 const vals = try allocator.alloc(Builder.Constant, vector_type.len);
3829 defer allocator.free(vals);
3830
3831 switch (aggregate.storage) {
3832 .bytes => |bytes| for (vals, bytes) |*result_val, byte| {
3833 result_val.* = try o.builder.intConst(.i8, byte);
3834 },
3835 .elems => |elems| for (vals, elems) |*result_val, elem| {
3836 result_val.* = try o.lowerValue(elem);
3837 },
3838 .repeated_elem => unreachable,
3839 }
3840 return o.builder.vectorConst(vector_ty, vals);
3841 },
3842 .repeated_elem => |elem| return o.builder.splatConst(
3843 vector_ty,
3844 try o.lowerValue(elem),
3845 ),
34683846 }
3469 return llvm.constVector(
3470 llvm_elems.ptr,
3471 @as(c_uint, @intCast(llvm_elems.len)),
3472 );
34733847 },
34743848 .anon_struct_type => |tuple| {
3475 var llvm_fields: std.ArrayListUnmanaged(*llvm.Value) = .{};
3476 defer llvm_fields.deinit(gpa);
3849 const struct_ty = try o.lowerType(ty);
3850 const llvm_len = struct_ty.aggregateLen(&o.builder);
34773851
3478 try llvm_fields.ensureUnusedCapacity(gpa, tuple.types.len);
3852 const ExpectedContents = extern struct {
3853 vals: [Builder.expected_fields_len]Builder.Constant,
3854 fields: [Builder.expected_fields_len]Builder.Type,
3855 };
3856 var stack align(@max(
3857 @alignOf(std.heap.StackFallbackAllocator(0)),
3858 @alignOf(ExpectedContents),
3859 )) = std.heap.stackFallback(@sizeOf(ExpectedContents), o.gpa);
3860 const allocator = stack.get();
3861 const vals = try allocator.alloc(Builder.Constant, llvm_len);
3862 defer allocator.free(vals);
3863 const fields = try allocator.alloc(Builder.Type, llvm_len);
3864 defer allocator.free(fields);
34793865
34803866 comptime assert(struct_layout_version == 2);
3867 var llvm_index: usize = 0;
34813868 var offset: u64 = 0;
34823869 var big_align: u32 = 0;
34833870 var need_unnamed = false;
3484
3485 for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| {
3871 for (tuple.types, tuple.values, 0..) |field_ty, field_val, field_index| {
34863872 if (field_val != .none) continue;
34873873 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
34883874
......@@ -3493,20 +3879,20 @@ pub const Object = struct {
34933879
34943880 const padding_len = offset - prev_offset;
34953881 if (padding_len > 0) {
3496 const llvm_array_ty = o.context.intType(8).arrayType(@as(c_uint, @intCast(padding_len)));
34973882 // TODO make this and all other padding elsewhere in debug
34983883 // builds be 0xaa not undef.
3499 llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef());
3884 fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);
3885 vals[llvm_index] = try o.builder.undefConst(fields[llvm_index]);
3886 assert(fields[llvm_index] == struct_ty.structFields(&o.builder)[llvm_index]);
3887 llvm_index += 1;
35003888 }
35013889
3502 const field_llvm_val = try o.lowerValue(.{
3503 .ty = field_ty.toType(),
3504 .val = try tv.val.fieldValue(mod, i),
3505 });
3506
3507 need_unnamed = need_unnamed or o.isUnnamedType(field_ty.toType(), field_llvm_val);
3508
3509 llvm_fields.appendAssumeCapacity(field_llvm_val);
3890 vals[llvm_index] =
3891 try o.lowerValue((try val.fieldValue(mod, field_index)).toIntern());
3892 fields[llvm_index] = vals[llvm_index].typeOf(&o.builder);
3893 if (fields[llvm_index] != struct_ty.structFields(&o.builder)[llvm_index])
3894 need_unnamed = true;
3895 llvm_index += 1;
35103896
35113897 offset += field_ty.toType().abiSize(mod);
35123898 }
......@@ -3515,73 +3901,71 @@ pub const Object = struct {
35153901 offset = std.mem.alignForward(u64, offset, big_align);
35163902 const padding_len = offset - prev_offset;
35173903 if (padding_len > 0) {
3518 const llvm_array_ty = o.context.intType(8).arrayType(@as(c_uint, @intCast(padding_len)));
3519 llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef());
3904 fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);
3905 vals[llvm_index] = try o.builder.undefConst(fields[llvm_index]);
3906 assert(fields[llvm_index] == struct_ty.structFields(&o.builder)[llvm_index]);
3907 llvm_index += 1;
35203908 }
35213909 }
3910 assert(llvm_index == llvm_len);
35223911
3523 if (need_unnamed) {
3524 return o.context.constStruct(
3525 llvm_fields.items.ptr,
3526 @as(c_uint, @intCast(llvm_fields.items.len)),
3527 .False,
3528 );
3529 } else {
3530 const llvm_struct_ty = try o.lowerType(tv.ty);
3531 return llvm_struct_ty.constNamedStruct(
3532 llvm_fields.items.ptr,
3533 @as(c_uint, @intCast(llvm_fields.items.len)),
3534 );
3535 }
3912 return o.builder.structConst(if (need_unnamed)
3913 try o.builder.structType(struct_ty.structKind(&o.builder), fields)
3914 else
3915 struct_ty, vals);
35363916 },
35373917 .struct_type => |struct_type| {
35383918 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3539 const llvm_struct_ty = try o.lowerType(tv.ty);
3540
3919 assert(struct_obj.haveLayout());
3920 const struct_ty = try o.lowerType(ty);
35413921 if (struct_obj.layout == .Packed) {
3542 assert(struct_obj.haveLayout());
3543 const big_bits = struct_obj.backing_int_ty.bitSize(mod);
3544 const int_llvm_ty = o.context.intType(@as(c_uint, @intCast(big_bits)));
3545 const fields = struct_obj.fields.values();
35463922 comptime assert(Type.packed_struct_layout_version == 2);
3547 var running_int: *llvm.Value = int_llvm_ty.constNull();
3923 var running_int = try o.builder.intConst(struct_ty, 0);
35483924 var running_bits: u16 = 0;
3549 for (fields, 0..) |field, i| {
3925 for (struct_obj.fields.values(), 0..) |field, field_index| {
35503926 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
35513927
3552 const non_int_val = try o.lowerValue(.{
3553 .ty = field.ty,
3554 .val = try tv.val.fieldValue(mod, i),
3555 });
3556 const ty_bit_size = @as(u16, @intCast(field.ty.bitSize(mod)));
3557 const small_int_ty = o.context.intType(ty_bit_size);
3558 const small_int_val = if (field.ty.isPtrAtRuntime(mod))
3559 non_int_val.constPtrToInt(small_int_ty)
3560 else
3561 non_int_val.constBitCast(small_int_ty);
3562 const shift_rhs = int_llvm_ty.constInt(running_bits, .False);
3563 // If the field is as large as the entire packed struct, this
3564 // zext would go from, e.g. i16 to i16. This is legal with
3565 // constZExtOrBitCast but not legal with constZExt.
3566 const extended_int_val = small_int_val.constZExtOrBitCast(int_llvm_ty);
3567 const shifted = extended_int_val.constShl(shift_rhs);
3568 running_int = running_int.constOr(shifted);
3928 const non_int_val =
3929 try o.lowerValue((try val.fieldValue(mod, field_index)).toIntern());
3930 const ty_bit_size: u16 = @intCast(field.ty.bitSize(mod));
3931 const small_int_ty = try o.builder.intType(ty_bit_size);
3932 const small_int_val = try o.builder.castConst(
3933 if (field.ty.isPtrAtRuntime(mod)) .ptrtoint else .bitcast,
3934 non_int_val,
3935 small_int_ty,
3936 );
3937 const shift_rhs = try o.builder.intConst(struct_ty, running_bits);
3938 const extended_int_val =
3939 try o.builder.convConst(.unsigned, small_int_val, struct_ty);
3940 const shifted = try o.builder.binConst(.shl, extended_int_val, shift_rhs);
3941 running_int = try o.builder.binConst(.@"or", running_int, shifted);
35693942 running_bits += ty_bit_size;
35703943 }
35713944 return running_int;
35723945 }
3946 const llvm_len = struct_ty.aggregateLen(&o.builder);
35733947
3574 const llvm_field_count = llvm_struct_ty.countStructElementTypes();
3575 var llvm_fields = try std.ArrayListUnmanaged(*llvm.Value).initCapacity(gpa, llvm_field_count);
3576 defer llvm_fields.deinit(gpa);
3948 const ExpectedContents = extern struct {
3949 vals: [Builder.expected_fields_len]Builder.Constant,
3950 fields: [Builder.expected_fields_len]Builder.Type,
3951 };
3952 var stack align(@max(
3953 @alignOf(std.heap.StackFallbackAllocator(0)),
3954 @alignOf(ExpectedContents),
3955 )) = std.heap.stackFallback(@sizeOf(ExpectedContents), o.gpa);
3956 const allocator = stack.get();
3957 const vals = try allocator.alloc(Builder.Constant, llvm_len);
3958 defer allocator.free(vals);
3959 const fields = try allocator.alloc(Builder.Type, llvm_len);
3960 defer allocator.free(fields);
35773961
35783962 comptime assert(struct_layout_version == 2);
3963 var llvm_index: usize = 0;
35793964 var offset: u64 = 0;
35803965 var big_align: u32 = 0;
35813966 var need_unnamed = false;
3582
3583 var it = struct_obj.runtimeFieldIterator(mod);
3584 while (it.next()) |field_and_index| {
3967 var field_it = struct_obj.runtimeFieldIterator(mod);
3968 while (field_it.next()) |field_and_index| {
35853969 const field = field_and_index.field;
35863970 const field_align = field.alignment(mod, struct_obj.layout);
35873971 big_align = @max(big_align, field_align);
......@@ -3590,20 +3974,22 @@ pub const Object = struct {
35903974
35913975 const padding_len = offset - prev_offset;
35923976 if (padding_len > 0) {
3593 const llvm_array_ty = o.context.intType(8).arrayType(@as(c_uint, @intCast(padding_len)));
35943977 // TODO make this and all other padding elsewhere in debug
35953978 // builds be 0xaa not undef.
3596 llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef());
3979 fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);
3980 vals[llvm_index] = try o.builder.undefConst(fields[llvm_index]);
3981 assert(fields[llvm_index] ==
3982 struct_ty.structFields(&o.builder)[llvm_index]);
3983 llvm_index += 1;
35973984 }
35983985
3599 const field_llvm_val = try o.lowerValue(.{
3600 .ty = field.ty,
3601 .val = try tv.val.fieldValue(mod, field_and_index.index),
3602 });
3603
3604 need_unnamed = need_unnamed or o.isUnnamedType(field.ty, field_llvm_val);
3605
3606 llvm_fields.appendAssumeCapacity(field_llvm_val);
3986 vals[llvm_index] = try o.lowerValue(
3987 (try val.fieldValue(mod, field_and_index.index)).toIntern(),
3988 );
3989 fields[llvm_index] = vals[llvm_index].typeOf(&o.builder);
3990 if (fields[llvm_index] != struct_ty.structFields(&o.builder)[llvm_index])
3991 need_unnamed = true;
3992 llvm_index += 1;
36073993
36083994 offset += field.ty.abiSize(mod);
36093995 }
......@@ -3612,202 +3998,158 @@ pub const Object = struct {
36123998 offset = std.mem.alignForward(u64, offset, big_align);
36133999 const padding_len = offset - prev_offset;
36144000 if (padding_len > 0) {
3615 const llvm_array_ty = o.context.intType(8).arrayType(@as(c_uint, @intCast(padding_len)));
3616 llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef());
4001 fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);
4002 vals[llvm_index] = try o.builder.undefConst(fields[llvm_index]);
4003 assert(fields[llvm_index] == struct_ty.structFields(&o.builder)[llvm_index]);
4004 llvm_index += 1;
36174005 }
36184006 }
4007 assert(llvm_index == llvm_len);
36194008
3620 if (need_unnamed) {
3621 return o.context.constStruct(
3622 llvm_fields.items.ptr,
3623 @as(c_uint, @intCast(llvm_fields.items.len)),
3624 .False,
3625 );
3626 } else {
3627 return llvm_struct_ty.constNamedStruct(
3628 llvm_fields.items.ptr,
3629 @as(c_uint, @intCast(llvm_fields.items.len)),
3630 );
3631 }
4009 return o.builder.structConst(if (need_unnamed)
4010 try o.builder.structType(struct_ty.structKind(&o.builder), fields)
4011 else
4012 struct_ty, vals);
36324013 },
36334014 else => unreachable,
36344015 },
3635 .un => {
3636 const llvm_union_ty = try o.lowerType(tv.ty);
3637 const tag_and_val: Value.Payload.Union.Data = switch (tv.val.toIntern()) {
3638 .none => tv.val.castTag(.@"union").?.data,
3639 else => switch (mod.intern_pool.indexToKey(tv.val.toIntern())) {
3640 .un => |un| .{ .tag = un.tag.toValue(), .val = un.val.toValue() },
3641 else => unreachable,
3642 },
3643 };
3644
3645 const layout = tv.ty.unionGetLayout(mod);
4016 .un => |un| {
4017 const union_ty = try o.lowerType(ty);
4018 const layout = ty.unionGetLayout(mod);
4019 if (layout.payload_size == 0) return o.lowerValue(un.tag);
36464020
3647 if (layout.payload_size == 0) {
3648 return lowerValue(o, .{
3649 .ty = tv.ty.unionTagTypeSafety(mod).?,
3650 .val = tag_and_val.tag,
3651 });
3652 }
3653 const union_obj = mod.typeToUnion(tv.ty).?;
3654 const field_index = tv.ty.unionTagFieldIndex(tag_and_val.tag, o.module).?;
4021 const union_obj = mod.typeToUnion(ty).?;
4022 const field_index = ty.unionTagFieldIndex(un.tag.toValue(), o.module).?;
36554023 assert(union_obj.haveFieldTypes());
36564024
36574025 const field_ty = union_obj.fields.values()[field_index].ty;
36584026 if (union_obj.layout == .Packed) {
3659 if (!field_ty.hasRuntimeBits(mod))
3660 return llvm_union_ty.constNull();
3661 const non_int_val = try lowerValue(o, .{ .ty = field_ty, .val = tag_and_val.val });
3662 const ty_bit_size = @as(u16, @intCast(field_ty.bitSize(mod)));
3663 const small_int_ty = o.context.intType(ty_bit_size);
3664 const small_int_val = if (field_ty.isPtrAtRuntime(mod))
3665 non_int_val.constPtrToInt(small_int_ty)
3666 else
3667 non_int_val.constBitCast(small_int_ty);
3668 return small_int_val.constZExtOrBitCast(llvm_union_ty);
4027 if (!field_ty.hasRuntimeBits(mod)) return o.builder.intConst(union_ty, 0);
4028 const small_int_val = try o.builder.castConst(
4029 if (field_ty.isPtrAtRuntime(mod)) .ptrtoint else .bitcast,
4030 try o.lowerValue(un.val),
4031 try o.builder.intType(@intCast(field_ty.bitSize(mod))),
4032 );
4033 return o.builder.convConst(.unsigned, small_int_val, union_ty);
36694034 }
36704035
36714036 // Sometimes we must make an unnamed struct because LLVM does
36724037 // not support bitcasting our payload struct to the true union payload type.
36734038 // Instead we use an unnamed struct and every reference to the global
36744039 // must pointer cast to the expected type before accessing the union.
3675 var need_unnamed: bool = layout.most_aligned_field != field_index;
4040 var need_unnamed = layout.most_aligned_field != field_index;
36764041 const payload = p: {
36774042 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) {
3678 const padding_len = @as(c_uint, @intCast(layout.payload_size));
3679 break :p o.context.intType(8).arrayType(padding_len).getUndef();
4043 const padding_len = layout.payload_size;
4044 break :p try o.builder.undefConst(try o.builder.arrayType(padding_len, .i8));
36804045 }
3681 const field = try lowerValue(o, .{ .ty = field_ty, .val = tag_and_val.val });
3682 need_unnamed = need_unnamed or o.isUnnamedType(field_ty, field);
4046 const payload = try o.lowerValue(un.val);
4047 const payload_ty = payload.typeOf(&o.builder);
4048 if (payload_ty != union_ty.structFields(&o.builder)[
4049 @intFromBool(layout.tag_align >= layout.payload_align)
4050 ]) need_unnamed = true;
36834051 const field_size = field_ty.abiSize(mod);
3684 if (field_size == layout.payload_size) {
3685 break :p field;
3686 }
3687 const padding_len = @as(c_uint, @intCast(layout.payload_size - field_size));
3688 const fields: [2]*llvm.Value = .{
3689 field, o.context.intType(8).arrayType(padding_len).getUndef(),
3690 };
3691 break :p o.context.constStruct(&fields, fields.len, .True);
4052 if (field_size == layout.payload_size) break :p payload;
4053 const padding_len = layout.payload_size - field_size;
4054 const padding_ty = try o.builder.arrayType(padding_len, .i8);
4055 break :p try o.builder.structConst(
4056 try o.builder.structType(.@"packed", &.{ payload_ty, padding_ty }),
4057 &.{ payload, try o.builder.undefConst(padding_ty) },
4058 );
36924059 };
4060 const payload_ty = payload.typeOf(&o.builder);
36934061
3694 if (layout.tag_size == 0) {
3695 const fields: [1]*llvm.Value = .{payload};
3696 if (need_unnamed) {
3697 return o.context.constStruct(&fields, fields.len, .False);
3698 } else {
3699 return llvm_union_ty.constNamedStruct(&fields, fields.len);
3700 }
3701 }
3702 const llvm_tag_value = try lowerValue(o, .{
3703 .ty = tv.ty.unionTagTypeSafety(mod).?,
3704 .val = tag_and_val.tag,
3705 });
3706 var fields: [3]*llvm.Value = undefined;
3707 var fields_len: c_uint = 2;
4062 if (layout.tag_size == 0) return o.builder.structConst(if (need_unnamed)
4063 try o.builder.structType(union_ty.structKind(&o.builder), &.{payload_ty})
4064 else
4065 union_ty, &.{payload});
4066 const tag = try o.lowerValue(un.tag);
4067 const tag_ty = tag.typeOf(&o.builder);
4068 var fields: [3]Builder.Type = undefined;
4069 var vals: [3]Builder.Constant = undefined;
4070 var len: usize = 2;
37084071 if (layout.tag_align >= layout.payload_align) {
3709 fields = .{ llvm_tag_value, payload, undefined };
4072 fields = .{ tag_ty, payload_ty, undefined };
4073 vals = .{ tag, payload, undefined };
37104074 } else {
3711 fields = .{ payload, llvm_tag_value, undefined };
4075 fields = .{ payload_ty, tag_ty, undefined };
4076 vals = .{ payload, tag, undefined };
37124077 }
37134078 if (layout.padding != 0) {
3714 fields[2] = o.context.intType(8).arrayType(layout.padding).getUndef();
3715 fields_len = 3;
3716 }
3717 if (need_unnamed) {
3718 return o.context.constStruct(&fields, fields_len, .False);
3719 } else {
3720 return llvm_union_ty.constNamedStruct(&fields, fields_len);
4079 fields[2] = try o.builder.arrayType(layout.padding, .i8);
4080 vals[2] = try o.builder.undefConst(fields[2]);
4081 len = 3;
37214082 }
4083 return o.builder.structConst(if (need_unnamed)
4084 try o.builder.structType(union_ty.structKind(&o.builder), fields[0..len])
4085 else
4086 union_ty, vals[0..len]);
37224087 },
37234088 .memoized_call => unreachable,
3724 }
4089 };
37254090 }
37264091
3727 fn lowerIntAsPtr(o: *Object, val: Value) Error!*llvm.Value {
4092 fn lowerIntAsPtr(o: *Object, val: InternPool.Index) Allocator.Error!Builder.Constant {
37284093 const mod = o.module;
3729 switch (mod.intern_pool.indexToKey(val.toIntern())) {
3730 .undef => return o.context.pointerType(0).getUndef(),
4094 switch (mod.intern_pool.indexToKey(val)) {
4095 .undef => return o.builder.undefConst(.ptr),
37314096 .int => {
37324097 var bigint_space: Value.BigIntSpace = undefined;
3733 const bigint = val.toBigInt(&bigint_space, mod);
3734 const llvm_int = lowerBigInt(o, Type.usize, bigint);
3735 return llvm_int.constIntToPtr(o.context.pointerType(0));
4098 const bigint = val.toValue().toBigInt(&bigint_space, mod);
4099 const llvm_int = try lowerBigInt(o, Type.usize, bigint);
4100 return o.builder.castConst(.inttoptr, llvm_int, .ptr);
37364101 },
37374102 else => unreachable,
37384103 }
37394104 }
37404105
3741 fn lowerBigInt(o: *Object, ty: Type, bigint: std.math.big.int.Const) *llvm.Value {
4106 fn lowerBigInt(
4107 o: *Object,
4108 ty: Type,
4109 bigint: std.math.big.int.Const,
4110 ) Allocator.Error!Builder.Constant {
37424111 const mod = o.module;
3743 const int_info = ty.intInfo(mod);
3744 assert(int_info.bits != 0);
3745 const llvm_type = o.context.intType(int_info.bits);
3746
3747 const unsigned_val = v: {
3748 if (bigint.limbs.len == 1) {
3749 break :v llvm_type.constInt(bigint.limbs[0], .False);
3750 }
3751 if (@sizeOf(usize) == @sizeOf(u64)) {
3752 break :v llvm_type.constIntOfArbitraryPrecision(
3753 @as(c_uint, @intCast(bigint.limbs.len)),
3754 bigint.limbs.ptr,
3755 );
3756 }
3757 @panic("TODO implement bigint to llvm int for 32-bit compiler builds");
3758 };
3759 if (!bigint.positive) {
3760 return llvm.constNeg(unsigned_val);
3761 }
3762 return unsigned_val;
4112 return o.builder.bigIntConst(try o.builder.intType(ty.intInfo(mod).bits), bigint);
37634113 }
37644114
37654115 const ParentPtr = struct {
37664116 ty: Type,
3767 llvm_ptr: *llvm.Value,
4117 llvm_ptr: Builder.Value,
37684118 };
37694119
3770 fn lowerParentPtrDecl(
3771 o: *Object,
3772 ptr_val: Value,
3773 decl_index: Module.Decl.Index,
3774 ) Error!*llvm.Value {
4120 fn lowerParentPtrDecl(o: *Object, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant {
37754121 const mod = o.module;
37764122 const decl = mod.declPtr(decl_index);
37774123 try mod.markDeclAlive(decl);
37784124 const ptr_ty = try mod.singleMutPtrType(decl.ty);
3779 return try o.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index);
4125 return o.lowerDeclRefValue(ptr_ty, decl_index);
37804126 }
37814127
3782 fn lowerParentPtr(o: *Object, ptr_val: Value, byte_aligned: bool) Error!*llvm.Value {
4128 fn lowerParentPtr(o: *Object, ptr_val: Value, byte_aligned: bool) Allocator.Error!Builder.Constant {
37834129 const mod = o.module;
3784 const target = mod.getTarget();
37854130 return switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) {
3786 .decl => |decl| o.lowerParentPtrDecl(ptr_val, decl),
3787 .mut_decl => |mut_decl| o.lowerParentPtrDecl(ptr_val, mut_decl.decl),
3788 .int => |int| o.lowerIntAsPtr(int.toValue()),
4131 .decl => |decl| o.lowerParentPtrDecl(decl),
4132 .mut_decl => |mut_decl| o.lowerParentPtrDecl(mut_decl.decl),
4133 .int => |int| try o.lowerIntAsPtr(int),
37894134 .eu_payload => |eu_ptr| {
3790 const parent_llvm_ptr = try o.lowerParentPtr(eu_ptr.toValue(), true);
4135 const parent_ptr = try o.lowerParentPtr(eu_ptr.toValue(), true);
37914136
37924137 const eu_ty = mod.intern_pool.typeOf(eu_ptr).toType().childType(mod);
37934138 const payload_ty = eu_ty.errorUnionPayload(mod);
37944139 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
37954140 // In this case, we represent pointer to error union the same as pointer
37964141 // to the payload.
3797 return parent_llvm_ptr;
4142 return parent_ptr;
37984143 }
37994144
3800 const payload_offset: u8 = if (payload_ty.abiAlignment(mod) > Type.anyerror.abiSize(mod)) 2 else 1;
3801 const llvm_u32 = o.context.intType(32);
3802 const indices: [2]*llvm.Value = .{
3803 llvm_u32.constInt(0, .False),
3804 llvm_u32.constInt(payload_offset, .False),
3805 };
3806 const eu_llvm_ty = try o.lowerType(eu_ty);
3807 return eu_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
4145 const index: u32 =
4146 if (payload_ty.abiAlignment(mod) > Type.err_int.abiSize(mod)) 2 else 1;
4147 return o.builder.gepConst(.inbounds, try o.lowerType(eu_ty), parent_ptr, null, &.{
4148 try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, index),
4149 });
38084150 },
38094151 .opt_payload => |opt_ptr| {
3810 const parent_llvm_ptr = try o.lowerParentPtr(opt_ptr.toValue(), true);
4152 const parent_ptr = try o.lowerParentPtr(opt_ptr.toValue(), true);
38114153
38124154 const opt_ty = mod.intern_pool.typeOf(opt_ptr).toType().childType(mod);
38134155 const payload_ty = opt_ty.optionalChild(mod);
......@@ -3816,99 +4158,89 @@ pub const Object = struct {
38164158 {
38174159 // In this case, we represent pointer to optional the same as pointer
38184160 // to the payload.
3819 return parent_llvm_ptr;
4161 return parent_ptr;
38204162 }
38214163
3822 const llvm_u32 = o.context.intType(32);
3823 const indices: [2]*llvm.Value = .{
3824 llvm_u32.constInt(0, .False),
3825 llvm_u32.constInt(0, .False),
3826 };
3827 const opt_llvm_ty = try o.lowerType(opt_ty);
3828 return opt_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
4164 return o.builder.gepConst(.inbounds, try o.lowerType(opt_ty), parent_ptr, null, &.{
4165 try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, 0),
4166 });
38294167 },
38304168 .comptime_field => unreachable,
38314169 .elem => |elem_ptr| {
3832 const parent_llvm_ptr = try o.lowerParentPtr(elem_ptr.base.toValue(), true);
3833
3834 const llvm_usize = try o.lowerType(Type.usize);
3835 const indices: [1]*llvm.Value = .{
3836 llvm_usize.constInt(elem_ptr.index, .False),
3837 };
4170 const parent_ptr = try o.lowerParentPtr(elem_ptr.base.toValue(), true);
38384171 const elem_ty = mod.intern_pool.typeOf(elem_ptr.base).toType().elemType2(mod);
3839 const elem_llvm_ty = try o.lowerType(elem_ty);
3840 return elem_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
4172
4173 return o.builder.gepConst(.inbounds, try o.lowerType(elem_ty), parent_ptr, null, &.{
4174 try o.builder.intConst(try o.lowerType(Type.usize), elem_ptr.index),
4175 });
38414176 },
38424177 .field => |field_ptr| {
3843 const parent_llvm_ptr = try o.lowerParentPtr(field_ptr.base.toValue(), byte_aligned);
4178 const parent_ptr = try o.lowerParentPtr(field_ptr.base.toValue(), byte_aligned);
38444179 const parent_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod);
38454180
3846 const field_index = @as(u32, @intCast(field_ptr.index));
3847 const llvm_u32 = o.context.intType(32);
4181 const field_index: u32 = @intCast(field_ptr.index);
38484182 switch (parent_ty.zigTypeTag(mod)) {
38494183 .Union => {
38504184 if (parent_ty.containerLayout(mod) == .Packed) {
3851 return parent_llvm_ptr;
4185 return parent_ptr;
38524186 }
38534187
38544188 const layout = parent_ty.unionGetLayout(mod);
38554189 if (layout.payload_size == 0) {
38564190 // In this case a pointer to the union and a pointer to any
38574191 // (void) payload is the same.
3858 return parent_llvm_ptr;
4192 return parent_ptr;
38594193 }
3860 const llvm_pl_index = if (layout.tag_size == 0)
3861 0
3862 else
3863 @intFromBool(layout.tag_align >= layout.payload_align);
3864 const indices: [2]*llvm.Value = .{
3865 llvm_u32.constInt(0, .False),
3866 llvm_u32.constInt(llvm_pl_index, .False),
3867 };
4194
38684195 const parent_llvm_ty = try o.lowerType(parent_ty);
3869 return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
4196 return o.builder.gepConst(.inbounds, parent_llvm_ty, parent_ptr, null, &.{
4197 try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, @intFromBool(
4198 layout.tag_size > 0 and layout.tag_align >= layout.payload_align,
4199 )),
4200 });
38704201 },
38714202 .Struct => {
38724203 if (parent_ty.containerLayout(mod) == .Packed) {
3873 if (!byte_aligned) return parent_llvm_ptr;
3874 const llvm_usize = o.context.intType(target.ptrBitWidth());
3875 const base_addr = parent_llvm_ptr.constPtrToInt(llvm_usize);
4204 if (!byte_aligned) return parent_ptr;
4205 const llvm_usize = try o.lowerType(Type.usize);
4206 const base_addr =
4207 try o.builder.castConst(.ptrtoint, parent_ptr, llvm_usize);
38764208 // count bits of fields before this one
38774209 const prev_bits = b: {
38784210 var b: usize = 0;
38794211 for (parent_ty.structFields(mod).values()[0..field_index]) |field| {
3880 if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
3881 b += @as(usize, @intCast(field.ty.bitSize(mod)));
4212 if (field.is_comptime) continue;
4213 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
4214 b += @intCast(field.ty.bitSize(mod));
38824215 }
38834216 break :b b;
38844217 };
3885 const byte_offset = llvm_usize.constInt(prev_bits / 8, .False);
3886 const field_addr = base_addr.constAdd(byte_offset);
3887 const final_llvm_ty = o.context.pointerType(0);
3888 return field_addr.constIntToPtr(final_llvm_ty);
4218 const byte_offset = try o.builder.intConst(llvm_usize, prev_bits / 8);
4219 const field_addr = try o.builder.binConst(.add, base_addr, byte_offset);
4220 return o.builder.castConst(.inttoptr, field_addr, .ptr);
38894221 }
38904222
3891 const parent_llvm_ty = try o.lowerType(parent_ty);
3892 if (llvmField(parent_ty, field_index, mod)) |llvm_field| {
3893 const indices: [2]*llvm.Value = .{
3894 llvm_u32.constInt(0, .False),
3895 llvm_u32.constInt(llvm_field.index, .False),
3896 };
3897 return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
3898 } else {
3899 const llvm_index = llvm_u32.constInt(@intFromBool(parent_ty.hasRuntimeBitsIgnoreComptime(mod)), .False);
3900 const indices: [1]*llvm.Value = .{llvm_index};
3901 return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
3902 }
4223 return o.builder.gepConst(
4224 .inbounds,
4225 try o.lowerType(parent_ty),
4226 parent_ptr,
4227 null,
4228 if (llvmField(parent_ty, field_index, mod)) |llvm_field| &.{
4229 try o.builder.intConst(.i32, 0),
4230 try o.builder.intConst(.i32, llvm_field.index),
4231 } else &.{
4232 try o.builder.intConst(.i32, @intFromBool(
4233 parent_ty.hasRuntimeBitsIgnoreComptime(mod),
4234 )),
4235 },
4236 );
39034237 },
39044238 .Pointer => {
39054239 assert(parent_ty.isSlice(mod));
3906 const indices: [2]*llvm.Value = .{
3907 llvm_u32.constInt(0, .False),
3908 llvm_u32.constInt(field_index, .False),
3909 };
39104240 const parent_llvm_ty = try o.lowerType(parent_ty);
3911 return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
4241 return o.builder.gepConst(.inbounds, parent_llvm_ty, parent_ptr, null, &.{
4242 try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, field_index),
4243 });
39124244 },
39134245 else => unreachable,
39144246 }
......@@ -3916,11 +4248,7 @@ pub const Object = struct {
39164248 };
39174249 }
39184250
3919 fn lowerDeclRefValue(
3920 o: *Object,
3921 tv: TypedValue,
3922 decl_index: Module.Decl.Index,
3923 ) Error!*llvm.Value {
4251 fn lowerDeclRefValue(o: *Object, ty: Type, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant {
39244252 const mod = o.module;
39254253
39264254 // In the case of something like:
......@@ -3931,69 +4259,59 @@ pub const Object = struct {
39314259 const decl = mod.declPtr(decl_index);
39324260 if (decl.val.getFunction(mod)) |func| {
39334261 if (func.owner_decl != decl_index) {
3934 return o.lowerDeclRefValue(tv, func.owner_decl);
4262 return o.lowerDeclRefValue(ty, func.owner_decl);
39354263 }
39364264 } else if (decl.val.getExternFunc(mod)) |func| {
39374265 if (func.decl != decl_index) {
3938 return o.lowerDeclRefValue(tv, func.decl);
4266 return o.lowerDeclRefValue(ty, func.decl);
39394267 }
39404268 }
39414269
39424270 const is_fn_body = decl.ty.zigTypeTag(mod) == .Fn;
39434271 if ((!is_fn_body and !decl.ty.hasRuntimeBits(mod)) or
3944 (is_fn_body and mod.typeToFunc(decl.ty).?.is_generic))
3945 {
3946 return o.lowerPtrToVoid(tv.ty);
3947 }
4272 (is_fn_body and mod.typeToFunc(decl.ty).?.is_generic)) return o.lowerPtrToVoid(ty);
39484273
39494274 try mod.markDeclAlive(decl);
39504275
3951 const llvm_decl_val = if (is_fn_body)
3952 try o.resolveLlvmFunction(decl_index)
4276 const llvm_global = if (is_fn_body)
4277 (try o.resolveLlvmFunction(decl_index)).ptrConst(&o.builder).global
39534278 else
3954 try o.resolveGlobalDecl(decl_index);
4279 (try o.resolveGlobalDecl(decl_index)).ptrConst(&o.builder).global;
39554280
3956 const target = mod.getTarget();
3957 const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);
3958 const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);
3959 const llvm_val = if (llvm_wanted_addrspace != llvm_actual_addrspace) blk: {
3960 const llvm_decl_wanted_ptr_ty = o.context.pointerType(llvm_wanted_addrspace);
3961 break :blk llvm_decl_val.constAddrSpaceCast(llvm_decl_wanted_ptr_ty);
3962 } else llvm_decl_val;
3963
3964 const llvm_type = try o.lowerType(tv.ty);
3965 if (tv.ty.zigTypeTag(mod) == .Int) {
3966 return llvm_val.constPtrToInt(llvm_type);
3967 } else {
3968 return llvm_val.constBitCast(llvm_type);
3969 }
4281 const llvm_val = try o.builder.convConst(
4282 .unneeded,
4283 llvm_global.toConst(),
4284 try o.builder.ptrType(toLlvmAddressSpace(decl.@"addrspace", mod.getTarget())),
4285 );
4286
4287 return o.builder.convConst(if (ty.isAbiInt(mod)) switch (ty.intInfo(mod).signedness) {
4288 .signed => .signed,
4289 .unsigned => .unsigned,
4290 } else .unneeded, llvm_val, try o.lowerType(ty));
39704291 }
39714292
3972 fn lowerPtrToVoid(o: *Object, ptr_ty: Type) !*llvm.Value {
4293 fn lowerPtrToVoid(o: *Object, ptr_ty: Type) Allocator.Error!Builder.Constant {
39734294 const mod = o.module;
39744295 // Even though we are pointing at something which has zero bits (e.g. `void`),
39754296 // Pointers are defined to have bits. So we must return something here.
39764297 // The value cannot be undefined, because we use the `nonnull` annotation
39774298 // for non-optional pointers. We also need to respect the alignment, even though
39784299 // the address will never be dereferenced.
3979 const llvm_usize = try o.lowerType(Type.usize);
3980 const llvm_ptr_ty = try o.lowerType(ptr_ty);
3981 if (ptr_ty.ptrInfo(mod).flags.alignment.toByteUnitsOptional()) |alignment| {
3982 return llvm_usize.constInt(alignment, .False).constIntToPtr(llvm_ptr_ty);
3983 }
3984 // Note that these 0xaa values are appropriate even in release-optimized builds
3985 // because we need a well-defined value that is not null, and LLVM does not
3986 // have an "undef_but_not_null" attribute. As an example, if this `alloc` AIR
3987 // instruction is followed by a `wrap_optional`, it will return this value
3988 // verbatim, and the result should test as non-null.
3989 const target = mod.getTarget();
3990 const int = switch (target.ptrBitWidth()) {
3991 16 => llvm_usize.constInt(0xaaaa, .False),
3992 32 => llvm_usize.constInt(0xaaaaaaaa, .False),
3993 64 => llvm_usize.constInt(0xaaaaaaaa_aaaaaaaa, .False),
4300 const int: u64 = ptr_ty.ptrInfo(mod).flags.alignment.toByteUnitsOptional() orelse
4301 // Note that these 0xaa values are appropriate even in release-optimized builds
4302 // because we need a well-defined value that is not null, and LLVM does not
4303 // have an "undef_but_not_null" attribute. As an example, if this `alloc` AIR
4304 // instruction is followed by a `wrap_optional`, it will return this value
4305 // verbatim, and the result should test as non-null.
4306 switch (mod.getTarget().ptrBitWidth()) {
4307 16 => 0xaaaa,
4308 32 => 0xaaaaaaaa,
4309 64 => 0xaaaaaaaa_aaaaaaaa,
39944310 else => unreachable,
39954311 };
3996 return int.constIntToPtr(llvm_ptr_ty);
4312 const llvm_usize = try o.lowerType(Type.usize);
4313 const llvm_ptr_ty = try o.lowerType(ptr_ty);
4314 return o.builder.castConst(.inttoptr, try o.builder.intConst(llvm_usize, int), llvm_ptr_ty);
39974315 }
39984316
39994317 fn addAttr(o: *Object, val: *llvm.Value, index: llvm.AttributeIndex, name: []const u8) void {
......@@ -4023,7 +4341,7 @@ pub const Object = struct {
40234341 ) void {
40244342 const kind_id = llvm.getEnumAttributeKindForName(name.ptr, name.len);
40254343 assert(kind_id != 0);
4026 const llvm_attr = o.context.createEnumAttribute(kind_id, int);
4344 const llvm_attr = o.builder.llvm.context.createEnumAttribute(kind_id, int);
40274345 val.addAttributeAtIndex(index, llvm_attr);
40284346 }
40294347
......@@ -4034,11 +4352,11 @@ pub const Object = struct {
40344352 name: []const u8,
40354353 value: []const u8,
40364354 ) void {
4037 const llvm_attr = o.context.createStringAttribute(
4355 const llvm_attr = o.builder.llvm.context.createStringAttribute(
40384356 name.ptr,
4039 @as(c_uint, @intCast(name.len)),
4357 @intCast(name.len),
40404358 value.ptr,
4041 @as(c_uint, @intCast(value.len)),
4359 @intCast(value.len),
40424360 );
40434361 val.addAttributeAtIndex(index, llvm_attr);
40444362 }
......@@ -4063,23 +4381,23 @@ pub const Object = struct {
40634381 /// widen it before using it and then truncate the result.
40644382 /// RMW exchange of floating-point values is bitcasted to same-sized integer
40654383 /// types to work around a LLVM deficiency when targeting ARM/AArch64.
4066 fn getAtomicAbiType(o: *Object, ty: Type, is_rmw_xchg: bool) ?*llvm.Type {
4384 fn getAtomicAbiType(o: *Object, ty: Type, is_rmw_xchg: bool) Allocator.Error!Builder.Type {
40674385 const mod = o.module;
40684386 const int_ty = switch (ty.zigTypeTag(mod)) {
40694387 .Int => ty,
40704388 .Enum => ty.intTagType(mod),
40714389 .Float => {
4072 if (!is_rmw_xchg) return null;
4073 return o.context.intType(@as(c_uint, @intCast(ty.abiSize(mod) * 8)));
4390 if (!is_rmw_xchg) return .none;
4391 return o.builder.intType(@intCast(ty.abiSize(mod) * 8));
40744392 },
4075 .Bool => return o.context.intType(8),
4076 else => return null,
4393 .Bool => return .i8,
4394 else => return .none,
40774395 };
40784396 const bit_count = int_ty.intInfo(mod).bits;
40794397 if (!std.math.isPowerOfTwo(bit_count) or (bit_count % 8) != 0) {
4080 return o.context.intType(@as(c_uint, @intCast(int_ty.abiSize(mod) * 8)));
4398 return o.builder.intType(@intCast(int_ty.abiSize(mod) * 8));
40814399 } else {
4082 return null;
4400 return .none;
40834401 }
40844402 }
40854403
......@@ -4120,13 +4438,13 @@ pub const Object = struct {
41204438 llvm_arg_i: u32,
41214439 alignment: u32,
41224440 byval_attr: bool,
4123 param_llvm_ty: *llvm.Type,
4441 param_llvm_ty: Builder.Type,
41244442 ) void {
41254443 o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");
41264444 o.addArgAttr(llvm_fn, llvm_arg_i, "readonly");
41274445 o.addArgAttrInt(llvm_fn, llvm_arg_i, "align", alignment);
41284446 if (byval_attr) {
4129 llvm_fn.addByValAttr(llvm_arg_i, param_llvm_ty);
4447 llvm_fn.addByValAttr(llvm_arg_i, param_llvm_ty.toLlvm(&o.builder));
41304448 }
41314449 }
41324450};
......@@ -4159,20 +4477,26 @@ pub const DeclGen = struct {
41594477 _ = try o.resolveLlvmFunction(extern_func.decl);
41604478 } else {
41614479 const target = mod.getTarget();
4162 var global = try o.resolveGlobalDecl(decl_index);
4163 global.setAlignment(decl.getAlignment(mod));
4164 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| global.setSection(s);
4480 const variable = try o.resolveGlobalDecl(decl_index);
4481 const global = variable.ptrConst(&o.builder).global;
4482 var llvm_global = global.toLlvm(&o.builder);
4483 variable.ptr(&o.builder).alignment = Builder.Alignment.fromByteUnits(decl.getAlignment(mod));
4484 llvm_global.setAlignment(decl.getAlignment(mod));
4485 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |section| {
4486 variable.ptr(&o.builder).section = try o.builder.string(section);
4487 llvm_global.setSection(section);
4488 }
41654489 assert(decl.has_tv);
4166 const init_val = if (decl.val.getVariable(mod)) |variable| init_val: {
4167 break :init_val variable.init;
4168 } else init_val: {
4169 global.setGlobalConstant(.True);
4490 const init_val = if (decl.val.getVariable(mod)) |decl_var| decl_var.init else init_val: {
4491 variable.ptr(&o.builder).mutability = .constant;
4492 llvm_global.setGlobalConstant(.True);
41704493 break :init_val decl.val.toIntern();
41714494 };
41724495 if (init_val != .none) {
4173 const llvm_init = try o.lowerValue(.{ .ty = decl.ty, .val = init_val.toValue() });
4174 if (global.globalGetValueType() == llvm_init.typeOf()) {
4175 global.setInitializer(llvm_init);
4496 const llvm_init = try o.lowerValue(init_val);
4497 const llvm_init_ty = llvm_init.typeOf(&o.builder);
4498 if (global.ptrConst(&o.builder).type == llvm_init_ty) {
4499 llvm_global.setInitializer(llvm_init.toLlvm(&o.builder));
41764500 } else {
41774501 // LLVM does not allow us to change the type of globals. So we must
41784502 // create a new global with the correct type, copy all its attributes,
......@@ -4189,23 +4513,27 @@ pub const DeclGen = struct {
41894513 // Related: https://github.com/ziglang/zig/issues/13265
41904514 const llvm_global_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);
41914515 const new_global = o.llvm_module.addGlobalInAddressSpace(
4192 llvm_init.typeOf(),
4516 llvm_init_ty.toLlvm(&o.builder),
41934517 "",
4194 llvm_global_addrspace,
4518 @intFromEnum(llvm_global_addrspace),
41954519 );
4196 new_global.setLinkage(global.getLinkage());
4197 new_global.setUnnamedAddr(global.getUnnamedAddress());
4198 new_global.setAlignment(global.getAlignment());
4199 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s|
4200 new_global.setSection(s);
4201 new_global.setInitializer(llvm_init);
4520 new_global.setLinkage(llvm_global.getLinkage());
4521 new_global.setUnnamedAddr(llvm_global.getUnnamedAddress());
4522 new_global.setAlignment(llvm_global.getAlignment());
4523 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |section|
4524 new_global.setSection(section);
4525 new_global.setInitializer(llvm_init.toLlvm(&o.builder));
42024526 // TODO: How should this work then the address space of a global changed?
4203 global.replaceAllUsesWith(new_global);
4204 o.decl_map.putAssumeCapacity(decl_index, new_global);
4205 new_global.takeName(global);
4206 global.deleteGlobal();
4207 global = new_global;
4527 llvm_global.replaceAllUsesWith(new_global);
4528 new_global.takeName(llvm_global);
4529 o.builder.llvm.globals.items[@intFromEnum(variable.ptrConst(&o.builder).global)] =
4530 new_global;
4531 llvm_global.deleteGlobal();
4532 llvm_global = new_global;
4533 variable.ptr(&o.builder).mutability = .global;
4534 global.ptr(&o.builder).type = llvm_init_ty;
42084535 }
4536 variable.ptr(&o.builder).init = llvm_init;
42094537 }
42104538
42114539 if (o.di_builder) |dib| {
......@@ -4216,7 +4544,7 @@ pub const DeclGen = struct {
42164544 const di_global = dib.createGlobalVariableExpression(
42174545 di_file.toScope(),
42184546 mod.intern_pool.stringToSlice(decl.name),
4219 global.getValueName(),
4547 llvm_global.getValueName(),
42204548 di_file,
42214549 line_number,
42224550 try o.lowerDebugType(decl.ty, .full),
......@@ -4224,7 +4552,7 @@ pub const DeclGen = struct {
42244552 );
42254553
42264554 try o.di_map.put(o.gpa, dg.decl, di_global.getVariable().toNode());
4227 if (!is_internal_linkage or decl.isExtern(mod)) global.attachMetaData(di_global);
4555 if (!is_internal_linkage or decl.isExtern(mod)) llvm_global.attachMetaData(di_global);
42284556 }
42294557 }
42304558 }
......@@ -4235,7 +4563,7 @@ pub const FuncGen = struct {
42354563 dg: *DeclGen,
42364564 air: Air,
42374565 liveness: Liveness,
4238 context: *llvm.Context,
4566 wip: Builder.WipFunction,
42394567 builder: *llvm.Builder,
42404568 di_scope: ?*llvm.DIScope,
42414569 di_file: ?*llvm.DIFile,
......@@ -4252,43 +4580,44 @@ pub const FuncGen = struct {
42524580
42534581 /// This stores the LLVM values used in a function, such that they can be referred to
42544582 /// in other instructions. This table is cleared before every function is generated.
4255 func_inst_table: std.AutoHashMapUnmanaged(Air.Inst.Ref, *llvm.Value),
4583 func_inst_table: std.AutoHashMapUnmanaged(Air.Inst.Ref, Builder.Value),
42564584
42574585 /// If the return type is sret, this is the result pointer. Otherwise null.
42584586 /// Note that this can disagree with isByRef for the return type in the case
42594587 /// of C ABI functions.
4260 ret_ptr: ?*llvm.Value,
4588 ret_ptr: Builder.Value,
42614589 /// Any function that needs to perform Valgrind client requests needs an array alloca
42624590 /// instruction, however a maximum of one per function is needed.
4263 valgrind_client_request_array: ?*llvm.Value = null,
4591 valgrind_client_request_array: Builder.Value = .none,
42644592 /// These fields are used to refer to the LLVM value of the function parameters
42654593 /// in an Arg instruction.
42664594 /// This list may be shorter than the list according to the zig type system;
42674595 /// it omits 0-bit types. If the function uses sret as the first parameter,
42684596 /// this slice does not include it.
4269 args: []const *llvm.Value,
4270 arg_index: c_uint,
4597 args: []const Builder.Value,
4598 arg_index: usize,
42714599
4272 llvm_func: *llvm.Value,
4273
4274 err_ret_trace: ?*llvm.Value = null,
4600 err_ret_trace: Builder.Value = .none,
42754601
42764602 /// This data structure is used to implement breaking to blocks.
42774603 blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, struct {
4278 parent_bb: *llvm.BasicBlock,
4604 parent_bb: Builder.Function.Block.Index,
42794605 breaks: *BreakList,
42804606 }),
42814607
4282 single_threaded: bool,
4608 sync_scope: Builder.SyncScope,
42834609
42844610 const DbgState = struct { loc: *llvm.DILocation, scope: *llvm.DIScope, base_line: u32 };
4285 const BreakList = std.MultiArrayList(struct {
4286 bb: *llvm.BasicBlock,
4287 val: *llvm.Value,
4288 });
4611 const BreakList = union {
4612 list: std.MultiArrayList(struct {
4613 bb: Builder.Function.Block.Index,
4614 val: Builder.Value,
4615 }),
4616 len: usize,
4617 };
42894618
42904619 fn deinit(self: *FuncGen) void {
4291 self.builder.dispose();
4620 self.wip.deinit();
42924621 self.dbg_inlined.deinit(self.gpa);
42934622 self.dbg_block_stack.deinit(self.gpa);
42944623 self.func_inst_table.deinit(self.gpa);
......@@ -4300,7 +4629,7 @@ pub const FuncGen = struct {
43004629 return self.dg.todo(format, args);
43014630 }
43024631
4303 fn resolveInst(self: *FuncGen, inst: Air.Inst.Ref) !*llvm.Value {
4632 fn resolveInst(self: *FuncGen, inst: Air.Inst.Ref) !Builder.Value {
43044633 const gpa = self.gpa;
43054634 const gop = try self.func_inst_table.getOrPut(gpa, inst);
43064635 if (gop.found_existing) return gop.value_ptr.*;
......@@ -4311,14 +4640,14 @@ pub const FuncGen = struct {
43114640 .ty = self.typeOf(inst),
43124641 .val = (try self.air.value(inst, mod)).?,
43134642 });
4314 gop.value_ptr.* = llvm_val;
4315 return llvm_val;
4643 gop.value_ptr.* = llvm_val.toValue();
4644 return llvm_val.toValue();
43164645 }
43174646
4318 fn resolveValue(self: *FuncGen, tv: TypedValue) !*llvm.Value {
4647 fn resolveValue(self: *FuncGen, tv: TypedValue) Error!Builder.Constant {
43194648 const o = self.dg.object;
43204649 const mod = o.module;
4321 const llvm_val = try o.lowerValue(tv);
4650 const llvm_val = try o.lowerValue(tv.val.toIntern());
43224651 if (!isByRef(tv.ty, mod)) return llvm_val;
43234652
43244653 // We have an LLVM value but we need to create a global constant and
......@@ -4326,17 +4655,50 @@ pub const FuncGen = struct {
43264655 const target = mod.getTarget();
43274656 const llvm_wanted_addrspace = toLlvmAddressSpace(.generic, target);
43284657 const llvm_actual_addrspace = toLlvmGlobalAddressSpace(.generic, target);
4329 const global = o.llvm_module.addGlobalInAddressSpace(llvm_val.typeOf(), "", llvm_actual_addrspace);
4330 global.setInitializer(llvm_val);
4331 global.setLinkage(.Private);
4332 global.setGlobalConstant(.True);
4333 global.setUnnamedAddr(.True);
4334 global.setAlignment(tv.ty.abiAlignment(mod));
4335 const addrspace_casted_ptr = if (llvm_actual_addrspace != llvm_wanted_addrspace)
4336 global.constAddrSpaceCast(self.context.pointerType(llvm_wanted_addrspace))
4337 else
4338 global;
4339 return addrspace_casted_ptr;
4658 const llvm_ty = llvm_val.typeOf(&o.builder);
4659 const llvm_alignment = tv.ty.abiAlignment(mod);
4660 const llvm_global = o.llvm_module.addGlobalInAddressSpace(llvm_ty.toLlvm(&o.builder), "", @intFromEnum(llvm_actual_addrspace));
4661 llvm_global.setInitializer(llvm_val.toLlvm(&o.builder));
4662 llvm_global.setLinkage(.Private);
4663 llvm_global.setGlobalConstant(.True);
4664 llvm_global.setUnnamedAddr(.True);
4665 llvm_global.setAlignment(llvm_alignment);
4666
4667 var global = Builder.Global{
4668 .linkage = .private,
4669 .unnamed_addr = .unnamed_addr,
4670 .addr_space = llvm_actual_addrspace,
4671 .type = llvm_ty,
4672 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
4673 };
4674 var variable = Builder.Variable{
4675 .global = @enumFromInt(o.builder.globals.count()),
4676 .mutability = .constant,
4677 .init = llvm_val,
4678 .alignment = Builder.Alignment.fromByteUnits(llvm_alignment),
4679 };
4680 try o.builder.llvm.globals.append(o.gpa, llvm_global);
4681 const global_index = try o.builder.addGlobal(.empty, global);
4682 try o.builder.variables.append(o.gpa, variable);
4683
4684 return o.builder.convConst(
4685 .unneeded,
4686 global_index.toConst(),
4687 try o.builder.ptrType(llvm_wanted_addrspace),
4688 );
4689 }
4690
4691 fn resolveNullOptUsize(self: *FuncGen) Error!Builder.Constant {
4692 const o = self.dg.object;
4693 const mod = o.module;
4694 if (o.null_opt_usize == .no_init) {
4695 const ty = try mod.intern(.{ .opt_type = .usize_type });
4696 o.null_opt_usize = try self.resolveValue(.{
4697 .ty = ty.toType(),
4698 .val = (try mod.intern(.{ .opt = .{ .ty = ty, .val = .none } })).toValue(),
4699 });
4700 }
4701 return o.null_opt_usize;
43404702 }
43414703
43424704 fn genBody(self: *FuncGen, body: []const Air.Inst.Index) Error!void {
......@@ -4345,10 +4707,9 @@ pub const FuncGen = struct {
43454707 const ip = &mod.intern_pool;
43464708 const air_tags = self.air.instructions.items(.tag);
43474709 for (body, 0..) |inst, i| {
4348 if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip))
4349 continue;
4710 if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) continue;
43504711
4351 const opt_value: ?*llvm.Value = switch (air_tags[inst]) {
4712 const val: Builder.Value = switch (air_tags[inst]) {
43524713 // zig fmt: off
43534714 .add => try self.airAdd(inst, false),
43544715 .add_optimized => try self.airAdd(inst, true),
......@@ -4439,15 +4800,15 @@ pub const FuncGen = struct {
44394800 .cmp_vector_optimized => try self.airCmpVector(inst, true),
44404801 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),
44414802
4442 .is_non_null => try self.airIsNonNull(inst, false, .NE),
4443 .is_non_null_ptr => try self.airIsNonNull(inst, true , .NE),
4444 .is_null => try self.airIsNonNull(inst, false, .EQ),
4445 .is_null_ptr => try self.airIsNonNull(inst, true , .EQ),
4803 .is_non_null => try self.airIsNonNull(inst, false, .ne),
4804 .is_non_null_ptr => try self.airIsNonNull(inst, true , .ne),
4805 .is_null => try self.airIsNonNull(inst, false, .eq),
4806 .is_null_ptr => try self.airIsNonNull(inst, true , .eq),
44464807
4447 .is_non_err => try self.airIsErr(inst, .EQ, false),
4448 .is_non_err_ptr => try self.airIsErr(inst, .EQ, true),
4449 .is_err => try self.airIsErr(inst, .NE, false),
4450 .is_err_ptr => try self.airIsErr(inst, .NE, true),
4808 .is_non_err => try self.airIsErr(inst, .eq, false),
4809 .is_non_err_ptr => try self.airIsErr(inst, .eq, true),
4810 .is_err => try self.airIsErr(inst, .ne, false),
4811 .is_err_ptr => try self.airIsErr(inst, .ne, true),
44514812
44524813 .alloc => try self.airAlloc(inst),
44534814 .ret_ptr => try self.airRetPtr(inst),
......@@ -4524,10 +4885,10 @@ pub const FuncGen = struct {
45244885 .reduce => try self.airReduce(inst, false),
45254886 .reduce_optimized => try self.airReduce(inst, true),
45264887
4527 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
4528 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
4529 .atomic_store_release => try self.airAtomicStore(inst, .Release),
4530 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SequentiallyConsistent),
4888 .atomic_store_unordered => try self.airAtomicStore(inst, .unordered),
4889 .atomic_store_monotonic => try self.airAtomicStore(inst, .monotonic),
4890 .atomic_store_release => try self.airAtomicStore(inst, .release),
4891 .atomic_store_seq_cst => try self.airAtomicStore(inst, .seq_cst),
45314892
45324893 .struct_field_ptr => try self.airStructFieldPtr(inst),
45334894 .struct_field_val => try self.airStructFieldVal(body[i..]),
......@@ -4569,8 +4930,8 @@ pub const FuncGen = struct {
45694930
45704931 .inferred_alloc, .inferred_alloc_comptime => unreachable,
45714932
4572 .unreach => self.airUnreach(inst),
4573 .dbg_stmt => self.airDbgStmt(inst),
4933 .unreach => try self.airUnreach(inst),
4934 .dbg_stmt => try self.airDbgStmt(inst),
45744935 .dbg_inline_begin => try self.airDbgInlineBegin(inst),
45754936 .dbg_inline_end => try self.airDbgInlineEnd(inst),
45764937 .dbg_block_begin => try self.airDbgBlockBegin(),
......@@ -4588,17 +4949,14 @@ pub const FuncGen = struct {
45884949 .work_group_id => try self.airWorkGroupId(inst),
45894950 // zig fmt: on
45904951 };
4591 if (opt_value) |val| {
4592 const ref = Air.indexToRef(inst);
4593 try self.func_inst_table.putNoClobber(self.gpa, ref, val);
4594 }
4952 if (val != .none) try self.func_inst_table.putNoClobber(self.gpa, Air.indexToRef(inst), val);
45954953 }
45964954 }
45974955
4598 fn airCall(self: *FuncGen, inst: Air.Inst.Index, attr: llvm.CallAttr) !?*llvm.Value {
4956 fn airCall(self: *FuncGen, inst: Air.Inst.Index, attr: llvm.CallAttr) !Builder.Value {
45994957 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
46004958 const extra = self.air.extraData(Air.Call, pl_op.payload);
4601 const args = @as([]const Air.Inst.Ref, @ptrCast(self.air.extra[extra.end..][0..extra.data.args_len]));
4959 const args: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra.end..][0..extra.data.args_len]);
46024960 const o = self.dg.object;
46034961 const mod = o.module;
46044962 const ip = &mod.intern_pool;
......@@ -4619,19 +4977,21 @@ pub const FuncGen = struct {
46194977
46204978 const ret_ptr = if (!sret) null else blk: {
46214979 const llvm_ret_ty = try o.lowerType(return_type);
4622 const ret_ptr = self.buildAlloca(llvm_ret_ty, return_type.abiAlignment(mod));
4623 try llvm_args.append(ret_ptr);
4980 const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));
4981 const ret_ptr = try self.buildAlloca(llvm_ret_ty, alignment);
4982 try llvm_args.append(ret_ptr.toLlvm(&self.wip));
46244983 break :blk ret_ptr;
46254984 };
46264985
46274986 const err_return_tracing = return_type.isError(mod) and
46284987 o.module.comp.bin_file.options.error_return_tracing;
46294988 if (err_return_tracing) {
4630 try llvm_args.append(self.err_ret_trace.?);
4989 assert(self.err_ret_trace != .none);
4990 try llvm_args.append(self.err_ret_trace.toLlvm(&self.wip));
46314991 }
46324992
46334993 var it = iterateParamTypes(o, fn_info);
4634 while (it.nextCall(self, args)) |lowering| switch (lowering) {
4994 while (try it.nextCall(self, args)) |lowering| switch (lowering) {
46354995 .no_bits => continue,
46364996 .byval => {
46374997 const arg = args[it.zig_index - 1];
......@@ -4639,12 +4999,11 @@ pub const FuncGen = struct {
46394999 const llvm_arg = try self.resolveInst(arg);
46405000 const llvm_param_ty = try o.lowerType(param_ty);
46415001 if (isByRef(param_ty, mod)) {
4642 const alignment = param_ty.abiAlignment(mod);
4643 const load_inst = self.builder.buildLoad(llvm_param_ty, llvm_arg, "");
4644 load_inst.setAlignment(alignment);
4645 try llvm_args.append(load_inst);
5002 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5003 const loaded = try self.wip.load(.normal, llvm_param_ty, llvm_arg, alignment, "");
5004 try llvm_args.append(loaded.toLlvm(&self.wip));
46465005 } else {
4647 try llvm_args.append(llvm_arg);
5006 try llvm_args.append(llvm_arg.toLlvm(&self.wip));
46485007 }
46495008 },
46505009 .byref => {
......@@ -4652,14 +5011,13 @@ pub const FuncGen = struct {
46525011 const param_ty = self.typeOf(arg);
46535012 const llvm_arg = try self.resolveInst(arg);
46545013 if (isByRef(param_ty, mod)) {
4655 try llvm_args.append(llvm_arg);
5014 try llvm_args.append(llvm_arg.toLlvm(&self.wip));
46565015 } else {
4657 const alignment = param_ty.abiAlignment(mod);
4658 const param_llvm_ty = llvm_arg.typeOf();
4659 const arg_ptr = self.buildAlloca(param_llvm_ty, alignment);
4660 const store_inst = self.builder.buildStore(llvm_arg, arg_ptr);
4661 store_inst.setAlignment(alignment);
4662 try llvm_args.append(arg_ptr);
5016 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5017 const param_llvm_ty = llvm_arg.typeOfWip(&self.wip);
5018 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);
5019 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);
5020 try llvm_args.append(arg_ptr.toLlvm(&self.wip));
46635021 }
46645022 },
46655023 .byref_mut => {
......@@ -4667,134 +5025,124 @@ pub const FuncGen = struct {
46675025 const param_ty = self.typeOf(arg);
46685026 const llvm_arg = try self.resolveInst(arg);
46695027
4670 const alignment = param_ty.abiAlignment(mod);
5028 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
46715029 const param_llvm_ty = try o.lowerType(param_ty);
4672 const arg_ptr = self.buildAlloca(param_llvm_ty, alignment);
5030 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);
46735031 if (isByRef(param_ty, mod)) {
4674 const load_inst = self.builder.buildLoad(param_llvm_ty, llvm_arg, "");
4675 load_inst.setAlignment(alignment);
4676
4677 const store_inst = self.builder.buildStore(load_inst, arg_ptr);
4678 store_inst.setAlignment(alignment);
4679 try llvm_args.append(arg_ptr);
5032 const loaded = try self.wip.load(.normal, param_llvm_ty, llvm_arg, alignment, "");
5033 _ = try self.wip.store(.normal, loaded, arg_ptr, alignment);
46805034 } else {
4681 const store_inst = self.builder.buildStore(llvm_arg, arg_ptr);
4682 store_inst.setAlignment(alignment);
4683 try llvm_args.append(arg_ptr);
5035 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);
46845036 }
5037 try llvm_args.append(arg_ptr.toLlvm(&self.wip));
46855038 },
46865039 .abi_sized_int => {
46875040 const arg = args[it.zig_index - 1];
46885041 const param_ty = self.typeOf(arg);
46895042 const llvm_arg = try self.resolveInst(arg);
4690 const abi_size = @as(c_uint, @intCast(param_ty.abiSize(mod)));
4691 const int_llvm_ty = self.context.intType(abi_size * 8);
5043 const int_llvm_ty = try o.builder.intType(@intCast(param_ty.abiSize(mod) * 8));
46925044
46935045 if (isByRef(param_ty, mod)) {
4694 const alignment = param_ty.abiAlignment(mod);
4695 const load_inst = self.builder.buildLoad(int_llvm_ty, llvm_arg, "");
4696 load_inst.setAlignment(alignment);
4697 try llvm_args.append(load_inst);
5046 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5047 const loaded = try self.wip.load(.normal, int_llvm_ty, llvm_arg, alignment, "");
5048 try llvm_args.append(loaded.toLlvm(&self.wip));
46985049 } else {
46995050 // LLVM does not allow bitcasting structs so we must allocate
47005051 // a local, store as one type, and then load as another type.
4701 const alignment = @max(
5052 const alignment = Builder.Alignment.fromByteUnits(@max(
47025053 param_ty.abiAlignment(mod),
4703 o.target_data.abiAlignmentOfType(int_llvm_ty),
4704 );
4705 const int_ptr = self.buildAlloca(int_llvm_ty, alignment);
4706 const store_inst = self.builder.buildStore(llvm_arg, int_ptr);
4707 store_inst.setAlignment(alignment);
4708 const load_inst = self.builder.buildLoad(int_llvm_ty, int_ptr, "");
4709 load_inst.setAlignment(alignment);
4710 try llvm_args.append(load_inst);
5054 o.target_data.abiAlignmentOfType(int_llvm_ty.toLlvm(&o.builder)),
5055 ));
5056 const int_ptr = try self.buildAlloca(int_llvm_ty, alignment);
5057 _ = try self.wip.store(.normal, llvm_arg, int_ptr, alignment);
5058 const loaded = try self.wip.load(.normal, int_llvm_ty, int_ptr, alignment, "");
5059 try llvm_args.append(loaded.toLlvm(&self.wip));
47115060 }
47125061 },
47135062 .slice => {
47145063 const arg = args[it.zig_index - 1];
47155064 const llvm_arg = try self.resolveInst(arg);
4716 const ptr = self.builder.buildExtractValue(llvm_arg, 0, "");
4717 const len = self.builder.buildExtractValue(llvm_arg, 1, "");
4718 try llvm_args.ensureUnusedCapacity(2);
4719 llvm_args.appendAssumeCapacity(ptr);
4720 llvm_args.appendAssumeCapacity(len);
5065 const ptr = try self.wip.extractValue(llvm_arg, &.{0}, "");
5066 const len = try self.wip.extractValue(llvm_arg, &.{1}, "");
5067 try llvm_args.appendSlice(&.{ ptr.toLlvm(&self.wip), len.toLlvm(&self.wip) });
47215068 },
47225069 .multiple_llvm_types => {
47235070 const arg = args[it.zig_index - 1];
47245071 const param_ty = self.typeOf(arg);
4725 const llvm_types = it.llvm_types_buffer[0..it.llvm_types_len];
5072 const llvm_types = it.types_buffer[0..it.types_len];
47265073 const llvm_arg = try self.resolveInst(arg);
47275074 const is_by_ref = isByRef(param_ty, mod);
4728 const arg_ptr = if (is_by_ref) llvm_arg else p: {
4729 const p = self.buildAlloca(llvm_arg.typeOf(), null);
4730 const store_inst = self.builder.buildStore(llvm_arg, p);
4731 store_inst.setAlignment(param_ty.abiAlignment(mod));
4732 break :p p;
5075 const arg_ptr = if (is_by_ref) llvm_arg else ptr: {
5076 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5077 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);
5078 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);
5079 break :ptr ptr;
47335080 };
47345081
4735 const llvm_ty = self.context.structType(llvm_types.ptr, @as(c_uint, @intCast(llvm_types.len)), .False);
4736 try llvm_args.ensureUnusedCapacity(it.llvm_types_len);
4737 for (llvm_types, 0..) |field_ty, i_usize| {
4738 const i = @as(c_uint, @intCast(i_usize));
4739 const field_ptr = self.builder.buildStructGEP(llvm_ty, arg_ptr, i, "");
4740 const load_inst = self.builder.buildLoad(field_ty, field_ptr, "");
4741 load_inst.setAlignment(target.ptrBitWidth() / 8);
4742 llvm_args.appendAssumeCapacity(load_inst);
5082 const llvm_ty = try o.builder.structType(.normal, llvm_types);
5083 try llvm_args.ensureUnusedCapacity(it.types_len);
5084 for (llvm_types, 0..) |field_ty, i| {
5085 const alignment =
5086 Builder.Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
5087 const field_ptr = try self.wip.gepStruct(llvm_ty, arg_ptr, i, "");
5088 const loaded = try self.wip.load(.normal, field_ty, field_ptr, alignment, "");
5089 llvm_args.appendAssumeCapacity(loaded.toLlvm(&self.wip));
47435090 }
47445091 },
47455092 .as_u16 => {
47465093 const arg = args[it.zig_index - 1];
47475094 const llvm_arg = try self.resolveInst(arg);
4748 const casted = self.builder.buildBitCast(llvm_arg, self.context.intType(16), "");
4749 try llvm_args.append(casted);
5095 const casted = try self.wip.cast(.bitcast, llvm_arg, .i16, "");
5096 try llvm_args.append(casted.toLlvm(&self.wip));
47505097 },
47515098 .float_array => |count| {
47525099 const arg = args[it.zig_index - 1];
47535100 const arg_ty = self.typeOf(arg);
47545101 var llvm_arg = try self.resolveInst(arg);
5102 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
47555103 if (!isByRef(arg_ty, mod)) {
4756 const p = self.buildAlloca(llvm_arg.typeOf(), null);
4757 const store_inst = self.builder.buildStore(llvm_arg, p);
4758 store_inst.setAlignment(arg_ty.abiAlignment(mod));
4759 llvm_arg = store_inst;
5104 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);
5105 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);
5106 llvm_arg = ptr;
47605107 }
47615108
47625109 const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(arg_ty, mod).?);
4763 const array_llvm_ty = float_ty.arrayType(count);
5110 const array_ty = try o.builder.arrayType(count, float_ty);
47645111
4765 const alignment = arg_ty.abiAlignment(mod);
4766 const load_inst = self.builder.buildLoad(array_llvm_ty, llvm_arg, "");
4767 load_inst.setAlignment(alignment);
4768 try llvm_args.append(load_inst);
5112 const loaded = try self.wip.load(.normal, array_ty, llvm_arg, alignment, "");
5113 try llvm_args.append(loaded.toLlvm(&self.wip));
47695114 },
47705115 .i32_array, .i64_array => |arr_len| {
47715116 const elem_size: u8 = if (lowering == .i32_array) 32 else 64;
47725117 const arg = args[it.zig_index - 1];
47735118 const arg_ty = self.typeOf(arg);
47745119 var llvm_arg = try self.resolveInst(arg);
5120 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
47755121 if (!isByRef(arg_ty, mod)) {
4776 const p = self.buildAlloca(llvm_arg.typeOf(), null);
4777 const store_inst = self.builder.buildStore(llvm_arg, p);
4778 store_inst.setAlignment(arg_ty.abiAlignment(mod));
4779 llvm_arg = store_inst;
5122 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);
5123 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);
5124 llvm_arg = ptr;
47805125 }
47815126
4782 const array_llvm_ty = self.context.intType(elem_size).arrayType(arr_len);
4783 const alignment = arg_ty.abiAlignment(mod);
4784 const load_inst = self.builder.buildLoad(array_llvm_ty, llvm_arg, "");
4785 load_inst.setAlignment(alignment);
4786 try llvm_args.append(load_inst);
5127 const array_ty =
5128 try o.builder.arrayType(arr_len, try o.builder.intType(@intCast(elem_size)));
5129 const loaded = try self.wip.load(.normal, array_ty, llvm_arg, alignment, "");
5130 try llvm_args.append(loaded.toLlvm(&self.wip));
47875131 },
47885132 };
47895133
4790 const call = self.builder.buildCall(
4791 try o.lowerType(zig_fn_ty),
4792 llvm_fn,
4793 llvm_args.items.ptr,
4794 @as(c_uint, @intCast(llvm_args.items.len)),
4795 toLlvmCallConv(fn_info.cc, target),
4796 attr,
4797 "",
5134 const llvm_fn_ty = try o.lowerType(zig_fn_ty);
5135 const call = (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(
5136 self.builder.buildCall(
5137 llvm_fn_ty.toLlvm(&o.builder),
5138 llvm_fn.toLlvm(&self.wip),
5139 llvm_args.items.ptr,
5140 @intCast(llvm_args.items.len),
5141 toLlvmCallConv(fn_info.cc, target),
5142 attr,
5143 "",
5144 ),
5145 &self.wip,
47985146 );
47995147
48005148 if (callee_ty.zigTypeTag(mod) == .Pointer) {
......@@ -4802,12 +5150,12 @@ pub const FuncGen = struct {
48025150 it = iterateParamTypes(o, fn_info);
48035151 it.llvm_index += @intFromBool(sret);
48045152 it.llvm_index += @intFromBool(err_return_tracing);
4805 while (it.next()) |lowering| switch (lowering) {
5153 while (try it.next()) |lowering| switch (lowering) {
48065154 .byval => {
48075155 const param_index = it.zig_index - 1;
48085156 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
48095157 if (!isByRef(param_ty, mod)) {
4810 o.addByValParamAttrs(call, param_ty, param_index, fn_info, it.llvm_index - 1);
5158 o.addByValParamAttrs(call.toLlvm(&self.wip), param_ty, param_index, fn_info, it.llvm_index - 1);
48115159 }
48125160 },
48135161 .byref => {
......@@ -4815,10 +5163,10 @@ pub const FuncGen = struct {
48155163 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
48165164 const param_llvm_ty = try o.lowerType(param_ty);
48175165 const alignment = param_ty.abiAlignment(mod);
4818 o.addByRefParamAttrs(call, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
5166 o.addByRefParamAttrs(call.toLlvm(&self.wip), it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
48195167 },
48205168 .byref_mut => {
4821 o.addArgAttr(call, it.llvm_index - 1, "noundef");
5169 o.addArgAttr(call.toLlvm(&self.wip), it.llvm_index - 1, "noundef");
48225170 },
48235171 // No attributes needed for these.
48245172 .no_bits,
......@@ -4838,41 +5186,40 @@ pub const FuncGen = struct {
48385186
48395187 if (math.cast(u5, it.zig_index - 1)) |i| {
48405188 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
4841 o.addArgAttr(call, llvm_arg_i, "noalias");
5189 o.addArgAttr(call.toLlvm(&self.wip), llvm_arg_i, "noalias");
48425190 }
48435191 }
48445192 if (param_ty.zigTypeTag(mod) != .Optional) {
4845 o.addArgAttr(call, llvm_arg_i, "nonnull");
5193 o.addArgAttr(call.toLlvm(&self.wip), llvm_arg_i, "nonnull");
48465194 }
48475195 if (ptr_info.flags.is_const) {
4848 o.addArgAttr(call, llvm_arg_i, "readonly");
5196 o.addArgAttr(call.toLlvm(&self.wip), llvm_arg_i, "readonly");
48495197 }
48505198 const elem_align = ptr_info.flags.alignment.toByteUnitsOptional() orelse
48515199 @max(ptr_info.child.toType().abiAlignment(mod), 1);
4852 o.addArgAttrInt(call, llvm_arg_i, "align", elem_align);
5200 o.addArgAttrInt(call.toLlvm(&self.wip), llvm_arg_i, "align", elem_align);
48535201 },
48545202 };
48555203 }
48565204
48575205 if (fn_info.return_type == .noreturn_type and attr != .AlwaysTail) {
4858 return null;
5206 return .none;
48595207 }
48605208
48615209 if (self.liveness.isUnused(inst) or !return_type.hasRuntimeBitsIgnoreComptime(mod)) {
4862 return null;
5210 return .none;
48635211 }
48645212
48655213 const llvm_ret_ty = try o.lowerType(return_type);
48665214
48675215 if (ret_ptr) |rp| {
4868 call.setCallSret(llvm_ret_ty);
5216 call.toLlvm(&self.wip).setCallSret(llvm_ret_ty.toLlvm(&o.builder));
48695217 if (isByRef(return_type, mod)) {
48705218 return rp;
48715219 } else {
48725220 // our by-ref status disagrees with sret so we must load.
4873 const loaded = self.builder.buildLoad(llvm_ret_ty, rp, "");
4874 loaded.setAlignment(return_type.abiAlignment(mod));
4875 return loaded;
5221 const return_alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));
5222 return self.wip.load(.normal, llvm_ret_ty, rp, return_alignment, "");
48765223 }
48775224 }
48785225
......@@ -4882,26 +5229,23 @@ pub const FuncGen = struct {
48825229 // In this case the function return type is honoring the calling convention by having
48835230 // a different LLVM type than the usual one. We solve this here at the callsite
48845231 // by using our canonical type, then loading it if necessary.
4885 const alignment = o.target_data.abiAlignmentOfType(abi_ret_ty);
4886 const rp = self.buildAlloca(llvm_ret_ty, alignment);
4887 const store_inst = self.builder.buildStore(call, rp);
4888 store_inst.setAlignment(alignment);
4889 if (isByRef(return_type, mod)) {
4890 return rp;
4891 } else {
4892 const load_inst = self.builder.buildLoad(llvm_ret_ty, rp, "");
4893 load_inst.setAlignment(alignment);
4894 return load_inst;
4895 }
5232 const alignment = Builder.Alignment.fromByteUnits(
5233 o.target_data.abiAlignmentOfType(abi_ret_ty.toLlvm(&o.builder)),
5234 );
5235 const rp = try self.buildAlloca(llvm_ret_ty, alignment);
5236 _ = try self.wip.store(.normal, call, rp, alignment);
5237 return if (isByRef(return_type, mod))
5238 rp
5239 else
5240 try self.wip.load(.normal, llvm_ret_ty, rp, alignment, "");
48965241 }
48975242
48985243 if (isByRef(return_type, mod)) {
48995244 // our by-ref status disagrees with sret so we must allocate, store,
49005245 // and return the allocation pointer.
4901 const alignment = return_type.abiAlignment(mod);
4902 const rp = self.buildAlloca(llvm_ret_ty, alignment);
4903 const store_inst = self.builder.buildStore(call, rp);
4904 store_inst.setAlignment(alignment);
5246 const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));
5247 const rp = try self.buildAlloca(llvm_ret_ty, alignment);
5248 _ = try self.wip.store(.normal, call, rp, alignment);
49055249 return rp;
49065250 } else {
49075251 return call;
......@@ -4914,13 +5258,10 @@ pub const FuncGen = struct {
49145258 const msg_decl_index = mod.panic_messages[@intFromEnum(panic_id)].unwrap().?;
49155259 const msg_decl = mod.declPtr(msg_decl_index);
49165260 const msg_len = msg_decl.ty.childType(mod).arrayLen(mod);
4917 const msg_ptr = try o.lowerValue(.{
4918 .ty = msg_decl.ty,
4919 .val = msg_decl.val,
4920 });
4921 const null_opt_addr_global = try o.getNullOptAddr();
5261 const msg_ptr = try o.lowerValue(try msg_decl.internValue(mod));
5262 const null_opt_addr_global = try fg.resolveNullOptUsize();
49225263 const target = mod.getTarget();
4923 const llvm_usize = fg.context.intType(target.ptrBitWidth());
5264 const llvm_usize = try o.lowerType(Type.usize);
49245265 // example:
49255266 // call fastcc void @test2.panic(
49265267 // ptr @builtin.panic_messages.integer_overflow__anon_987, ; msg.ptr
......@@ -4929,38 +5270,38 @@ pub const FuncGen = struct {
49295270 // ptr @2, ; addr (null ?usize)
49305271 // )
49315272 const args = [4]*llvm.Value{
4932 msg_ptr,
4933 llvm_usize.constInt(msg_len, .False),
4934 fg.context.pointerType(0).constNull(),
4935 null_opt_addr_global,
5273 msg_ptr.toLlvm(&o.builder),
5274 (try o.builder.intConst(llvm_usize, msg_len)).toLlvm(&o.builder),
5275 (try o.builder.nullConst(.ptr)).toLlvm(&o.builder),
5276 null_opt_addr_global.toLlvm(&o.builder),
49365277 };
49375278 const panic_func = mod.funcInfo(mod.panic_func_index);
49385279 const panic_decl = mod.declPtr(panic_func.owner_decl);
49395280 const fn_info = mod.typeToFunc(panic_decl.ty).?;
49405281 const panic_global = try o.resolveLlvmFunction(panic_func.owner_decl);
4941 _ = fg.builder.buildCall(
4942 try o.lowerType(panic_decl.ty),
4943 panic_global,
5282 _ = (try fg.wip.unimplemented(.void, "")).finish(fg.builder.buildCall(
5283 (try o.lowerType(panic_decl.ty)).toLlvm(&o.builder),
5284 panic_global.toLlvm(&o.builder),
49445285 &args,
49455286 args.len,
49465287 toLlvmCallConv(fn_info.cc, target),
49475288 .Auto,
49485289 "",
4949 );
4950 _ = fg.builder.buildUnreachable();
5290 ), &fg.wip);
5291 _ = try fg.wip.@"unreachable"();
49515292 }
49525293
4953 fn airRet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5294 fn airRet(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
49545295 const o = self.dg.object;
49555296 const mod = o.module;
49565297 const un_op = self.air.instructions.items(.data)[inst].un_op;
49575298 const ret_ty = self.typeOf(un_op);
4958 if (self.ret_ptr) |ret_ptr| {
5299 if (self.ret_ptr != .none) {
49595300 const operand = try self.resolveInst(un_op);
49605301 const ptr_ty = try mod.singleMutPtrType(ret_ty);
4961 try self.store(ret_ptr, ptr_ty, operand, .NotAtomic);
4962 _ = self.builder.buildRetVoid();
4963 return null;
5302 try self.store(self.ret_ptr, ptr_ty, operand, .none);
5303 _ = try self.wip.retVoid();
5304 return .none;
49645305 }
49655306 const fn_info = mod.typeToFunc(self.dg.decl.ty).?;
49665307 if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) {
......@@ -4968,43 +5309,37 @@ pub const FuncGen = struct {
49685309 // Functions with an empty error set are emitted with an error code
49695310 // return type and return zero so they can be function pointers coerced
49705311 // to functions that return anyerror.
4971 const err_int = try o.lowerType(Type.anyerror);
4972 _ = self.builder.buildRet(err_int.constInt(0, .False));
5312 _ = try self.wip.ret(try o.builder.intValue(Builder.Type.err_int, 0));
49735313 } else {
4974 _ = self.builder.buildRetVoid();
5314 _ = try self.wip.retVoid();
49755315 }
4976 return null;
5316 return .none;
49775317 }
49785318
49795319 const abi_ret_ty = try lowerFnRetTy(o, fn_info);
49805320 const operand = try self.resolveInst(un_op);
4981 const alignment = ret_ty.abiAlignment(mod);
5321 const alignment = Builder.Alignment.fromByteUnits(ret_ty.abiAlignment(mod));
49825322
49835323 if (isByRef(ret_ty, mod)) {
49845324 // operand is a pointer however self.ret_ptr is null so that means
49855325 // we need to return a value.
4986 const load_inst = self.builder.buildLoad(abi_ret_ty, operand, "");
4987 load_inst.setAlignment(alignment);
4988 _ = self.builder.buildRet(load_inst);
4989 return null;
5326 _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, operand, alignment, ""));
5327 return .none;
49905328 }
49915329
4992 const llvm_ret_ty = operand.typeOf();
5330 const llvm_ret_ty = operand.typeOfWip(&self.wip);
49935331 if (abi_ret_ty == llvm_ret_ty) {
4994 _ = self.builder.buildRet(operand);
4995 return null;
5332 _ = try self.wip.ret(operand);
5333 return .none;
49965334 }
49975335
4998 const rp = self.buildAlloca(llvm_ret_ty, alignment);
4999 const store_inst = self.builder.buildStore(operand, rp);
5000 store_inst.setAlignment(alignment);
5001 const load_inst = self.builder.buildLoad(abi_ret_ty, rp, "");
5002 load_inst.setAlignment(alignment);
5003 _ = self.builder.buildRet(load_inst);
5004 return null;
5336 const rp = try self.buildAlloca(llvm_ret_ty, alignment);
5337 _ = try self.wip.store(.normal, operand, rp, alignment);
5338 _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, rp, alignment, ""));
5339 return .none;
50055340 }
50065341
5007 fn airRetLoad(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5342 fn airRetLoad(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
50085343 const o = self.dg.object;
50095344 const mod = o.module;
50105345 const un_op = self.air.instructions.items(.data)[inst].un_op;
......@@ -5016,36 +5351,34 @@ pub const FuncGen = struct {
50165351 // Functions with an empty error set are emitted with an error code
50175352 // return type and return zero so they can be function pointers coerced
50185353 // to functions that return anyerror.
5019 const err_int = try o.lowerType(Type.anyerror);
5020 _ = self.builder.buildRet(err_int.constInt(0, .False));
5354 _ = try self.wip.ret(try o.builder.intValue(Builder.Type.err_int, 0));
50215355 } else {
5022 _ = self.builder.buildRetVoid();
5356 _ = try self.wip.retVoid();
50235357 }
5024 return null;
5358 return .none;
50255359 }
5026 if (self.ret_ptr != null) {
5027 _ = self.builder.buildRetVoid();
5028 return null;
5360 if (self.ret_ptr != .none) {
5361 _ = try self.wip.retVoid();
5362 return .none;
50295363 }
50305364 const ptr = try self.resolveInst(un_op);
50315365 const abi_ret_ty = try lowerFnRetTy(o, fn_info);
5032 const loaded = self.builder.buildLoad(abi_ret_ty, ptr, "");
5033 loaded.setAlignment(ret_ty.abiAlignment(mod));
5034 _ = self.builder.buildRet(loaded);
5035 return null;
5366 const alignment = Builder.Alignment.fromByteUnits(ret_ty.abiAlignment(mod));
5367 _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, ptr, alignment, ""));
5368 return .none;
50365369 }
50375370
5038 fn airCVaArg(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5371 fn airCVaArg(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
50395372 const o = self.dg.object;
50405373 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
50415374 const list = try self.resolveInst(ty_op.operand);
50425375 const arg_ty = self.air.getRefType(ty_op.ty);
50435376 const llvm_arg_ty = try o.lowerType(arg_ty);
50445377
5045 return self.builder.buildVAArg(list, llvm_arg_ty, "");
5378 return self.wip.vaArg(list, llvm_arg_ty, "");
50465379 }
50475380
5048 fn airCVaCopy(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5381 fn airCVaCopy(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
50495382 const o = self.dg.object;
50505383 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
50515384 const src_list = try self.resolveInst(ty_op.operand);
......@@ -5053,75 +5386,86 @@ pub const FuncGen = struct {
50535386 const llvm_va_list_ty = try o.lowerType(va_list_ty);
50545387 const mod = o.module;
50555388
5056 const result_alignment = va_list_ty.abiAlignment(mod);
5057 const dest_list = self.buildAlloca(llvm_va_list_ty, result_alignment);
5389 const result_alignment = Builder.Alignment.fromByteUnits(va_list_ty.abiAlignment(mod));
5390 const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment);
50585391
50595392 const llvm_fn_name = "llvm.va_copy";
5060 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {
5061 const param_types = [_]*llvm.Type{
5062 self.context.pointerType(0),
5063 self.context.pointerType(0),
5064 };
5065 const fn_type = llvm.functionType(self.context.voidType(), &param_types, param_types.len, .False);
5066 break :blk o.llvm_module.addFunction(llvm_fn_name, fn_type);
5067 };
5393 const llvm_fn_ty = try o.builder.fnType(.void, &.{ .ptr, .ptr }, .normal);
5394 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse
5395 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
50685396
5069 const args: [2]*llvm.Value = .{ dest_list, src_list };
5070 _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");
5397 const args: [2]*llvm.Value = .{ dest_list.toLlvm(&self.wip), src_list.toLlvm(&self.wip) };
5398 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
5399 llvm_fn_ty.toLlvm(&o.builder),
5400 llvm_fn,
5401 &args,
5402 args.len,
5403 .Fast,
5404 .Auto,
5405 "",
5406 ), &self.wip);
50715407
5072 if (isByRef(va_list_ty, mod)) {
5073 return dest_list;
5074 } else {
5075 const loaded = self.builder.buildLoad(llvm_va_list_ty, dest_list, "");
5076 loaded.setAlignment(result_alignment);
5077 return loaded;
5078 }
5408 return if (isByRef(va_list_ty, mod))
5409 dest_list
5410 else
5411 try self.wip.load(.normal, llvm_va_list_ty, dest_list, result_alignment, "");
50795412 }
50805413
5081 fn airCVaEnd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5414 fn airCVaEnd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
50825415 const o = self.dg.object;
50835416 const un_op = self.air.instructions.items(.data)[inst].un_op;
50845417 const list = try self.resolveInst(un_op);
50855418
50865419 const llvm_fn_name = "llvm.va_end";
5087 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {
5088 const param_types = [_]*llvm.Type{self.context.pointerType(0)};
5089 const fn_type = llvm.functionType(self.context.voidType(), &param_types, param_types.len, .False);
5090 break :blk o.llvm_module.addFunction(llvm_fn_name, fn_type);
5091 };
5092 const args: [1]*llvm.Value = .{list};
5093 _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");
5094 return null;
5420 const llvm_fn_ty = try o.builder.fnType(.void, &.{.ptr}, .normal);
5421 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse
5422 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
5423
5424 const args: [1]*llvm.Value = .{list.toLlvm(&self.wip)};
5425 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
5426 llvm_fn_ty.toLlvm(&o.builder),
5427 llvm_fn,
5428 &args,
5429 args.len,
5430 .Fast,
5431 .Auto,
5432 "",
5433 ), &self.wip);
5434 return .none;
50955435 }
50965436
5097 fn airCVaStart(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5437 fn airCVaStart(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
50985438 const o = self.dg.object;
50995439 const mod = o.module;
51005440 const va_list_ty = self.typeOfIndex(inst);
51015441 const llvm_va_list_ty = try o.lowerType(va_list_ty);
51025442
5103 const result_alignment = va_list_ty.abiAlignment(mod);
5104 const list = self.buildAlloca(llvm_va_list_ty, result_alignment);
5443 const result_alignment = Builder.Alignment.fromByteUnits(va_list_ty.abiAlignment(mod));
5444 const list = try self.buildAlloca(llvm_va_list_ty, result_alignment);
51055445
51065446 const llvm_fn_name = "llvm.va_start";
5107 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {
5108 const param_types = [_]*llvm.Type{self.context.pointerType(0)};
5109 const fn_type = llvm.functionType(self.context.voidType(), &param_types, param_types.len, .False);
5110 break :blk o.llvm_module.addFunction(llvm_fn_name, fn_type);
5111 };
5112 const args: [1]*llvm.Value = .{list};
5113 _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");
5447 const llvm_fn_ty = try o.builder.fnType(.void, &.{.ptr}, .normal);
5448 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse
5449 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
51145450
5115 if (isByRef(va_list_ty, mod)) {
5116 return list;
5117 } else {
5118 const loaded = self.builder.buildLoad(llvm_va_list_ty, list, "");
5119 loaded.setAlignment(result_alignment);
5120 return loaded;
5121 }
5451 const args: [1]*llvm.Value = .{list.toLlvm(&self.wip)};
5452 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
5453 llvm_fn_ty.toLlvm(&o.builder),
5454 llvm_fn,
5455 &args,
5456 args.len,
5457 .Fast,
5458 .Auto,
5459 "",
5460 ), &self.wip);
5461
5462 return if (isByRef(va_list_ty, mod))
5463 list
5464 else
5465 try self.wip.load(.normal, llvm_va_list_ty, list, result_alignment, "");
51225466 }
51235467
5124 fn airCmp(self: *FuncGen, inst: Air.Inst.Index, op: math.CompareOperator, want_fast_math: bool) !?*llvm.Value {
5468 fn airCmp(self: *FuncGen, inst: Air.Inst.Index, op: math.CompareOperator, want_fast_math: bool) !Builder.Value {
51255469 self.builder.setFastMath(want_fast_math);
51265470
51275471 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -5132,7 +5476,7 @@ pub const FuncGen = struct {
51325476 return self.cmp(lhs, rhs, operand_ty, op);
51335477 }
51345478
5135 fn airCmpVector(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
5479 fn airCmpVector(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
51365480 self.builder.setFastMath(want_fast_math);
51375481
51385482 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -5146,21 +5490,30 @@ pub const FuncGen = struct {
51465490 return self.cmp(lhs, rhs, vec_ty, cmp_op);
51475491 }
51485492
5149 fn airCmpLtErrorsLen(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5493 fn airCmpLtErrorsLen(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5494 const o = self.dg.object;
51505495 const un_op = self.air.instructions.items(.data)[inst].un_op;
51515496 const operand = try self.resolveInst(un_op);
51525497 const llvm_fn = try self.getCmpLtErrorsLenFunction();
5153 const args: [1]*llvm.Value = .{operand};
5154 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");
5498 const args: [1]*llvm.Value = .{operand.toLlvm(&self.wip)};
5499 return (try self.wip.unimplemented(.i1, "")).finish(self.builder.buildCall(
5500 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),
5501 llvm_fn.toLlvm(&o.builder),
5502 &args,
5503 args.len,
5504 .Fast,
5505 .Auto,
5506 "",
5507 ), &self.wip);
51555508 }
51565509
51575510 fn cmp(
51585511 self: *FuncGen,
5159 lhs: *llvm.Value,
5160 rhs: *llvm.Value,
5512 lhs: Builder.Value,
5513 rhs: Builder.Value,
51615514 operand_ty: Type,
51625515 op: math.CompareOperator,
5163 ) Allocator.Error!*llvm.Value {
5516 ) Allocator.Error!Builder.Value {
51645517 const o = self.dg.object;
51655518 const mod = o.module;
51665519 const scalar_ty = operand_ty.scalarType(mod);
......@@ -5178,46 +5531,47 @@ pub const FuncGen = struct {
51785531 // of optionals that are not pointers.
51795532 const is_by_ref = isByRef(scalar_ty, mod);
51805533 const opt_llvm_ty = try o.lowerType(scalar_ty);
5181 const lhs_non_null = self.optIsNonNull(opt_llvm_ty, lhs, is_by_ref);
5182 const rhs_non_null = self.optIsNonNull(opt_llvm_ty, rhs, is_by_ref);
5183 const llvm_i2 = self.context.intType(2);
5184 const lhs_non_null_i2 = self.builder.buildZExt(lhs_non_null, llvm_i2, "");
5185 const rhs_non_null_i2 = self.builder.buildZExt(rhs_non_null, llvm_i2, "");
5186 const lhs_shifted = self.builder.buildShl(lhs_non_null_i2, llvm_i2.constInt(1, .False), "");
5187 const lhs_rhs_ored = self.builder.buildOr(lhs_shifted, rhs_non_null_i2, "");
5188 const both_null_block = self.context.appendBasicBlock(self.llvm_func, "BothNull");
5189 const mixed_block = self.context.appendBasicBlock(self.llvm_func, "Mixed");
5190 const both_pl_block = self.context.appendBasicBlock(self.llvm_func, "BothNonNull");
5191 const end_block = self.context.appendBasicBlock(self.llvm_func, "End");
5192 const llvm_switch = self.builder.buildSwitch(lhs_rhs_ored, mixed_block, 2);
5193 const llvm_i2_00 = llvm_i2.constInt(0b00, .False);
5194 const llvm_i2_11 = llvm_i2.constInt(0b11, .False);
5195 llvm_switch.addCase(llvm_i2_00, both_null_block);
5196 llvm_switch.addCase(llvm_i2_11, both_pl_block);
5197
5198 self.builder.positionBuilderAtEnd(both_null_block);
5199 _ = self.builder.buildBr(end_block);
5200
5201 self.builder.positionBuilderAtEnd(mixed_block);
5202 _ = self.builder.buildBr(end_block);
5203
5204 self.builder.positionBuilderAtEnd(both_pl_block);
5534 const lhs_non_null = try self.optCmpNull(.ne, opt_llvm_ty, lhs, is_by_ref);
5535 const rhs_non_null = try self.optCmpNull(.ne, opt_llvm_ty, rhs, is_by_ref);
5536 const llvm_i2 = try o.builder.intType(2);
5537 const lhs_non_null_i2 = try self.wip.cast(.zext, lhs_non_null, llvm_i2, "");
5538 const rhs_non_null_i2 = try self.wip.cast(.zext, rhs_non_null, llvm_i2, "");
5539 const lhs_shifted = try self.wip.bin(.shl, lhs_non_null_i2, try o.builder.intValue(llvm_i2, 1), "");
5540 const lhs_rhs_ored = try self.wip.bin(.@"or", lhs_shifted, rhs_non_null_i2, "");
5541 const both_null_block = try self.wip.block(1, "BothNull");
5542 const mixed_block = try self.wip.block(1, "Mixed");
5543 const both_pl_block = try self.wip.block(1, "BothNonNull");
5544 const end_block = try self.wip.block(3, "End");
5545 var wip_switch = try self.wip.@"switch"(lhs_rhs_ored, mixed_block, 2);
5546 defer wip_switch.finish(&self.wip);
5547 try wip_switch.addCase(
5548 try o.builder.intConst(llvm_i2, 0b00),
5549 both_null_block,
5550 &self.wip,
5551 );
5552 try wip_switch.addCase(
5553 try o.builder.intConst(llvm_i2, 0b11),
5554 both_pl_block,
5555 &self.wip,
5556 );
5557
5558 self.wip.cursor = .{ .block = both_null_block };
5559 _ = try self.wip.br(end_block);
5560
5561 self.wip.cursor = .{ .block = mixed_block };
5562 _ = try self.wip.br(end_block);
5563
5564 self.wip.cursor = .{ .block = both_pl_block };
52055565 const lhs_payload = try self.optPayloadHandle(opt_llvm_ty, lhs, scalar_ty, true);
52065566 const rhs_payload = try self.optPayloadHandle(opt_llvm_ty, rhs, scalar_ty, true);
52075567 const payload_cmp = try self.cmp(lhs_payload, rhs_payload, payload_ty, op);
5208 _ = self.builder.buildBr(end_block);
5209 const both_pl_block_end = self.builder.getInsertBlock();
5568 _ = try self.wip.br(end_block);
5569 const both_pl_block_end = self.wip.cursor.block;
52105570
5211 self.builder.positionBuilderAtEnd(end_block);
5212 const incoming_blocks: [3]*llvm.BasicBlock = .{
5213 both_null_block,
5214 mixed_block,
5215 both_pl_block_end,
5216 };
5217 const llvm_i1 = self.context.intType(1);
5218 const llvm_i1_0 = llvm_i1.constInt(0, .False);
5219 const llvm_i1_1 = llvm_i1.constInt(1, .False);
5220 const incoming_values: [3]*llvm.Value = .{
5571 self.wip.cursor = .{ .block = end_block };
5572 const llvm_i1_0 = try o.builder.intValue(.i1, 0);
5573 const llvm_i1_1 = try o.builder.intValue(.i1, 1);
5574 const incoming_values: [3]Builder.Value = .{
52215575 switch (op) {
52225576 .eq => llvm_i1_1,
52235577 .neq => llvm_i1_0,
......@@ -5231,47 +5585,48 @@ pub const FuncGen = struct {
52315585 payload_cmp,
52325586 };
52335587
5234 const phi_node = self.builder.buildPhi(llvm_i1, "");
5235 comptime assert(incoming_values.len == incoming_blocks.len);
5236 phi_node.addIncoming(
5588 const phi = try self.wip.phi(.i1, "");
5589 try phi.finish(
52375590 &incoming_values,
5238 &incoming_blocks,
5239 incoming_values.len,
5591 &.{ both_null_block, mixed_block, both_pl_block_end },
5592 &self.wip,
52405593 );
5241 return phi_node;
5594 return phi.toValue();
52425595 },
52435596 .Float => return self.buildFloatCmp(op, operand_ty, .{ lhs, rhs }),
52445597 else => unreachable,
52455598 };
52465599 const is_signed = int_ty.isSignedInt(mod);
5247 const operation: llvm.IntPredicate = switch (op) {
5248 .eq => .EQ,
5249 .neq => .NE,
5250 .lt => if (is_signed) llvm.IntPredicate.SLT else .ULT,
5251 .lte => if (is_signed) llvm.IntPredicate.SLE else .ULE,
5252 .gt => if (is_signed) llvm.IntPredicate.SGT else .UGT,
5253 .gte => if (is_signed) llvm.IntPredicate.SGE else .UGE,
5600 const cond: Builder.IntegerCondition = switch (op) {
5601 .eq => .eq,
5602 .neq => .ne,
5603 .lt => if (is_signed) .slt else .ult,
5604 .lte => if (is_signed) .sle else .ule,
5605 .gt => if (is_signed) .sgt else .ugt,
5606 .gte => if (is_signed) .sge else .uge,
52545607 };
5255 return self.builder.buildICmp(operation, lhs, rhs, "");
5608 return self.wip.icmp(cond, lhs, rhs, "");
52565609 }
52575610
5258 fn airBlock(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5611 fn airBlock(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
52595612 const o = self.dg.object;
52605613 const mod = o.module;
52615614 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
52625615 const extra = self.air.extraData(Air.Block, ty_pl.payload);
52635616 const body = self.air.extra[extra.end..][0..extra.data.body_len];
52645617 const inst_ty = self.typeOfIndex(inst);
5265 const parent_bb = self.context.createBasicBlock("Block");
52665618
52675619 if (inst_ty.isNoReturn(mod)) {
52685620 try self.genBody(body);
5269 return null;
5621 return .none;
52705622 }
52715623
5272 var breaks: BreakList = .{};
5273 defer breaks.deinit(self.gpa);
5624 const have_block_result = inst_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod);
52745625
5626 var breaks: BreakList = if (have_block_result) .{ .list = .{} } else .{ .len = 0 };
5627 defer if (have_block_result) breaks.list.deinit(self.gpa);
5628
5629 const parent_bb = try self.wip.block(0, "Block");
52755630 try self.blocks.putNoClobber(self.gpa, inst, .{
52765631 .parent_bb = parent_bb,
52775632 .breaks = &breaks,
......@@ -5280,36 +5635,33 @@ pub const FuncGen = struct {
52805635
52815636 try self.genBody(body);
52825637
5283 self.llvm_func.appendExistingBasicBlock(parent_bb);
5284 self.builder.positionBuilderAtEnd(parent_bb);
5638 self.wip.cursor = .{ .block = parent_bb };
52855639
52865640 // Create a phi node only if the block returns a value.
5287 const is_body = inst_ty.zigTypeTag(mod) == .Fn;
5288 if (!is_body and !inst_ty.hasRuntimeBitsIgnoreComptime(mod)) return null;
5289
5290 const raw_llvm_ty = try o.lowerType(inst_ty);
5291
5292 const llvm_ty = ty: {
5293 // If the zig tag type is a function, this represents an actual function body; not
5294 // a pointer to it. LLVM IR allows the call instruction to use function bodies instead
5295 // of function pointers, however the phi makes it a runtime value and therefore
5296 // the LLVM type has to be wrapped in a pointer.
5297 if (is_body or isByRef(inst_ty, mod)) {
5298 break :ty self.context.pointerType(0);
5299 }
5300 break :ty raw_llvm_ty;
5301 };
5641 if (have_block_result) {
5642 const raw_llvm_ty = try o.lowerType(inst_ty);
5643 const llvm_ty: Builder.Type = ty: {
5644 // If the zig tag type is a function, this represents an actual function body; not
5645 // a pointer to it. LLVM IR allows the call instruction to use function bodies instead
5646 // of function pointers, however the phi makes it a runtime value and therefore
5647 // the LLVM type has to be wrapped in a pointer.
5648 if (inst_ty.zigTypeTag(mod) == .Fn or isByRef(inst_ty, mod)) {
5649 break :ty .ptr;
5650 }
5651 break :ty raw_llvm_ty;
5652 };
53025653
5303 const phi_node = self.builder.buildPhi(llvm_ty, "");
5304 phi_node.addIncoming(
5305 breaks.items(.val).ptr,
5306 breaks.items(.bb).ptr,
5307 @as(c_uint, @intCast(breaks.len)),
5308 );
5309 return phi_node;
5654 parent_bb.ptr(&self.wip).incoming = @intCast(breaks.list.len);
5655 const phi = try self.wip.phi(llvm_ty, "");
5656 try phi.finish(breaks.list.items(.val), breaks.list.items(.bb), &self.wip);
5657 return phi.toValue();
5658 } else {
5659 parent_bb.ptr(&self.wip).incoming = @intCast(breaks.len);
5660 return .none;
5661 }
53105662 }
53115663
5312 fn airBr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5664 fn airBr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
53135665 const o = self.dg.object;
53145666 const branch = self.air.instructions.items(.data)[inst].br;
53155667 const block = self.blocks.get(branch.block_inst).?;
......@@ -5317,42 +5669,39 @@ pub const FuncGen = struct {
53175669 // Add the values to the lists only if the break provides a value.
53185670 const operand_ty = self.typeOf(branch.operand);
53195671 const mod = o.module;
5320 if (operand_ty.hasRuntimeBitsIgnoreComptime(mod) or operand_ty.zigTypeTag(mod) == .Fn) {
5672 if (operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) {
53215673 const val = try self.resolveInst(branch.operand);
53225674
53235675 // For the phi node, we need the basic blocks and the values of the
53245676 // break instructions.
5325 try block.breaks.append(self.gpa, .{
5326 .bb = self.builder.getInsertBlock(),
5327 .val = val,
5328 });
5329 }
5330 _ = self.builder.buildBr(block.parent_bb);
5331 return null;
5677 try block.breaks.list.append(self.gpa, .{ .bb = self.wip.cursor.block, .val = val });
5678 } else block.breaks.len += 1;
5679 _ = try self.wip.br(block.parent_bb);
5680 return .none;
53325681 }
53335682
5334 fn airCondBr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5683 fn airCondBr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
53355684 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
53365685 const cond = try self.resolveInst(pl_op.operand);
53375686 const extra = self.air.extraData(Air.CondBr, pl_op.payload);
53385687 const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len];
53395688 const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
53405689
5341 const then_block = self.context.appendBasicBlock(self.llvm_func, "Then");
5342 const else_block = self.context.appendBasicBlock(self.llvm_func, "Else");
5343 _ = self.builder.buildCondBr(cond, then_block, else_block);
5690 const then_block = try self.wip.block(1, "Then");
5691 const else_block = try self.wip.block(1, "Else");
5692 _ = try self.wip.brCond(cond, then_block, else_block);
53445693
5345 self.builder.positionBuilderAtEnd(then_block);
5694 self.wip.cursor = .{ .block = then_block };
53465695 try self.genBody(then_body);
53475696
5348 self.builder.positionBuilderAtEnd(else_block);
5697 self.wip.cursor = .{ .block = else_block };
53495698 try self.genBody(else_body);
53505699
53515700 // No need to reset the insert cursor since this instruction is noreturn.
5352 return null;
5701 return .none;
53535702 }
53545703
5355 fn airTry(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
5704 fn airTry(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
53565705 const o = self.dg.object;
53575706 const mod = o.module;
53585707 const inst = body_tail[0];
......@@ -5367,7 +5716,7 @@ pub const FuncGen = struct {
53675716 return lowerTry(self, err_union, body, err_union_ty, false, can_elide_load, is_unused);
53685717 }
53695718
5370 fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5719 fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
53715720 const o = self.dg.object;
53725721 const mod = o.module;
53735722 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -5381,13 +5730,13 @@ pub const FuncGen = struct {
53815730
53825731 fn lowerTry(
53835732 fg: *FuncGen,
5384 err_union: *llvm.Value,
5733 err_union: Builder.Value,
53855734 body: []const Air.Inst.Index,
53865735 err_union_ty: Type,
53875736 operand_is_ptr: bool,
53885737 can_elide_load: bool,
53895738 is_unused: bool,
5390 ) !?*llvm.Value {
5739 ) !Builder.Value {
53915740 const o = fg.dg.object;
53925741 const mod = o.module;
53935742 const payload_ty = err_union_ty.errorUnionPayload(mod);
......@@ -5395,122 +5744,135 @@ pub const FuncGen = struct {
53955744 const err_union_llvm_ty = try o.lowerType(err_union_ty);
53965745
53975746 if (!err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) {
5398 const is_err = err: {
5399 const err_set_ty = try o.lowerType(Type.anyerror);
5400 const zero = err_set_ty.constNull();
5747 const loaded = loaded: {
54015748 if (!payload_has_bits) {
54025749 // TODO add alignment to this load
5403 const loaded = if (operand_is_ptr)
5404 fg.builder.buildLoad(err_set_ty, err_union, "")
5750 break :loaded if (operand_is_ptr)
5751 try fg.wip.load(.normal, Builder.Type.err_int, err_union, .default, "")
54055752 else
54065753 err_union;
5407 break :err fg.builder.buildICmp(.NE, loaded, zero, "");
54085754 }
54095755 const err_field_index = errUnionErrorOffset(payload_ty, mod);
54105756 if (operand_is_ptr or isByRef(err_union_ty, mod)) {
5411 const err_field_ptr = fg.builder.buildStructGEP(err_union_llvm_ty, err_union, err_field_index, "");
5757 const err_field_ptr =
5758 try fg.wip.gepStruct(err_union_llvm_ty, err_union, err_field_index, "");
54125759 // TODO add alignment to this load
5413 const loaded = fg.builder.buildLoad(err_set_ty, err_field_ptr, "");
5414 break :err fg.builder.buildICmp(.NE, loaded, zero, "");
5760 break :loaded try fg.wip.load(
5761 .normal,
5762 Builder.Type.err_int,
5763 err_field_ptr,
5764 .default,
5765 "",
5766 );
54155767 }
5416 const loaded = fg.builder.buildExtractValue(err_union, err_field_index, "");
5417 break :err fg.builder.buildICmp(.NE, loaded, zero, "");
5768 break :loaded try fg.wip.extractValue(err_union, &.{err_field_index}, "");
54185769 };
5770 const zero = try o.builder.intValue(Builder.Type.err_int, 0);
5771 const is_err = try fg.wip.icmp(.ne, loaded, zero, "");
54195772
5420 const return_block = fg.context.appendBasicBlock(fg.llvm_func, "TryRet");
5421 const continue_block = fg.context.appendBasicBlock(fg.llvm_func, "TryCont");
5422 _ = fg.builder.buildCondBr(is_err, return_block, continue_block);
5773 const return_block = try fg.wip.block(1, "TryRet");
5774 const continue_block = try fg.wip.block(1, "TryCont");
5775 _ = try fg.wip.brCond(is_err, return_block, continue_block);
54235776
5424 fg.builder.positionBuilderAtEnd(return_block);
5777 fg.wip.cursor = .{ .block = return_block };
54255778 try fg.genBody(body);
54265779
5427 fg.builder.positionBuilderAtEnd(continue_block);
5428 }
5429 if (is_unused) {
5430 return null;
5431 }
5432 if (!payload_has_bits) {
5433 return if (operand_is_ptr) err_union else null;
5780 fg.wip.cursor = .{ .block = continue_block };
54345781 }
5782 if (is_unused) return .none;
5783 if (!payload_has_bits) return if (operand_is_ptr) err_union else .none;
54355784 const offset = errUnionPayloadOffset(payload_ty, mod);
54365785 if (operand_is_ptr) {
5437 return fg.builder.buildStructGEP(err_union_llvm_ty, err_union, offset, "");
5786 return fg.wip.gepStruct(err_union_llvm_ty, err_union, offset, "");
54385787 } else if (isByRef(err_union_ty, mod)) {
5439 const payload_ptr = fg.builder.buildStructGEP(err_union_llvm_ty, err_union, offset, "");
5788 const payload_ptr = try fg.wip.gepStruct(err_union_llvm_ty, err_union, offset, "");
5789 const payload_alignment = Builder.Alignment.fromByteUnits(payload_ty.abiAlignment(mod));
54405790 if (isByRef(payload_ty, mod)) {
54415791 if (can_elide_load)
54425792 return payload_ptr;
54435793
5444 return fg.loadByRef(payload_ptr, payload_ty, payload_ty.abiAlignment(mod), false);
5794 return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, false);
54455795 }
5446 const load_inst = fg.builder.buildLoad(err_union_llvm_ty.structGetTypeAtIndex(offset), payload_ptr, "");
5447 load_inst.setAlignment(payload_ty.abiAlignment(mod));
5448 return load_inst;
5796 const load_ty = err_union_llvm_ty.structFields(&o.builder)[offset];
5797 return fg.wip.load(.normal, load_ty, payload_ptr, payload_alignment, "");
54495798 }
5450 return fg.builder.buildExtractValue(err_union, offset, "");
5799 return fg.wip.extractValue(err_union, &.{offset}, "");
54515800 }
54525801
5453 fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5802 fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
54545803 const o = self.dg.object;
5455 const mod = o.module;
54565804 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
54575805 const cond = try self.resolveInst(pl_op.operand);
54585806 const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload);
5459 const else_block = self.context.appendBasicBlock(self.llvm_func, "Else");
5460 const target = mod.getTarget();
5461 const llvm_usize = self.context.intType(target.ptrBitWidth());
5462 const cond_int = if (cond.typeOf().getTypeKind() == .Pointer)
5463 self.builder.buildPtrToInt(cond, llvm_usize, "")
5807 const else_block = try self.wip.block(1, "Default");
5808 const llvm_usize = try o.lowerType(Type.usize);
5809 const cond_int = if (cond.typeOfWip(&self.wip).isPointer(&o.builder))
5810 try self.wip.cast(.ptrtoint, cond, llvm_usize, "")
54645811 else
54655812 cond;
5466 const llvm_switch = self.builder.buildSwitch(cond_int, else_block, switch_br.data.cases_len);
54675813
54685814 var extra_index: usize = switch_br.end;
54695815 var case_i: u32 = 0;
5816 var llvm_cases_len: u32 = 0;
5817 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
5818 const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
5819 const items: []const Air.Inst.Ref =
5820 @ptrCast(self.air.extra[case.end..][0..case.data.items_len]);
5821 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
5822 extra_index = case.end + case.data.items_len + case_body.len;
5823
5824 llvm_cases_len += @intCast(items.len);
5825 }
5826
5827 var wip_switch = try self.wip.@"switch"(cond_int, else_block, llvm_cases_len);
5828 defer wip_switch.finish(&self.wip);
54705829
5830 extra_index = switch_br.end;
5831 case_i = 0;
54715832 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
54725833 const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
5473 const items = @as([]const Air.Inst.Ref, @ptrCast(self.air.extra[case.end..][0..case.data.items_len]));
5834 const items: []const Air.Inst.Ref =
5835 @ptrCast(self.air.extra[case.end..][0..case.data.items_len]);
54745836 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
54755837 extra_index = case.end + case.data.items_len + case_body.len;
54765838
5477 const case_block = self.context.appendBasicBlock(self.llvm_func, "Case");
5839 const case_block = try self.wip.block(@intCast(items.len), "Case");
54785840
54795841 for (items) |item| {
5480 const llvm_item = try self.resolveInst(item);
5481 const llvm_int_item = if (llvm_item.typeOf().getTypeKind() == .Pointer)
5482 llvm_item.constPtrToInt(llvm_usize)
5842 const llvm_item = (try self.resolveInst(item)).toConst().?;
5843 const llvm_int_item = if (llvm_item.typeOf(&o.builder).isPointer(&o.builder))
5844 try o.builder.castConst(.ptrtoint, llvm_item, llvm_usize)
54835845 else
54845846 llvm_item;
5485 llvm_switch.addCase(llvm_int_item, case_block);
5847 try wip_switch.addCase(llvm_int_item, case_block, &self.wip);
54865848 }
54875849
5488 self.builder.positionBuilderAtEnd(case_block);
5850 self.wip.cursor = .{ .block = case_block };
54895851 try self.genBody(case_body);
54905852 }
54915853
5492 self.builder.positionBuilderAtEnd(else_block);
5854 self.wip.cursor = .{ .block = else_block };
54935855 const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];
54945856 if (else_body.len != 0) {
54955857 try self.genBody(else_body);
54965858 } else {
5497 _ = self.builder.buildUnreachable();
5859 _ = try self.wip.@"unreachable"();
54985860 }
54995861
55005862 // No need to reset the insert cursor since this instruction is noreturn.
5501 return null;
5863 return .none;
55025864 }
55035865
5504 fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5866 fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
55055867 const o = self.dg.object;
55065868 const mod = o.module;
55075869 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
55085870 const loop = self.air.extraData(Air.Block, ty_pl.payload);
55095871 const body = self.air.extra[loop.end..][0..loop.data.body_len];
5510 const loop_block = self.context.appendBasicBlock(self.llvm_func, "Loop");
5511 _ = self.builder.buildBr(loop_block);
5872 const loop_block = try self.wip.block(2, "Loop");
5873 _ = try self.wip.br(loop_block);
55125874
5513 self.builder.positionBuilderAtEnd(loop_block);
5875 self.wip.cursor = .{ .block = loop_block };
55145876 try self.genBody(body);
55155877
55165878 // TODO instead of this logic, change AIR to have the property that
......@@ -5520,35 +5882,30 @@ pub const FuncGen = struct {
55205882 // be while(true) instead of for(body), which will eliminate 1 branch on
55215883 // a hot path.
55225884 if (body.len == 0 or !self.typeOfIndex(body[body.len - 1]).isNoReturn(mod)) {
5523 _ = self.builder.buildBr(loop_block);
5885 _ = try self.wip.br(loop_block);
55245886 }
5525 return null;
5887 return .none;
55265888 }
55275889
5528 fn airArrayToSlice(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5890 fn airArrayToSlice(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
55295891 const o = self.dg.object;
55305892 const mod = o.module;
55315893 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
55325894 const operand_ty = self.typeOf(ty_op.operand);
55335895 const array_ty = operand_ty.childType(mod);
55345896 const llvm_usize = try o.lowerType(Type.usize);
5535 const len = llvm_usize.constInt(array_ty.arrayLen(mod), .False);
5897 const len = try o.builder.intValue(llvm_usize, array_ty.arrayLen(mod));
55365898 const slice_llvm_ty = try o.lowerType(self.typeOfIndex(inst));
55375899 const operand = try self.resolveInst(ty_op.operand);
5538 if (!array_ty.hasRuntimeBitsIgnoreComptime(mod)) {
5539 const partial = self.builder.buildInsertValue(slice_llvm_ty.getUndef(), operand, 0, "");
5540 return self.builder.buildInsertValue(partial, len, 1, "");
5541 }
5542 const indices: [2]*llvm.Value = .{
5543 llvm_usize.constNull(), llvm_usize.constNull(),
5544 };
5545 const array_llvm_ty = try o.lowerType(array_ty);
5546 const ptr = self.builder.buildInBoundsGEP(array_llvm_ty, operand, &indices, indices.len, "");
5547 const partial = self.builder.buildInsertValue(slice_llvm_ty.getUndef(), ptr, 0, "");
5548 return self.builder.buildInsertValue(partial, len, 1, "");
5900 if (!array_ty.hasRuntimeBitsIgnoreComptime(mod))
5901 return self.wip.buildAggregate(slice_llvm_ty, &.{ operand, len }, "");
5902 const ptr = try self.wip.gep(.inbounds, try o.lowerType(array_ty), operand, &.{
5903 try o.builder.intValue(llvm_usize, 0), try o.builder.intValue(llvm_usize, 0),
5904 }, "");
5905 return self.wip.buildAggregate(slice_llvm_ty, &.{ ptr, len }, "");
55495906 }
55505907
5551 fn airFloatFromInt(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5908 fn airFloatFromInt(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
55525909 const o = self.dg.object;
55535910 const mod = o.module;
55545911 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -5562,51 +5919,53 @@ pub const FuncGen = struct {
55625919 const dest_llvm_ty = try o.lowerType(dest_ty);
55635920 const target = mod.getTarget();
55645921
5565 if (intrinsicsAllowed(dest_scalar_ty, target)) {
5566 if (operand_scalar_ty.isSignedInt(mod)) {
5567 return self.builder.buildSIToFP(operand, dest_llvm_ty, "");
5568 } else {
5569 return self.builder.buildUIToFP(operand, dest_llvm_ty, "");
5570 }
5571 }
5922 if (intrinsicsAllowed(dest_scalar_ty, target)) return self.wip.conv(
5923 if (operand_scalar_ty.isSignedInt(mod)) .signed else .unsigned,
5924 operand,
5925 dest_llvm_ty,
5926 "",
5927 );
55725928
5573 const operand_bits = @as(u16, @intCast(operand_scalar_ty.bitSize(mod)));
5574 const rt_int_bits = compilerRtIntBits(operand_bits);
5575 const rt_int_ty = self.context.intType(rt_int_bits);
5576 var extended = e: {
5577 if (operand_scalar_ty.isSignedInt(mod)) {
5578 break :e self.builder.buildSExtOrBitCast(operand, rt_int_ty, "");
5579 } else {
5580 break :e self.builder.buildZExtOrBitCast(operand, rt_int_ty, "");
5581 }
5582 };
5929 const rt_int_bits = compilerRtIntBits(@intCast(operand_scalar_ty.bitSize(mod)));
5930 const rt_int_ty = try o.builder.intType(rt_int_bits);
5931 var extended = try self.wip.conv(
5932 if (operand_scalar_ty.isSignedInt(mod)) .signed else .unsigned,
5933 operand,
5934 rt_int_ty,
5935 "",
5936 );
55835937 const dest_bits = dest_scalar_ty.floatBits(target);
55845938 const compiler_rt_operand_abbrev = compilerRtIntAbbrev(rt_int_bits);
55855939 const compiler_rt_dest_abbrev = compilerRtFloatAbbrev(dest_bits);
55865940 const sign_prefix = if (operand_scalar_ty.isSignedInt(mod)) "" else "un";
5587 var fn_name_buf: [64]u8 = undefined;
5588 const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__float{s}{s}i{s}f", .{
5941 const fn_name = try o.builder.fmt("__float{s}{s}i{s}f", .{
55895942 sign_prefix,
55905943 compiler_rt_operand_abbrev,
55915944 compiler_rt_dest_abbrev,
5592 }) catch unreachable;
5945 });
55935946
5594 var param_types = [1]*llvm.Type{rt_int_ty};
5947 var param_type = rt_int_ty;
55955948 if (rt_int_bits == 128 and (target.os.tag == .windows and target.cpu.arch == .x86_64)) {
55965949 // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard
55975950 // i128 calling convention to adhere to the ABI that LLVM expects compiler-rt to have.
5598 const v2i64 = self.context.intType(64).vectorType(2);
5599 extended = self.builder.buildBitCast(extended, v2i64, "");
5600 param_types = [1]*llvm.Type{v2i64};
5951 param_type = try o.builder.vectorType(.normal, 2, .i64);
5952 extended = try self.wip.cast(.bitcast, extended, param_type, "");
56015953 }
56025954
5603 const libc_fn = self.getLibcFunction(fn_name, &param_types, dest_llvm_ty);
5604 const params = [1]*llvm.Value{extended};
5605
5606 return self.builder.buildCall(libc_fn.globalGetValueType(), libc_fn, &params, params.len, .C, .Auto, "");
5955 const libc_fn = try self.getLibcFunction(fn_name, &.{param_type}, dest_llvm_ty);
5956 const params = [1]*llvm.Value{extended.toLlvm(&self.wip)};
5957 return (try self.wip.unimplemented(dest_llvm_ty, "")).finish(self.builder.buildCall(
5958 libc_fn.typeOf(&o.builder).toLlvm(&o.builder),
5959 libc_fn.toLlvm(&o.builder),
5960 &params,
5961 params.len,
5962 .C,
5963 .Auto,
5964 "",
5965 ), &self.wip);
56075966 }
56085967
5609 fn airIntFromFloat(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
5968 fn airIntFromFloat(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
56105969 self.builder.setFastMath(want_fast_math);
56115970
56125971 const o = self.dg.object;
......@@ -5624,19 +5983,20 @@ pub const FuncGen = struct {
56245983
56255984 if (intrinsicsAllowed(operand_scalar_ty, target)) {
56265985 // TODO set fast math flag
5627 if (dest_scalar_ty.isSignedInt(mod)) {
5628 return self.builder.buildFPToSI(operand, dest_llvm_ty, "");
5629 } else {
5630 return self.builder.buildFPToUI(operand, dest_llvm_ty, "");
5631 }
5986 return self.wip.conv(
5987 if (dest_scalar_ty.isSignedInt(mod)) .signed else .unsigned,
5988 operand,
5989 dest_llvm_ty,
5990 "",
5991 );
56325992 }
56335993
5634 const rt_int_bits = compilerRtIntBits(@as(u16, @intCast(dest_scalar_ty.bitSize(mod))));
5635 const ret_ty = self.context.intType(rt_int_bits);
5994 const rt_int_bits = compilerRtIntBits(@intCast(dest_scalar_ty.bitSize(mod)));
5995 const ret_ty = try o.builder.intType(rt_int_bits);
56365996 const libc_ret_ty = if (rt_int_bits == 128 and (target.os.tag == .windows and target.cpu.arch == .x86_64)) b: {
56375997 // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard
56385998 // i128 calling convention to adhere to the ABI that LLVM expects compiler-rt to have.
5639 break :b self.context.intType(64).vectorType(2);
5999 break :b try o.builder.vectorType(.normal, 2, .i64);
56406000 } else ret_ty;
56416001
56426002 const operand_bits = operand_scalar_ty.floatBits(target);
......@@ -5645,66 +6005,66 @@ pub const FuncGen = struct {
56456005 const compiler_rt_dest_abbrev = compilerRtIntAbbrev(rt_int_bits);
56466006 const sign_prefix = if (dest_scalar_ty.isSignedInt(mod)) "" else "uns";
56476007
5648 var fn_name_buf: [64]u8 = undefined;
5649 const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__fix{s}{s}f{s}i", .{
6008 const fn_name = try o.builder.fmt("__fix{s}{s}f{s}i", .{
56506009 sign_prefix,
56516010 compiler_rt_operand_abbrev,
56526011 compiler_rt_dest_abbrev,
5653 }) catch unreachable;
6012 });
56546013
56556014 const operand_llvm_ty = try o.lowerType(operand_ty);
5656 const param_types = [1]*llvm.Type{operand_llvm_ty};
5657 const libc_fn = self.getLibcFunction(fn_name, &param_types, libc_ret_ty);
5658 const params = [1]*llvm.Value{operand};
5659
5660 var result = self.builder.buildCall(libc_fn.globalGetValueType(), libc_fn, &params, params.len, .C, .Auto, "");
6015 const libc_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, libc_ret_ty);
6016 const params = [1]*llvm.Value{operand.toLlvm(&self.wip)};
6017 var result = (try self.wip.unimplemented(libc_ret_ty, "")).finish(self.builder.buildCall(
6018 libc_fn.typeOf(&o.builder).toLlvm(&o.builder),
6019 libc_fn.toLlvm(&o.builder),
6020 &params,
6021 params.len,
6022 .C,
6023 .Auto,
6024 "",
6025 ), &self.wip);
56616026
5662 if (libc_ret_ty != ret_ty) result = self.builder.buildBitCast(result, ret_ty, "");
5663 if (ret_ty != dest_llvm_ty) result = self.builder.buildTrunc(result, dest_llvm_ty, "");
6027 if (libc_ret_ty != ret_ty) result = try self.wip.cast(.bitcast, result, ret_ty, "");
6028 if (ret_ty != dest_llvm_ty) result = try self.wip.cast(.trunc, result, dest_llvm_ty, "");
56646029 return result;
56656030 }
56666031
5667 fn sliceOrArrayPtr(fg: *FuncGen, ptr: *llvm.Value, ty: Type) *llvm.Value {
6032 fn sliceOrArrayPtr(fg: *FuncGen, ptr: Builder.Value, ty: Type) Allocator.Error!Builder.Value {
56686033 const o = fg.dg.object;
56696034 const mod = o.module;
5670 if (ty.isSlice(mod)) {
5671 return fg.builder.buildExtractValue(ptr, 0, "");
5672 } else {
5673 return ptr;
5674 }
6035 return if (ty.isSlice(mod)) fg.wip.extractValue(ptr, &.{0}, "") else ptr;
56756036 }
56766037
5677 fn sliceOrArrayLenInBytes(fg: *FuncGen, ptr: *llvm.Value, ty: Type) *llvm.Value {
6038 fn sliceOrArrayLenInBytes(fg: *FuncGen, ptr: Builder.Value, ty: Type) Allocator.Error!Builder.Value {
56786039 const o = fg.dg.object;
56796040 const mod = o.module;
5680 const target = mod.getTarget();
5681 const llvm_usize_ty = fg.context.intType(target.ptrBitWidth());
6041 const llvm_usize = try o.lowerType(Type.usize);
56826042 switch (ty.ptrSize(mod)) {
56836043 .Slice => {
5684 const len = fg.builder.buildExtractValue(ptr, 1, "");
6044 const len = try fg.wip.extractValue(ptr, &.{1}, "");
56856045 const elem_ty = ty.childType(mod);
56866046 const abi_size = elem_ty.abiSize(mod);
56876047 if (abi_size == 1) return len;
5688 const abi_size_llvm_val = llvm_usize_ty.constInt(abi_size, .False);
5689 return fg.builder.buildMul(len, abi_size_llvm_val, "");
6048 const abi_size_llvm_val = try o.builder.intValue(llvm_usize, abi_size);
6049 return fg.wip.bin(.@"mul nuw", len, abi_size_llvm_val, "");
56906050 },
56916051 .One => {
56926052 const array_ty = ty.childType(mod);
56936053 const elem_ty = array_ty.childType(mod);
56946054 const abi_size = elem_ty.abiSize(mod);
5695 return llvm_usize_ty.constInt(array_ty.arrayLen(mod) * abi_size, .False);
6055 return o.builder.intValue(llvm_usize, array_ty.arrayLen(mod) * abi_size);
56966056 },
56976057 .Many, .C => unreachable,
56986058 }
56996059 }
57006060
5701 fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*llvm.Value {
6061 fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: u32) !Builder.Value {
57026062 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
57036063 const operand = try self.resolveInst(ty_op.operand);
5704 return self.builder.buildExtractValue(operand, index, "");
6064 return self.wip.extractValue(operand, &.{index}, "");
57056065 }
57066066
5707 fn airPtrSliceFieldPtr(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*llvm.Value {
6067 fn airPtrSliceFieldPtr(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !Builder.Value {
57086068 const o = self.dg.object;
57096069 const mod = o.module;
57106070 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -5712,10 +6072,10 @@ pub const FuncGen = struct {
57126072 const slice_ptr_ty = self.typeOf(ty_op.operand);
57136073 const slice_llvm_ty = try o.lowerPtrElemTy(slice_ptr_ty.childType(mod));
57146074
5715 return self.builder.buildStructGEP(slice_llvm_ty, slice_ptr, index, "");
6075 return self.wip.gepStruct(slice_llvm_ty, slice_ptr, index, "");
57166076 }
57176077
5718 fn airSliceElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
6078 fn airSliceElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
57196079 const o = self.dg.object;
57206080 const mod = o.module;
57216081 const inst = body_tail[0];
......@@ -5725,20 +6085,20 @@ pub const FuncGen = struct {
57256085 const index = try self.resolveInst(bin_op.rhs);
57266086 const elem_ty = slice_ty.childType(mod);
57276087 const llvm_elem_ty = try o.lowerPtrElemTy(elem_ty);
5728 const base_ptr = self.builder.buildExtractValue(slice, 0, "");
5729 const indices: [1]*llvm.Value = .{index};
5730 const ptr = self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
6088 const base_ptr = try self.wip.extractValue(slice, &.{0}, "");
6089 const ptr = try self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{index}, "");
57316090 if (isByRef(elem_ty, mod)) {
57326091 if (self.canElideLoad(body_tail))
57336092 return ptr;
57346093
5735 return self.loadByRef(ptr, elem_ty, elem_ty.abiAlignment(mod), false);
6094 const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
6095 return self.loadByRef(ptr, elem_ty, elem_alignment, false);
57366096 }
57376097
57386098 return self.load(ptr, slice_ty);
57396099 }
57406100
5741 fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6101 fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
57426102 const o = self.dg.object;
57436103 const mod = o.module;
57446104 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -5748,12 +6108,11 @@ pub const FuncGen = struct {
57486108 const slice = try self.resolveInst(bin_op.lhs);
57496109 const index = try self.resolveInst(bin_op.rhs);
57506110 const llvm_elem_ty = try o.lowerPtrElemTy(slice_ty.childType(mod));
5751 const base_ptr = self.builder.buildExtractValue(slice, 0, "");
5752 const indices: [1]*llvm.Value = .{index};
5753 return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
6111 const base_ptr = try self.wip.extractValue(slice, &.{0}, "");
6112 return self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{index}, "");
57546113 }
57556114
5756 fn airArrayElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
6115 fn airArrayElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
57576116 const o = self.dg.object;
57586117 const mod = o.module;
57596118 const inst = body_tail[0];
......@@ -5765,13 +6124,15 @@ pub const FuncGen = struct {
57656124 const array_llvm_ty = try o.lowerType(array_ty);
57666125 const elem_ty = array_ty.childType(mod);
57676126 if (isByRef(array_ty, mod)) {
5768 const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), rhs };
6127 const indices: [2]Builder.Value = .{
6128 try o.builder.intValue(try o.lowerType(Type.usize), 0), rhs,
6129 };
57696130 if (isByRef(elem_ty, mod)) {
5770 const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, array_llvm_val, &indices, indices.len, "");
5771 if (canElideLoad(self, body_tail))
5772 return elem_ptr;
5773
5774 return self.loadByRef(elem_ptr, elem_ty, elem_ty.abiAlignment(mod), false);
6131 const elem_ptr =
6132 try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &indices, "");
6133 if (canElideLoad(self, body_tail)) return elem_ptr;
6134 const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
6135 return self.loadByRef(elem_ptr, elem_ty, elem_alignment, false);
57756136 } else {
57766137 const elem_llvm_ty = try o.lowerType(elem_ty);
57776138 if (Air.refToIndex(bin_op.lhs)) |lhs_index| {
......@@ -5781,26 +6142,38 @@ pub const FuncGen = struct {
57816142 if (Air.refToIndex(load_ptr)) |load_ptr_index| {
57826143 const load_ptr_tag = self.air.instructions.items(.tag)[load_ptr_index];
57836144 switch (load_ptr_tag) {
5784 .struct_field_ptr, .struct_field_ptr_index_0, .struct_field_ptr_index_1, .struct_field_ptr_index_2, .struct_field_ptr_index_3 => {
6145 .struct_field_ptr,
6146 .struct_field_ptr_index_0,
6147 .struct_field_ptr_index_1,
6148 .struct_field_ptr_index_2,
6149 .struct_field_ptr_index_3,
6150 => {
57856151 const load_ptr_inst = try self.resolveInst(load_ptr);
5786 const gep = self.builder.buildInBoundsGEP(array_llvm_ty, load_ptr_inst, &indices, indices.len, "");
5787 return self.builder.buildLoad(elem_llvm_ty, gep, "");
6152 const gep = try self.wip.gep(
6153 .inbounds,
6154 array_llvm_ty,
6155 load_ptr_inst,
6156 &indices,
6157 "",
6158 );
6159 return self.wip.load(.normal, elem_llvm_ty, gep, .default, "");
57886160 },
57896161 else => {},
57906162 }
57916163 }
57926164 }
57936165 }
5794 const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, array_llvm_val, &indices, indices.len, "");
5795 return self.builder.buildLoad(elem_llvm_ty, elem_ptr, "");
6166 const elem_ptr =
6167 try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &indices, "");
6168 return self.wip.load(.normal, elem_llvm_ty, elem_ptr, .default, "");
57966169 }
57976170 }
57986171
57996172 // This branch can be reached for vectors, which are always by-value.
5800 return self.builder.buildExtractElement(array_llvm_val, rhs, "");
6173 return self.wip.extractElement(array_llvm_val, rhs, "");
58016174 }
58026175
5803 fn airPtrElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
6176 fn airPtrElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
58046177 const o = self.dg.object;
58056178 const mod = o.module;
58066179 const inst = body_tail[0];
......@@ -5811,32 +6184,28 @@ pub const FuncGen = struct {
58116184 const base_ptr = try self.resolveInst(bin_op.lhs);
58126185 const rhs = try self.resolveInst(bin_op.rhs);
58136186 // TODO: when we go fully opaque pointers in LLVM 16 we can remove this branch
5814 const ptr = if (ptr_ty.isSinglePointer(mod)) ptr: {
6187 const ptr = try self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, if (ptr_ty.isSinglePointer(mod))
58156188 // If this is a single-item pointer to an array, we need another index in the GEP.
5816 const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), rhs };
5817 break :ptr self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
5818 } else ptr: {
5819 const indices: [1]*llvm.Value = .{rhs};
5820 break :ptr self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
5821 };
6189 &.{ try o.builder.intValue(try o.lowerType(Type.usize), 0), rhs }
6190 else
6191 &.{rhs}, "");
58226192 if (isByRef(elem_ty, mod)) {
5823 if (self.canElideLoad(body_tail))
5824 return ptr;
5825
5826 return self.loadByRef(ptr, elem_ty, elem_ty.abiAlignment(mod), false);
6193 if (self.canElideLoad(body_tail)) return ptr;
6194 const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
6195 return self.loadByRef(ptr, elem_ty, elem_alignment, false);
58276196 }
58286197
58296198 return self.load(ptr, ptr_ty);
58306199 }
58316200
5832 fn airPtrElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6201 fn airPtrElemPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
58336202 const o = self.dg.object;
58346203 const mod = o.module;
58356204 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
58366205 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
58376206 const ptr_ty = self.typeOf(bin_op.lhs);
58386207 const elem_ty = ptr_ty.childType(mod);
5839 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return o.lowerPtrToVoid(ptr_ty);
6208 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return (try o.lowerPtrToVoid(ptr_ty)).toValue();
58406209
58416210 const base_ptr = try self.resolveInst(bin_op.lhs);
58426211 const rhs = try self.resolveInst(bin_op.rhs);
......@@ -5845,17 +6214,14 @@ pub const FuncGen = struct {
58456214 if (elem_ptr.ptrInfo(mod).flags.vector_index != .none) return base_ptr;
58466215
58476216 const llvm_elem_ty = try o.lowerPtrElemTy(elem_ty);
5848 if (ptr_ty.isSinglePointer(mod)) {
6217 return try self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, if (ptr_ty.isSinglePointer(mod))
58496218 // If this is a single-item pointer to an array, we need another index in the GEP.
5850 const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), rhs };
5851 return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
5852 } else {
5853 const indices: [1]*llvm.Value = .{rhs};
5854 return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
5855 }
6219 &.{ try o.builder.intValue(try o.lowerType(Type.usize), 0), rhs }
6220 else
6221 &.{rhs}, "");
58566222 }
58576223
5858 fn airStructFieldPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6224 fn airStructFieldPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
58596225 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
58606226 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
58616227 const struct_ptr = try self.resolveInst(struct_field.struct_operand);
......@@ -5867,14 +6233,14 @@ pub const FuncGen = struct {
58676233 self: *FuncGen,
58686234 inst: Air.Inst.Index,
58696235 field_index: u32,
5870 ) !?*llvm.Value {
6236 ) !Builder.Value {
58716237 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
58726238 const struct_ptr = try self.resolveInst(ty_op.operand);
58736239 const struct_ptr_ty = self.typeOf(ty_op.operand);
58746240 return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, field_index);
58756241 }
58766242
5877 fn airStructFieldVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
6243 fn airStructFieldVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
58786244 const o = self.dg.object;
58796245 const mod = o.module;
58806246 const inst = body_tail[0];
......@@ -5884,9 +6250,7 @@ pub const FuncGen = struct {
58846250 const struct_llvm_val = try self.resolveInst(struct_field.struct_operand);
58856251 const field_index = struct_field.field_index;
58866252 const field_ty = struct_ty.structFieldType(field_index, mod);
5887 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) {
5888 return null;
5889 }
6253 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none;
58906254
58916255 if (!isByRef(struct_ty, mod)) {
58926256 assert(!isByRef(field_ty, mod));
......@@ -5896,25 +6260,26 @@ pub const FuncGen = struct {
58966260 const struct_obj = mod.typeToStruct(struct_ty).?;
58976261 const bit_offset = struct_obj.packedFieldBitOffset(mod, field_index);
58986262 const containing_int = struct_llvm_val;
5899 const shift_amt = containing_int.typeOf().constInt(bit_offset, .False);
5900 const shifted_value = self.builder.buildLShr(containing_int, shift_amt, "");
6263 const shift_amt =
6264 try o.builder.intValue(containing_int.typeOfWip(&self.wip), bit_offset);
6265 const shifted_value = try self.wip.bin(.lshr, containing_int, shift_amt, "");
59016266 const elem_llvm_ty = try o.lowerType(field_ty);
59026267 if (field_ty.zigTypeTag(mod) == .Float or field_ty.zigTypeTag(mod) == .Vector) {
5903 const elem_bits = @as(c_uint, @intCast(field_ty.bitSize(mod)));
5904 const same_size_int = self.context.intType(elem_bits);
5905 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
5906 return self.builder.buildBitCast(truncated_int, elem_llvm_ty, "");
6268 const same_size_int = try o.builder.intType(@intCast(field_ty.bitSize(mod)));
6269 const truncated_int =
6270 try self.wip.cast(.trunc, shifted_value, same_size_int, "");
6271 return self.wip.cast(.bitcast, truncated_int, elem_llvm_ty, "");
59076272 } else if (field_ty.isPtrAtRuntime(mod)) {
5908 const elem_bits = @as(c_uint, @intCast(field_ty.bitSize(mod)));
5909 const same_size_int = self.context.intType(elem_bits);
5910 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
5911 return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, "");
6273 const same_size_int = try o.builder.intType(@intCast(field_ty.bitSize(mod)));
6274 const truncated_int =
6275 try self.wip.cast(.trunc, shifted_value, same_size_int, "");
6276 return self.wip.cast(.inttoptr, truncated_int, elem_llvm_ty, "");
59126277 }
5913 return self.builder.buildTrunc(shifted_value, elem_llvm_ty, "");
6278 return self.wip.cast(.trunc, shifted_value, elem_llvm_ty, "");
59146279 },
59156280 else => {
59166281 const llvm_field_index = llvmField(struct_ty, field_index, mod).?.index;
5917 return self.builder.buildExtractValue(struct_llvm_val, llvm_field_index, "");
6282 return self.wip.extractValue(struct_llvm_val, &.{llvm_field_index}, "");
59186283 },
59196284 },
59206285 .Union => {
......@@ -5922,17 +6287,17 @@ pub const FuncGen = struct {
59226287 const containing_int = struct_llvm_val;
59236288 const elem_llvm_ty = try o.lowerType(field_ty);
59246289 if (field_ty.zigTypeTag(mod) == .Float or field_ty.zigTypeTag(mod) == .Vector) {
5925 const elem_bits = @as(c_uint, @intCast(field_ty.bitSize(mod)));
5926 const same_size_int = self.context.intType(elem_bits);
5927 const truncated_int = self.builder.buildTrunc(containing_int, same_size_int, "");
5928 return self.builder.buildBitCast(truncated_int, elem_llvm_ty, "");
6290 const same_size_int = try o.builder.intType(@intCast(field_ty.bitSize(mod)));
6291 const truncated_int =
6292 try self.wip.cast(.trunc, containing_int, same_size_int, "");
6293 return self.wip.cast(.bitcast, truncated_int, elem_llvm_ty, "");
59296294 } else if (field_ty.isPtrAtRuntime(mod)) {
5930 const elem_bits = @as(c_uint, @intCast(field_ty.bitSize(mod)));
5931 const same_size_int = self.context.intType(elem_bits);
5932 const truncated_int = self.builder.buildTrunc(containing_int, same_size_int, "");
5933 return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, "");
6295 const same_size_int = try o.builder.intType(@intCast(field_ty.bitSize(mod)));
6296 const truncated_int =
6297 try self.wip.cast(.trunc, containing_int, same_size_int, "");
6298 return self.wip.cast(.inttoptr, truncated_int, elem_llvm_ty, "");
59346299 }
5935 return self.builder.buildTrunc(containing_int, elem_llvm_ty, "");
6300 return self.wip.cast(.trunc, containing_int, elem_llvm_ty, "");
59366301 },
59376302 else => unreachable,
59386303 }
......@@ -5943,7 +6308,8 @@ pub const FuncGen = struct {
59436308 assert(struct_ty.containerLayout(mod) != .Packed);
59446309 const llvm_field = llvmField(struct_ty, field_index, mod).?;
59456310 const struct_llvm_ty = try o.lowerType(struct_ty);
5946 const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, struct_llvm_val, llvm_field.index, "");
6311 const field_ptr =
6312 try self.wip.gepStruct(struct_llvm_ty, struct_llvm_val, llvm_field.index, "");
59476313 const field_ptr_ty = try mod.ptrType(.{
59486314 .child = llvm_field.ty.toIntern(),
59496315 .flags = .{
......@@ -5955,7 +6321,8 @@ pub const FuncGen = struct {
59556321 return field_ptr;
59566322
59576323 assert(llvm_field.alignment != 0);
5958 return self.loadByRef(field_ptr, field_ty, llvm_field.alignment, false);
6324 const field_alignment = Builder.Alignment.fromByteUnits(llvm_field.alignment);
6325 return self.loadByRef(field_ptr, field_ty, field_alignment, false);
59596326 } else {
59606327 return self.load(field_ptr, field_ptr_ty);
59616328 }
......@@ -5964,22 +6331,22 @@ pub const FuncGen = struct {
59646331 const union_llvm_ty = try o.lowerType(struct_ty);
59656332 const layout = struct_ty.unionGetLayout(mod);
59666333 const payload_index = @intFromBool(layout.tag_align >= layout.payload_align);
5967 const field_ptr = self.builder.buildStructGEP(union_llvm_ty, struct_llvm_val, payload_index, "");
6334 const field_ptr =
6335 try self.wip.gepStruct(union_llvm_ty, struct_llvm_val, payload_index, "");
59686336 const llvm_field_ty = try o.lowerType(field_ty);
6337 const payload_alignment = Builder.Alignment.fromByteUnits(layout.payload_align);
59696338 if (isByRef(field_ty, mod)) {
5970 if (canElideLoad(self, body_tail))
5971 return field_ptr;
5972
5973 return self.loadByRef(field_ptr, field_ty, layout.payload_align, false);
6339 if (canElideLoad(self, body_tail)) return field_ptr;
6340 return self.loadByRef(field_ptr, field_ty, payload_alignment, false);
59746341 } else {
5975 return self.builder.buildLoad(llvm_field_ty, field_ptr, "");
6342 return self.wip.load(.normal, llvm_field_ty, field_ptr, payload_alignment, "");
59766343 }
59776344 },
59786345 else => unreachable,
59796346 }
59806347 }
59816348
5982 fn airFieldParentPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6349 fn airFieldParentPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
59836350 const o = self.dg.object;
59846351 const mod = o.module;
59856352 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -5987,50 +6354,52 @@ pub const FuncGen = struct {
59876354
59886355 const field_ptr = try self.resolveInst(extra.field_ptr);
59896356
5990 const target = o.module.getTarget();
59916357 const parent_ty = self.air.getRefType(ty_pl.ty).childType(mod);
59926358 const field_offset = parent_ty.structFieldOffset(extra.field_index, mod);
6359 if (field_offset == 0) return field_ptr;
59936360
59946361 const res_ty = try o.lowerType(self.air.getRefType(ty_pl.ty));
5995 if (field_offset == 0) {
5996 return field_ptr;
5997 }
5998 const llvm_usize_ty = self.context.intType(target.ptrBitWidth());
6362 const llvm_usize = try o.lowerType(Type.usize);
59996363
6000 const field_ptr_int = self.builder.buildPtrToInt(field_ptr, llvm_usize_ty, "");
6001 const base_ptr_int = self.builder.buildNUWSub(field_ptr_int, llvm_usize_ty.constInt(field_offset, .False), "");
6002 return self.builder.buildIntToPtr(base_ptr_int, res_ty, "");
6364 const field_ptr_int = try self.wip.cast(.ptrtoint, field_ptr, llvm_usize, "");
6365 const base_ptr_int = try self.wip.bin(
6366 .@"sub nuw",
6367 field_ptr_int,
6368 try o.builder.intValue(llvm_usize, field_offset),
6369 "",
6370 );
6371 return self.wip.cast(.inttoptr, base_ptr_int, res_ty, "");
60036372 }
60046373
6005 fn airNot(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6374 fn airNot(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
60066375 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
60076376 const operand = try self.resolveInst(ty_op.operand);
60086377
6009 return self.builder.buildNot(operand, "");
6378 return self.wip.not(operand, "");
60106379 }
60116380
6012 fn airUnreach(self: *FuncGen, inst: Air.Inst.Index) ?*llvm.Value {
6381 fn airUnreach(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
60136382 _ = inst;
6014 _ = self.builder.buildUnreachable();
6015 return null;
6383 _ = try self.wip.@"unreachable"();
6384 return .none;
60166385 }
60176386
6018 fn airDbgStmt(self: *FuncGen, inst: Air.Inst.Index) ?*llvm.Value {
6019 const di_scope = self.di_scope orelse return null;
6387 fn airDbgStmt(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6388 const di_scope = self.di_scope orelse return .none;
60206389 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
6021 self.prev_dbg_line = @as(c_uint, @intCast(self.base_line + dbg_stmt.line + 1));
6022 self.prev_dbg_column = @as(c_uint, @intCast(dbg_stmt.column + 1));
6390 self.prev_dbg_line = @intCast(self.base_line + dbg_stmt.line + 1);
6391 self.prev_dbg_column = @intCast(dbg_stmt.column + 1);
60236392 const inlined_at = if (self.dbg_inlined.items.len > 0)
60246393 self.dbg_inlined.items[self.dbg_inlined.items.len - 1].loc
60256394 else
60266395 null;
60276396 self.builder.setCurrentDebugLocation(self.prev_dbg_line, self.prev_dbg_column, di_scope, inlined_at);
6028 return null;
6397 return .none;
60296398 }
60306399
6031 fn airDbgInlineBegin(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6400 fn airDbgInlineBegin(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
60326401 const o = self.dg.object;
6033 const dib = o.di_builder orelse return null;
6402 const dib = o.di_builder orelse return .none;
60346403 const ty_fn = self.air.instructions.items(.data)[inst].ty_fn;
60356404
60366405 const mod = o.module;
......@@ -6083,12 +6452,12 @@ pub const FuncGen = struct {
60836452 const lexical_block = dib.createLexicalBlock(subprogram.toScope(), di_file, line_number, 1);
60846453 self.di_scope = lexical_block.toScope();
60856454 self.base_line = decl.src_line;
6086 return null;
6455 return .none;
60876456 }
60886457
6089 fn airDbgInlineEnd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6458 fn airDbgInlineEnd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
60906459 const o = self.dg.object;
6091 if (o.di_builder == null) return null;
6460 if (o.di_builder == null) return .none;
60926461 const ty_fn = self.air.instructions.items(.data)[inst].ty_fn;
60936462
60946463 const mod = o.module;
......@@ -6098,30 +6467,30 @@ pub const FuncGen = struct {
60986467 const old = self.dbg_inlined.pop();
60996468 self.di_scope = old.scope;
61006469 self.base_line = old.base_line;
6101 return null;
6470 return .none;
61026471 }
61036472
6104 fn airDbgBlockBegin(self: *FuncGen) !?*llvm.Value {
6473 fn airDbgBlockBegin(self: *FuncGen) !Builder.Value {
61056474 const o = self.dg.object;
6106 const dib = o.di_builder orelse return null;
6475 const dib = o.di_builder orelse return .none;
61076476 const old_scope = self.di_scope.?;
61086477 try self.dbg_block_stack.append(self.gpa, old_scope);
61096478 const lexical_block = dib.createLexicalBlock(old_scope, self.di_file.?, self.prev_dbg_line, self.prev_dbg_column);
61106479 self.di_scope = lexical_block.toScope();
6111 return null;
6480 return .none;
61126481 }
61136482
6114 fn airDbgBlockEnd(self: *FuncGen) !?*llvm.Value {
6483 fn airDbgBlockEnd(self: *FuncGen) !Builder.Value {
61156484 const o = self.dg.object;
6116 if (o.di_builder == null) return null;
6485 if (o.di_builder == null) return .none;
61176486 self.di_scope = self.dbg_block_stack.pop();
6118 return null;
6487 return .none;
61196488 }
61206489
6121 fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6490 fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
61226491 const o = self.dg.object;
61236492 const mod = o.module;
6124 const dib = o.di_builder orelse return null;
6493 const dib = o.di_builder orelse return .none;
61256494 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
61266495 const operand = try self.resolveInst(pl_op.operand);
61276496 const name = self.air.nullTerminatedString(pl_op.payload);
......@@ -6141,22 +6510,20 @@ pub const FuncGen = struct {
61416510 else
61426511 null;
61436512 const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?, inlined_at);
6144 const insert_block = self.builder.getInsertBlock();
6145 _ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block);
6146 return null;
6513 const insert_block = self.wip.cursor.block.toLlvm(&self.wip);
6514 _ = dib.insertDeclareAtEnd(operand.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
6515 return .none;
61476516 }
61486517
6149 fn airDbgVarVal(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6518 fn airDbgVarVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
61506519 const o = self.dg.object;
6151 const dib = o.di_builder orelse return null;
6520 const dib = o.di_builder orelse return .none;
61526521 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
61536522 const operand = try self.resolveInst(pl_op.operand);
61546523 const operand_ty = self.typeOf(pl_op.operand);
61556524 const name = self.air.nullTerminatedString(pl_op.payload);
61566525
6157 if (needDbgVarWorkaround(o)) {
6158 return null;
6159 }
6526 if (needDbgVarWorkaround(o)) return .none;
61606527
61616528 const di_local_var = dib.createAutoVariable(
61626529 self.di_scope.?,
......@@ -6172,23 +6539,22 @@ pub const FuncGen = struct {
61726539 else
61736540 null;
61746541 const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?, inlined_at);
6175 const insert_block = self.builder.getInsertBlock();
6542 const insert_block = self.wip.cursor.block.toLlvm(&self.wip);
61766543 const mod = o.module;
61776544 if (isByRef(operand_ty, mod)) {
6178 _ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block);
6545 _ = dib.insertDeclareAtEnd(operand.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
61796546 } else if (o.module.comp.bin_file.options.optimize_mode == .Debug) {
6180 const alignment = operand_ty.abiAlignment(mod);
6181 const alloca = self.buildAlloca(operand.typeOf(), alignment);
6182 const store_inst = self.builder.buildStore(operand, alloca);
6183 store_inst.setAlignment(alignment);
6184 _ = dib.insertDeclareAtEnd(alloca, di_local_var, debug_loc, insert_block);
6547 const alignment = Builder.Alignment.fromByteUnits(operand_ty.abiAlignment(mod));
6548 const alloca = try self.buildAlloca(operand.typeOfWip(&self.wip), alignment);
6549 _ = try self.wip.store(.normal, operand, alloca, alignment);
6550 _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
61856551 } else {
6186 _ = dib.insertDbgValueIntrinsicAtEnd(operand, di_local_var, debug_loc, insert_block);
6552 _ = dib.insertDbgValueIntrinsicAtEnd(operand.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
61876553 }
6188 return null;
6554 return .none;
61896555 }
61906556
6191 fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6557 fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
61926558 // Eventually, the Zig compiler needs to be reworked to have inline
61936559 // assembly go through the same parsing code regardless of backend, and
61946560 // have LLVM-flavored inline assembly be *output* from that assembler.
......@@ -6199,12 +6565,12 @@ pub const FuncGen = struct {
61996565 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
62006566 const extra = self.air.extraData(Air.Asm, ty_pl.payload);
62016567 const is_volatile = @as(u1, @truncate(extra.data.flags >> 31)) != 0;
6202 const clobbers_len = @as(u31, @truncate(extra.data.flags));
6568 const clobbers_len: u31 = @truncate(extra.data.flags);
62036569 var extra_i: usize = extra.end;
62046570
6205 const outputs = @as([]const Air.Inst.Ref, @ptrCast(self.air.extra[extra_i..][0..extra.data.outputs_len]));
6571 const outputs: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra_i..][0..extra.data.outputs_len]);
62066572 extra_i += outputs.len;
6207 const inputs = @as([]const Air.Inst.Ref, @ptrCast(self.air.extra[extra_i..][0..extra.data.inputs_len]));
6573 const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra_i..][0..extra.data.inputs_len]);
62086574 extra_i += inputs.len;
62096575
62106576 var llvm_constraints: std.ArrayListUnmanaged(u8) = .{};
......@@ -6217,15 +6583,15 @@ pub const FuncGen = struct {
62176583 // The exact number of return / parameter values depends on which output values
62186584 // are passed by reference as indirect outputs (determined below).
62196585 const max_return_count = outputs.len;
6220 const llvm_ret_types = try arena.alloc(*llvm.Type, max_return_count);
6586 const llvm_ret_types = try arena.alloc(Builder.Type, max_return_count);
62216587 const llvm_ret_indirect = try arena.alloc(bool, max_return_count);
62226588
62236589 const max_param_count = inputs.len + outputs.len;
6224 const llvm_param_types = try arena.alloc(*llvm.Type, max_param_count);
6590 const llvm_param_types = try arena.alloc(Builder.Type, max_param_count);
62256591 const llvm_param_values = try arena.alloc(*llvm.Value, max_param_count);
62266592 // This stores whether we need to add an elementtype attribute and
62276593 // if so, the element type itself.
6228 const llvm_param_attrs = try arena.alloc(?*llvm.Type, max_param_count);
6594 const llvm_param_attrs = try arena.alloc(Builder.Type, max_param_count);
62296595 const mod = o.module;
62306596 const target = mod.getTarget();
62316597
......@@ -6262,8 +6628,8 @@ pub const FuncGen = struct {
62626628 // Pass the result by reference as an indirect output (e.g. "=*m")
62636629 llvm_constraints.appendAssumeCapacity('*');
62646630
6265 llvm_param_values[llvm_param_i] = output_inst;
6266 llvm_param_types[llvm_param_i] = output_inst.typeOf();
6631 llvm_param_values[llvm_param_i] = output_inst.toLlvm(&self.wip);
6632 llvm_param_types[llvm_param_i] = output_inst.typeOfWip(&self.wip);
62676633 llvm_param_attrs[llvm_param_i] = elem_llvm_ty;
62686634 llvm_param_i += 1;
62696635 } else {
......@@ -6308,31 +6674,30 @@ pub const FuncGen = struct {
63086674
63096675 const arg_llvm_value = try self.resolveInst(input);
63106676 const arg_ty = self.typeOf(input);
6311 var llvm_elem_ty: ?*llvm.Type = null;
6677 var llvm_elem_ty: Builder.Type = .none;
63126678 if (isByRef(arg_ty, mod)) {
63136679 llvm_elem_ty = try o.lowerPtrElemTy(arg_ty);
63146680 if (constraintAllowsMemory(constraint)) {
6315 llvm_param_values[llvm_param_i] = arg_llvm_value;
6316 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOf();
6681 llvm_param_values[llvm_param_i] = arg_llvm_value.toLlvm(&self.wip);
6682 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
63176683 } else {
6318 const alignment = arg_ty.abiAlignment(mod);
6684 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
63196685 const arg_llvm_ty = try o.lowerType(arg_ty);
6320 const load_inst = self.builder.buildLoad(arg_llvm_ty, arg_llvm_value, "");
6321 load_inst.setAlignment(alignment);
6322 llvm_param_values[llvm_param_i] = load_inst;
6686 const load_inst =
6687 try self.wip.load(.normal, arg_llvm_ty, arg_llvm_value, alignment, "");
6688 llvm_param_values[llvm_param_i] = load_inst.toLlvm(&self.wip);
63236689 llvm_param_types[llvm_param_i] = arg_llvm_ty;
63246690 }
63256691 } else {
63266692 if (constraintAllowsRegister(constraint)) {
6327 llvm_param_values[llvm_param_i] = arg_llvm_value;
6328 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOf();
6693 llvm_param_values[llvm_param_i] = arg_llvm_value.toLlvm(&self.wip);
6694 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
63296695 } else {
6330 const alignment = arg_ty.abiAlignment(mod);
6331 const arg_ptr = self.buildAlloca(arg_llvm_value.typeOf(), alignment);
6332 const store_inst = self.builder.buildStore(arg_llvm_value, arg_ptr);
6333 store_inst.setAlignment(alignment);
6334 llvm_param_values[llvm_param_i] = arg_ptr;
6335 llvm_param_types[llvm_param_i] = arg_ptr.typeOf();
6696 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
6697 const arg_ptr = try self.buildAlloca(arg_llvm_value.typeOfWip(&self.wip), alignment);
6698 _ = try self.wip.store(.normal, arg_llvm_value, arg_ptr, alignment);
6699 llvm_param_values[llvm_param_i] = arg_ptr.toLlvm(&self.wip);
6700 llvm_param_types[llvm_param_i] = arg_ptr.typeOfWip(&self.wip);
63366701 }
63376702 }
63386703
......@@ -6356,10 +6721,12 @@ pub const FuncGen = struct {
63566721 // In the case of indirect inputs, LLVM requires the callsite to have
63576722 // an elementtype(<ty>) attribute.
63586723 if (constraint[0] == '*') {
6359 llvm_param_attrs[llvm_param_i] = llvm_elem_ty orelse
6724 llvm_param_attrs[llvm_param_i] = if (llvm_elem_ty != .none)
6725 llvm_elem_ty
6726 else
63606727 try o.lowerPtrElemTy(arg_ty.childType(mod));
63616728 } else {
6362 llvm_param_attrs[llvm_param_i] = null;
6729 llvm_param_attrs[llvm_param_i] = .none;
63636730 }
63646731
63656732 llvm_param_i += 1;
......@@ -6477,23 +6844,14 @@ pub const FuncGen = struct {
64776844 }
64786845
64796846 const ret_llvm_ty = switch (return_count) {
6480 0 => self.context.voidType(),
6847 0 => .void,
64816848 1 => llvm_ret_types[0],
6482 else => self.context.structType(
6483 llvm_ret_types.ptr,
6484 @as(c_uint, @intCast(return_count)),
6485 .False,
6486 ),
6849 else => try o.builder.structType(.normal, llvm_ret_types),
64876850 };
64886851
6489 const llvm_fn_ty = llvm.functionType(
6490 ret_llvm_ty,
6491 llvm_param_types.ptr,
6492 @as(c_uint, @intCast(param_count)),
6493 .False,
6494 );
6852 const llvm_fn_ty = try o.builder.fnType(ret_llvm_ty, llvm_param_types[0..param_count], .normal);
64956853 const asm_fn = llvm.getInlineAsm(
6496 llvm_fn_ty,
6854 llvm_fn_ty.toLlvm(&o.builder),
64976855 rendered_template.items.ptr,
64986856 rendered_template.items.len,
64996857 llvm_constraints.items.ptr,
......@@ -6503,18 +6861,18 @@ pub const FuncGen = struct {
65036861 .ATT,
65046862 .False,
65056863 );
6506 const call = self.builder.buildCall(
6507 llvm_fn_ty,
6864 const call = (try self.wip.unimplemented(ret_llvm_ty, "")).finish(self.builder.buildCall(
6865 llvm_fn_ty.toLlvm(&o.builder),
65086866 asm_fn,
65096867 llvm_param_values.ptr,
6510 @as(c_uint, @intCast(param_count)),
6868 @intCast(param_count),
65116869 .C,
65126870 .Auto,
65136871 "",
6514 );
6872 ), &self.wip);
65156873 for (llvm_param_attrs[0..param_count], 0..) |llvm_elem_ty, i| {
6516 if (llvm_elem_ty) |llvm_ty| {
6517 llvm.setCallElemTypeAttr(call, i, llvm_ty);
6874 if (llvm_elem_ty != .none) {
6875 llvm.setCallElemTypeAttr(call.toLlvm(&self.wip), i, llvm_elem_ty.toLlvm(&o.builder));
65186876 }
65196877 }
65206878
......@@ -6523,16 +6881,17 @@ pub const FuncGen = struct {
65236881 for (outputs, 0..) |output, i| {
65246882 if (llvm_ret_indirect[i]) continue;
65256883
6526 const output_value = if (return_count > 1) b: {
6527 break :b self.builder.buildExtractValue(call, @as(c_uint, @intCast(llvm_ret_i)), "");
6528 } else call;
6884 const output_value = if (return_count > 1)
6885 try self.wip.extractValue(call, &[_]u32{@intCast(llvm_ret_i)}, "")
6886 else
6887 call;
65296888
65306889 if (output != .none) {
65316890 const output_ptr = try self.resolveInst(output);
65326891 const output_ptr_ty = self.typeOf(output);
65336892
6534 const store_inst = self.builder.buildStore(output_value, output_ptr);
6535 store_inst.setAlignment(output_ptr_ty.ptrAlignment(mod));
6893 const alignment = Builder.Alignment.fromByteUnits(output_ptr_ty.ptrAlignment(mod));
6894 _ = try self.wip.store(.normal, output_value, output_ptr, alignment);
65366895 } else {
65376896 ret_val = output_value;
65386897 }
......@@ -6546,8 +6905,8 @@ pub const FuncGen = struct {
65466905 self: *FuncGen,
65476906 inst: Air.Inst.Index,
65486907 operand_is_ptr: bool,
6549 pred: llvm.IntPredicate,
6550 ) !?*llvm.Value {
6908 cond: Builder.IntegerCondition,
6909 ) !Builder.Value {
65516910 const o = self.dg.object;
65526911 const mod = o.module;
65536912 const un_op = self.air.instructions.items(.data)[inst].un_op;
......@@ -6558,43 +6917,40 @@ pub const FuncGen = struct {
65586917 const payload_ty = optional_ty.optionalChild(mod);
65596918 if (optional_ty.optionalReprIsPayload(mod)) {
65606919 const loaded = if (operand_is_ptr)
6561 self.builder.buildLoad(optional_llvm_ty, operand, "")
6920 try self.wip.load(.normal, optional_llvm_ty, operand, .default, "")
65626921 else
65636922 operand;
65646923 if (payload_ty.isSlice(mod)) {
6565 const slice_ptr = self.builder.buildExtractValue(loaded, 0, "");
6566 const ptr_ty = try o.lowerType(payload_ty.slicePtrFieldType(mod));
6567 return self.builder.buildICmp(pred, slice_ptr, ptr_ty.constNull(), "");
6924 const slice_ptr = try self.wip.extractValue(loaded, &.{0}, "");
6925 const ptr_ty = try o.builder.ptrType(toLlvmAddressSpace(
6926 payload_ty.ptrAddressSpace(mod),
6927 mod.getTarget(),
6928 ));
6929 return self.wip.icmp(cond, slice_ptr, try o.builder.nullValue(ptr_ty), "");
65686930 }
6569 return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), "");
6931 return self.wip.icmp(cond, loaded, try o.builder.zeroInitValue(optional_llvm_ty), "");
65706932 }
65716933
65726934 comptime assert(optional_layout_version == 3);
65736935
65746936 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
65756937 const loaded = if (operand_is_ptr)
6576 self.builder.buildLoad(optional_llvm_ty, operand, "")
6938 try self.wip.load(.normal, optional_llvm_ty, operand, .default, "")
65776939 else
65786940 operand;
6579 const llvm_i8 = self.context.intType(8);
6580 return self.builder.buildICmp(pred, loaded, llvm_i8.constNull(), "");
6941 return self.wip.icmp(cond, loaded, try o.builder.intValue(.i8, 0), "");
65816942 }
65826943
65836944 const is_by_ref = operand_is_ptr or isByRef(optional_ty, mod);
6584 const non_null_bit = self.optIsNonNull(optional_llvm_ty, operand, is_by_ref);
6585 if (pred == .EQ) {
6586 return self.builder.buildNot(non_null_bit, "");
6587 } else {
6588 return non_null_bit;
6589 }
6945 return self.optCmpNull(cond, optional_llvm_ty, operand, is_by_ref);
65906946 }
65916947
65926948 fn airIsErr(
65936949 self: *FuncGen,
65946950 inst: Air.Inst.Index,
6595 op: llvm.IntPredicate,
6951 cond: Builder.IntegerCondition,
65966952 operand_is_ptr: bool,
6597 ) !?*llvm.Value {
6953 ) !Builder.Value {
65986954 const o = self.dg.object;
65996955 const mod = o.module;
66006956 const un_op = self.air.instructions.items(.data)[inst].un_op;
......@@ -6602,40 +6958,37 @@ pub const FuncGen = struct {
66026958 const operand_ty = self.typeOf(un_op);
66036959 const err_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty;
66046960 const payload_ty = err_union_ty.errorUnionPayload(mod);
6605 const err_set_ty = try o.lowerType(Type.anyerror);
6606 const zero = err_set_ty.constNull();
6961 const zero = try o.builder.intValue(Builder.Type.err_int, 0);
66076962
66086963 if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) {
6609 const llvm_i1 = self.context.intType(1);
6610 switch (op) {
6611 .EQ => return llvm_i1.constInt(1, .False), // 0 == 0
6612 .NE => return llvm_i1.constInt(0, .False), // 0 != 0
6964 const val: Builder.Constant = switch (cond) {
6965 .eq => .true, // 0 == 0
6966 .ne => .false, // 0 != 0
66136967 else => unreachable,
6614 }
6968 };
6969 return val.toValue();
66156970 }
66166971
66176972 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
66186973 const loaded = if (operand_is_ptr)
6619 self.builder.buildLoad(try o.lowerType(err_union_ty), operand, "")
6974 try self.wip.load(.normal, try o.lowerType(err_union_ty), operand, .default, "")
66206975 else
66216976 operand;
6622 return self.builder.buildICmp(op, loaded, zero, "");
6977 return self.wip.icmp(cond, loaded, zero, "");
66236978 }
66246979
66256980 const err_field_index = errUnionErrorOffset(payload_ty, mod);
66266981
6627 if (operand_is_ptr or isByRef(err_union_ty, mod)) {
6982 const loaded = if (operand_is_ptr or isByRef(err_union_ty, mod)) loaded: {
66286983 const err_union_llvm_ty = try o.lowerType(err_union_ty);
6629 const err_field_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, err_field_index, "");
6630 const loaded = self.builder.buildLoad(err_set_ty, err_field_ptr, "");
6631 return self.builder.buildICmp(op, loaded, zero, "");
6632 }
6633
6634 const loaded = self.builder.buildExtractValue(operand, err_field_index, "");
6635 return self.builder.buildICmp(op, loaded, zero, "");
6984 const err_field_ptr =
6985 try self.wip.gepStruct(err_union_llvm_ty, operand, err_field_index, "");
6986 break :loaded try self.wip.load(.normal, Builder.Type.err_int, err_field_ptr, .default, "");
6987 } else try self.wip.extractValue(operand, &.{err_field_index}, "");
6988 return self.wip.icmp(cond, loaded, zero, "");
66366989 }
66376990
6638 fn airOptionalPayloadPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6991 fn airOptionalPayloadPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
66396992 const o = self.dg.object;
66406993 const mod = o.module;
66416994 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -6651,11 +7004,10 @@ pub const FuncGen = struct {
66517004 // The payload and the optional are the same value.
66527005 return operand;
66537006 }
6654 const optional_llvm_ty = try o.lowerType(optional_ty);
6655 return self.builder.buildStructGEP(optional_llvm_ty, operand, 0, "");
7007 return self.wip.gepStruct(try o.lowerType(optional_ty), operand, 0, "");
66567008 }
66577009
6658 fn airOptionalPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7010 fn airOptionalPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
66597011 comptime assert(optional_layout_version == 3);
66607012
66617013 const o = self.dg.object;
......@@ -6664,10 +7016,10 @@ pub const FuncGen = struct {
66647016 const operand = try self.resolveInst(ty_op.operand);
66657017 const optional_ty = self.typeOf(ty_op.operand).childType(mod);
66667018 const payload_ty = optional_ty.optionalChild(mod);
6667 const non_null_bit = self.context.intType(8).constInt(1, .False);
7019 const non_null_bit = try o.builder.intValue(.i8, 1);
66687020 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
66697021 // We have a pointer to a i8. We need to set it to 1 and then return the same pointer.
6670 _ = self.builder.buildStore(non_null_bit, operand);
7022 _ = try self.wip.store(.normal, non_null_bit, operand, .default);
66717023 return operand;
66727024 }
66737025 if (optional_ty.optionalReprIsPayload(mod)) {
......@@ -6678,18 +7030,17 @@ pub const FuncGen = struct {
66787030
66797031 // First set the non-null bit.
66807032 const optional_llvm_ty = try o.lowerType(optional_ty);
6681 const non_null_ptr = self.builder.buildStructGEP(optional_llvm_ty, operand, 1, "");
7033 const non_null_ptr = try self.wip.gepStruct(optional_llvm_ty, operand, 1, "");
66827034 // TODO set alignment on this store
6683 _ = self.builder.buildStore(non_null_bit, non_null_ptr);
7035 _ = try self.wip.store(.normal, non_null_bit, non_null_ptr, .default);
66847036
66857037 // Then return the payload pointer (only if it's used).
6686 if (self.liveness.isUnused(inst))
6687 return null;
7038 if (self.liveness.isUnused(inst)) return .none;
66887039
6689 return self.builder.buildStructGEP(optional_llvm_ty, operand, 0, "");
7040 return self.wip.gepStruct(optional_llvm_ty, operand, 0, "");
66907041 }
66917042
6692 fn airOptionalPayload(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
7043 fn airOptionalPayload(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
66937044 const o = self.dg.object;
66947045 const mod = o.module;
66957046 const inst = body_tail[0];
......@@ -6697,7 +7048,7 @@ pub const FuncGen = struct {
66977048 const operand = try self.resolveInst(ty_op.operand);
66987049 const optional_ty = self.typeOf(ty_op.operand);
66997050 const payload_ty = self.typeOfIndex(inst);
6700 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return null;
7051 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none;
67017052
67027053 if (optional_ty.optionalReprIsPayload(mod)) {
67037054 // Payload value is the same as the optional value.
......@@ -6713,7 +7064,7 @@ pub const FuncGen = struct {
67137064 self: *FuncGen,
67147065 body_tail: []const Air.Inst.Index,
67157066 operand_is_ptr: bool,
6716 ) !?*llvm.Value {
7067 ) !Builder.Value {
67177068 const o = self.dg.object;
67187069 const mod = o.module;
67197070 const inst = body_tail[0];
......@@ -6725,32 +7076,30 @@ pub const FuncGen = struct {
67257076 const payload_ty = if (operand_is_ptr) result_ty.childType(mod) else result_ty;
67267077
67277078 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
6728 return if (operand_is_ptr) operand else null;
7079 return if (operand_is_ptr) operand else .none;
67297080 }
67307081 const offset = errUnionPayloadOffset(payload_ty, mod);
67317082 const err_union_llvm_ty = try o.lowerType(err_union_ty);
67327083 if (operand_is_ptr) {
6733 return self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, "");
7084 return self.wip.gepStruct(err_union_llvm_ty, operand, offset, "");
67347085 } else if (isByRef(err_union_ty, mod)) {
6735 const payload_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, "");
7086 const payload_alignment = Builder.Alignment.fromByteUnits(payload_ty.abiAlignment(mod));
7087 const payload_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, "");
67367088 if (isByRef(payload_ty, mod)) {
6737 if (self.canElideLoad(body_tail))
6738 return payload_ptr;
6739
6740 return self.loadByRef(payload_ptr, payload_ty, payload_ty.abiAlignment(mod), false);
7089 if (self.canElideLoad(body_tail)) return payload_ptr;
7090 return self.loadByRef(payload_ptr, payload_ty, payload_alignment, false);
67417091 }
6742 const load_inst = self.builder.buildLoad(err_union_llvm_ty.structGetTypeAtIndex(offset), payload_ptr, "");
6743 load_inst.setAlignment(payload_ty.abiAlignment(mod));
6744 return load_inst;
7092 const payload_llvm_ty = err_union_llvm_ty.structFields(&o.builder)[offset];
7093 return self.wip.load(.normal, payload_llvm_ty, payload_ptr, payload_alignment, "");
67457094 }
6746 return self.builder.buildExtractValue(operand, offset, "");
7095 return self.wip.extractValue(operand, &.{offset}, "");
67477096 }
67487097
67497098 fn airErrUnionErr(
67507099 self: *FuncGen,
67517100 inst: Air.Inst.Index,
67527101 operand_is_ptr: bool,
6753 ) !?*llvm.Value {
7102 ) !Builder.Value {
67547103 const o = self.dg.object;
67557104 const mod = o.module;
67567105 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -6758,34 +7107,31 @@ pub const FuncGen = struct {
67587107 const operand_ty = self.typeOf(ty_op.operand);
67597108 const err_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty;
67607109 if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) {
6761 const err_llvm_ty = try o.lowerType(Type.anyerror);
67627110 if (operand_is_ptr) {
67637111 return operand;
67647112 } else {
6765 return err_llvm_ty.constInt(0, .False);
7113 return o.builder.intValue(Builder.Type.err_int, 0);
67667114 }
67677115 }
67687116
6769 const err_set_llvm_ty = try o.lowerType(Type.anyerror);
6770
67717117 const payload_ty = err_union_ty.errorUnionPayload(mod);
67727118 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
67737119 if (!operand_is_ptr) return operand;
6774 return self.builder.buildLoad(err_set_llvm_ty, operand, "");
7120 return self.wip.load(.normal, Builder.Type.err_int, operand, .default, "");
67757121 }
67767122
67777123 const offset = errUnionErrorOffset(payload_ty, mod);
67787124
67797125 if (operand_is_ptr or isByRef(err_union_ty, mod)) {
67807126 const err_union_llvm_ty = try o.lowerType(err_union_ty);
6781 const err_field_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, "");
6782 return self.builder.buildLoad(err_set_llvm_ty, err_field_ptr, "");
7127 const err_field_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, "");
7128 return self.wip.load(.normal, Builder.Type.err_int, err_field_ptr, .default, "");
67837129 }
67847130
6785 return self.builder.buildExtractValue(operand, offset, "");
7131 return self.wip.extractValue(operand, &.{offset}, "");
67867132 }
67877133
6788 fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7134 fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
67897135 const o = self.dg.object;
67907136 const mod = o.module;
67917137 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -6793,49 +7139,49 @@ pub const FuncGen = struct {
67937139 const err_union_ty = self.typeOf(ty_op.operand).childType(mod);
67947140
67957141 const payload_ty = err_union_ty.errorUnionPayload(mod);
6796 const non_error_val = try o.lowerValue(.{ .ty = Type.anyerror, .val = try mod.intValue(Type.err_int, 0) });
7142 const non_error_val = try o.builder.intValue(Builder.Type.err_int, 0);
67977143 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
6798 _ = self.builder.buildStore(non_error_val, operand);
7144 _ = try self.wip.store(.normal, non_error_val, operand, .default);
67997145 return operand;
68007146 }
68017147 const err_union_llvm_ty = try o.lowerType(err_union_ty);
68027148 {
7149 const error_alignment = Builder.Alignment.fromByteUnits(Type.err_int.abiAlignment(mod));
68037150 const error_offset = errUnionErrorOffset(payload_ty, mod);
68047151 // First set the non-error value.
6805 const non_null_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, error_offset, "");
6806 const store_inst = self.builder.buildStore(non_error_val, non_null_ptr);
6807 store_inst.setAlignment(Type.anyerror.abiAlignment(mod));
7152 const non_null_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, error_offset, "");
7153 _ = try self.wip.store(.normal, non_error_val, non_null_ptr, error_alignment);
68087154 }
68097155 // Then return the payload pointer (only if it is used).
6810 if (self.liveness.isUnused(inst))
6811 return null;
7156 if (self.liveness.isUnused(inst)) return .none;
68127157
68137158 const payload_offset = errUnionPayloadOffset(payload_ty, mod);
6814 return self.builder.buildStructGEP(err_union_llvm_ty, operand, payload_offset, "");
7159 return self.wip.gepStruct(err_union_llvm_ty, operand, payload_offset, "");
68157160 }
68167161
6817 fn airErrReturnTrace(self: *FuncGen, _: Air.Inst.Index) !?*llvm.Value {
6818 return self.err_ret_trace.?;
7162 fn airErrReturnTrace(self: *FuncGen, _: Air.Inst.Index) !Builder.Value {
7163 assert(self.err_ret_trace != .none);
7164 return self.err_ret_trace;
68197165 }
68207166
6821 fn airSetErrReturnTrace(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7167 fn airSetErrReturnTrace(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
68227168 const un_op = self.air.instructions.items(.data)[inst].un_op;
6823 const operand = try self.resolveInst(un_op);
6824 self.err_ret_trace = operand;
6825 return null;
7169 self.err_ret_trace = try self.resolveInst(un_op);
7170 return .none;
68267171 }
68277172
6828 fn airSaveErrReturnTraceIndex(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7173 fn airSaveErrReturnTraceIndex(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
68297174 const o = self.dg.object;
68307175 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
6831 //const struct_ty = try self.resolveInst(ty_pl.ty);
68327176 const struct_ty = self.air.getRefType(ty_pl.ty);
68337177 const field_index = ty_pl.payload;
68347178
68357179 const mod = o.module;
68367180 const llvm_field = llvmField(struct_ty, field_index, mod).?;
68377181 const struct_llvm_ty = try o.lowerType(struct_ty);
6838 const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, self.err_ret_trace.?, llvm_field.index, "");
7182 assert(self.err_ret_trace != .none);
7183 const field_ptr =
7184 try self.wip.gepStruct(struct_llvm_ty, self.err_ret_trace, llvm_field.index, "");
68397185 const field_ptr_ty = try mod.ptrType(.{
68407186 .child = llvm_field.ty.toIntern(),
68417187 .flags = .{
......@@ -6845,34 +7191,32 @@ pub const FuncGen = struct {
68457191 return self.load(field_ptr, field_ptr_ty);
68467192 }
68477193
6848 fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7194 fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
68497195 const o = self.dg.object;
68507196 const mod = o.module;
68517197 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
68527198 const payload_ty = self.typeOf(ty_op.operand);
6853 const non_null_bit = self.context.intType(8).constInt(1, .False);
7199 const non_null_bit = try o.builder.intValue(.i8, 1);
68547200 comptime assert(optional_layout_version == 3);
68557201 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return non_null_bit;
68567202 const operand = try self.resolveInst(ty_op.operand);
68577203 const optional_ty = self.typeOfIndex(inst);
6858 if (optional_ty.optionalReprIsPayload(mod)) {
6859 return operand;
6860 }
7204 if (optional_ty.optionalReprIsPayload(mod)) return operand;
68617205 const llvm_optional_ty = try o.lowerType(optional_ty);
68627206 if (isByRef(optional_ty, mod)) {
6863 const optional_ptr = self.buildAlloca(llvm_optional_ty, optional_ty.abiAlignment(mod));
6864 const payload_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 0, "");
7207 const alignment = Builder.Alignment.fromByteUnits(optional_ty.abiAlignment(mod));
7208 const optional_ptr = try self.buildAlloca(llvm_optional_ty, alignment);
7209 const payload_ptr = try self.wip.gepStruct(llvm_optional_ty, optional_ptr, 0, "");
68657210 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);
6866 try self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic);
6867 const non_null_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 1, "");
6868 _ = self.builder.buildStore(non_null_bit, non_null_ptr);
7211 try self.store(payload_ptr, payload_ptr_ty, operand, .none);
7212 const non_null_ptr = try self.wip.gepStruct(llvm_optional_ty, optional_ptr, 1, "");
7213 _ = try self.wip.store(.normal, non_null_bit, non_null_ptr, .default);
68697214 return optional_ptr;
68707215 }
6871 const partial = self.builder.buildInsertValue(llvm_optional_ty.getUndef(), operand, 0, "");
6872 return self.builder.buildInsertValue(partial, non_null_bit, 1, "");
7216 return self.wip.buildAggregate(llvm_optional_ty, &.{ operand, non_null_bit }, "");
68737217 }
68747218
6875 fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7219 fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
68767220 const o = self.dg.object;
68777221 const mod = o.module;
68787222 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -6882,46 +7226,47 @@ pub const FuncGen = struct {
68827226 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
68837227 return operand;
68847228 }
6885 const ok_err_code = (try o.lowerType(Type.anyerror)).constNull();
7229 const ok_err_code = try o.builder.intValue(Builder.Type.err_int, 0);
68867230 const err_un_llvm_ty = try o.lowerType(err_un_ty);
68877231
68887232 const payload_offset = errUnionPayloadOffset(payload_ty, mod);
68897233 const error_offset = errUnionErrorOffset(payload_ty, mod);
68907234 if (isByRef(err_un_ty, mod)) {
6891 const result_ptr = self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(mod));
6892 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");
6893 const store_inst = self.builder.buildStore(ok_err_code, err_ptr);
6894 store_inst.setAlignment(Type.anyerror.abiAlignment(mod));
6895 const payload_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, payload_offset, "");
7235 const alignment = Builder.Alignment.fromByteUnits(err_un_ty.abiAlignment(mod));
7236 const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment);
7237 const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, "");
7238 const error_alignment = Builder.Alignment.fromByteUnits(Type.err_int.abiAlignment(mod));
7239 _ = try self.wip.store(.normal, ok_err_code, err_ptr, error_alignment);
7240 const payload_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, payload_offset, "");
68967241 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);
6897 try self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic);
7242 try self.store(payload_ptr, payload_ptr_ty, operand, .none);
68987243 return result_ptr;
68997244 }
6900
6901 const partial = self.builder.buildInsertValue(err_un_llvm_ty.getUndef(), ok_err_code, error_offset, "");
6902 return self.builder.buildInsertValue(partial, operand, payload_offset, "");
7245 var fields: [2]Builder.Value = undefined;
7246 fields[payload_offset] = operand;
7247 fields[error_offset] = ok_err_code;
7248 return self.wip.buildAggregate(err_un_llvm_ty, &fields, "");
69037249 }
69047250
6905 fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7251 fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
69067252 const o = self.dg.object;
69077253 const mod = o.module;
69087254 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
69097255 const err_un_ty = self.typeOfIndex(inst);
69107256 const payload_ty = err_un_ty.errorUnionPayload(mod);
69117257 const operand = try self.resolveInst(ty_op.operand);
6912 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
6913 return operand;
6914 }
7258 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return operand;
69157259 const err_un_llvm_ty = try o.lowerType(err_un_ty);
69167260
69177261 const payload_offset = errUnionPayloadOffset(payload_ty, mod);
69187262 const error_offset = errUnionErrorOffset(payload_ty, mod);
69197263 if (isByRef(err_un_ty, mod)) {
6920 const result_ptr = self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(mod));
6921 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");
6922 const store_inst = self.builder.buildStore(operand, err_ptr);
6923 store_inst.setAlignment(Type.anyerror.abiAlignment(mod));
6924 const payload_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, payload_offset, "");
7264 const alignment = Builder.Alignment.fromByteUnits(err_un_ty.abiAlignment(mod));
7265 const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment);
7266 const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, "");
7267 const error_alignment = Builder.Alignment.fromByteUnits(Type.err_int.abiAlignment(mod));
7268 _ = try self.wip.store(.normal, operand, err_ptr, error_alignment);
7269 const payload_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, payload_offset, "");
69257270 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);
69267271 // TODO store undef to payload_ptr
69277272 _ = payload_ptr;
......@@ -6929,34 +7274,52 @@ pub const FuncGen = struct {
69297274 return result_ptr;
69307275 }
69317276
6932 const partial = self.builder.buildInsertValue(err_un_llvm_ty.getUndef(), operand, error_offset, "");
69337277 // TODO set payload bytes to undef
6934 return partial;
7278 const undef = try o.builder.undefValue(err_un_llvm_ty);
7279 return self.wip.insertValue(undef, operand, &.{error_offset}, "");
69357280 }
69367281
6937 fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7282 fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7283 const o = self.dg.object;
69387284 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
69397285 const index = pl_op.payload;
6940 const llvm_u32 = self.context.intType(32);
6941 const llvm_fn = self.getIntrinsic("llvm.wasm.memory.size", &.{llvm_u32});
6942 const args: [1]*llvm.Value = .{llvm_u32.constInt(index, .False)};
6943 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");
7286 const llvm_fn = try self.getIntrinsic("llvm.wasm.memory.size", &.{.i32});
7287 const args: [1]*llvm.Value = .{
7288 (try o.builder.intConst(.i32, index)).toLlvm(&o.builder),
7289 };
7290 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCall(
7291 (try o.builder.fnType(.i32, &.{.i32}, .normal)).toLlvm(&o.builder),
7292 llvm_fn,
7293 &args,
7294 args.len,
7295 .Fast,
7296 .Auto,
7297 "",
7298 ), &self.wip);
69447299 }
69457300
6946 fn airWasmMemoryGrow(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7301 fn airWasmMemoryGrow(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7302 const o = self.dg.object;
69477303 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
69487304 const index = pl_op.payload;
69497305 const operand = try self.resolveInst(pl_op.operand);
6950 const llvm_u32 = self.context.intType(32);
6951 const llvm_fn = self.getIntrinsic("llvm.wasm.memory.grow", &.{llvm_u32});
7306 const llvm_fn = try self.getIntrinsic("llvm.wasm.memory.grow", &.{.i32});
69527307 const args: [2]*llvm.Value = .{
6953 llvm_u32.constInt(index, .False),
6954 operand,
7308 (try o.builder.intConst(.i32, index)).toLlvm(&o.builder),
7309 operand.toLlvm(&self.wip),
69557310 };
6956 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");
7311 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCall(
7312 (try o.builder.fnType(.i32, &.{ .i32, .i32 }, .normal)).toLlvm(&o.builder),
7313 llvm_fn,
7314 &args,
7315 args.len,
7316 .Fast,
7317 .Auto,
7318 "",
7319 ), &self.wip);
69577320 }
69587321
6959 fn airVectorStoreElem(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7322 fn airVectorStoreElem(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
69607323 const o = self.dg.object;
69617324 const mod = o.module;
69627325 const data = self.air.instructions.items(.data)[inst].vector_store_elem;
......@@ -6967,19 +7330,20 @@ pub const FuncGen = struct {
69677330 const index = try self.resolveInst(extra.lhs);
69687331 const operand = try self.resolveInst(extra.rhs);
69697332
6970 const loaded_vector = blk: {
6971 const elem_llvm_ty = try o.lowerType(vector_ptr_ty.childType(mod));
6972 const load_inst = self.builder.buildLoad(elem_llvm_ty, vector_ptr, "");
6973 load_inst.setAlignment(vector_ptr_ty.ptrAlignment(mod));
6974 load_inst.setVolatile(llvm.Bool.fromBool(vector_ptr_ty.isVolatilePtr(mod)));
6975 break :blk load_inst;
7333 const kind: Builder.MemoryAccessKind = switch (vector_ptr_ty.isVolatilePtr(mod)) {
7334 false => .normal,
7335 true => .@"volatile",
69767336 };
6977 const modified_vector = self.builder.buildInsertElement(loaded_vector, operand, index, "");
6978 try self.store(vector_ptr, vector_ptr_ty, modified_vector, .NotAtomic);
6979 return null;
7337 const elem_llvm_ty = try o.lowerType(vector_ptr_ty.childType(mod));
7338 const alignment = Builder.Alignment.fromByteUnits(vector_ptr_ty.ptrAlignment(mod));
7339 const loaded = try self.wip.load(kind, elem_llvm_ty, vector_ptr, alignment, "");
7340
7341 const new_vector = try self.wip.insertElement(loaded, operand, index, "");
7342 _ = try self.store(vector_ptr, vector_ptr_ty, new_vector, .none);
7343 return .none;
69807344 }
69817345
6982 fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7346 fn airMin(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
69837347 const o = self.dg.object;
69847348 const mod = o.module;
69857349 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -6988,11 +7352,13 @@ pub const FuncGen = struct {
69887352 const scalar_ty = self.typeOfIndex(inst).scalarType(mod);
69897353
69907354 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.fmin, scalar_ty, 2, .{ lhs, rhs });
6991 if (scalar_ty.isSignedInt(mod)) return self.builder.buildSMin(lhs, rhs, "");
6992 return self.builder.buildUMin(lhs, rhs, "");
7355 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7356 .@"llvm.smin."
7357 else
7358 .@"llvm.umin.", lhs, rhs, "");
69937359 }
69947360
6995 fn airMax(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7361 fn airMax(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
69967362 const o = self.dg.object;
69977363 const mod = o.module;
69987364 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7001,26 +7367,23 @@ pub const FuncGen = struct {
70017367 const scalar_ty = self.typeOfIndex(inst).scalarType(mod);
70027368
70037369 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.fmax, scalar_ty, 2, .{ lhs, rhs });
7004 if (scalar_ty.isSignedInt(mod)) return self.builder.buildSMax(lhs, rhs, "");
7005 return self.builder.buildUMax(lhs, rhs, "");
7370 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7371 .@"llvm.smax."
7372 else
7373 .@"llvm.umax.", lhs, rhs, "");
70067374 }
70077375
7008 fn airSlice(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7376 fn airSlice(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
70097377 const o = self.dg.object;
70107378 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
70117379 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
70127380 const ptr = try self.resolveInst(bin_op.lhs);
70137381 const len = try self.resolveInst(bin_op.rhs);
70147382 const inst_ty = self.typeOfIndex(inst);
7015 const llvm_slice_ty = try o.lowerType(inst_ty);
7016
7017 // In case of slicing a global, the result type looks something like `{ i8*, i64 }`
7018 // but `ptr` is pointing to the global directly.
7019 const partial = self.builder.buildInsertValue(llvm_slice_ty.getUndef(), ptr, 0, "");
7020 return self.builder.buildInsertValue(partial, len, 1, "");
7383 return self.wip.buildAggregate(try o.lowerType(inst_ty), &.{ ptr, len }, "");
70217384 }
70227385
7023 fn airAdd(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7386 fn airAdd(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
70247387 self.builder.setFastMath(want_fast_math);
70257388
70267389 const o = self.dg.object;
......@@ -7032,8 +7395,7 @@ pub const FuncGen = struct {
70327395 const scalar_ty = inst_ty.scalarType(mod);
70337396
70347397 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.add, inst_ty, 2, .{ lhs, rhs });
7035 if (scalar_ty.isSignedInt(mod)) return self.builder.buildNSWAdd(lhs, rhs, "");
7036 return self.builder.buildNUWAdd(lhs, rhs, "");
7398 return self.wip.bin(if (scalar_ty.isSignedInt(mod)) .@"add nsw" else .@"add nuw", lhs, rhs, "");
70377399 }
70387400
70397401 fn airSafeArithmetic(
......@@ -7041,7 +7403,7 @@ pub const FuncGen = struct {
70417403 inst: Air.Inst.Index,
70427404 signed_intrinsic: []const u8,
70437405 unsigned_intrinsic: []const u8,
7044 ) !?*llvm.Value {
7406 ) !Builder.Value {
70457407 const o = fg.dg.object;
70467408 const mod = o.module;
70477409
......@@ -7057,42 +7419,50 @@ pub const FuncGen = struct {
70577419 false => unsigned_intrinsic,
70587420 };
70597421 const llvm_inst_ty = try o.lowerType(inst_ty);
7060 const llvm_fn = fg.getIntrinsic(intrinsic_name, &.{llvm_inst_ty});
7061 const result_struct = fg.builder.buildCall(
7062 llvm_fn.globalGetValueType(),
7422 const llvm_ret_ty = try o.builder.structType(.normal, &.{
7423 llvm_inst_ty,
7424 try llvm_inst_ty.changeScalar(.i1, &o.builder),
7425 });
7426 const llvm_fn_ty = try o.builder.fnType(llvm_ret_ty, &.{ llvm_inst_ty, llvm_inst_ty }, .normal);
7427 const llvm_fn = try fg.getIntrinsic(intrinsic_name, &.{llvm_inst_ty});
7428 const result_struct = (try fg.wip.unimplemented(llvm_ret_ty, "")).finish(fg.builder.buildCall(
7429 llvm_fn_ty.toLlvm(&o.builder),
70637430 llvm_fn,
7064 &[_]*llvm.Value{ lhs, rhs },
7431 &[_]*llvm.Value{ lhs.toLlvm(&fg.wip), rhs.toLlvm(&fg.wip) },
70657432 2,
70667433 .Fast,
70677434 .Auto,
70687435 "",
7069 );
7070 const overflow_bit = fg.builder.buildExtractValue(result_struct, 1, "");
7436 ), &fg.wip);
7437 const overflow_bit = try fg.wip.extractValue(result_struct, &.{1}, "");
70717438 const scalar_overflow_bit = switch (is_scalar) {
70727439 true => overflow_bit,
7073 false => fg.builder.buildOrReduce(overflow_bit),
7440 false => (try fg.wip.unimplemented(.i1, "")).finish(
7441 fg.builder.buildOrReduce(overflow_bit.toLlvm(&fg.wip)),
7442 &fg.wip,
7443 ),
70747444 };
70757445
7076 const fail_block = fg.context.appendBasicBlock(fg.llvm_func, "OverflowFail");
7077 const ok_block = fg.context.appendBasicBlock(fg.llvm_func, "OverflowOk");
7078 _ = fg.builder.buildCondBr(scalar_overflow_bit, fail_block, ok_block);
7446 const fail_block = try fg.wip.block(1, "OverflowFail");
7447 const ok_block = try fg.wip.block(1, "OverflowOk");
7448 _ = try fg.wip.brCond(scalar_overflow_bit, fail_block, ok_block);
70797449
7080 fg.builder.positionBuilderAtEnd(fail_block);
7450 fg.wip.cursor = .{ .block = fail_block };
70817451 try fg.buildSimplePanic(.integer_overflow);
70827452
7083 fg.builder.positionBuilderAtEnd(ok_block);
7084 return fg.builder.buildExtractValue(result_struct, 0, "");
7453 fg.wip.cursor = .{ .block = ok_block };
7454 return fg.wip.extractValue(result_struct, &.{0}, "");
70857455 }
70867456
7087 fn airAddWrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7457 fn airAddWrap(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
70887458 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
70897459 const lhs = try self.resolveInst(bin_op.lhs);
70907460 const rhs = try self.resolveInst(bin_op.rhs);
70917461
7092 return self.builder.buildAdd(lhs, rhs, "");
7462 return self.wip.bin(.add, lhs, rhs, "");
70937463 }
70947464
7095 fn airAddSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7465 fn airAddSat(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
70967466 const o = self.dg.object;
70977467 const mod = o.module;
70987468 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7102,12 +7472,13 @@ pub const FuncGen = struct {
71027472 const scalar_ty = inst_ty.scalarType(mod);
71037473
71047474 if (scalar_ty.isAnyFloat()) return self.todo("saturating float add", .{});
7105 if (scalar_ty.isSignedInt(mod)) return self.builder.buildSAddSat(lhs, rhs, "");
7106
7107 return self.builder.buildUAddSat(lhs, rhs, "");
7475 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7476 .@"llvm.sadd.sat."
7477 else
7478 .@"llvm.uadd.sat.", lhs, rhs, "");
71087479 }
71097480
7110 fn airSub(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7481 fn airSub(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
71117482 self.builder.setFastMath(want_fast_math);
71127483
71137484 const o = self.dg.object;
......@@ -7119,19 +7490,18 @@ pub const FuncGen = struct {
71197490 const scalar_ty = inst_ty.scalarType(mod);
71207491
71217492 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.sub, inst_ty, 2, .{ lhs, rhs });
7122 if (scalar_ty.isSignedInt(mod)) return self.builder.buildNSWSub(lhs, rhs, "");
7123 return self.builder.buildNUWSub(lhs, rhs, "");
7493 return self.wip.bin(if (scalar_ty.isSignedInt(mod)) .@"sub nsw" else .@"sub nuw", lhs, rhs, "");
71247494 }
71257495
7126 fn airSubWrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7496 fn airSubWrap(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
71277497 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
71287498 const lhs = try self.resolveInst(bin_op.lhs);
71297499 const rhs = try self.resolveInst(bin_op.rhs);
71307500
7131 return self.builder.buildSub(lhs, rhs, "");
7501 return self.wip.bin(.sub, lhs, rhs, "");
71327502 }
71337503
7134 fn airSubSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7504 fn airSubSat(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
71357505 const o = self.dg.object;
71367506 const mod = o.module;
71377507 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7141,11 +7511,13 @@ pub const FuncGen = struct {
71417511 const scalar_ty = inst_ty.scalarType(mod);
71427512
71437513 if (scalar_ty.isAnyFloat()) return self.todo("saturating float sub", .{});
7144 if (scalar_ty.isSignedInt(mod)) return self.builder.buildSSubSat(lhs, rhs, "");
7145 return self.builder.buildUSubSat(lhs, rhs, "");
7514 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7515 .@"llvm.ssub.sat."
7516 else
7517 .@"llvm.usub.sat.", lhs, rhs, "");
71467518 }
71477519
7148 fn airMul(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7520 fn airMul(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
71497521 self.builder.setFastMath(want_fast_math);
71507522
71517523 const o = self.dg.object;
......@@ -7157,19 +7529,18 @@ pub const FuncGen = struct {
71577529 const scalar_ty = inst_ty.scalarType(mod);
71587530
71597531 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.mul, inst_ty, 2, .{ lhs, rhs });
7160 if (scalar_ty.isSignedInt(mod)) return self.builder.buildNSWMul(lhs, rhs, "");
7161 return self.builder.buildNUWMul(lhs, rhs, "");
7532 return self.wip.bin(if (scalar_ty.isSignedInt(mod)) .@"mul nsw" else .@"mul nuw", lhs, rhs, "");
71627533 }
71637534
7164 fn airMulWrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7535 fn airMulWrap(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
71657536 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
71667537 const lhs = try self.resolveInst(bin_op.lhs);
71677538 const rhs = try self.resolveInst(bin_op.rhs);
71687539
7169 return self.builder.buildMul(lhs, rhs, "");
7540 return self.wip.bin(.mul, lhs, rhs, "");
71707541 }
71717542
7172 fn airMulSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7543 fn airMulSat(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
71737544 const o = self.dg.object;
71747545 const mod = o.module;
71757546 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7179,11 +7550,13 @@ pub const FuncGen = struct {
71797550 const scalar_ty = inst_ty.scalarType(mod);
71807551
71817552 if (scalar_ty.isAnyFloat()) return self.todo("saturating float mul", .{});
7182 if (scalar_ty.isSignedInt(mod)) return self.builder.buildSMulFixSat(lhs, rhs, "");
7183 return self.builder.buildUMulFixSat(lhs, rhs, "");
7553 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7554 .@"llvm.smul.fix.sat."
7555 else
7556 .@"llvm.umul.fix.sat.", lhs, rhs, "");
71847557 }
71857558
7186 fn airDivFloat(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7559 fn airDivFloat(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
71877560 self.builder.setFastMath(want_fast_math);
71887561
71897562 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7194,7 +7567,7 @@ pub const FuncGen = struct {
71947567 return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });
71957568 }
71967569
7197 fn airDivTrunc(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7570 fn airDivTrunc(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
71987571 self.builder.setFastMath(want_fast_math);
71997572
72007573 const o = self.dg.object;
......@@ -7209,11 +7582,10 @@ pub const FuncGen = struct {
72097582 const result = try self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });
72107583 return self.buildFloatOp(.trunc, inst_ty, 1, .{result});
72117584 }
7212 if (scalar_ty.isSignedInt(mod)) return self.builder.buildSDiv(lhs, rhs, "");
7213 return self.builder.buildUDiv(lhs, rhs, "");
7585 return self.wip.bin(if (scalar_ty.isSignedInt(mod)) .sdiv else .udiv, lhs, rhs, "");
72147586 }
72157587
7216 fn airDivFloor(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7588 fn airDivFloor(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
72177589 self.builder.setFastMath(want_fast_math);
72187590
72197591 const o = self.dg.object;
......@@ -7230,31 +7602,24 @@ pub const FuncGen = struct {
72307602 }
72317603 if (scalar_ty.isSignedInt(mod)) {
72327604 const inst_llvm_ty = try o.lowerType(inst_ty);
7233 const scalar_bit_size_minus_one = scalar_ty.bitSize(mod) - 1;
7234 const bit_size_minus_one = if (inst_ty.zigTypeTag(mod) == .Vector) const_vector: {
7235 const vec_len = inst_ty.vectorLen(mod);
7236 const scalar_llvm_ty = try o.lowerType(scalar_ty);
7237
7238 const shifts = try self.gpa.alloc(*llvm.Value, vec_len);
7239 defer self.gpa.free(shifts);
7605 const bit_size_minus_one = try o.builder.splatValue(inst_llvm_ty, try o.builder.intConst(
7606 inst_llvm_ty.scalarType(&o.builder),
7607 inst_llvm_ty.scalarBits(&o.builder) - 1,
7608 ));
72407609
7241 @memset(shifts, scalar_llvm_ty.constInt(scalar_bit_size_minus_one, .False));
7242 break :const_vector llvm.constVector(shifts.ptr, vec_len);
7243 } else inst_llvm_ty.constInt(scalar_bit_size_minus_one, .False);
7244
7245 const div = self.builder.buildSDiv(lhs, rhs, "");
7246 const rem = self.builder.buildSRem(lhs, rhs, "");
7247 const div_sign = self.builder.buildXor(lhs, rhs, "");
7248 const div_sign_mask = self.builder.buildAShr(div_sign, bit_size_minus_one, "");
7249 const zero = inst_llvm_ty.constNull();
7250 const rem_nonzero = self.builder.buildICmp(.NE, rem, zero, "");
7251 const correction = self.builder.buildSelect(rem_nonzero, div_sign_mask, zero, "");
7252 return self.builder.buildNSWAdd(div, correction, "");
7610 const div = try self.wip.bin(.sdiv, lhs, rhs, "");
7611 const rem = try self.wip.bin(.srem, lhs, rhs, "");
7612 const div_sign = try self.wip.bin(.xor, lhs, rhs, "");
7613 const div_sign_mask = try self.wip.bin(.ashr, div_sign, bit_size_minus_one, "");
7614 const zero = try o.builder.zeroInitValue(inst_llvm_ty);
7615 const rem_nonzero = try self.wip.icmp(.ne, rem, zero, "");
7616 const correction = try self.wip.select(rem_nonzero, div_sign_mask, zero, "");
7617 return self.wip.bin(.@"add nsw", div, correction, "");
72537618 }
7254 return self.builder.buildUDiv(lhs, rhs, "");
7619 return self.wip.bin(.udiv, lhs, rhs, "");
72557620 }
72567621
7257 fn airDivExact(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7622 fn airDivExact(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
72587623 self.builder.setFastMath(want_fast_math);
72597624
72607625 const o = self.dg.object;
......@@ -7266,11 +7631,13 @@ pub const FuncGen = struct {
72667631 const scalar_ty = inst_ty.scalarType(mod);
72677632
72687633 if (scalar_ty.isRuntimeFloat()) return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });
7269 if (scalar_ty.isSignedInt(mod)) return self.builder.buildExactSDiv(lhs, rhs, "");
7270 return self.builder.buildExactUDiv(lhs, rhs, "");
7634 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7635 .@"sdiv exact"
7636 else
7637 .@"udiv exact", lhs, rhs, "");
72717638 }
72727639
7273 fn airRem(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7640 fn airRem(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
72747641 self.builder.setFastMath(want_fast_math);
72757642
72767643 const o = self.dg.object;
......@@ -7282,11 +7649,13 @@ pub const FuncGen = struct {
72827649 const scalar_ty = inst_ty.scalarType(mod);
72837650
72847651 if (scalar_ty.isRuntimeFloat()) return self.buildFloatOp(.fmod, inst_ty, 2, .{ lhs, rhs });
7285 if (scalar_ty.isSignedInt(mod)) return self.builder.buildSRem(lhs, rhs, "");
7286 return self.builder.buildURem(lhs, rhs, "");
7652 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7653 .srem
7654 else
7655 .urem, lhs, rhs, "");
72877656 }
72887657
7289 fn airMod(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7658 fn airMod(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
72907659 self.builder.setFastMath(want_fast_math);
72917660
72927661 const o = self.dg.object;
......@@ -7302,36 +7671,29 @@ pub const FuncGen = struct {
73027671 const a = try self.buildFloatOp(.fmod, inst_ty, 2, .{ lhs, rhs });
73037672 const b = try self.buildFloatOp(.add, inst_ty, 2, .{ a, rhs });
73047673 const c = try self.buildFloatOp(.fmod, inst_ty, 2, .{ b, rhs });
7305 const zero = inst_llvm_ty.constNull();
7674 const zero = try o.builder.zeroInitValue(inst_llvm_ty);
73067675 const ltz = try self.buildFloatCmp(.lt, inst_ty, .{ lhs, zero });
7307 return self.builder.buildSelect(ltz, c, a, "");
7676 return self.wip.select(ltz, c, a, "");
73087677 }
73097678 if (scalar_ty.isSignedInt(mod)) {
7310 const scalar_bit_size_minus_one = scalar_ty.bitSize(mod) - 1;
7311 const bit_size_minus_one = if (inst_ty.zigTypeTag(mod) == .Vector) const_vector: {
7312 const vec_len = inst_ty.vectorLen(mod);
7313 const scalar_llvm_ty = try o.lowerType(scalar_ty);
7314
7315 const shifts = try self.gpa.alloc(*llvm.Value, vec_len);
7316 defer self.gpa.free(shifts);
7679 const bit_size_minus_one = try o.builder.splatValue(inst_llvm_ty, try o.builder.intConst(
7680 inst_llvm_ty.scalarType(&o.builder),
7681 inst_llvm_ty.scalarBits(&o.builder) - 1,
7682 ));
73177683
7318 @memset(shifts, scalar_llvm_ty.constInt(scalar_bit_size_minus_one, .False));
7319 break :const_vector llvm.constVector(shifts.ptr, vec_len);
7320 } else inst_llvm_ty.constInt(scalar_bit_size_minus_one, .False);
7321
7322 const rem = self.builder.buildSRem(lhs, rhs, "");
7323 const div_sign = self.builder.buildXor(lhs, rhs, "");
7324 const div_sign_mask = self.builder.buildAShr(div_sign, bit_size_minus_one, "");
7325 const rhs_masked = self.builder.buildAnd(rhs, div_sign_mask, "");
7326 const zero = inst_llvm_ty.constNull();
7327 const rem_nonzero = self.builder.buildICmp(.NE, rem, zero, "");
7328 const correction = self.builder.buildSelect(rem_nonzero, rhs_masked, zero, "");
7329 return self.builder.buildNSWAdd(rem, correction, "");
7684 const rem = try self.wip.bin(.srem, lhs, rhs, "");
7685 const div_sign = try self.wip.bin(.xor, lhs, rhs, "");
7686 const div_sign_mask = try self.wip.bin(.ashr, div_sign, bit_size_minus_one, "");
7687 const rhs_masked = try self.wip.bin(.@"and", rhs, div_sign_mask, "");
7688 const zero = try o.builder.zeroInitValue(inst_llvm_ty);
7689 const rem_nonzero = try self.wip.icmp(.ne, rem, zero, "");
7690 const correction = try self.wip.select(rem_nonzero, rhs_masked, zero, "");
7691 return self.wip.bin(.@"add nsw", rem, correction, "");
73307692 }
7331 return self.builder.buildURem(lhs, rhs, "");
7693 return self.wip.bin(.urem, lhs, rhs, "");
73327694 }
73337695
7334 fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7696 fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
73357697 const o = self.dg.object;
73367698 const mod = o.module;
73377699 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -7341,49 +7703,37 @@ pub const FuncGen = struct {
73417703 const ptr_ty = self.typeOf(bin_op.lhs);
73427704 const llvm_elem_ty = try o.lowerPtrElemTy(ptr_ty.childType(mod));
73437705 switch (ptr_ty.ptrSize(mod)) {
7344 .One => {
7345 // It's a pointer to an array, so according to LLVM we need an extra GEP index.
7346 const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), offset };
7347 return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, "");
7348 },
7349 .C, .Many => {
7350 const indices: [1]*llvm.Value = .{offset};
7351 return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, "");
7352 },
7706 // It's a pointer to an array, so according to LLVM we need an extra GEP index.
7707 .One => return self.wip.gep(.inbounds, llvm_elem_ty, ptr, &.{
7708 try o.builder.intValue(try o.lowerType(Type.usize), 0), offset,
7709 }, ""),
7710 .C, .Many => return self.wip.gep(.inbounds, llvm_elem_ty, ptr, &.{offset}, ""),
73537711 .Slice => {
7354 const base = self.builder.buildExtractValue(ptr, 0, "");
7355 const indices: [1]*llvm.Value = .{offset};
7356 return self.builder.buildInBoundsGEP(llvm_elem_ty, base, &indices, indices.len, "");
7712 const base = try self.wip.extractValue(ptr, &.{0}, "");
7713 return self.wip.gep(.inbounds, llvm_elem_ty, base, &.{offset}, "");
73577714 },
73587715 }
73597716 }
73607717
7361 fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7718 fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
73627719 const o = self.dg.object;
73637720 const mod = o.module;
73647721 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
73657722 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
73667723 const ptr = try self.resolveInst(bin_op.lhs);
73677724 const offset = try self.resolveInst(bin_op.rhs);
7368 const negative_offset = self.builder.buildNeg(offset, "");
7725 const negative_offset = try self.wip.neg(offset, "");
73697726 const ptr_ty = self.typeOf(bin_op.lhs);
73707727 const llvm_elem_ty = try o.lowerPtrElemTy(ptr_ty.childType(mod));
73717728 switch (ptr_ty.ptrSize(mod)) {
7372 .One => {
7373 // It's a pointer to an array, so according to LLVM we need an extra GEP index.
7374 const indices: [2]*llvm.Value = .{
7375 self.context.intType(32).constNull(), negative_offset,
7376 };
7377 return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, "");
7378 },
7379 .C, .Many => {
7380 const indices: [1]*llvm.Value = .{negative_offset};
7381 return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, "");
7382 },
7729 // It's a pointer to an array, so according to LLVM we need an extra GEP index.
7730 .One => return self.wip.gep(.inbounds, llvm_elem_ty, ptr, &.{
7731 try o.builder.intValue(try o.lowerType(Type.usize), 0), negative_offset,
7732 }, ""),
7733 .C, .Many => return self.wip.gep(.inbounds, llvm_elem_ty, ptr, &.{negative_offset}, ""),
73837734 .Slice => {
7384 const base = self.builder.buildExtractValue(ptr, 0, "");
7385 const indices: [1]*llvm.Value = .{negative_offset};
7386 return self.builder.buildInBoundsGEP(llvm_elem_ty, base, &indices, indices.len, "");
7735 const base = try self.wip.extractValue(ptr, &.{0}, "");
7736 return self.wip.gep(.inbounds, llvm_elem_ty, base, &.{negative_offset}, "");
73877737 },
73887738 }
73897739 }
......@@ -7393,7 +7743,7 @@ pub const FuncGen = struct {
73937743 inst: Air.Inst.Index,
73947744 signed_intrinsic: []const u8,
73957745 unsigned_intrinsic: []const u8,
7396 ) !?*llvm.Value {
7746 ) !Builder.Value {
73977747 const o = self.dg.object;
73987748 const mod = o.module;
73997749 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -7408,81 +7758,123 @@ pub const FuncGen = struct {
74087758
74097759 const intrinsic_name = if (scalar_ty.isSignedInt(mod)) signed_intrinsic else unsigned_intrinsic;
74107760
7411 const llvm_lhs_ty = try o.lowerType(lhs_ty);
74127761 const llvm_dest_ty = try o.lowerType(dest_ty);
7762 const llvm_lhs_ty = try o.lowerType(lhs_ty);
74137763
7414 const llvm_fn = self.getIntrinsic(intrinsic_name, &.{llvm_lhs_ty});
7415 const result_struct = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &[_]*llvm.Value{ lhs, rhs }, 2, .Fast, .Auto, "");
7764 const llvm_fn = try self.getIntrinsic(intrinsic_name, &.{llvm_lhs_ty});
7765 const llvm_ret_ty = try o.builder.structType(
7766 .normal,
7767 &.{ llvm_lhs_ty, try llvm_lhs_ty.changeScalar(.i1, &o.builder) },
7768 );
7769 const llvm_fn_ty = try o.builder.fnType(llvm_ret_ty, &.{ llvm_lhs_ty, llvm_lhs_ty }, .normal);
7770 const result_struct = (try self.wip.unimplemented(llvm_ret_ty, "")).finish(
7771 self.builder.buildCall(
7772 llvm_fn_ty.toLlvm(&o.builder),
7773 llvm_fn,
7774 &[_]*llvm.Value{ lhs.toLlvm(&self.wip), rhs.toLlvm(&self.wip) },
7775 2,
7776 .Fast,
7777 .Auto,
7778 "",
7779 ),
7780 &self.wip,
7781 );
74167782
7417 const result = self.builder.buildExtractValue(result_struct, 0, "");
7418 const overflow_bit = self.builder.buildExtractValue(result_struct, 1, "");
7783 const result = try self.wip.extractValue(result_struct, &.{0}, "");
7784 const overflow_bit = try self.wip.extractValue(result_struct, &.{1}, "");
74197785
74207786 const result_index = llvmField(dest_ty, 0, mod).?.index;
74217787 const overflow_index = llvmField(dest_ty, 1, mod).?.index;
74227788
74237789 if (isByRef(dest_ty, mod)) {
7424 const result_alignment = dest_ty.abiAlignment(mod);
7425 const alloca_inst = self.buildAlloca(llvm_dest_ty, result_alignment);
7790 const result_alignment = Builder.Alignment.fromByteUnits(dest_ty.abiAlignment(mod));
7791 const alloca_inst = try self.buildAlloca(llvm_dest_ty, result_alignment);
74267792 {
7427 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, "");
7428 const store_inst = self.builder.buildStore(result, field_ptr);
7429 store_inst.setAlignment(result_alignment);
7793 const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, result_index, "");
7794 _ = try self.wip.store(.normal, result, field_ptr, result_alignment);
74307795 }
74317796 {
7432 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, overflow_index, "");
7433 const store_inst = self.builder.buildStore(overflow_bit, field_ptr);
7434 store_inst.setAlignment(1);
7797 const overflow_alignment = comptime Builder.Alignment.fromByteUnits(1);
7798 const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, overflow_index, "");
7799 _ = try self.wip.store(.normal, overflow_bit, field_ptr, overflow_alignment);
74357800 }
74367801
74377802 return alloca_inst;
74387803 }
74397804
7440 const partial = self.builder.buildInsertValue(llvm_dest_ty.getUndef(), result, result_index, "");
7441 return self.builder.buildInsertValue(partial, overflow_bit, overflow_index, "");
7805 var fields: [2]Builder.Value = undefined;
7806 fields[result_index] = result;
7807 fields[overflow_index] = overflow_bit;
7808 return self.wip.buildAggregate(llvm_dest_ty, &fields, "");
74427809 }
74437810
74447811 fn buildElementwiseCall(
74457812 self: *FuncGen,
7446 llvm_fn: *llvm.Value,
7447 args_vectors: []const *llvm.Value,
7448 result_vector: *llvm.Value,
7813 llvm_fn: Builder.Function.Index,
7814 args_vectors: []const Builder.Value,
7815 result_vector: Builder.Value,
74497816 vector_len: usize,
7450 ) !*llvm.Value {
7451 const args_len = @as(c_uint, @intCast(args_vectors.len));
7452 const llvm_i32 = self.context.intType(32);
7453 assert(args_len <= 3);
7817 ) !Builder.Value {
7818 const o = self.dg.object;
7819 assert(args_vectors.len <= 3);
7820
7821 const llvm_fn_ty = llvm_fn.typeOf(&o.builder);
7822 const llvm_scalar_ty = llvm_fn_ty.functionReturn(&o.builder);
74547823
74557824 var i: usize = 0;
74567825 var result = result_vector;
74577826 while (i < vector_len) : (i += 1) {
7458 const index_i32 = llvm_i32.constInt(i, .False);
7827 const index_i32 = try o.builder.intValue(.i32, i);
74597828
74607829 var args: [3]*llvm.Value = undefined;
7461 for (args_vectors, 0..) |arg_vector, k| {
7462 args[k] = self.builder.buildExtractElement(arg_vector, index_i32, "");
7830 for (args[0..args_vectors.len], args_vectors) |*arg_elem, arg_vector| {
7831 arg_elem.* = (try self.wip.extractElement(arg_vector, index_i32, "")).toLlvm(&self.wip);
74637832 }
7464 const result_elem = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args_len, .C, .Auto, "");
7465 result = self.builder.buildInsertElement(result, result_elem, index_i32, "");
7833 const result_elem = (try self.wip.unimplemented(llvm_scalar_ty, "")).finish(
7834 self.builder.buildCall(
7835 llvm_fn_ty.toLlvm(&o.builder),
7836 llvm_fn.toLlvm(&o.builder),
7837 &args,
7838 @intCast(args_vectors.len),
7839 .C,
7840 .Auto,
7841 "",
7842 ),
7843 &self.wip,
7844 );
7845 result = try self.wip.insertElement(result, result_elem, index_i32, "");
74667846 }
74677847 return result;
74687848 }
74697849
74707850 fn getLibcFunction(
74717851 self: *FuncGen,
7472 fn_name: [:0]const u8,
7473 param_types: []const *llvm.Type,
7474 return_type: *llvm.Type,
7475 ) *llvm.Value {
7476 const o = self.dg.object;
7477 return o.llvm_module.getNamedFunction(fn_name.ptr) orelse b: {
7478 const alias = o.llvm_module.getNamedGlobalAlias(fn_name.ptr, fn_name.len);
7479 break :b if (alias) |a| a.getAliasee() else null;
7480 } orelse b: {
7481 const params_len = @as(c_uint, @intCast(param_types.len));
7482 const fn_type = llvm.functionType(return_type, param_types.ptr, params_len, .False);
7483 const f = o.llvm_module.addFunction(fn_name, fn_type);
7484 break :b f;
7852 fn_name: Builder.String,
7853 param_types: []const Builder.Type,
7854 return_type: Builder.Type,
7855 ) Allocator.Error!Builder.Function.Index {
7856 const o = self.dg.object;
7857 if (o.builder.getGlobal(fn_name)) |global| return switch (global.ptrConst(&o.builder).kind) {
7858 .alias => |alias| alias.getAliasee(&o.builder).ptrConst(&o.builder).kind.function,
7859 .function => |function| function,
7860 else => unreachable,
7861 };
7862
7863 const fn_type = try o.builder.fnType(return_type, param_types, .normal);
7864 const f = o.llvm_module.addFunction(fn_name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));
7865
7866 var global = Builder.Global{
7867 .type = fn_type,
7868 .kind = .{ .function = @enumFromInt(o.builder.functions.items.len) },
7869 };
7870 var function = Builder.Function{
7871 .global = @enumFromInt(o.builder.globals.count()),
74857872 };
7873
7874 try o.builder.llvm.globals.append(self.gpa, f);
7875 _ = try o.builder.addGlobal(fn_name, global);
7876 try o.builder.functions.append(self.gpa, function);
7877 return global.kind.function;
74867878 }
74877879
74887880 /// Creates a floating point comparison by lowering to the appropriate
......@@ -7491,8 +7883,8 @@ pub const FuncGen = struct {
74917883 self: *FuncGen,
74927884 pred: math.CompareOperator,
74937885 ty: Type,
7494 params: [2]*llvm.Value,
7495 ) !*llvm.Value {
7886 params: [2]Builder.Value,
7887 ) !Builder.Value {
74967888 const o = self.dg.object;
74977889 const mod = o.module;
74987890 const target = o.module.getTarget();
......@@ -7500,20 +7892,19 @@ pub const FuncGen = struct {
75007892 const scalar_llvm_ty = try o.lowerType(scalar_ty);
75017893
75027894 if (intrinsicsAllowed(scalar_ty, target)) {
7503 const llvm_predicate: llvm.RealPredicate = switch (pred) {
7504 .eq => .OEQ,
7505 .neq => .UNE,
7506 .lt => .OLT,
7507 .lte => .OLE,
7508 .gt => .OGT,
7509 .gte => .OGE,
7895 const cond: Builder.FloatCondition = switch (pred) {
7896 .eq => .oeq,
7897 .neq => .une,
7898 .lt => .olt,
7899 .lte => .ole,
7900 .gt => .ogt,
7901 .gte => .oge,
75107902 };
7511 return self.builder.buildFCmp(llvm_predicate, params[0], params[1], "");
7903 return self.wip.fcmp(cond, params[0], params[1], "");
75127904 }
75137905
75147906 const float_bits = scalar_ty.floatBits(target);
75157907 const compiler_rt_float_abbrev = compilerRtFloatAbbrev(float_bits);
7516 var fn_name_buf: [64]u8 = undefined;
75177908 const fn_base_name = switch (pred) {
75187909 .neq => "ne",
75197910 .eq => "eq",
......@@ -7522,37 +7913,50 @@ pub const FuncGen = struct {
75227913 .gt => "gt",
75237914 .gte => "ge",
75247915 };
7525 const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__{s}{s}f2", .{
7526 fn_base_name, compiler_rt_float_abbrev,
7527 }) catch unreachable;
7528
7529 const param_types = [2]*llvm.Type{ scalar_llvm_ty, scalar_llvm_ty };
7530 const llvm_i32 = self.context.intType(32);
7531 const libc_fn = self.getLibcFunction(fn_name, param_types[0..], llvm_i32);
7532
7533 const zero = llvm_i32.constInt(0, .False);
7534 const int_pred: llvm.IntPredicate = switch (pred) {
7535 .eq => .EQ,
7536 .neq => .NE,
7537 .lt => .SLT,
7538 .lte => .SLE,
7539 .gt => .SGT,
7540 .gte => .SGE,
7916 const fn_name = try o.builder.fmt("__{s}{s}f2", .{ fn_base_name, compiler_rt_float_abbrev });
7917
7918 const libc_fn = try self.getLibcFunction(
7919 fn_name,
7920 ([1]Builder.Type{scalar_llvm_ty} ** 2)[0..],
7921 .i32,
7922 );
7923
7924 const zero = try o.builder.intConst(.i32, 0);
7925 const int_cond: Builder.IntegerCondition = switch (pred) {
7926 .eq => .eq,
7927 .neq => .ne,
7928 .lt => .slt,
7929 .lte => .sle,
7930 .gt => .sgt,
7931 .gte => .sge,
75417932 };
75427933
75437934 if (ty.zigTypeTag(mod) == .Vector) {
75447935 const vec_len = ty.vectorLen(mod);
7545 const vector_result_ty = llvm_i32.vectorType(vec_len);
7936 const vector_result_ty = try o.builder.vectorType(.normal, vec_len, .i32);
75467937
7547 var result = vector_result_ty.getUndef();
7548 result = try self.buildElementwiseCall(libc_fn, &params, result, vec_len);
7938 const init = try o.builder.poisonValue(vector_result_ty);
7939 const result = try self.buildElementwiseCall(libc_fn, &params, init, vec_len);
75497940
7550 const zero_vector = self.builder.buildVectorSplat(vec_len, zero, "");
7551 return self.builder.buildICmp(int_pred, result, zero_vector, "");
7941 const zero_vector = try o.builder.splatValue(vector_result_ty, zero);
7942 return self.wip.icmp(int_cond, result, zero_vector, "");
75527943 }
75537944
7554 const result = self.builder.buildCall(libc_fn.globalGetValueType(), libc_fn, &params, params.len, .C, .Auto, "");
7555 return self.builder.buildICmp(int_pred, result, zero, "");
7945 const llvm_fn_ty = libc_fn.typeOf(&o.builder);
7946 const llvm_params = [2]*llvm.Value{ params[0].toLlvm(&self.wip), params[1].toLlvm(&self.wip) };
7947 const result = (try self.wip.unimplemented(
7948 llvm_fn_ty.functionReturn(&o.builder),
7949 "",
7950 )).finish(self.builder.buildCall(
7951 libc_fn.typeOf(&o.builder).toLlvm(&o.builder),
7952 libc_fn.toLlvm(&o.builder),
7953 &llvm_params,
7954 llvm_params.len,
7955 .C,
7956 .Auto,
7957 "",
7958 ), &self.wip);
7959 return self.wip.icmp(int_cond, result, zero.toValue(), "");
75567960 }
75577961
75587962 const FloatOp = enum {
......@@ -7583,7 +7987,7 @@ pub const FuncGen = struct {
75837987
75847988 const FloatOpStrat = union(enum) {
75857989 intrinsic: []const u8,
7586 libc: [:0]const u8,
7990 libc: Builder.String,
75877991 };
75887992
75897993 /// Creates a floating point operation (add, sub, fma, sqrt, exp, etc.)
......@@ -7594,27 +7998,25 @@ pub const FuncGen = struct {
75947998 comptime op: FloatOp,
75957999 ty: Type,
75968000 comptime params_len: usize,
7597 params: [params_len]*llvm.Value,
7598 ) !*llvm.Value {
8001 params: [params_len]Builder.Value,
8002 ) !Builder.Value {
75998003 const o = self.dg.object;
76008004 const mod = o.module;
76018005 const target = mod.getTarget();
76028006 const scalar_ty = ty.scalarType(mod);
76038007 const llvm_ty = try o.lowerType(ty);
7604 const scalar_llvm_ty = try o.lowerType(scalar_ty);
76058008
76068009 const intrinsics_allowed = op != .tan and intrinsicsAllowed(scalar_ty, target);
7607 var fn_name_buf: [64]u8 = undefined;
76088010 const strat: FloatOpStrat = if (intrinsics_allowed) switch (op) {
76098011 // Some operations are dedicated LLVM instructions, not available as intrinsics
7610 .neg => return self.builder.buildFNeg(params[0], ""),
7611 .add => return self.builder.buildFAdd(params[0], params[1], ""),
7612 .sub => return self.builder.buildFSub(params[0], params[1], ""),
7613 .mul => return self.builder.buildFMul(params[0], params[1], ""),
7614 .div => return self.builder.buildFDiv(params[0], params[1], ""),
7615 .fmod => return self.builder.buildFRem(params[0], params[1], ""),
7616 .fmax => return self.builder.buildMaxNum(params[0], params[1], ""),
7617 .fmin => return self.builder.buildMinNum(params[0], params[1], ""),
8012 .neg => return self.wip.un(.fneg, params[0], ""),
8013 .add => return self.wip.bin(.fadd, params[0], params[1], ""),
8014 .sub => return self.wip.bin(.fsub, params[0], params[1], ""),
8015 .mul => return self.wip.bin(.fmul, params[0], params[1], ""),
8016 .div => return self.wip.bin(.fdiv, params[0], params[1], ""),
8017 .fmod => return self.wip.bin(.frem, params[0], params[1], ""),
8018 .fmax => return self.wip.bin(.@"llvm.maxnum.", params[0], params[1], ""),
8019 .fmin => return self.wip.bin(.@"llvm.minnum.", params[0], params[1], ""),
76188020 else => .{ .intrinsic = "llvm." ++ @tagName(op) },
76198021 } else b: {
76208022 const float_bits = scalar_ty.floatBits(target);
......@@ -7622,26 +8024,19 @@ pub const FuncGen = struct {
76228024 .neg => {
76238025 // In this case we can generate a softfloat negation by XORing the
76248026 // bits with a constant.
7625 const int_llvm_ty = self.context.intType(float_bits);
7626 const one = int_llvm_ty.constInt(1, .False);
7627 const shift_amt = int_llvm_ty.constInt(float_bits - 1, .False);
7628 const sign_mask = one.constShl(shift_amt);
7629 const result = if (ty.zigTypeTag(mod) == .Vector) blk: {
7630 const splat_sign_mask = self.builder.buildVectorSplat(ty.vectorLen(mod), sign_mask, "");
7631 const cast_ty = int_llvm_ty.vectorType(ty.vectorLen(mod));
7632 const bitcasted_operand = self.builder.buildBitCast(params[0], cast_ty, "");
7633 break :blk self.builder.buildXor(bitcasted_operand, splat_sign_mask, "");
7634 } else blk: {
7635 const bitcasted_operand = self.builder.buildBitCast(params[0], int_llvm_ty, "");
7636 break :blk self.builder.buildXor(bitcasted_operand, sign_mask, "");
7637 };
7638 return self.builder.buildBitCast(result, llvm_ty, "");
7639 },
7640 .add, .sub, .div, .mul => FloatOpStrat{
7641 .libc = std.fmt.bufPrintZ(&fn_name_buf, "__{s}{s}f3", .{
7642 @tagName(op), compilerRtFloatAbbrev(float_bits),
7643 }) catch unreachable,
8027 const int_ty = try o.builder.intType(@intCast(float_bits));
8028 const cast_ty = try llvm_ty.changeScalar(int_ty, &o.builder);
8029 const sign_mask = try o.builder.splatValue(
8030 cast_ty,
8031 try o.builder.intConst(int_ty, @as(u128, 1) << @intCast(float_bits - 1)),
8032 );
8033 const bitcasted_operand = try self.wip.cast(.bitcast, params[0], cast_ty, "");
8034 const result = try self.wip.bin(.xor, bitcasted_operand, sign_mask, "");
8035 return self.wip.cast(.bitcast, result, llvm_ty, "");
76448036 },
8037 .add, .sub, .div, .mul => .{ .libc = try o.builder.fmt("__{s}{s}f3", .{
8038 @tagName(op), compilerRtFloatAbbrev(float_bits),
8039 }) },
76458040 .ceil,
76468041 .cos,
76478042 .exp,
......@@ -7660,31 +8055,48 @@ pub const FuncGen = struct {
76608055 .sqrt,
76618056 .tan,
76628057 .trunc,
7663 => FloatOpStrat{
7664 .libc = std.fmt.bufPrintZ(&fn_name_buf, "{s}{s}{s}", .{
7665 libcFloatPrefix(float_bits), @tagName(op), libcFloatSuffix(float_bits),
7666 }) catch unreachable,
7667 },
8058 => .{ .libc = try o.builder.fmt("{s}{s}{s}", .{
8059 libcFloatPrefix(float_bits), @tagName(op), libcFloatSuffix(float_bits),
8060 }) },
76688061 };
76698062 };
76708063
7671 const llvm_fn: *llvm.Value = switch (strat) {
7672 .intrinsic => |fn_name| self.getIntrinsic(fn_name, &.{llvm_ty}),
8064 const llvm_fn = switch (strat) {
8065 .intrinsic => |fn_name| try self.getIntrinsic(fn_name, &.{llvm_ty}),
76738066 .libc => |fn_name| b: {
7674 const param_types = [3]*llvm.Type{ scalar_llvm_ty, scalar_llvm_ty, scalar_llvm_ty };
7675 const libc_fn = self.getLibcFunction(fn_name, param_types[0..params.len], scalar_llvm_ty);
8067 const scalar_llvm_ty = llvm_ty.scalarType(&o.builder);
8068 const libc_fn = try self.getLibcFunction(
8069 fn_name,
8070 ([1]Builder.Type{scalar_llvm_ty} ** 3)[0..params.len],
8071 scalar_llvm_ty,
8072 );
76768073 if (ty.zigTypeTag(mod) == .Vector) {
7677 const result = llvm_ty.getUndef();
8074 const result = try o.builder.poisonValue(llvm_ty);
76788075 return self.buildElementwiseCall(libc_fn, &params, result, ty.vectorLen(mod));
76798076 }
76808077
7681 break :b libc_fn;
8078 break :b libc_fn.toLlvm(&o.builder);
76828079 },
76838080 };
7684 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params_len, .C, .Auto, "");
8081 const llvm_fn_ty = try o.builder.fnType(
8082 llvm_ty,
8083 ([1]Builder.Type{llvm_ty} ** 3)[0..params.len],
8084 .normal,
8085 );
8086 var llvm_params: [params_len]*llvm.Value = undefined;
8087 for (&llvm_params, params) |*llvm_param, param| llvm_param.* = param.toLlvm(&self.wip);
8088 return (try self.wip.unimplemented(llvm_ty, "")).finish(self.builder.buildCall(
8089 llvm_fn_ty.toLlvm(&o.builder),
8090 llvm_fn,
8091 &llvm_params,
8092 params_len,
8093 .C,
8094 .Auto,
8095 "",
8096 ), &self.wip);
76858097 }
76868098
7687 fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8099 fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
76888100 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
76898101 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
76908102
......@@ -7696,7 +8108,7 @@ pub const FuncGen = struct {
76968108 return self.buildFloatOp(.fma, ty, 3, .{ mulend1, mulend2, addend });
76978109 }
76988110
7699 fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8111 fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
77008112 const o = self.dg.object;
77018113 const mod = o.module;
77028114 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -7706,72 +8118,67 @@ pub const FuncGen = struct {
77068118 const rhs = try self.resolveInst(extra.rhs);
77078119
77088120 const lhs_ty = self.typeOf(extra.lhs);
7709 const rhs_ty = self.typeOf(extra.rhs);
77108121 const lhs_scalar_ty = lhs_ty.scalarType(mod);
7711 const rhs_scalar_ty = rhs_ty.scalarType(mod);
77128122
77138123 const dest_ty = self.typeOfIndex(inst);
77148124 const llvm_dest_ty = try o.lowerType(dest_ty);
77158125
7716 const casted_rhs = if (rhs_scalar_ty.bitSize(mod) < lhs_scalar_ty.bitSize(mod))
7717 self.builder.buildZExt(rhs, try o.lowerType(lhs_ty), "")
7718 else
7719 rhs;
8126 const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty), "");
77208127
7721 const result = self.builder.buildShl(lhs, casted_rhs, "");
7722 const reconstructed = if (lhs_scalar_ty.isSignedInt(mod))
7723 self.builder.buildAShr(result, casted_rhs, "")
8128 const result = try self.wip.bin(.shl, lhs, casted_rhs, "");
8129 const reconstructed = try self.wip.bin(if (lhs_scalar_ty.isSignedInt(mod))
8130 .ashr
77248131 else
7725 self.builder.buildLShr(result, casted_rhs, "");
8132 .lshr, result, casted_rhs, "");
77268133
7727 const overflow_bit = self.builder.buildICmp(.NE, lhs, reconstructed, "");
8134 const overflow_bit = try self.wip.icmp(.ne, lhs, reconstructed, "");
77288135
77298136 const result_index = llvmField(dest_ty, 0, mod).?.index;
77308137 const overflow_index = llvmField(dest_ty, 1, mod).?.index;
77318138
77328139 if (isByRef(dest_ty, mod)) {
7733 const result_alignment = dest_ty.abiAlignment(mod);
7734 const alloca_inst = self.buildAlloca(llvm_dest_ty, result_alignment);
8140 const result_alignment = Builder.Alignment.fromByteUnits(dest_ty.abiAlignment(mod));
8141 const alloca_inst = try self.buildAlloca(llvm_dest_ty, result_alignment);
77358142 {
7736 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, "");
7737 const store_inst = self.builder.buildStore(result, field_ptr);
7738 store_inst.setAlignment(result_alignment);
8143 const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, result_index, "");
8144 _ = try self.wip.store(.normal, result, field_ptr, result_alignment);
77398145 }
77408146 {
7741 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, overflow_index, "");
7742 const store_inst = self.builder.buildStore(overflow_bit, field_ptr);
7743 store_inst.setAlignment(1);
8147 const field_alignment = comptime Builder.Alignment.fromByteUnits(1);
8148 const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, overflow_index, "");
8149 _ = try self.wip.store(.normal, overflow_bit, field_ptr, field_alignment);
77448150 }
7745
77468151 return alloca_inst;
77478152 }
77488153
7749 const partial = self.builder.buildInsertValue(llvm_dest_ty.getUndef(), result, result_index, "");
7750 return self.builder.buildInsertValue(partial, overflow_bit, overflow_index, "");
8154 var fields: [2]Builder.Value = undefined;
8155 fields[result_index] = result;
8156 fields[overflow_index] = overflow_bit;
8157 return self.wip.buildAggregate(llvm_dest_ty, &fields, "");
77518158 }
77528159
7753 fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8160 fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
77548161 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
77558162 const lhs = try self.resolveInst(bin_op.lhs);
77568163 const rhs = try self.resolveInst(bin_op.rhs);
7757 return self.builder.buildAnd(lhs, rhs, "");
8164 return self.wip.bin(.@"and", lhs, rhs, "");
77588165 }
77598166
7760 fn airOr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8167 fn airOr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
77618168 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
77628169 const lhs = try self.resolveInst(bin_op.lhs);
77638170 const rhs = try self.resolveInst(bin_op.rhs);
7764 return self.builder.buildOr(lhs, rhs, "");
8171 return self.wip.bin(.@"or", lhs, rhs, "");
77658172 }
77668173
7767 fn airXor(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8174 fn airXor(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
77688175 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
77698176 const lhs = try self.resolveInst(bin_op.lhs);
77708177 const rhs = try self.resolveInst(bin_op.rhs);
7771 return self.builder.buildXor(lhs, rhs, "");
8178 return self.wip.bin(.xor, lhs, rhs, "");
77728179 }
77738180
7774 fn airShlExact(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8181 fn airShlExact(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
77758182 const o = self.dg.object;
77768183 const mod = o.module;
77778184 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7780,39 +8187,29 @@ pub const FuncGen = struct {
77808187 const rhs = try self.resolveInst(bin_op.rhs);
77818188
77828189 const lhs_ty = self.typeOf(bin_op.lhs);
7783 const rhs_ty = self.typeOf(bin_op.rhs);
77848190 const lhs_scalar_ty = lhs_ty.scalarType(mod);
7785 const rhs_scalar_ty = rhs_ty.scalarType(mod);
77868191
7787 const casted_rhs = if (rhs_scalar_ty.bitSize(mod) < lhs_scalar_ty.bitSize(mod))
7788 self.builder.buildZExt(rhs, try o.lowerType(lhs_ty), "")
8192 const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty), "");
8193 return self.wip.bin(if (lhs_scalar_ty.isSignedInt(mod))
8194 .@"shl nsw"
77898195 else
7790 rhs;
7791 if (lhs_scalar_ty.isSignedInt(mod)) return self.builder.buildNSWShl(lhs, casted_rhs, "");
7792 return self.builder.buildNUWShl(lhs, casted_rhs, "");
8196 .@"shl nuw", lhs, casted_rhs, "");
77938197 }
77948198
7795 fn airShl(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8199 fn airShl(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
77968200 const o = self.dg.object;
7797 const mod = o.module;
77988201 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
77998202
78008203 const lhs = try self.resolveInst(bin_op.lhs);
78018204 const rhs = try self.resolveInst(bin_op.rhs);
78028205
78038206 const lhs_type = self.typeOf(bin_op.lhs);
7804 const rhs_type = self.typeOf(bin_op.rhs);
7805 const lhs_scalar_ty = lhs_type.scalarType(mod);
7806 const rhs_scalar_ty = rhs_type.scalarType(mod);
78078207
7808 const casted_rhs = if (rhs_scalar_ty.bitSize(mod) < lhs_scalar_ty.bitSize(mod))
7809 self.builder.buildZExt(rhs, try o.lowerType(lhs_type), "")
7810 else
7811 rhs;
7812 return self.builder.buildShl(lhs, casted_rhs, "");
8208 const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_type), "");
8209 return self.wip.bin(.shl, lhs, casted_rhs, "");
78138210 }
78148211
7815 fn airShlSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8212 fn airShlSat(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
78168213 const o = self.dg.object;
78178214 const mod = o.module;
78188215 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7821,42 +8218,36 @@ pub const FuncGen = struct {
78218218 const rhs = try self.resolveInst(bin_op.rhs);
78228219
78238220 const lhs_ty = self.typeOf(bin_op.lhs);
7824 const rhs_ty = self.typeOf(bin_op.rhs);
78258221 const lhs_scalar_ty = lhs_ty.scalarType(mod);
7826 const rhs_scalar_ty = rhs_ty.scalarType(mod);
78278222 const lhs_bits = lhs_scalar_ty.bitSize(mod);
78288223
7829 const casted_rhs = if (rhs_scalar_ty.bitSize(mod) < lhs_bits)
7830 self.builder.buildZExt(rhs, lhs.typeOf(), "")
7831 else
7832 rhs;
8224 const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty), "");
78338225
7834 const result = if (lhs_scalar_ty.isSignedInt(mod))
7835 self.builder.buildSShlSat(lhs, casted_rhs, "")
8226 const result = try self.wip.bin(if (lhs_scalar_ty.isSignedInt(mod))
8227 .@"llvm.sshl.sat."
78368228 else
7837 self.builder.buildUShlSat(lhs, casted_rhs, "");
8229 .@"llvm.ushl.sat.", lhs, casted_rhs, "");
78388230
78398231 // LLVM langref says "If b is (statically or dynamically) equal to or
78408232 // larger than the integer bit width of the arguments, the result is a
78418233 // poison value."
78428234 // However Zig semantics says that saturating shift left can never produce
78438235 // undefined; instead it saturates.
7844 const lhs_scalar_llvm_ty = try o.lowerType(lhs_scalar_ty);
7845 const bits = lhs_scalar_llvm_ty.constInt(lhs_bits, .False);
7846 const lhs_max = lhs_scalar_llvm_ty.constAllOnes();
7847 if (rhs_ty.zigTypeTag(mod) == .Vector) {
7848 const vec_len = rhs_ty.vectorLen(mod);
7849 const bits_vec = self.builder.buildVectorSplat(vec_len, bits, "");
7850 const lhs_max_vec = self.builder.buildVectorSplat(vec_len, lhs_max, "");
7851 const in_range = self.builder.buildICmp(.ULT, rhs, bits_vec, "");
7852 return self.builder.buildSelect(in_range, result, lhs_max_vec, "");
7853 } else {
7854 const in_range = self.builder.buildICmp(.ULT, rhs, bits, "");
7855 return self.builder.buildSelect(in_range, result, lhs_max, "");
7856 }
8236 const lhs_llvm_ty = try o.lowerType(lhs_ty);
8237 const lhs_scalar_llvm_ty = lhs_llvm_ty.scalarType(&o.builder);
8238 const bits = try o.builder.splatValue(
8239 lhs_llvm_ty,
8240 try o.builder.intConst(lhs_scalar_llvm_ty, lhs_bits),
8241 );
8242 const lhs_max = try o.builder.splatValue(
8243 lhs_llvm_ty,
8244 try o.builder.intConst(lhs_scalar_llvm_ty, -1),
8245 );
8246 const in_range = try self.wip.icmp(.ult, rhs, bits, "");
8247 return self.wip.select(in_range, result, lhs_max, "");
78578248 }
78588249
7859 fn airShr(self: *FuncGen, inst: Air.Inst.Index, is_exact: bool) !?*llvm.Value {
8250 fn airShr(self: *FuncGen, inst: Air.Inst.Index, is_exact: bool) !Builder.Value {
78608251 const o = self.dg.object;
78618252 const mod = o.module;
78628253 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7865,63 +8256,41 @@ pub const FuncGen = struct {
78658256 const rhs = try self.resolveInst(bin_op.rhs);
78668257
78678258 const lhs_ty = self.typeOf(bin_op.lhs);
7868 const rhs_ty = self.typeOf(bin_op.rhs);
78698259 const lhs_scalar_ty = lhs_ty.scalarType(mod);
7870 const rhs_scalar_ty = rhs_ty.scalarType(mod);
78718260
7872 const casted_rhs = if (rhs_scalar_ty.bitSize(mod) < lhs_scalar_ty.bitSize(mod))
7873 self.builder.buildZExt(rhs, try o.lowerType(lhs_ty), "")
7874 else
7875 rhs;
8261 const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty), "");
78768262 const is_signed_int = lhs_scalar_ty.isSignedInt(mod);
78778263
7878 if (is_exact) {
7879 if (is_signed_int) {
7880 return self.builder.buildAShrExact(lhs, casted_rhs, "");
7881 } else {
7882 return self.builder.buildLShrExact(lhs, casted_rhs, "");
7883 }
7884 } else {
7885 if (is_signed_int) {
7886 return self.builder.buildAShr(lhs, casted_rhs, "");
7887 } else {
7888 return self.builder.buildLShr(lhs, casted_rhs, "");
7889 }
7890 }
8264 return self.wip.bin(if (is_exact)
8265 if (is_signed_int) .@"ashr exact" else .@"lshr exact"
8266 else if (is_signed_int) .ashr else .lshr, lhs, casted_rhs, "");
78918267 }
78928268
7893 fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8269 fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
78948270 const o = self.dg.object;
78958271 const mod = o.module;
78968272 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
78978273 const dest_ty = self.typeOfIndex(inst);
7898 const dest_info = dest_ty.intInfo(mod);
78998274 const dest_llvm_ty = try o.lowerType(dest_ty);
79008275 const operand = try self.resolveInst(ty_op.operand);
79018276 const operand_ty = self.typeOf(ty_op.operand);
79028277 const operand_info = operand_ty.intInfo(mod);
79038278
7904 if (operand_info.bits < dest_info.bits) {
7905 switch (operand_info.signedness) {
7906 .signed => return self.builder.buildSExt(operand, dest_llvm_ty, ""),
7907 .unsigned => return self.builder.buildZExt(operand, dest_llvm_ty, ""),
7908 }
7909 } else if (operand_info.bits > dest_info.bits) {
7910 return self.builder.buildTrunc(operand, dest_llvm_ty, "");
7911 } else {
7912 return operand;
7913 }
8279 return self.wip.conv(switch (operand_info.signedness) {
8280 .signed => .signed,
8281 .unsigned => .unsigned,
8282 }, operand, dest_llvm_ty, "");
79148283 }
79158284
7916 fn airTrunc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8285 fn airTrunc(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
79178286 const o = self.dg.object;
79188287 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
79198288 const operand = try self.resolveInst(ty_op.operand);
79208289 const dest_llvm_ty = try o.lowerType(self.typeOfIndex(inst));
7921 return self.builder.buildTrunc(operand, dest_llvm_ty, "");
8290 return self.wip.cast(.trunc, operand, dest_llvm_ty, "");
79228291 }
79238292
7924 fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8293 fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
79258294 const o = self.dg.object;
79268295 const mod = o.module;
79278296 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -7933,26 +8302,30 @@ pub const FuncGen = struct {
79338302 const src_bits = operand_ty.floatBits(target);
79348303
79358304 if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) {
7936 const dest_llvm_ty = try o.lowerType(dest_ty);
7937 return self.builder.buildFPTrunc(operand, dest_llvm_ty, "");
8305 return self.wip.cast(.fptrunc, operand, try o.lowerType(dest_ty), "");
79388306 } else {
79398307 const operand_llvm_ty = try o.lowerType(operand_ty);
79408308 const dest_llvm_ty = try o.lowerType(dest_ty);
79418309
7942 var fn_name_buf: [64]u8 = undefined;
7943 const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__trunc{s}f{s}f2", .{
8310 const fn_name = try o.builder.fmt("__trunc{s}f{s}f2", .{
79448311 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
7945 }) catch unreachable;
7946
7947 const params = [1]*llvm.Value{operand};
7948 const param_types = [1]*llvm.Type{operand_llvm_ty};
7949 const llvm_fn = self.getLibcFunction(fn_name, &param_types, dest_llvm_ty);
8312 });
79508313
7951 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .C, .Auto, "");
8314 const llvm_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);
8315 const params = [1]*llvm.Value{operand.toLlvm(&self.wip)};
8316 return (try self.wip.unimplemented(dest_llvm_ty, "")).finish(self.builder.buildCall(
8317 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),
8318 llvm_fn.toLlvm(&o.builder),
8319 &params,
8320 params.len,
8321 .C,
8322 .Auto,
8323 "",
8324 ), &self.wip);
79528325 }
79538326 }
79548327
7955 fn airFpext(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8328 fn airFpext(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
79568329 const o = self.dg.object;
79578330 const mod = o.module;
79588331 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -7964,36 +8337,40 @@ pub const FuncGen = struct {
79648337 const src_bits = operand_ty.floatBits(target);
79658338
79668339 if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) {
7967 const dest_llvm_ty = try o.lowerType(dest_ty);
7968 return self.builder.buildFPExt(operand, dest_llvm_ty, "");
8340 return self.wip.cast(.fpext, operand, try o.lowerType(dest_ty), "");
79698341 } else {
79708342 const operand_llvm_ty = try o.lowerType(operand_ty);
79718343 const dest_llvm_ty = try o.lowerType(dest_ty);
79728344
7973 var fn_name_buf: [64]u8 = undefined;
7974 const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__extend{s}f{s}f2", .{
8345 const fn_name = try o.builder.fmt("__extend{s}f{s}f2", .{
79758346 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
7976 }) catch unreachable;
7977
7978 const params = [1]*llvm.Value{operand};
7979 const param_types = [1]*llvm.Type{operand_llvm_ty};
7980 const llvm_fn = self.getLibcFunction(fn_name, &param_types, dest_llvm_ty);
8347 });
79818348
7982 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .C, .Auto, "");
8349 const llvm_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);
8350 const params = [1]*llvm.Value{operand.toLlvm(&self.wip)};
8351 return (try self.wip.unimplemented(dest_llvm_ty, "")).finish(self.builder.buildCall(
8352 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),
8353 llvm_fn.toLlvm(&o.builder),
8354 &params,
8355 params.len,
8356 .C,
8357 .Auto,
8358 "",
8359 ), &self.wip);
79838360 }
79848361 }
79858362
7986 fn airIntFromPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8363 fn airIntFromPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
79878364 const o = self.dg.object;
79888365 const un_op = self.air.instructions.items(.data)[inst].un_op;
79898366 const operand = try self.resolveInst(un_op);
79908367 const ptr_ty = self.typeOf(un_op);
7991 const operand_ptr = self.sliceOrArrayPtr(operand, ptr_ty);
8368 const operand_ptr = try self.sliceOrArrayPtr(operand, ptr_ty);
79928369 const dest_llvm_ty = try o.lowerType(self.typeOfIndex(inst));
7993 return self.builder.buildPtrToInt(operand_ptr, dest_llvm_ty, "");
8370 return self.wip.cast(.ptrtoint, operand_ptr, dest_llvm_ty, "");
79948371 }
79958372
7996 fn airBitCast(self: *FuncGen, inst: Air.Inst.Index) !*llvm.Value {
8373 fn airBitCast(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
79978374 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
79988375 const operand_ty = self.typeOf(ty_op.operand);
79998376 const inst_ty = self.typeOfIndex(inst);
......@@ -8001,7 +8378,7 @@ pub const FuncGen = struct {
80018378 return self.bitCast(operand, operand_ty, inst_ty);
80028379 }
80038380
8004 fn bitCast(self: *FuncGen, operand: *llvm.Value, operand_ty: Type, inst_ty: Type) !*llvm.Value {
8381 fn bitCast(self: *FuncGen, operand: Builder.Value, operand_ty: Type, inst_ty: Type) !Builder.Value {
80058382 const o = self.dg.object;
80068383 const mod = o.module;
80078384 const operand_is_ref = isByRef(operand_ty, mod);
......@@ -8013,14 +8390,14 @@ pub const FuncGen = struct {
80138390 return operand;
80148391 }
80158392
8016 if (llvm_dest_ty.getTypeKind() == .Integer and
8017 operand.typeOf().getTypeKind() == .Integer)
8393 if (llvm_dest_ty.isInteger(&o.builder) and
8394 operand.typeOfWip(&self.wip).isInteger(&o.builder))
80188395 {
8019 return self.builder.buildZExtOrBitCast(operand, llvm_dest_ty, "");
8396 return self.wip.conv(.unsigned, operand, llvm_dest_ty, "");
80208397 }
80218398
80228399 if (operand_ty.zigTypeTag(mod) == .Int and inst_ty.isPtrAtRuntime(mod)) {
8023 return self.builder.buildIntToPtr(operand, llvm_dest_ty, "");
8400 return self.wip.cast(.inttoptr, operand, llvm_dest_ty, "");
80248401 }
80258402
80268403 if (operand_ty.zigTypeTag(mod) == .Vector and inst_ty.zigTypeTag(mod) == .Array) {
......@@ -8028,104 +8405,97 @@ pub const FuncGen = struct {
80288405 if (!result_is_ref) {
80298406 return self.dg.todo("implement bitcast vector to non-ref array", .{});
80308407 }
8031 const array_ptr = self.buildAlloca(llvm_dest_ty, null);
8408 const array_ptr = try self.buildAlloca(llvm_dest_ty, .default);
80328409 const bitcast_ok = elem_ty.bitSize(mod) == elem_ty.abiSize(mod) * 8;
80338410 if (bitcast_ok) {
8034 const llvm_store = self.builder.buildStore(operand, array_ptr);
8035 llvm_store.setAlignment(inst_ty.abiAlignment(mod));
8411 const alignment = Builder.Alignment.fromByteUnits(inst_ty.abiAlignment(mod));
8412 _ = try self.wip.store(.normal, operand, array_ptr, alignment);
80368413 } else {
80378414 // If the ABI size of the element type is not evenly divisible by size in bits;
80388415 // a simple bitcast will not work, and we fall back to extractelement.
80398416 const llvm_usize = try o.lowerType(Type.usize);
8040 const llvm_u32 = self.context.intType(32);
8041 const zero = llvm_usize.constNull();
8417 const usize_zero = try o.builder.intValue(llvm_usize, 0);
80428418 const vector_len = operand_ty.arrayLen(mod);
80438419 var i: u64 = 0;
80448420 while (i < vector_len) : (i += 1) {
8045 const index_usize = llvm_usize.constInt(i, .False);
8046 const index_u32 = llvm_u32.constInt(i, .False);
8047 const indexes: [2]*llvm.Value = .{ zero, index_usize };
8048 const elem_ptr = self.builder.buildInBoundsGEP(llvm_dest_ty, array_ptr, &indexes, indexes.len, "");
8049 const elem = self.builder.buildExtractElement(operand, index_u32, "");
8050 _ = self.builder.buildStore(elem, elem_ptr);
8421 const elem_ptr = try self.wip.gep(.inbounds, llvm_dest_ty, array_ptr, &.{
8422 usize_zero, try o.builder.intValue(llvm_usize, i),
8423 }, "");
8424 const elem =
8425 try self.wip.extractElement(operand, try o.builder.intValue(.i32, i), "");
8426 _ = try self.wip.store(.normal, elem, elem_ptr, .default);
80518427 }
80528428 }
80538429 return array_ptr;
80548430 } else if (operand_ty.zigTypeTag(mod) == .Array and inst_ty.zigTypeTag(mod) == .Vector) {
80558431 const elem_ty = operand_ty.childType(mod);
80568432 const llvm_vector_ty = try o.lowerType(inst_ty);
8057 if (!operand_is_ref) {
8058 return self.dg.todo("implement bitcast non-ref array to vector", .{});
8059 }
8433 if (!operand_is_ref) return self.dg.todo("implement bitcast non-ref array to vector", .{});
80608434
80618435 const bitcast_ok = elem_ty.bitSize(mod) == elem_ty.abiSize(mod) * 8;
80628436 if (bitcast_ok) {
8063 const vector = self.builder.buildLoad(llvm_vector_ty, operand, "");
80648437 // The array is aligned to the element's alignment, while the vector might have a completely
80658438 // different alignment. This means we need to enforce the alignment of this load.
8066 vector.setAlignment(elem_ty.abiAlignment(mod));
8067 return vector;
8439 const alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
8440 return self.wip.load(.normal, llvm_vector_ty, operand, alignment, "");
80688441 } else {
80698442 // If the ABI size of the element type is not evenly divisible by size in bits;
80708443 // a simple bitcast will not work, and we fall back to extractelement.
80718444 const array_llvm_ty = try o.lowerType(operand_ty);
80728445 const elem_llvm_ty = try o.lowerType(elem_ty);
80738446 const llvm_usize = try o.lowerType(Type.usize);
8074 const llvm_u32 = self.context.intType(32);
8075 const zero = llvm_usize.constNull();
8447 const usize_zero = try o.builder.intValue(llvm_usize, 0);
80768448 const vector_len = operand_ty.arrayLen(mod);
8077 var vector = llvm_vector_ty.getUndef();
8449 var vector = try o.builder.poisonValue(llvm_vector_ty);
80788450 var i: u64 = 0;
80798451 while (i < vector_len) : (i += 1) {
8080 const index_usize = llvm_usize.constInt(i, .False);
8081 const index_u32 = llvm_u32.constInt(i, .False);
8082 const indexes: [2]*llvm.Value = .{ zero, index_usize };
8083 const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, operand, &indexes, indexes.len, "");
8084 const elem = self.builder.buildLoad(elem_llvm_ty, elem_ptr, "");
8085 vector = self.builder.buildInsertElement(vector, elem, index_u32, "");
8452 const elem_ptr = try self.wip.gep(.inbounds, array_llvm_ty, operand, &.{
8453 usize_zero, try o.builder.intValue(llvm_usize, i),
8454 }, "");
8455 const elem = try self.wip.load(.normal, elem_llvm_ty, elem_ptr, .default, "");
8456 vector =
8457 try self.wip.insertElement(vector, elem, try o.builder.intValue(.i32, i), "");
80868458 }
8087
80888459 return vector;
80898460 }
80908461 }
80918462
80928463 if (operand_is_ref) {
8093 const load_inst = self.builder.buildLoad(llvm_dest_ty, operand, "");
8094 load_inst.setAlignment(operand_ty.abiAlignment(mod));
8095 return load_inst;
8464 const alignment = Builder.Alignment.fromByteUnits(operand_ty.abiAlignment(mod));
8465 return self.wip.load(.normal, llvm_dest_ty, operand, alignment, "");
80968466 }
80978467
80988468 if (result_is_ref) {
8099 const alignment = @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod));
8100 const result_ptr = self.buildAlloca(llvm_dest_ty, alignment);
8101 const store_inst = self.builder.buildStore(operand, result_ptr);
8102 store_inst.setAlignment(alignment);
8469 const alignment = Builder.Alignment.fromByteUnits(
8470 @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod)),
8471 );
8472 const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment);
8473 _ = try self.wip.store(.normal, operand, result_ptr, alignment);
81038474 return result_ptr;
81048475 }
81058476
8106 if (llvm_dest_ty.getTypeKind() == .Struct) {
8477 if (llvm_dest_ty.isStruct(&o.builder)) {
81078478 // Both our operand and our result are values, not pointers,
81088479 // but LLVM won't let us bitcast struct values.
81098480 // Therefore, we store operand to alloca, then load for result.
8110 const alignment = @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod));
8111 const result_ptr = self.buildAlloca(llvm_dest_ty, alignment);
8112 const store_inst = self.builder.buildStore(operand, result_ptr);
8113 store_inst.setAlignment(alignment);
8114 const load_inst = self.builder.buildLoad(llvm_dest_ty, result_ptr, "");
8115 load_inst.setAlignment(alignment);
8116 return load_inst;
8481 const alignment = Builder.Alignment.fromByteUnits(
8482 @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod)),
8483 );
8484 const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment);
8485 _ = try self.wip.store(.normal, operand, result_ptr, alignment);
8486 return self.wip.load(.normal, llvm_dest_ty, result_ptr, alignment, "");
81178487 }
81188488
8119 return self.builder.buildBitCast(operand, llvm_dest_ty, "");
8489 return self.wip.cast(.bitcast, operand, llvm_dest_ty, "");
81208490 }
81218491
8122 fn airIntFromBool(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8492 fn airIntFromBool(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
81238493 const un_op = self.air.instructions.items(.data)[inst].un_op;
81248494 const operand = try self.resolveInst(un_op);
81258495 return operand;
81268496 }
81278497
8128 fn airArg(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8498 fn airArg(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
81298499 const o = self.dg.object;
81308500 const mod = o.module;
81318501 const arg_val = self.args[self.arg_index];
......@@ -8133,9 +8503,7 @@ pub const FuncGen = struct {
81338503
81348504 const inst_ty = self.typeOfIndex(inst);
81358505 if (o.di_builder) |dib| {
8136 if (needDbgVarWorkaround(o)) {
8137 return arg_val;
8138 }
8506 if (needDbgVarWorkaround(o)) return arg_val;
81398507
81408508 const src_index = self.air.instructions.items(.data)[inst].arg.src_index;
81418509 const func_index = self.dg.decl.getOwnedFunctionIndex();
......@@ -8150,61 +8518,64 @@ pub const FuncGen = struct {
81508518 try o.lowerDebugType(inst_ty, .full),
81518519 true, // always preserve
81528520 0, // flags
8153 self.arg_index, // includes +1 because 0 is return type
8521 @intCast(self.arg_index), // includes +1 because 0 is return type
81548522 );
81558523
81568524 const debug_loc = llvm.getDebugLoc(lbrace_line, lbrace_col, self.di_scope.?, null);
8157 const insert_block = self.builder.getInsertBlock();
8525 const insert_block = self.wip.cursor.block.toLlvm(&self.wip);
81588526 if (isByRef(inst_ty, mod)) {
8159 _ = dib.insertDeclareAtEnd(arg_val, di_local_var, debug_loc, insert_block);
8527 _ = dib.insertDeclareAtEnd(arg_val.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
81608528 } else if (o.module.comp.bin_file.options.optimize_mode == .Debug) {
8161 const alignment = inst_ty.abiAlignment(mod);
8162 const alloca = self.buildAlloca(arg_val.typeOf(), alignment);
8163 const store_inst = self.builder.buildStore(arg_val, alloca);
8164 store_inst.setAlignment(alignment);
8165 _ = dib.insertDeclareAtEnd(alloca, di_local_var, debug_loc, insert_block);
8529 const alignment = Builder.Alignment.fromByteUnits(inst_ty.abiAlignment(mod));
8530 const alloca = try self.buildAlloca(arg_val.typeOfWip(&self.wip), alignment);
8531 _ = try self.wip.store(.normal, arg_val, alloca, alignment);
8532 _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
81668533 } else {
8167 _ = dib.insertDbgValueIntrinsicAtEnd(arg_val, di_local_var, debug_loc, insert_block);
8534 _ = dib.insertDbgValueIntrinsicAtEnd(arg_val.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
81688535 }
81698536 }
81708537
81718538 return arg_val;
81728539 }
81738540
8174 fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8541 fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
81758542 const o = self.dg.object;
81768543 const mod = o.module;
81778544 const ptr_ty = self.typeOfIndex(inst);
81788545 const pointee_type = ptr_ty.childType(mod);
81798546 if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime(mod))
8180 return o.lowerPtrToVoid(ptr_ty);
8547 return (try o.lowerPtrToVoid(ptr_ty)).toValue();
81818548
81828549 const pointee_llvm_ty = try o.lowerType(pointee_type);
8183 const alignment = ptr_ty.ptrAlignment(mod);
8550 const alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
81848551 return self.buildAlloca(pointee_llvm_ty, alignment);
81858552 }
81868553
8187 fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8554 fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
81888555 const o = self.dg.object;
81898556 const mod = o.module;
81908557 const ptr_ty = self.typeOfIndex(inst);
81918558 const ret_ty = ptr_ty.childType(mod);
8192 if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return o.lowerPtrToVoid(ptr_ty);
8193 if (self.ret_ptr) |ret_ptr| return ret_ptr;
8559 if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod))
8560 return (try o.lowerPtrToVoid(ptr_ty)).toValue();
8561 if (self.ret_ptr != .none) return self.ret_ptr;
81948562 const ret_llvm_ty = try o.lowerType(ret_ty);
8195 return self.buildAlloca(ret_llvm_ty, ptr_ty.ptrAlignment(mod));
8563 const alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
8564 return self.buildAlloca(ret_llvm_ty, alignment);
81968565 }
81978566
81988567 /// Use this instead of builder.buildAlloca, because this function makes sure to
81998568 /// put the alloca instruction at the top of the function!
8200 fn buildAlloca(self: *FuncGen, llvm_ty: *llvm.Type, alignment: ?c_uint) *llvm.Value {
8201 const o = self.dg.object;
8202 const mod = o.module;
8203 const target = mod.getTarget();
8204 return buildAllocaInner(self.context, self.builder, self.llvm_func, self.di_scope != null, llvm_ty, alignment, target);
8569 fn buildAlloca(
8570 self: *FuncGen,
8571 llvm_ty: Builder.Type,
8572 alignment: Builder.Alignment,
8573 ) Allocator.Error!Builder.Value {
8574 const target = self.dg.object.module.getTarget();
8575 return buildAllocaInner(&self.wip, self.di_scope != null, llvm_ty, alignment, target);
82058576 }
82068577
8207 fn airStore(self: *FuncGen, inst: Air.Inst.Index, safety: bool) !?*llvm.Value {
8578 fn airStore(self: *FuncGen, inst: Air.Inst.Index, safety: bool) !Builder.Value {
82088579 const o = self.dg.object;
82098580 const mod = o.module;
82108581 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -8217,25 +8588,30 @@ pub const FuncGen = struct {
82178588 // Even if safety is disabled, we still emit a memset to undefined since it conveys
82188589 // extra information to LLVM. However, safety makes the difference between using
82198590 // 0xaa or actual undefined for the fill byte.
8220 const u8_llvm_ty = self.context.intType(8);
82218591 const fill_byte = if (safety)
8222 u8_llvm_ty.constInt(0xaa, .False)
8592 try o.builder.intConst(.i8, 0xaa)
82238593 else
8224 u8_llvm_ty.getUndef();
8594 try o.builder.undefConst(.i8);
82258595 const operand_size = operand_ty.abiSize(mod);
8226 const usize_llvm_ty = try o.lowerType(Type.usize);
8227 const len = usize_llvm_ty.constInt(operand_size, .False);
8228 const dest_ptr_align = ptr_ty.ptrAlignment(mod);
8229 _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, ptr_ty.isVolatilePtr(mod));
8596 const usize_ty = try o.lowerType(Type.usize);
8597 const len = try o.builder.intValue(usize_ty, operand_size);
8598 const dest_ptr_align = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
8599 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemSet(
8600 dest_ptr.toLlvm(&self.wip),
8601 fill_byte.toLlvm(&o.builder),
8602 len.toLlvm(&self.wip),
8603 @intCast(dest_ptr_align.toByteUnits() orelse 0),
8604 ptr_ty.isVolatilePtr(mod),
8605 ), &self.wip);
82308606 if (safety and mod.comp.bin_file.options.valgrind) {
8231 self.valgrindMarkUndef(dest_ptr, len);
8607 try self.valgrindMarkUndef(dest_ptr, len);
82328608 }
8233 return null;
8609 return .none;
82348610 }
82358611
82368612 const src_operand = try self.resolveInst(bin_op.rhs);
8237 try self.store(dest_ptr, ptr_ty, src_operand, .NotAtomic);
8238 return null;
8613 try self.store(dest_ptr, ptr_ty, src_operand, .none);
8614 return .none;
82398615 }
82408616
82418617 /// As an optimization, we want to avoid unnecessary copies of isByRef=true
......@@ -8260,7 +8636,7 @@ pub const FuncGen = struct {
82608636 return false;
82618637 }
82628638
8263 fn airLoad(fg: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
8639 fn airLoad(fg: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
82648640 const o = fg.dg.object;
82658641 const mod = o.module;
82668642 const inst = body_tail[0];
......@@ -8277,22 +8653,40 @@ pub const FuncGen = struct {
82778653 return fg.load(ptr, ptr_ty);
82788654 }
82798655
8280 fn airTrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8656 fn airTrap(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
82818657 _ = inst;
8282 const llvm_fn = self.getIntrinsic("llvm.trap", &.{});
8283 _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, undefined, 0, .Cold, .Auto, "");
8284 _ = self.builder.buildUnreachable();
8285 return null;
8658 const o = self.dg.object;
8659 const llvm_fn = try self.getIntrinsic("llvm.trap", &.{});
8660 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
8661 (try o.builder.fnType(.void, &.{}, .normal)).toLlvm(&o.builder),
8662 llvm_fn,
8663 undefined,
8664 0,
8665 .Cold,
8666 .Auto,
8667 "",
8668 ), &self.wip);
8669 _ = try self.wip.@"unreachable"();
8670 return .none;
82868671 }
82878672
8288 fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8673 fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
82898674 _ = inst;
8290 const llvm_fn = self.getIntrinsic("llvm.debugtrap", &.{});
8291 _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, undefined, 0, .C, .Auto, "");
8292 return null;
8675 const o = self.dg.object;
8676 const llvm_fn = try self.getIntrinsic("llvm.debugtrap", &.{});
8677 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
8678 (try o.builder.fnType(.void, &.{}, .normal)).toLlvm(&o.builder),
8679 llvm_fn,
8680 undefined,
8681 0,
8682 .C,
8683 .Auto,
8684 "",
8685 ), &self.wip);
8686 return .none;
82938687 }
82948688
8295 fn airRetAddr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8689 fn airRetAddr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
82968690 _ = inst;
82978691 const o = self.dg.object;
82988692 const mod = o.module;
......@@ -8300,43 +8694,61 @@ pub const FuncGen = struct {
83008694 const target = mod.getTarget();
83018695 if (!target_util.supportsReturnAddress(target)) {
83028696 // https://github.com/ziglang/zig/issues/11946
8303 return llvm_usize.constNull();
8697 return o.builder.intValue(llvm_usize, 0);
83048698 }
83058699
8306 const llvm_i32 = self.context.intType(32);
8307 const llvm_fn = self.getIntrinsic("llvm.returnaddress", &.{});
8308 const params = [_]*llvm.Value{llvm_i32.constNull()};
8309 const ptr_val = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, "");
8310 return self.builder.buildPtrToInt(ptr_val, llvm_usize, "");
8700 const llvm_fn = try self.getIntrinsic("llvm.returnaddress", &.{});
8701 const params = [_]*llvm.Value{
8702 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
8703 };
8704 const ptr_val = (try self.wip.unimplemented(.ptr, "")).finish(self.builder.buildCall(
8705 (try o.builder.fnType(.ptr, &.{.i32}, .normal)).toLlvm(&o.builder),
8706 llvm_fn,
8707 &params,
8708 params.len,
8709 .Fast,
8710 .Auto,
8711 "",
8712 ), &self.wip);
8713 return self.wip.cast(.ptrtoint, ptr_val, llvm_usize, "");
83118714 }
83128715
8313 fn airFrameAddress(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8716 fn airFrameAddress(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
83148717 _ = inst;
83158718 const o = self.dg.object;
8316 const llvm_i32 = self.context.intType(32);
83178719 const llvm_fn_name = "llvm.frameaddress.p0";
83188720 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {
8319 const llvm_p0i8 = self.context.pointerType(0);
8320 const param_types = [_]*llvm.Type{llvm_i32};
8321 const fn_type = llvm.functionType(llvm_p0i8, &param_types, param_types.len, .False);
8322 break :blk o.llvm_module.addFunction(llvm_fn_name, fn_type);
8721 const fn_type = try o.builder.fnType(.ptr, &.{.i32}, .normal);
8722 break :blk o.llvm_module.addFunction(llvm_fn_name, fn_type.toLlvm(&o.builder));
83238723 };
8724 const llvm_fn_ty = try o.builder.fnType(.ptr, &.{.i32}, .normal);
83248725
8325 const params = [_]*llvm.Value{llvm_i32.constNull()};
8326 const ptr_val = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, "");
8327 const llvm_usize = try o.lowerType(Type.usize);
8328 return self.builder.buildPtrToInt(ptr_val, llvm_usize, "");
8726 const params = [_]*llvm.Value{
8727 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
8728 };
8729 const ptr_val = (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(
8730 self.builder.buildCall(
8731 llvm_fn_ty.toLlvm(&o.builder),
8732 llvm_fn,
8733 &params,
8734 params.len,
8735 .Fast,
8736 .Auto,
8737 "",
8738 ),
8739 &self.wip,
8740 );
8741 return self.wip.cast(.ptrtoint, ptr_val, try o.lowerType(Type.usize), "");
83298742 }
83308743
8331 fn airFence(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8744 fn airFence(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
83328745 const atomic_order = self.air.instructions.items(.data)[inst].fence;
8333 const llvm_memory_order = toLlvmAtomicOrdering(atomic_order);
8334 const single_threaded = llvm.Bool.fromBool(self.single_threaded);
8335 _ = self.builder.buildFence(llvm_memory_order, single_threaded, "");
8336 return null;
8746 const ordering = toLlvmAtomicOrdering(atomic_order);
8747 _ = try self.wip.fence(self.sync_scope, ordering);
8748 return .none;
83378749 }
83388750
8339 fn airCmpxchg(self: *FuncGen, inst: Air.Inst.Index, is_weak: bool) !?*llvm.Value {
8751 fn airCmpxchg(self: *FuncGen, inst: Air.Inst.Index, is_weak: bool) !Builder.Value {
83408752 const o = self.dg.object;
83418753 const mod = o.module;
83428754 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -8345,46 +8757,51 @@ pub const FuncGen = struct {
83458757 var expected_value = try self.resolveInst(extra.expected_value);
83468758 var new_value = try self.resolveInst(extra.new_value);
83478759 const operand_ty = self.typeOf(extra.ptr).childType(mod);
8348 const opt_abi_ty = o.getAtomicAbiType(operand_ty, false);
8349 if (opt_abi_ty) |abi_ty| {
8760 const llvm_operand_ty = try o.lowerType(operand_ty);
8761 const llvm_abi_ty = try o.getAtomicAbiType(operand_ty, false);
8762 if (llvm_abi_ty != .none) {
83508763 // operand needs widening and truncating
8351 if (operand_ty.isSignedInt(mod)) {
8352 expected_value = self.builder.buildSExt(expected_value, abi_ty, "");
8353 new_value = self.builder.buildSExt(new_value, abi_ty, "");
8354 } else {
8355 expected_value = self.builder.buildZExt(expected_value, abi_ty, "");
8356 new_value = self.builder.buildZExt(new_value, abi_ty, "");
8357 }
8764 const signedness: Builder.Function.Instruction.Cast.Signedness =
8765 if (operand_ty.isSignedInt(mod)) .signed else .unsigned;
8766 expected_value = try self.wip.conv(signedness, expected_value, llvm_abi_ty, "");
8767 new_value = try self.wip.conv(signedness, new_value, llvm_abi_ty, "");
83588768 }
8359 const result = self.builder.buildAtomicCmpXchg(
8360 ptr,
8361 expected_value,
8362 new_value,
8363 toLlvmAtomicOrdering(extra.successOrder()),
8364 toLlvmAtomicOrdering(extra.failureOrder()),
8365 llvm.Bool.fromBool(self.single_threaded),
8769
8770 const llvm_result_ty = try o.builder.structType(.normal, &.{
8771 if (llvm_abi_ty != .none) llvm_abi_ty else llvm_operand_ty,
8772 .i1,
8773 });
8774 const result = (try self.wip.unimplemented(llvm_result_ty, "")).finish(
8775 self.builder.buildAtomicCmpXchg(
8776 ptr.toLlvm(&self.wip),
8777 expected_value.toLlvm(&self.wip),
8778 new_value.toLlvm(&self.wip),
8779 @enumFromInt(@intFromEnum(toLlvmAtomicOrdering(extra.successOrder()))),
8780 @enumFromInt(@intFromEnum(toLlvmAtomicOrdering(extra.failureOrder()))),
8781 llvm.Bool.fromBool(self.sync_scope == .singlethread),
8782 ),
8783 &self.wip,
83668784 );
8367 result.setWeak(llvm.Bool.fromBool(is_weak));
8785 result.toLlvm(&self.wip).setWeak(llvm.Bool.fromBool(is_weak));
83688786
83698787 const optional_ty = self.typeOfIndex(inst);
83708788
8371 var payload = self.builder.buildExtractValue(result, 0, "");
8372 if (opt_abi_ty != null) {
8373 payload = self.builder.buildTrunc(payload, try o.lowerType(operand_ty), "");
8374 }
8375 const success_bit = self.builder.buildExtractValue(result, 1, "");
8789 var payload = try self.wip.extractValue(result, &.{0}, "");
8790 if (llvm_abi_ty != .none) payload = try self.wip.cast(.trunc, payload, llvm_operand_ty, "");
8791 const success_bit = try self.wip.extractValue(result, &.{1}, "");
83768792
83778793 if (optional_ty.optionalReprIsPayload(mod)) {
8378 return self.builder.buildSelect(success_bit, payload.typeOf().constNull(), payload, "");
8794 const zero = try o.builder.zeroInitValue(payload.typeOfWip(&self.wip));
8795 return self.wip.select(success_bit, zero, payload, "");
83798796 }
83808797
83818798 comptime assert(optional_layout_version == 3);
83828799
8383 const non_null_bit = self.builder.buildNot(success_bit, "");
8800 const non_null_bit = try self.wip.not(success_bit, "");
83848801 return buildOptional(self, optional_ty, payload, non_null_bit);
83858802 }
83868803
8387 fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8804 fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
83888805 const o = self.dg.object;
83898806 const mod = o.module;
83908807 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
......@@ -8397,120 +8814,146 @@ pub const FuncGen = struct {
83978814 const is_float = operand_ty.isRuntimeFloat();
83988815 const op = toLlvmAtomicRmwBinOp(extra.op(), is_signed_int, is_float);
83998816 const ordering = toLlvmAtomicOrdering(extra.ordering());
8400 const single_threaded = llvm.Bool.fromBool(self.single_threaded);
8401 const opt_abi_ty = o.getAtomicAbiType(operand_ty, op == .Xchg);
8402 if (opt_abi_ty) |abi_ty| {
8817 const single_threaded = llvm.Bool.fromBool(self.sync_scope == .singlethread);
8818 const llvm_abi_ty = try o.getAtomicAbiType(operand_ty, op == .Xchg);
8819 const llvm_operand_ty = try o.lowerType(operand_ty);
8820 if (llvm_abi_ty != .none) {
84038821 // operand needs widening and truncating or bitcasting.
8404 const casted_operand = if (is_float)
8405 self.builder.buildBitCast(operand, abi_ty, "")
8406 else if (is_signed_int)
8407 self.builder.buildSExt(operand, abi_ty, "")
8408 else
8409 self.builder.buildZExt(operand, abi_ty, "");
8822 const casted_operand = try self.wip.cast(
8823 if (is_float) .bitcast else if (is_signed_int) .sext else .zext,
8824 @enumFromInt(@intFromEnum(operand)),
8825 llvm_abi_ty,
8826 "",
8827 );
84108828
8411 const uncasted_result = self.builder.buildAtomicRmw(
8412 op,
8413 ptr,
8414 casted_operand,
8415 ordering,
8416 single_threaded,
8829 const uncasted_result = (try self.wip.unimplemented(llvm_abi_ty, "")).finish(
8830 self.builder.buildAtomicRmw(
8831 op,
8832 ptr.toLlvm(&self.wip),
8833 casted_operand.toLlvm(&self.wip),
8834 @enumFromInt(@intFromEnum(ordering)),
8835 single_threaded,
8836 ),
8837 &self.wip,
84178838 );
8418 const operand_llvm_ty = try o.lowerType(operand_ty);
8839
84198840 if (is_float) {
8420 return self.builder.buildBitCast(uncasted_result, operand_llvm_ty, "");
8841 return self.wip.cast(.bitcast, uncasted_result, llvm_operand_ty, "");
84218842 } else {
8422 return self.builder.buildTrunc(uncasted_result, operand_llvm_ty, "");
8843 return self.wip.cast(.trunc, uncasted_result, llvm_operand_ty, "");
84238844 }
84248845 }
84258846
8426 if (operand.typeOf().getTypeKind() != .Pointer) {
8427 return self.builder.buildAtomicRmw(op, ptr, operand, ordering, single_threaded);
8847 if (!llvm_operand_ty.isPointer(&o.builder)) {
8848 return (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
8849 self.builder.buildAtomicRmw(
8850 op,
8851 ptr.toLlvm(&self.wip),
8852 operand.toLlvm(&self.wip),
8853 @enumFromInt(@intFromEnum(ordering)),
8854 single_threaded,
8855 ),
8856 &self.wip,
8857 );
84288858 }
84298859
84308860 // It's a pointer but we need to treat it as an int.
8431 const usize_llvm_ty = try o.lowerType(Type.usize);
8432 const casted_operand = self.builder.buildPtrToInt(operand, usize_llvm_ty, "");
8433 const uncasted_result = self.builder.buildAtomicRmw(
8434 op,
8435 ptr,
8436 casted_operand,
8437 ordering,
8438 single_threaded,
8861 const llvm_usize = try o.lowerType(Type.usize);
8862 const casted_operand = try self.wip.cast(.ptrtoint, operand, llvm_usize, "");
8863 const uncasted_result = (try self.wip.unimplemented(llvm_usize, "")).finish(
8864 self.builder.buildAtomicRmw(
8865 op,
8866 ptr.toLlvm(&self.wip),
8867 casted_operand.toLlvm(&self.wip),
8868 @enumFromInt(@intFromEnum(ordering)),
8869 single_threaded,
8870 ),
8871 &self.wip,
84398872 );
8440 const operand_llvm_ty = try o.lowerType(operand_ty);
8441 return self.builder.buildIntToPtr(uncasted_result, operand_llvm_ty, "");
8873 return self.wip.cast(.inttoptr, uncasted_result, llvm_operand_ty, "");
84428874 }
84438875
8444 fn airAtomicLoad(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8876 fn airAtomicLoad(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
84458877 const o = self.dg.object;
84468878 const mod = o.module;
84478879 const atomic_load = self.air.instructions.items(.data)[inst].atomic_load;
84488880 const ptr = try self.resolveInst(atomic_load.ptr);
84498881 const ptr_ty = self.typeOf(atomic_load.ptr);
8450 const ptr_info = ptr_ty.ptrInfo(mod);
8451 const elem_ty = ptr_info.child.toType();
8452 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod))
8453 return null;
8882 const info = ptr_ty.ptrInfo(mod);
8883 const elem_ty = info.child.toType();
8884 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none;
84548885 const ordering = toLlvmAtomicOrdering(atomic_load.order);
8455 const opt_abi_llvm_ty = o.getAtomicAbiType(elem_ty, false);
8456 const ptr_alignment = @as(u32, @intCast(ptr_info.flags.alignment.toByteUnitsOptional() orelse
8457 ptr_info.child.toType().abiAlignment(mod)));
8458 const ptr_volatile = llvm.Bool.fromBool(ptr_info.flags.is_volatile);
8886 const llvm_abi_ty = try o.getAtomicAbiType(elem_ty, false);
8887 const ptr_alignment = Builder.Alignment.fromByteUnits(
8888 info.flags.alignment.toByteUnitsOptional() orelse info.child.toType().abiAlignment(mod),
8889 );
8890 const ptr_kind: Builder.MemoryAccessKind = switch (info.flags.is_volatile) {
8891 false => .normal,
8892 true => .@"volatile",
8893 };
84598894 const elem_llvm_ty = try o.lowerType(elem_ty);
84608895
8461 if (opt_abi_llvm_ty) |abi_llvm_ty| {
8896 if (llvm_abi_ty != .none) {
84628897 // operand needs widening and truncating
8463 const load_inst = self.builder.buildLoad(abi_llvm_ty, ptr, "");
8464 load_inst.setAlignment(ptr_alignment);
8465 load_inst.setVolatile(ptr_volatile);
8466 load_inst.setOrdering(ordering);
8467 return self.builder.buildTrunc(load_inst, elem_llvm_ty, "");
8898 const loaded = try self.wip.loadAtomic(
8899 ptr_kind,
8900 llvm_abi_ty,
8901 ptr,
8902 self.sync_scope,
8903 ordering,
8904 ptr_alignment,
8905 "",
8906 );
8907 return self.wip.cast(.trunc, loaded, elem_llvm_ty, "");
84688908 }
8469 const load_inst = self.builder.buildLoad(elem_llvm_ty, ptr, "");
8470 load_inst.setAlignment(ptr_alignment);
8471 load_inst.setVolatile(ptr_volatile);
8472 load_inst.setOrdering(ordering);
8473 return load_inst;
8909 return self.wip.loadAtomic(
8910 ptr_kind,
8911 elem_llvm_ty,
8912 ptr,
8913 self.sync_scope,
8914 ordering,
8915 ptr_alignment,
8916 "",
8917 );
84748918 }
84758919
84768920 fn airAtomicStore(
84778921 self: *FuncGen,
84788922 inst: Air.Inst.Index,
8479 ordering: llvm.AtomicOrdering,
8480 ) !?*llvm.Value {
8923 ordering: Builder.AtomicOrdering,
8924 ) !Builder.Value {
84818925 const o = self.dg.object;
84828926 const mod = o.module;
84838927 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
84848928 const ptr_ty = self.typeOf(bin_op.lhs);
84858929 const operand_ty = ptr_ty.childType(mod);
8486 if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return null;
8930 if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return .none;
84878931 const ptr = try self.resolveInst(bin_op.lhs);
84888932 var element = try self.resolveInst(bin_op.rhs);
8489 const opt_abi_ty = o.getAtomicAbiType(operand_ty, false);
8933 const llvm_abi_ty = try o.getAtomicAbiType(operand_ty, false);
84908934
8491 if (opt_abi_ty) |abi_ty| {
8935 if (llvm_abi_ty != .none) {
84928936 // operand needs widening
8493 if (operand_ty.isSignedInt(mod)) {
8494 element = self.builder.buildSExt(element, abi_ty, "");
8495 } else {
8496 element = self.builder.buildZExt(element, abi_ty, "");
8497 }
8937 element = try self.wip.conv(
8938 if (operand_ty.isSignedInt(mod)) .signed else .unsigned,
8939 element,
8940 llvm_abi_ty,
8941 "",
8942 );
84988943 }
84998944 try self.store(ptr, ptr_ty, element, ordering);
8500 return null;
8945 return .none;
85018946 }
85028947
8503 fn airMemset(self: *FuncGen, inst: Air.Inst.Index, safety: bool) !?*llvm.Value {
8948 fn airMemset(self: *FuncGen, inst: Air.Inst.Index, safety: bool) !Builder.Value {
85048949 const o = self.dg.object;
85058950 const mod = o.module;
85068951 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
85078952 const dest_slice = try self.resolveInst(bin_op.lhs);
85088953 const ptr_ty = self.typeOf(bin_op.lhs);
85098954 const elem_ty = self.typeOf(bin_op.rhs);
8510 const target = mod.getTarget();
8511 const dest_ptr_align = ptr_ty.ptrAlignment(mod);
8512 const u8_llvm_ty = self.context.intType(8);
8513 const dest_ptr = self.sliceOrArrayPtr(dest_slice, ptr_ty);
8955 const dest_ptr_align = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
8956 const dest_ptr = try self.sliceOrArrayPtr(dest_slice, ptr_ty);
85148957 const is_volatile = ptr_ty.isVolatilePtr(mod);
85158958
85168959 // Any WebAssembly runtime will trap when the destination pointer is out-of-bounds, regardless
......@@ -8527,20 +8970,26 @@ pub const FuncGen = struct {
85278970 // extra information to LLVM. However, safety makes the difference between using
85288971 // 0xaa or actual undefined for the fill byte.
85298972 const fill_byte = if (safety)
8530 u8_llvm_ty.constInt(0xaa, .False)
8973 try o.builder.intValue(.i8, 0xaa)
85318974 else
8532 u8_llvm_ty.getUndef();
8533 const len = self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
8975 try o.builder.undefValue(.i8);
8976 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
85348977 if (intrinsic_len0_traps) {
85358978 try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);
85368979 } else {
8537 _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);
8980 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemSet(
8981 dest_ptr.toLlvm(&self.wip),
8982 fill_byte.toLlvm(&self.wip),
8983 len.toLlvm(&self.wip),
8984 @intCast(dest_ptr_align.toByteUnits() orelse 0),
8985 is_volatile,
8986 ), &self.wip);
85388987 }
85398988
85408989 if (safety and mod.comp.bin_file.options.valgrind) {
8541 self.valgrindMarkUndef(dest_ptr, len);
8990 try self.valgrindMarkUndef(dest_ptr, len);
85428991 }
8543 return null;
8992 return .none;
85448993 }
85458994
85468995 // Test if the element value is compile-time known to be a
......@@ -8548,18 +8997,21 @@ pub const FuncGen = struct {
85488997 // repeating byte pattern of 0 bytes. In such case, the memset
85498998 // intrinsic can be used.
85508999 if (try elem_val.hasRepeatedByteRepr(elem_ty, mod)) |byte_val| {
8551 const fill_byte = try self.resolveValue(.{
8552 .ty = Type.u8,
8553 .val = byte_val,
8554 });
8555 const len = self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
9000 const fill_byte = try self.resolveValue(.{ .ty = Type.u8, .val = byte_val });
9001 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
85569002
85579003 if (intrinsic_len0_traps) {
8558 try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);
9004 try self.safeWasmMemset(dest_ptr, fill_byte.toValue(), len, dest_ptr_align, is_volatile);
85599005 } else {
8560 _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);
9006 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemSet(
9007 dest_ptr.toLlvm(&self.wip),
9008 fill_byte.toLlvm(&o.builder),
9009 len.toLlvm(&self.wip),
9010 @intCast(dest_ptr_align.toByteUnits() orelse 0),
9011 is_volatile,
9012 ), &self.wip);
85619013 }
8562 return null;
9014 return .none;
85639015 }
85649016 }
85659017
......@@ -8569,14 +9021,20 @@ pub const FuncGen = struct {
85699021 if (elem_abi_size == 1) {
85709022 // In this case we can take advantage of LLVM's intrinsic.
85719023 const fill_byte = try self.bitCast(value, elem_ty, Type.u8);
8572 const len = self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
9024 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
85739025
85749026 if (intrinsic_len0_traps) {
85759027 try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);
85769028 } else {
8577 _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);
9029 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemSet(
9030 dest_ptr.toLlvm(&self.wip),
9031 fill_byte.toLlvm(&self.wip),
9032 len.toLlvm(&self.wip),
9033 @intCast(dest_ptr_align.toByteUnits() orelse 0),
9034 is_volatile,
9035 ), &self.wip);
85789036 }
8579 return null;
9037 return .none;
85809038 }
85819039
85829040 // non-byte-sized element. lower with a loop. something like this:
......@@ -8584,88 +9042,92 @@ pub const FuncGen = struct {
85849042 // entry:
85859043 // ...
85869044 // %end_ptr = getelementptr %ptr, %len
8587 // br loop
9045 // br %loop
85889046 // loop:
85899047 // %it_ptr = phi body %next_ptr, entry %ptr
85909048 // %end = cmp eq %it_ptr, %end_ptr
8591 // cond_br %end body, end
9049 // br %end, %body, %end
85929050 // body:
85939051 // store %it_ptr, %value
85949052 // %next_ptr = getelementptr %it_ptr, 1
8595 // br loop
9053 // br %loop
85969054 // end:
85979055 // ...
8598 const entry_block = self.builder.getInsertBlock();
8599 const loop_block = self.context.appendBasicBlock(self.llvm_func, "InlineMemsetLoop");
8600 const body_block = self.context.appendBasicBlock(self.llvm_func, "InlineMemsetBody");
8601 const end_block = self.context.appendBasicBlock(self.llvm_func, "InlineMemsetEnd");
9056 const entry_block = self.wip.cursor.block;
9057 const loop_block = try self.wip.block(2, "InlineMemsetLoop");
9058 const body_block = try self.wip.block(1, "InlineMemsetBody");
9059 const end_block = try self.wip.block(1, "InlineMemsetEnd");
86029060
8603 const llvm_usize_ty = self.context.intType(target.ptrBitWidth());
9061 const usize_ty = try o.lowerType(Type.usize);
86049062 const len = switch (ptr_ty.ptrSize(mod)) {
8605 .Slice => self.builder.buildExtractValue(dest_slice, 1, ""),
8606 .One => llvm_usize_ty.constInt(ptr_ty.childType(mod).arrayLen(mod), .False),
9063 .Slice => try self.wip.extractValue(dest_slice, &.{1}, ""),
9064 .One => try o.builder.intValue(usize_ty, ptr_ty.childType(mod).arrayLen(mod)),
86079065 .Many, .C => unreachable,
86089066 };
86099067 const elem_llvm_ty = try o.lowerType(elem_ty);
8610 const len_gep = [_]*llvm.Value{len};
8611 const end_ptr = self.builder.buildInBoundsGEP(elem_llvm_ty, dest_ptr, &len_gep, len_gep.len, "");
8612 _ = self.builder.buildBr(loop_block);
9068 const end_ptr = try self.wip.gep(.inbounds, elem_llvm_ty, dest_ptr, &.{len}, "");
9069 _ = try self.wip.br(loop_block);
86139070
8614 self.builder.positionBuilderAtEnd(loop_block);
8615 const it_ptr = self.builder.buildPhi(self.context.pointerType(0), "");
8616 const end = self.builder.buildICmp(.NE, it_ptr, end_ptr, "");
8617 _ = self.builder.buildCondBr(end, body_block, end_block);
9071 self.wip.cursor = .{ .block = loop_block };
9072 const it_ptr = try self.wip.phi(.ptr, "");
9073 const end = try self.wip.icmp(.ne, it_ptr.toValue(), end_ptr, "");
9074 _ = try self.wip.brCond(end, body_block, end_block);
86189075
8619 self.builder.positionBuilderAtEnd(body_block);
9076 self.wip.cursor = .{ .block = body_block };
86209077 const elem_abi_alignment = elem_ty.abiAlignment(mod);
8621 const it_ptr_alignment = @min(elem_abi_alignment, dest_ptr_align);
9078 const it_ptr_alignment = Builder.Alignment.fromByteUnits(
9079 @min(elem_abi_alignment, dest_ptr_align.toByteUnits() orelse std.math.maxInt(u64)),
9080 );
86229081 if (isByRef(elem_ty, mod)) {
8623 _ = self.builder.buildMemCpy(
8624 it_ptr,
8625 it_ptr_alignment,
8626 value,
9082 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy(
9083 it_ptr.toValue().toLlvm(&self.wip),
9084 @intCast(it_ptr_alignment.toByteUnits() orelse 0),
9085 value.toLlvm(&self.wip),
86279086 elem_abi_alignment,
8628 llvm_usize_ty.constInt(elem_abi_size, .False),
9087 (try o.builder.intConst(usize_ty, elem_abi_size)).toLlvm(&o.builder),
86299088 is_volatile,
8630 );
8631 } else {
8632 const store_inst = self.builder.buildStore(value, it_ptr);
8633 store_inst.setAlignment(it_ptr_alignment);
8634 store_inst.setVolatile(llvm.Bool.fromBool(is_volatile));
8635 }
8636 const one_gep = [_]*llvm.Value{llvm_usize_ty.constInt(1, .False)};
8637 const next_ptr = self.builder.buildInBoundsGEP(elem_llvm_ty, it_ptr, &one_gep, one_gep.len, "");
8638 _ = self.builder.buildBr(loop_block);
8639
8640 self.builder.positionBuilderAtEnd(end_block);
9089 ), &self.wip);
9090 } else _ = try self.wip.store(switch (is_volatile) {
9091 false => .normal,
9092 true => .@"volatile",
9093 }, value, it_ptr.toValue(), it_ptr_alignment);
9094 const next_ptr = try self.wip.gep(.inbounds, elem_llvm_ty, it_ptr.toValue(), &.{
9095 try o.builder.intValue(usize_ty, 1),
9096 }, "");
9097 _ = try self.wip.br(loop_block);
86419098
8642 const incoming_values: [2]*llvm.Value = .{ next_ptr, dest_ptr };
8643 const incoming_blocks: [2]*llvm.BasicBlock = .{ body_block, entry_block };
8644 it_ptr.addIncoming(&incoming_values, &incoming_blocks, 2);
8645
8646 return null;
9099 self.wip.cursor = .{ .block = end_block };
9100 try it_ptr.finish(&.{ next_ptr, dest_ptr }, &.{ body_block, entry_block }, &self.wip);
9101 return .none;
86479102 }
86489103
86499104 fn safeWasmMemset(
86509105 self: *FuncGen,
8651 dest_ptr: *llvm.Value,
8652 fill_byte: *llvm.Value,
8653 len: *llvm.Value,
8654 dest_ptr_align: u32,
9106 dest_ptr: Builder.Value,
9107 fill_byte: Builder.Value,
9108 len: Builder.Value,
9109 dest_ptr_align: Builder.Alignment,
86559110 is_volatile: bool,
86569111 ) !void {
8657 const llvm_usize_ty = self.context.intType(self.dg.object.target.ptrBitWidth());
8658 const cond = try self.cmp(len, llvm_usize_ty.constInt(0, .False), Type.usize, .neq);
8659 const memset_block = self.context.appendBasicBlock(self.llvm_func, "MemsetTrapSkip");
8660 const end_block = self.context.appendBasicBlock(self.llvm_func, "MemsetTrapEnd");
8661 _ = self.builder.buildCondBr(cond, memset_block, end_block);
8662 self.builder.positionBuilderAtEnd(memset_block);
8663 _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);
8664 _ = self.builder.buildBr(end_block);
8665 self.builder.positionBuilderAtEnd(end_block);
9112 const o = self.dg.object;
9113 const llvm_usize_ty = try o.lowerType(Type.usize);
9114 const cond = try self.cmp(len, try o.builder.intValue(llvm_usize_ty, 0), Type.usize, .neq);
9115 const memset_block = try self.wip.block(1, "MemsetTrapSkip");
9116 const end_block = try self.wip.block(2, "MemsetTrapEnd");
9117 _ = try self.wip.brCond(cond, memset_block, end_block);
9118 self.wip.cursor = .{ .block = memset_block };
9119 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemSet(
9120 dest_ptr.toLlvm(&self.wip),
9121 fill_byte.toLlvm(&self.wip),
9122 len.toLlvm(&self.wip),
9123 @intCast(dest_ptr_align.toByteUnits() orelse 0),
9124 is_volatile,
9125 ), &self.wip);
9126 _ = try self.wip.br(end_block);
9127 self.wip.cursor = .{ .block = end_block };
86669128 }
86679129
8668 fn airMemcpy(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9130 fn airMemcpy(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
86699131 const o = self.dg.object;
86709132 const mod = o.module;
86719133 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -8673,9 +9135,9 @@ pub const FuncGen = struct {
86739135 const dest_ptr_ty = self.typeOf(bin_op.lhs);
86749136 const src_slice = try self.resolveInst(bin_op.rhs);
86759137 const src_ptr_ty = self.typeOf(bin_op.rhs);
8676 const src_ptr = self.sliceOrArrayPtr(src_slice, src_ptr_ty);
8677 const len = self.sliceOrArrayLenInBytes(dest_slice, dest_ptr_ty);
8678 const dest_ptr = self.sliceOrArrayPtr(dest_slice, dest_ptr_ty);
9138 const src_ptr = try self.sliceOrArrayPtr(src_slice, src_ptr_ty);
9139 const len = try self.sliceOrArrayLenInBytes(dest_slice, dest_ptr_ty);
9140 const dest_ptr = try self.sliceOrArrayPtr(dest_slice, dest_ptr_ty);
86799141 const is_volatile = src_ptr_ty.isVolatilePtr(mod) or dest_ptr_ty.isVolatilePtr(mod);
86809142
86819143 // When bulk-memory is enabled, this will be lowered to WebAssembly's memory.copy instruction.
......@@ -8687,84 +9149,81 @@ pub const FuncGen = struct {
86879149 std.Target.wasm.featureSetHas(o.target.cpu.features, .bulk_memory) and
86889150 dest_ptr_ty.isSlice(mod))
86899151 {
8690 const llvm_usize_ty = self.context.intType(self.dg.object.target.ptrBitWidth());
8691 const cond = try self.cmp(len, llvm_usize_ty.constInt(0, .False), Type.usize, .neq);
8692 const memcpy_block = self.context.appendBasicBlock(self.llvm_func, "MemcpyTrapSkip");
8693 const end_block = self.context.appendBasicBlock(self.llvm_func, "MemcpyTrapEnd");
8694 _ = self.builder.buildCondBr(cond, memcpy_block, end_block);
8695 self.builder.positionBuilderAtEnd(memcpy_block);
8696 _ = self.builder.buildMemCpy(
8697 dest_ptr,
9152 const zero_usize = try o.builder.intValue(try o.lowerType(Type.usize), 0);
9153 const cond = try self.cmp(len, zero_usize, Type.usize, .neq);
9154 const memcpy_block = try self.wip.block(1, "MemcpyTrapSkip");
9155 const end_block = try self.wip.block(2, "MemcpyTrapEnd");
9156 _ = try self.wip.brCond(cond, memcpy_block, end_block);
9157 self.wip.cursor = .{ .block = memcpy_block };
9158 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy(
9159 dest_ptr.toLlvm(&self.wip),
86989160 dest_ptr_ty.ptrAlignment(mod),
8699 src_ptr,
9161 src_ptr.toLlvm(&self.wip),
87009162 src_ptr_ty.ptrAlignment(mod),
8701 len,
9163 len.toLlvm(&self.wip),
87029164 is_volatile,
8703 );
8704 _ = self.builder.buildBr(end_block);
8705 self.builder.positionBuilderAtEnd(end_block);
8706 return null;
9165 ), &self.wip);
9166 _ = try self.wip.br(end_block);
9167 self.wip.cursor = .{ .block = end_block };
9168 return .none;
87079169 }
87089170
8709 _ = self.builder.buildMemCpy(
8710 dest_ptr,
9171 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy(
9172 dest_ptr.toLlvm(&self.wip),
87119173 dest_ptr_ty.ptrAlignment(mod),
8712 src_ptr,
9174 src_ptr.toLlvm(&self.wip),
87139175 src_ptr_ty.ptrAlignment(mod),
8714 len,
9176 len.toLlvm(&self.wip),
87159177 is_volatile,
8716 );
8717 return null;
9178 ), &self.wip);
9179 return .none;
87189180 }
87199181
8720 fn airSetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9182 fn airSetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
87219183 const o = self.dg.object;
87229184 const mod = o.module;
87239185 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
87249186 const un_ty = self.typeOf(bin_op.lhs).childType(mod);
87259187 const layout = un_ty.unionGetLayout(mod);
8726 if (layout.tag_size == 0) return null;
9188 if (layout.tag_size == 0) return .none;
87279189 const union_ptr = try self.resolveInst(bin_op.lhs);
87289190 const new_tag = try self.resolveInst(bin_op.rhs);
87299191 if (layout.payload_size == 0) {
87309192 // TODO alignment on this store
8731 _ = self.builder.buildStore(new_tag, union_ptr);
8732 return null;
9193 _ = try self.wip.store(.normal, new_tag, union_ptr, .default);
9194 return .none;
87339195 }
8734 const un_llvm_ty = try o.lowerType(un_ty);
87359196 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);
8736 const tag_field_ptr = self.builder.buildStructGEP(un_llvm_ty, union_ptr, tag_index, "");
9197 const tag_field_ptr = try self.wip.gepStruct(try o.lowerType(un_ty), union_ptr, tag_index, "");
87379198 // TODO alignment on this store
8738 _ = self.builder.buildStore(new_tag, tag_field_ptr);
8739 return null;
9199 _ = try self.wip.store(.normal, new_tag, tag_field_ptr, .default);
9200 return .none;
87409201 }
87419202
8742 fn airGetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9203 fn airGetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
87439204 const o = self.dg.object;
87449205 const mod = o.module;
87459206 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
87469207 const un_ty = self.typeOf(ty_op.operand);
87479208 const layout = un_ty.unionGetLayout(mod);
8748 if (layout.tag_size == 0) return null;
9209 if (layout.tag_size == 0) return .none;
87499210 const union_handle = try self.resolveInst(ty_op.operand);
87509211 if (isByRef(un_ty, mod)) {
87519212 const llvm_un_ty = try o.lowerType(un_ty);
8752 if (layout.payload_size == 0) {
8753 return self.builder.buildLoad(llvm_un_ty, union_handle, "");
8754 }
9213 if (layout.payload_size == 0)
9214 return self.wip.load(.normal, llvm_un_ty, union_handle, .default, "");
87559215 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);
8756 const tag_field_ptr = self.builder.buildStructGEP(llvm_un_ty, union_handle, tag_index, "");
8757 return self.builder.buildLoad(llvm_un_ty.structGetTypeAtIndex(tag_index), tag_field_ptr, "");
9216 const tag_field_ptr = try self.wip.gepStruct(llvm_un_ty, union_handle, tag_index, "");
9217 const llvm_tag_ty = llvm_un_ty.structFields(&o.builder)[tag_index];
9218 return self.wip.load(.normal, llvm_tag_ty, tag_field_ptr, .default, "");
87589219 } else {
8759 if (layout.payload_size == 0) {
8760 return union_handle;
8761 }
9220 if (layout.payload_size == 0) return union_handle;
87629221 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);
8763 return self.builder.buildExtractValue(union_handle, tag_index, "");
9222 return self.wip.extractValue(union_handle, &.{tag_index}, "");
87649223 }
87659224 }
87669225
8767 fn airUnaryOp(self: *FuncGen, inst: Air.Inst.Index, comptime op: FloatOp) !?*llvm.Value {
9226 fn airUnaryOp(self: *FuncGen, inst: Air.Inst.Index, comptime op: FloatOp) !Builder.Value {
87689227 const un_op = self.air.instructions.items(.data)[inst].un_op;
87699228 const operand = try self.resolveInst(un_op);
87709229 const operand_ty = self.typeOf(un_op);
......@@ -8772,7 +9231,7 @@ pub const FuncGen = struct {
87729231 return self.buildFloatOp(op, operand_ty, 1, .{operand});
87739232 }
87749233
8775 fn airNeg(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
9234 fn airNeg(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
87769235 self.builder.setFastMath(want_fast_math);
87779236
87789237 const un_op = self.air.instructions.items(.data)[inst].un_op;
......@@ -8782,60 +9241,64 @@ pub const FuncGen = struct {
87829241 return self.buildFloatOp(.neg, operand_ty, 1, .{operand});
87839242 }
87849243
8785 fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value {
9244 fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !Builder.Value {
87869245 const o = self.dg.object;
8787 const mod = o.module;
87889246 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
87899247 const operand_ty = self.typeOf(ty_op.operand);
87909248 const operand = try self.resolveInst(ty_op.operand);
87919249
8792 const llvm_i1 = self.context.intType(1);
8793 const operand_llvm_ty = try o.lowerType(operand_ty);
8794 const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty});
9250 const llvm_operand_ty = try o.lowerType(operand_ty);
9251 const llvm_fn_ty = try o.builder.fnType(llvm_operand_ty, &.{ llvm_operand_ty, .i1 }, .normal);
9252 const fn_val = try self.getIntrinsic(llvm_fn_name, &.{llvm_operand_ty});
87959253
8796 const params = [_]*llvm.Value{ operand, llvm_i1.constNull() };
8797 const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, "");
9254 const params = [_]*llvm.Value{
9255 operand.toLlvm(&self.wip),
9256 Builder.Constant.false.toLlvm(&o.builder),
9257 };
9258 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
9259 self.builder.buildCall(
9260 llvm_fn_ty.toLlvm(&o.builder),
9261 fn_val,
9262 &params,
9263 params.len,
9264 .C,
9265 .Auto,
9266 "",
9267 ),
9268 &self.wip,
9269 );
87989270 const result_ty = self.typeOfIndex(inst);
8799 const result_llvm_ty = try o.lowerType(result_ty);
8800
8801 const bits = operand_ty.intInfo(mod).bits;
8802 const result_bits = result_ty.intInfo(mod).bits;
8803 if (bits > result_bits) {
8804 return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, "");
8805 } else if (bits < result_bits) {
8806 return self.builder.buildZExt(wrong_size_result, result_llvm_ty, "");
8807 } else {
8808 return wrong_size_result;
8809 }
9271 return self.wip.conv(.unsigned, wrong_size_result, try o.lowerType(result_ty), "");
88109272 }
88119273
8812 fn airBitOp(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value {
9274 fn airBitOp(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !Builder.Value {
88139275 const o = self.dg.object;
8814 const mod = o.module;
88159276 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
88169277 const operand_ty = self.typeOf(ty_op.operand);
88179278 const operand = try self.resolveInst(ty_op.operand);
88189279
8819 const params = [_]*llvm.Value{operand};
8820 const operand_llvm_ty = try o.lowerType(operand_ty);
8821 const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty});
8822
8823 const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, "");
9280 const llvm_operand_ty = try o.lowerType(operand_ty);
9281 const llvm_fn_ty = try o.builder.fnType(llvm_operand_ty, &.{llvm_operand_ty}, .normal);
9282 const fn_val = try self.getIntrinsic(llvm_fn_name, &.{llvm_operand_ty});
9283
9284 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
9285 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
9286 self.builder.buildCall(
9287 llvm_fn_ty.toLlvm(&o.builder),
9288 fn_val,
9289 &params,
9290 params.len,
9291 .C,
9292 .Auto,
9293 "",
9294 ),
9295 &self.wip,
9296 );
88249297 const result_ty = self.typeOfIndex(inst);
8825 const result_llvm_ty = try o.lowerType(result_ty);
8826
8827 const bits = operand_ty.intInfo(mod).bits;
8828 const result_bits = result_ty.intInfo(mod).bits;
8829 if (bits > result_bits) {
8830 return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, "");
8831 } else if (bits < result_bits) {
8832 return self.builder.buildZExt(wrong_size_result, result_llvm_ty, "");
8833 } else {
8834 return wrong_size_result;
8835 }
9298 return self.wip.conv(.unsigned, wrong_size_result, try o.lowerType(result_ty), "");
88369299 }
88379300
8838 fn airByteSwap(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value {
9301 fn airByteSwap(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !Builder.Value {
88399302 const o = self.dg.object;
88409303 const mod = o.module;
88419304 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -8844,52 +9307,47 @@ pub const FuncGen = struct {
88449307 assert(bits % 8 == 0);
88459308
88469309 var operand = try self.resolveInst(ty_op.operand);
8847 var operand_llvm_ty = try o.lowerType(operand_ty);
9310 var llvm_operand_ty = try o.lowerType(operand_ty);
88489311
88499312 if (bits % 16 == 8) {
88509313 // If not an even byte-multiple, we need zero-extend + shift-left 1 byte
88519314 // The truncated result at the end will be the correct bswap
8852 const scalar_llvm_ty = self.context.intType(bits + 8);
9315 const scalar_ty = try o.builder.intType(@intCast(bits + 8));
88539316 if (operand_ty.zigTypeTag(mod) == .Vector) {
88549317 const vec_len = operand_ty.vectorLen(mod);
8855 operand_llvm_ty = scalar_llvm_ty.vectorType(vec_len);
9318 llvm_operand_ty = try o.builder.vectorType(.normal, vec_len, scalar_ty);
9319 } else llvm_operand_ty = scalar_ty;
88569320
8857 const shifts = try self.gpa.alloc(*llvm.Value, vec_len);
8858 defer self.gpa.free(shifts);
8859
8860 for (shifts) |*elem| {
8861 elem.* = scalar_llvm_ty.constInt(8, .False);
8862 }
8863 const shift_vec = llvm.constVector(shifts.ptr, vec_len);
9321 const shift_amt =
9322 try o.builder.splatValue(llvm_operand_ty, try o.builder.intConst(scalar_ty, 8));
9323 const extended = try self.wip.cast(.zext, operand, llvm_operand_ty, "");
9324 operand = try self.wip.bin(.shl, extended, shift_amt, "");
88649325
8865 const extended = self.builder.buildZExt(operand, operand_llvm_ty, "");
8866 operand = self.builder.buildShl(extended, shift_vec, "");
8867 } else {
8868 const extended = self.builder.buildZExt(operand, scalar_llvm_ty, "");
8869 operand = self.builder.buildShl(extended, scalar_llvm_ty.constInt(8, .False), "");
8870 operand_llvm_ty = scalar_llvm_ty;
8871 }
88729326 bits = bits + 8;
88739327 }
88749328
8875 const params = [_]*llvm.Value{operand};
8876 const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty});
9329 const llvm_fn_ty = try o.builder.fnType(llvm_operand_ty, &.{llvm_operand_ty}, .normal);
9330 const fn_val = try self.getIntrinsic(llvm_fn_name, &.{llvm_operand_ty});
88779331
8878 const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, "");
9332 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
9333 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
9334 self.builder.buildCall(
9335 llvm_fn_ty.toLlvm(&o.builder),
9336 fn_val,
9337 &params,
9338 params.len,
9339 .C,
9340 .Auto,
9341 "",
9342 ),
9343 &self.wip,
9344 );
88799345
88809346 const result_ty = self.typeOfIndex(inst);
8881 const result_llvm_ty = try o.lowerType(result_ty);
8882 const result_bits = result_ty.intInfo(mod).bits;
8883 if (bits > result_bits) {
8884 return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, "");
8885 } else if (bits < result_bits) {
8886 return self.builder.buildZExt(wrong_size_result, result_llvm_ty, "");
8887 } else {
8888 return wrong_size_result;
8889 }
9347 return self.wip.conv(.unsigned, wrong_size_result, try o.lowerType(result_ty), "");
88909348 }
88919349
8892 fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9350 fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
88939351 const o = self.dg.object;
88949352 const mod = o.module;
88959353 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -8897,50 +9355,53 @@ pub const FuncGen = struct {
88979355 const error_set_ty = self.air.getRefType(ty_op.ty);
88989356
88999357 const names = error_set_ty.errorSetNames(mod);
8900 const valid_block = self.context.appendBasicBlock(self.llvm_func, "Valid");
8901 const invalid_block = self.context.appendBasicBlock(self.llvm_func, "Invalid");
8902 const end_block = self.context.appendBasicBlock(self.llvm_func, "End");
8903 const switch_instr = self.builder.buildSwitch(operand, invalid_block, @as(c_uint, @intCast(names.len)));
9358 const valid_block = try self.wip.block(@intCast(names.len), "Valid");
9359 const invalid_block = try self.wip.block(1, "Invalid");
9360 const end_block = try self.wip.block(2, "End");
9361 var wip_switch = try self.wip.@"switch"(operand, invalid_block, @intCast(names.len));
9362 defer wip_switch.finish(&self.wip);
89049363
89059364 for (names) |name| {
8906 const err_int = @as(Module.ErrorInt, @intCast(mod.global_error_set.getIndex(name).?));
8907 const this_tag_int_value = try o.lowerValue(.{
8908 .ty = Type.err_int,
8909 .val = try mod.intValue(Type.err_int, err_int),
8910 });
8911 switch_instr.addCase(this_tag_int_value, valid_block);
8912 }
8913 self.builder.positionBuilderAtEnd(valid_block);
8914 _ = self.builder.buildBr(end_block);
8915
8916 self.builder.positionBuilderAtEnd(invalid_block);
8917 _ = self.builder.buildBr(end_block);
8918
8919 self.builder.positionBuilderAtEnd(end_block);
8920
8921 const llvm_type = self.context.intType(1);
8922 const incoming_values: [2]*llvm.Value = .{
8923 llvm_type.constInt(1, .False), llvm_type.constInt(0, .False),
8924 };
8925 const incoming_blocks: [2]*llvm.BasicBlock = .{
8926 valid_block, invalid_block,
8927 };
8928 const phi_node = self.builder.buildPhi(llvm_type, "");
8929 phi_node.addIncoming(&incoming_values, &incoming_blocks, 2);
8930 return phi_node;
9365 const err_int = mod.global_error_set.getIndex(name).?;
9366 const this_tag_int_value = try o.builder.intConst(Builder.Type.err_int, err_int);
9367 try wip_switch.addCase(this_tag_int_value, valid_block, &self.wip);
9368 }
9369 self.wip.cursor = .{ .block = valid_block };
9370 _ = try self.wip.br(end_block);
9371
9372 self.wip.cursor = .{ .block = invalid_block };
9373 _ = try self.wip.br(end_block);
9374
9375 self.wip.cursor = .{ .block = end_block };
9376 const phi = try self.wip.phi(.i1, "");
9377 try phi.finish(
9378 &.{ Builder.Constant.true.toValue(), Builder.Constant.false.toValue() },
9379 &.{ valid_block, invalid_block },
9380 &self.wip,
9381 );
9382 return phi.toValue();
89319383 }
89329384
8933 fn airIsNamedEnumValue(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9385 fn airIsNamedEnumValue(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9386 const o = self.dg.object;
89349387 const un_op = self.air.instructions.items(.data)[inst].un_op;
89359388 const operand = try self.resolveInst(un_op);
89369389 const enum_ty = self.typeOf(un_op);
89379390
89389391 const llvm_fn = try self.getIsNamedEnumValueFunction(enum_ty);
8939 const params = [_]*llvm.Value{operand};
8940 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, "");
9392 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
9393 return (try self.wip.unimplemented(.i1, "")).finish(self.builder.buildCall(
9394 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),
9395 llvm_fn.toLlvm(&o.builder),
9396 &params,
9397 params.len,
9398 .Fast,
9399 .Auto,
9400 "",
9401 ), &self.wip);
89419402 }
89429403
8943 fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !*llvm.Value {
9404 fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index {
89449405 const o = self.dg.object;
89459406 const mod = o.module;
89469407 const enum_type = mod.intern_pool.indexToKey(enum_ty.toIntern()).enum_type;
......@@ -8950,185 +9411,207 @@ pub const FuncGen = struct {
89509411 if (gop.found_existing) return gop.value_ptr.*;
89519412 errdefer assert(o.named_enum_map.remove(enum_type.decl));
89529413
8953 var arena_allocator = std.heap.ArenaAllocator.init(self.gpa);
8954 defer arena_allocator.deinit();
8955 const arena = arena_allocator.allocator();
8956
89579414 const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);
8958 const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_is_named_enum_value_{}", .{fqn.fmt(&mod.intern_pool)});
8959
8960 const param_types = [_]*llvm.Type{try o.lowerType(enum_type.tag_ty.toType())};
9415 const llvm_fn_name = try o.builder.fmt("__zig_is_named_enum_value_{}", .{
9416 fqn.fmt(&mod.intern_pool),
9417 });
89619418
8962 const llvm_ret_ty = try o.lowerType(Type.bool);
8963 const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False);
8964 const fn_val = o.llvm_module.addFunction(llvm_fn_name, fn_type);
9419 const fn_type = try o.builder.fnType(.i1, &.{
9420 try o.lowerType(enum_type.tag_ty.toType()),
9421 }, .normal);
9422 const fn_val = o.llvm_module.addFunction(llvm_fn_name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));
89659423 fn_val.setLinkage(.Internal);
89669424 fn_val.setFunctionCallConv(.Fast);
89679425 o.addCommonFnAttributes(fn_val);
8968 gop.value_ptr.* = fn_val;
89699426
8970 const prev_block = self.builder.getInsertBlock();
8971 const prev_debug_location = self.builder.getCurrentDebugLocation2();
8972 defer {
8973 self.builder.positionBuilderAtEnd(prev_block);
8974 if (self.di_scope != null) {
8975 self.builder.setCurrentDebugLocation2(prev_debug_location);
8976 }
9427 var global = Builder.Global{
9428 .linkage = .internal,
9429 .type = fn_type,
9430 .kind = .{ .function = @enumFromInt(o.builder.functions.items.len) },
9431 };
9432 var function = Builder.Function{
9433 .global = @enumFromInt(o.builder.globals.count()),
9434 };
9435 try o.builder.llvm.globals.append(self.gpa, fn_val);
9436 _ = try o.builder.addGlobal(llvm_fn_name, global);
9437 try o.builder.functions.append(self.gpa, function);
9438 gop.value_ptr.* = global.kind.function;
9439
9440 var wip = try Builder.WipFunction.init(&o.builder, global.kind.function);
9441 defer wip.deinit();
9442 wip.cursor = .{ .block = try wip.block(0, "Entry") };
9443
9444 const named_block = try wip.block(@intCast(enum_type.names.len), "Named");
9445 const unnamed_block = try wip.block(1, "Unnamed");
9446 const tag_int_value = wip.arg(0);
9447 var wip_switch = try wip.@"switch"(tag_int_value, unnamed_block, @intCast(enum_type.names.len));
9448 defer wip_switch.finish(&wip);
9449
9450 for (0..enum_type.names.len) |field_index| {
9451 const this_tag_int_value = try o.lowerValue(
9452 (try mod.enumValueFieldIndex(enum_ty, @intCast(field_index))).toIntern(),
9453 );
9454 try wip_switch.addCase(this_tag_int_value, named_block, &wip);
89779455 }
9456 wip.cursor = .{ .block = named_block };
9457 _ = try wip.ret(Builder.Constant.true.toValue());
89789458
8979 const entry_block = self.context.appendBasicBlock(fn_val, "Entry");
8980 self.builder.positionBuilderAtEnd(entry_block);
8981 self.builder.clearCurrentDebugLocation();
8982
8983 const named_block = self.context.appendBasicBlock(fn_val, "Named");
8984 const unnamed_block = self.context.appendBasicBlock(fn_val, "Unnamed");
8985 const tag_int_value = fn_val.getParam(0);
8986 const switch_instr = self.builder.buildSwitch(tag_int_value, unnamed_block, @as(c_uint, @intCast(enum_type.names.len)));
8987
8988 for (enum_type.names, 0..) |_, field_index_usize| {
8989 const field_index = @as(u32, @intCast(field_index_usize));
8990 const this_tag_int_value = int: {
8991 break :int try o.lowerValue(.{
8992 .ty = enum_ty,
8993 .val = try mod.enumValueFieldIndex(enum_ty, field_index),
8994 });
8995 };
8996 switch_instr.addCase(this_tag_int_value, named_block);
8997 }
8998 self.builder.positionBuilderAtEnd(named_block);
8999 _ = self.builder.buildRet(self.context.intType(1).constInt(1, .False));
9459 wip.cursor = .{ .block = unnamed_block };
9460 _ = try wip.ret(Builder.Constant.false.toValue());
90009461
9001 self.builder.positionBuilderAtEnd(unnamed_block);
9002 _ = self.builder.buildRet(self.context.intType(1).constInt(0, .False));
9003 return fn_val;
9462 try wip.finish();
9463 return global.kind.function;
90049464 }
90059465
9006 fn airTagName(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9466 fn airTagName(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9467 const o = self.dg.object;
90079468 const un_op = self.air.instructions.items(.data)[inst].un_op;
90089469 const operand = try self.resolveInst(un_op);
90099470 const enum_ty = self.typeOf(un_op);
90109471
90119472 const llvm_fn = try self.getEnumTagNameFunction(enum_ty);
9012 const params = [_]*llvm.Value{operand};
9013 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, "");
9473 const llvm_fn_ty = llvm_fn.typeOf(&o.builder);
9474 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
9475 return (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(
9476 self.builder.buildCall(
9477 llvm_fn_ty.toLlvm(&o.builder),
9478 llvm_fn.toLlvm(&o.builder),
9479 &params,
9480 params.len,
9481 .Fast,
9482 .Auto,
9483 "",
9484 ),
9485 &self.wip,
9486 );
90149487 }
90159488
9016 fn getEnumTagNameFunction(self: *FuncGen, enum_ty: Type) !*llvm.Value {
9489 fn getEnumTagNameFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index {
90179490 const o = self.dg.object;
90189491 const mod = o.module;
90199492 const enum_type = mod.intern_pool.indexToKey(enum_ty.toIntern()).enum_type;
90209493
90219494 // TODO: detect when the type changes and re-emit this function.
90229495 const gop = try o.decl_map.getOrPut(o.gpa, enum_type.decl);
9023 if (gop.found_existing) return gop.value_ptr.*;
9496 if (gop.found_existing) return gop.value_ptr.ptrConst(&o.builder).kind.function;
90249497 errdefer assert(o.decl_map.remove(enum_type.decl));
90259498
9026 var arena_allocator = std.heap.ArenaAllocator.init(self.gpa);
9027 defer arena_allocator.deinit();
9028 const arena = arena_allocator.allocator();
9029
90309499 const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);
9031 const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{}", .{fqn.fmt(&mod.intern_pool)});
9032
9033 const slice_ty = Type.slice_const_u8_sentinel_0;
9034 const llvm_ret_ty = try o.lowerType(slice_ty);
9035 const usize_llvm_ty = try o.lowerType(Type.usize);
9036 const slice_alignment = slice_ty.abiAlignment(mod);
9500 const llvm_fn_name = try o.builder.fmt("__zig_tag_name_{}", .{fqn.fmt(&mod.intern_pool)});
90379501
9038 const param_types = [_]*llvm.Type{try o.lowerType(enum_type.tag_ty.toType())};
9502 const ret_ty = try o.lowerType(Type.slice_const_u8_sentinel_0);
9503 const usize_ty = try o.lowerType(Type.usize);
90399504
9040 const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False);
9041 const fn_val = o.llvm_module.addFunction(llvm_fn_name, fn_type);
9505 const fn_type = try o.builder.fnType(ret_ty, &.{
9506 try o.lowerType(enum_type.tag_ty.toType()),
9507 }, .normal);
9508 const fn_val = o.llvm_module.addFunction(llvm_fn_name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));
90429509 fn_val.setLinkage(.Internal);
90439510 fn_val.setFunctionCallConv(.Fast);
90449511 o.addCommonFnAttributes(fn_val);
9045 gop.value_ptr.* = fn_val;
9046
9047 const prev_block = self.builder.getInsertBlock();
9048 const prev_debug_location = self.builder.getCurrentDebugLocation2();
9049 defer {
9050 self.builder.positionBuilderAtEnd(prev_block);
9051 if (self.di_scope != null) {
9052 self.builder.setCurrentDebugLocation2(prev_debug_location);
9053 }
9054 }
9055
9056 const entry_block = self.context.appendBasicBlock(fn_val, "Entry");
9057 self.builder.positionBuilderAtEnd(entry_block);
9058 self.builder.clearCurrentDebugLocation();
90599512
9060 const bad_value_block = self.context.appendBasicBlock(fn_val, "BadValue");
9061 const tag_int_value = fn_val.getParam(0);
9062 const switch_instr = self.builder.buildSwitch(tag_int_value, bad_value_block, @as(c_uint, @intCast(enum_type.names.len)));
9063
9064 const array_ptr_indices = [_]*llvm.Value{
9065 usize_llvm_ty.constNull(), usize_llvm_ty.constNull(),
9513 var global = Builder.Global{
9514 .linkage = .internal,
9515 .type = fn_type,
9516 .kind = .{ .function = @enumFromInt(o.builder.functions.items.len) },
90669517 };
9067
9068 for (enum_type.names, 0..) |name_ip, field_index_usize| {
9069 const field_index = @as(u32, @intCast(field_index_usize));
9070 const name = mod.intern_pool.stringToSlice(name_ip);
9071 const str_init = self.context.constString(name.ptr, @as(c_uint, @intCast(name.len)), .False);
9072 const str_init_llvm_ty = str_init.typeOf();
9073 const str_global = o.llvm_module.addGlobal(str_init_llvm_ty, "");
9074 str_global.setInitializer(str_init);
9075 str_global.setLinkage(.Private);
9076 str_global.setGlobalConstant(.True);
9077 str_global.setUnnamedAddr(.True);
9078 str_global.setAlignment(1);
9079
9080 const slice_fields = [_]*llvm.Value{
9081 str_init_llvm_ty.constInBoundsGEP(str_global, &array_ptr_indices, array_ptr_indices.len),
9082 usize_llvm_ty.constInt(name.len, .False),
9518 var function = Builder.Function{
9519 .global = @enumFromInt(o.builder.globals.count()),
9520 };
9521 try o.builder.llvm.globals.append(self.gpa, fn_val);
9522 gop.value_ptr.* = try o.builder.addGlobal(llvm_fn_name, global);
9523 try o.builder.functions.append(self.gpa, function);
9524
9525 var wip = try Builder.WipFunction.init(&o.builder, global.kind.function);
9526 defer wip.deinit();
9527 wip.cursor = .{ .block = try wip.block(0, "Entry") };
9528
9529 const bad_value_block = try wip.block(1, "BadValue");
9530 const tag_int_value = wip.arg(0);
9531 var wip_switch =
9532 try wip.@"switch"(tag_int_value, bad_value_block, @intCast(enum_type.names.len));
9533 defer wip_switch.finish(&wip);
9534
9535 for (enum_type.names, 0..) |name_ip, field_index| {
9536 const name = try o.builder.string(mod.intern_pool.stringToSlice(name_ip));
9537 const str_init = try o.builder.stringNullConst(name);
9538 const str_ty = str_init.typeOf(&o.builder);
9539 const str_llvm_global = o.llvm_module.addGlobal(str_ty.toLlvm(&o.builder), "");
9540 str_llvm_global.setInitializer(str_init.toLlvm(&o.builder));
9541 str_llvm_global.setLinkage(.Private);
9542 str_llvm_global.setGlobalConstant(.True);
9543 str_llvm_global.setUnnamedAddr(.True);
9544 str_llvm_global.setAlignment(1);
9545
9546 var str_global = Builder.Global{
9547 .linkage = .private,
9548 .unnamed_addr = .unnamed_addr,
9549 .type = str_ty,
9550 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
9551 };
9552 var str_variable = Builder.Variable{
9553 .global = @enumFromInt(o.builder.globals.count()),
9554 .mutability = .constant,
9555 .init = str_init,
9556 .alignment = comptime Builder.Alignment.fromByteUnits(1),
90839557 };
9084 const slice_init = llvm_ret_ty.constNamedStruct(&slice_fields, slice_fields.len);
9085 const slice_global = o.llvm_module.addGlobal(slice_init.typeOf(), "");
9086 slice_global.setInitializer(slice_init);
9087 slice_global.setLinkage(.Private);
9088 slice_global.setGlobalConstant(.True);
9089 slice_global.setUnnamedAddr(.True);
9090 slice_global.setAlignment(slice_alignment);
9091
9092 const return_block = self.context.appendBasicBlock(fn_val, "Name");
9093 const this_tag_int_value = try o.lowerValue(.{
9094 .ty = enum_ty,
9095 .val = try mod.enumValueFieldIndex(enum_ty, field_index),
9558 try o.builder.llvm.globals.append(o.gpa, str_llvm_global);
9559 const global_index = try o.builder.addGlobal(.empty, str_global);
9560 try o.builder.variables.append(o.gpa, str_variable);
9561
9562 const slice_val = try o.builder.structValue(ret_ty, &.{
9563 global_index.toConst(),
9564 try o.builder.intConst(usize_ty, name.toSlice(&o.builder).?.len),
90969565 });
9097 switch_instr.addCase(this_tag_int_value, return_block);
90989566
9099 self.builder.positionBuilderAtEnd(return_block);
9100 const loaded = self.builder.buildLoad(llvm_ret_ty, slice_global, "");
9101 loaded.setAlignment(slice_alignment);
9102 _ = self.builder.buildRet(loaded);
9567 const return_block = try wip.block(1, "Name");
9568 const this_tag_int_value = try o.lowerValue(
9569 (try mod.enumValueFieldIndex(enum_ty, @intCast(field_index))).toIntern(),
9570 );
9571 try wip_switch.addCase(this_tag_int_value, return_block, &wip);
9572
9573 wip.cursor = .{ .block = return_block };
9574 _ = try wip.ret(slice_val);
91039575 }
91049576
9105 self.builder.positionBuilderAtEnd(bad_value_block);
9106 _ = self.builder.buildUnreachable();
9107 return fn_val;
9577 wip.cursor = .{ .block = bad_value_block };
9578 _ = try wip.@"unreachable"();
9579
9580 try wip.finish();
9581 return global.kind.function;
91089582 }
91099583
9110 fn getCmpLtErrorsLenFunction(self: *FuncGen) !*llvm.Value {
9584 fn getCmpLtErrorsLenFunction(self: *FuncGen) !Builder.Function.Index {
91119585 const o = self.dg.object;
91129586
9113 if (o.llvm_module.getNamedFunction(lt_errors_fn_name)) |llvm_fn| {
9114 return llvm_fn;
9115 }
9587 const name = try o.builder.string(lt_errors_fn_name);
9588 if (o.builder.getGlobal(name)) |llvm_fn| return llvm_fn.ptrConst(&o.builder).kind.function;
91169589
91179590 // Function signature: fn (anyerror) bool
91189591
9119 const ret_llvm_ty = try o.lowerType(Type.bool);
9120 const anyerror_llvm_ty = try o.lowerType(Type.anyerror);
9121 const param_types = [_]*llvm.Type{anyerror_llvm_ty};
9592 const fn_type = try o.builder.fnType(.i1, &.{Builder.Type.err_int}, .normal);
9593 const llvm_fn = o.llvm_module.addFunction(name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));
91229594
9123 const fn_type = llvm.functionType(ret_llvm_ty, &param_types, param_types.len, .False);
9124 const llvm_fn = o.llvm_module.addFunction(lt_errors_fn_name, fn_type);
91259595 llvm_fn.setLinkage(.Internal);
91269596 llvm_fn.setFunctionCallConv(.Fast);
91279597 o.addCommonFnAttributes(llvm_fn);
9128 return llvm_fn;
9598
9599 var global = Builder.Global{
9600 .linkage = .internal,
9601 .type = fn_type,
9602 .kind = .{ .function = @enumFromInt(o.builder.functions.items.len) },
9603 };
9604 var function = Builder.Function{
9605 .global = @enumFromInt(o.builder.globals.count()),
9606 };
9607
9608 try o.builder.llvm.globals.append(self.gpa, llvm_fn);
9609 _ = try o.builder.addGlobal(name, global);
9610 try o.builder.functions.append(self.gpa, function);
9611 return global.kind.function;
91299612 }
91309613
9131 fn airErrorName(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9614 fn airErrorName(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
91329615 const o = self.dg.object;
91339616 const un_op = self.air.instructions.items(.data)[inst].un_op;
91349617 const operand = try self.resolveInst(un_op);
......@@ -9136,34 +9619,32 @@ pub const FuncGen = struct {
91369619 const slice_llvm_ty = try o.lowerType(slice_ty);
91379620
91389621 const error_name_table_ptr = try self.getErrorNameTable();
9139 const ptr_slice_llvm_ty = self.context.pointerType(0);
9140 const error_name_table = self.builder.buildLoad(ptr_slice_llvm_ty, error_name_table_ptr, "");
9141 const indices = [_]*llvm.Value{operand};
9142 const error_name_ptr = self.builder.buildInBoundsGEP(slice_llvm_ty, error_name_table, &indices, indices.len, "");
9143 return self.builder.buildLoad(slice_llvm_ty, error_name_ptr, "");
9622 const error_name_table =
9623 try self.wip.load(.normal, .ptr, error_name_table_ptr.toValue(&o.builder), .default, "");
9624 const error_name_ptr =
9625 try self.wip.gep(.inbounds, slice_llvm_ty, error_name_table, &.{operand}, "");
9626 return self.wip.load(.normal, slice_llvm_ty, error_name_ptr, .default, "");
91449627 }
91459628
9146 fn airSplat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9629 fn airSplat(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
91479630 const o = self.dg.object;
9148 const mod = o.module;
91499631 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
91509632 const scalar = try self.resolveInst(ty_op.operand);
91519633 const vector_ty = self.typeOfIndex(inst);
9152 const len = vector_ty.vectorLen(mod);
9153 return self.builder.buildVectorSplat(len, scalar, "");
9634 return self.wip.splatVector(try o.lowerType(vector_ty), scalar, "");
91549635 }
91559636
9156 fn airSelect(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9637 fn airSelect(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
91579638 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
91589639 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
91599640 const pred = try self.resolveInst(pl_op.operand);
91609641 const a = try self.resolveInst(extra.lhs);
91619642 const b = try self.resolveInst(extra.rhs);
91629643
9163 return self.builder.buildSelect(pred, a, b, "");
9644 return self.wip.select(pred, a, b, "");
91649645 }
91659646
9166 fn airShuffle(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9647 fn airShuffle(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
91679648 const o = self.dg.object;
91689649 const mod = o.module;
91699650 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -9179,24 +9660,25 @@ pub const FuncGen = struct {
91799660 // when changing code, so Zig uses negative numbers to index the
91809661 // second vector. These start at -1 and go down, and are easiest to use
91819662 // with the ~ operator. Here we convert between the two formats.
9182 const values = try self.gpa.alloc(*llvm.Value, mask_len);
9663 const values = try self.gpa.alloc(Builder.Constant, mask_len);
91839664 defer self.gpa.free(values);
91849665
9185 const llvm_i32 = self.context.intType(32);
9186
91879666 for (values, 0..) |*val, i| {
91889667 const elem = try mask.elemValue(mod, i);
91899668 if (elem.isUndef(mod)) {
9190 val.* = llvm_i32.getUndef();
9669 val.* = try o.builder.undefConst(.i32);
91919670 } else {
91929671 const int = elem.toSignedInt(mod);
9193 const unsigned = if (int >= 0) @as(u32, @intCast(int)) else @as(u32, @intCast(~int + a_len));
9194 val.* = llvm_i32.constInt(unsigned, .False);
9672 const unsigned: u32 = @intCast(if (int >= 0) int else ~int + a_len);
9673 val.* = try o.builder.intConst(.i32, unsigned);
91959674 }
91969675 }
91979676
9198 const llvm_mask_value = llvm.constVector(values.ptr, mask_len);
9199 return self.builder.buildShuffleVector(a, b, llvm_mask_value, "");
9677 const llvm_mask_value = try o.builder.vectorValue(
9678 try o.builder.vectorType(.normal, mask_len, .i32),
9679 values,
9680 );
9681 return self.wip.shuffleVector(a, b, llvm_mask_value, "");
92009682 }
92019683
92029684 /// Reduce a vector by repeatedly applying `llvm_fn` to produce an accumulated result.
......@@ -9213,58 +9695,69 @@ pub const FuncGen = struct {
92139695 ///
92149696 fn buildReducedCall(
92159697 self: *FuncGen,
9216 llvm_fn: *llvm.Value,
9217 operand_vector: *llvm.Value,
9698 llvm_fn: Builder.Function.Index,
9699 operand_vector: Builder.Value,
92189700 vector_len: usize,
9219 accum_init: *llvm.Value,
9220 ) !*llvm.Value {
9701 accum_init: Builder.Value,
9702 ) !Builder.Value {
92219703 const o = self.dg.object;
9222 const llvm_usize_ty = try o.lowerType(Type.usize);
9223 const llvm_vector_len = llvm_usize_ty.constInt(vector_len, .False);
9224 const llvm_result_ty = accum_init.typeOf();
9704 const usize_ty = try o.lowerType(Type.usize);
9705 const llvm_vector_len = try o.builder.intValue(usize_ty, vector_len);
9706 const llvm_result_ty = accum_init.typeOfWip(&self.wip);
92259707
92269708 // Allocate and initialize our mutable variables
9227 const i_ptr = self.buildAlloca(llvm_usize_ty, null);
9228 _ = self.builder.buildStore(llvm_usize_ty.constInt(0, .False), i_ptr);
9229 const accum_ptr = self.buildAlloca(llvm_result_ty, null);
9230 _ = self.builder.buildStore(accum_init, accum_ptr);
9709 const i_ptr = try self.buildAlloca(usize_ty, .default);
9710 _ = try self.wip.store(.normal, try o.builder.intValue(usize_ty, 0), i_ptr, .default);
9711 const accum_ptr = try self.buildAlloca(llvm_result_ty, .default);
9712 _ = try self.wip.store(.normal, accum_init, accum_ptr, .default);
92319713
92329714 // Setup the loop
9233 const loop = self.context.appendBasicBlock(self.llvm_func, "ReduceLoop");
9234 const loop_exit = self.context.appendBasicBlock(self.llvm_func, "AfterReduce");
9235 _ = self.builder.buildBr(loop);
9715 const loop = try self.wip.block(2, "ReduceLoop");
9716 const loop_exit = try self.wip.block(1, "AfterReduce");
9717 _ = try self.wip.br(loop);
92369718 {
9237 self.builder.positionBuilderAtEnd(loop);
9719 self.wip.cursor = .{ .block = loop };
92389720
92399721 // while (i < vec.len)
9240 const i = self.builder.buildLoad(llvm_usize_ty, i_ptr, "");
9241 const cond = self.builder.buildICmp(.ULT, i, llvm_vector_len, "");
9242 const loop_then = self.context.appendBasicBlock(self.llvm_func, "ReduceLoopThen");
9722 const i = try self.wip.load(.normal, usize_ty, i_ptr, .default, "");
9723 const cond = try self.wip.icmp(.ult, i, llvm_vector_len, "");
9724 const loop_then = try self.wip.block(1, "ReduceLoopThen");
92439725
9244 _ = self.builder.buildCondBr(cond, loop_then, loop_exit);
9726 _ = try self.wip.brCond(cond, loop_then, loop_exit);
92459727
92469728 {
9247 self.builder.positionBuilderAtEnd(loop_then);
9729 self.wip.cursor = .{ .block = loop_then };
92489730
92499731 // accum = f(accum, vec[i]);
9250 const accum = self.builder.buildLoad(llvm_result_ty, accum_ptr, "");
9251 const element = self.builder.buildExtractElement(operand_vector, i, "");
9252 const params = [2]*llvm.Value{ accum, element };
9253 const new_accum = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .C, .Auto, "");
9254 _ = self.builder.buildStore(new_accum, accum_ptr);
9732 const accum = try self.wip.load(.normal, llvm_result_ty, accum_ptr, .default, "");
9733 const element = try self.wip.extractElement(operand_vector, i, "");
9734 const params = [2]*llvm.Value{ accum.toLlvm(&self.wip), element.toLlvm(&self.wip) };
9735 const new_accum = (try self.wip.unimplemented(llvm_result_ty, "")).finish(
9736 self.builder.buildCall(
9737 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),
9738 llvm_fn.toLlvm(&o.builder),
9739 &params,
9740 params.len,
9741 .C,
9742 .Auto,
9743 "",
9744 ),
9745 &self.wip,
9746 );
9747 _ = try self.wip.store(.normal, new_accum, accum_ptr, .default);
92559748
92569749 // i += 1
9257 const new_i = self.builder.buildAdd(i, llvm_usize_ty.constInt(1, .False), "");
9258 _ = self.builder.buildStore(new_i, i_ptr);
9259 _ = self.builder.buildBr(loop);
9750 const new_i = try self.wip.bin(.add, i, try o.builder.intValue(usize_ty, 1), "");
9751 _ = try self.wip.store(.normal, new_i, i_ptr, .default);
9752 _ = try self.wip.br(loop);
92609753 }
92619754 }
92629755
9263 self.builder.positionBuilderAtEnd(loop_exit);
9264 return self.builder.buildLoad(llvm_result_ty, accum_ptr, "");
9756 self.wip.cursor = .{ .block = loop_exit };
9757 return self.wip.load(.normal, llvm_result_ty, accum_ptr, .default, "");
92659758 }
92669759
9267 fn airReduce(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
9760 fn airReduce(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
92689761 self.builder.setFastMath(want_fast_math);
92699762 const o = self.dg.object;
92709763 const mod = o.module;
......@@ -9274,40 +9767,70 @@ pub const FuncGen = struct {
92749767 const operand = try self.resolveInst(reduce.operand);
92759768 const operand_ty = self.typeOf(reduce.operand);
92769769 const scalar_ty = self.typeOfIndex(inst);
9770 const llvm_scalar_ty = try o.lowerType(scalar_ty);
92779771
92789772 switch (reduce.operation) {
9279 .And => return self.builder.buildAndReduce(operand),
9280 .Or => return self.builder.buildOrReduce(operand),
9281 .Xor => return self.builder.buildXorReduce(operand),
9773 .And => return (try self.wip.unimplemented(llvm_scalar_ty, ""))
9774 .finish(self.builder.buildAndReduce(operand.toLlvm(&self.wip)), &self.wip),
9775 .Or => return (try self.wip.unimplemented(llvm_scalar_ty, ""))
9776 .finish(self.builder.buildOrReduce(operand.toLlvm(&self.wip)), &self.wip),
9777 .Xor => return (try self.wip.unimplemented(llvm_scalar_ty, ""))
9778 .finish(self.builder.buildXorReduce(operand.toLlvm(&self.wip)), &self.wip),
92829779 .Min => switch (scalar_ty.zigTypeTag(mod)) {
9283 .Int => return self.builder.buildIntMinReduce(operand, scalar_ty.isSignedInt(mod)),
9780 .Int => return (try self.wip.unimplemented(llvm_scalar_ty, "")).finish(
9781 self.builder.buildIntMinReduce(
9782 operand.toLlvm(&self.wip),
9783 scalar_ty.isSignedInt(mod),
9784 ),
9785 &self.wip,
9786 ),
92849787 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
9285 return self.builder.buildFPMinReduce(operand);
9788 return (try self.wip.unimplemented(llvm_scalar_ty, ""))
9789 .finish(self.builder.buildFPMinReduce(operand.toLlvm(&self.wip)), &self.wip);
92869790 },
92879791 else => unreachable,
92889792 },
92899793 .Max => switch (scalar_ty.zigTypeTag(mod)) {
9290 .Int => return self.builder.buildIntMaxReduce(operand, scalar_ty.isSignedInt(mod)),
9794 .Int => return (try self.wip.unimplemented(llvm_scalar_ty, "")).finish(
9795 self.builder.buildIntMaxReduce(
9796 operand.toLlvm(&self.wip),
9797 scalar_ty.isSignedInt(mod),
9798 ),
9799 &self.wip,
9800 ),
92919801 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
9292 return self.builder.buildFPMaxReduce(operand);
9802 return (try self.wip.unimplemented(llvm_scalar_ty, ""))
9803 .finish(self.builder.buildFPMaxReduce(operand.toLlvm(&self.wip)), &self.wip);
92939804 },
92949805 else => unreachable,
92959806 },
92969807 .Add => switch (scalar_ty.zigTypeTag(mod)) {
9297 .Int => return self.builder.buildAddReduce(operand),
9808 .Int => return (try self.wip.unimplemented(llvm_scalar_ty, ""))
9809 .finish(self.builder.buildAddReduce(operand.toLlvm(&self.wip)), &self.wip),
92989810 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
9299 const scalar_llvm_ty = try o.lowerType(scalar_ty);
9300 const neutral_value = scalar_llvm_ty.constReal(-0.0);
9301 return self.builder.buildFPAddReduce(neutral_value, operand);
9811 const neutral_value = try o.builder.fpConst(llvm_scalar_ty, -0.0);
9812 return (try self.wip.unimplemented(llvm_scalar_ty, "")).finish(
9813 self.builder.buildFPAddReduce(
9814 neutral_value.toLlvm(&o.builder),
9815 operand.toLlvm(&self.wip),
9816 ),
9817 &self.wip,
9818 );
93029819 },
93039820 else => unreachable,
93049821 },
93059822 .Mul => switch (scalar_ty.zigTypeTag(mod)) {
9306 .Int => return self.builder.buildMulReduce(operand),
9823 .Int => return (try self.wip.unimplemented(llvm_scalar_ty, ""))
9824 .finish(self.builder.buildMulReduce(operand.toLlvm(&self.wip)), &self.wip),
93079825 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
9308 const scalar_llvm_ty = try o.lowerType(scalar_ty);
9309 const neutral_value = scalar_llvm_ty.constReal(1.0);
9310 return self.builder.buildFPMulReduce(neutral_value, operand);
9826 const neutral_value = try o.builder.fpConst(llvm_scalar_ty, 1.0);
9827 return (try self.wip.unimplemented(llvm_scalar_ty, "")).finish(
9828 self.builder.buildFPMulReduce(
9829 neutral_value.toLlvm(&o.builder),
9830 operand.toLlvm(&self.wip),
9831 ),
9832 &self.wip,
9833 );
93119834 },
93129835 else => unreachable,
93139836 },
......@@ -9315,58 +9838,71 @@ pub const FuncGen = struct {
93159838
93169839 // Reduction could not be performed with intrinsics.
93179840 // Use a manual loop over a softfloat call instead.
9318 var fn_name_buf: [64]u8 = undefined;
93199841 const float_bits = scalar_ty.floatBits(target);
93209842 const fn_name = switch (reduce.operation) {
9321 .Min => std.fmt.bufPrintZ(&fn_name_buf, "{s}fmin{s}", .{
9843 .Min => try o.builder.fmt("{s}fmin{s}", .{
93229844 libcFloatPrefix(float_bits), libcFloatSuffix(float_bits),
9323 }) catch unreachable,
9324 .Max => std.fmt.bufPrintZ(&fn_name_buf, "{s}fmax{s}", .{
9845 }),
9846 .Max => try o.builder.fmt("{s}fmax{s}", .{
93259847 libcFloatPrefix(float_bits), libcFloatSuffix(float_bits),
9326 }) catch unreachable,
9327 .Add => std.fmt.bufPrintZ(&fn_name_buf, "__add{s}f3", .{
9848 }),
9849 .Add => try o.builder.fmt("__add{s}f3", .{
93289850 compilerRtFloatAbbrev(float_bits),
9329 }) catch unreachable,
9330 .Mul => std.fmt.bufPrintZ(&fn_name_buf, "__mul{s}f3", .{
9851 }),
9852 .Mul => try o.builder.fmt("__mul{s}f3", .{
93319853 compilerRtFloatAbbrev(float_bits),
9332 }) catch unreachable,
9854 }),
93339855 else => unreachable,
93349856 };
93359857
9336 const param_llvm_ty = try o.lowerType(scalar_ty);
9337 const param_types = [2]*llvm.Type{ param_llvm_ty, param_llvm_ty };
9338 const libc_fn = self.getLibcFunction(fn_name, &param_types, param_llvm_ty);
9339 const init_value = try o.lowerValue(.{
9340 .ty = scalar_ty,
9341 .val = try mod.floatValue(scalar_ty, switch (reduce.operation) {
9342 .Min => std.math.nan(f32),
9343 .Max => std.math.nan(f32),
9344 .Add => -0.0,
9345 .Mul => 1.0,
9346 else => unreachable,
9347 }),
9348 });
9349 return self.buildReducedCall(libc_fn, operand, operand_ty.vectorLen(mod), init_value);
9858 const libc_fn =
9859 try self.getLibcFunction(fn_name, &.{ llvm_scalar_ty, llvm_scalar_ty }, llvm_scalar_ty);
9860 const init_val = switch (llvm_scalar_ty) {
9861 .i16 => try o.builder.intValue(.i16, @as(i16, @bitCast(
9862 @as(f16, switch (reduce.operation) {
9863 .Min, .Max => std.math.nan(f16),
9864 .Add => -0.0,
9865 .Mul => 1.0,
9866 else => unreachable,
9867 }),
9868 ))),
9869 .i80 => try o.builder.intValue(.i80, @as(i80, @bitCast(
9870 @as(f80, switch (reduce.operation) {
9871 .Min, .Max => std.math.nan(f80),
9872 .Add => -0.0,
9873 .Mul => 1.0,
9874 else => unreachable,
9875 }),
9876 ))),
9877 .i128 => try o.builder.intValue(.i128, @as(i128, @bitCast(
9878 @as(f128, switch (reduce.operation) {
9879 .Min, .Max => std.math.nan(f128),
9880 .Add => -0.0,
9881 .Mul => 1.0,
9882 else => unreachable,
9883 }),
9884 ))),
9885 else => unreachable,
9886 };
9887 return self.buildReducedCall(libc_fn, operand, operand_ty.vectorLen(mod), init_val);
93509888 }
93519889
9352 fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9890 fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
93539891 const o = self.dg.object;
93549892 const mod = o.module;
93559893 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
93569894 const result_ty = self.typeOfIndex(inst);
9357 const len = @as(usize, @intCast(result_ty.arrayLen(mod)));
9358 const elements = @as([]const Air.Inst.Ref, @ptrCast(self.air.extra[ty_pl.payload..][0..len]));
9895 const len: usize = @intCast(result_ty.arrayLen(mod));
9896 const elements: []const Air.Inst.Ref = @ptrCast(self.air.extra[ty_pl.payload..][0..len]);
93599897 const llvm_result_ty = try o.lowerType(result_ty);
93609898
93619899 switch (result_ty.zigTypeTag(mod)) {
93629900 .Vector => {
9363 const llvm_u32 = self.context.intType(32);
9364
9365 var vector = llvm_result_ty.getUndef();
9901 var vector = try o.builder.poisonValue(llvm_result_ty);
93669902 for (elements, 0..) |elem, i| {
9367 const index_u32 = llvm_u32.constInt(i, .False);
9903 const index_u32 = try o.builder.intValue(.i32, i);
93689904 const llvm_elem = try self.resolveInst(elem);
9369 vector = self.builder.buildInsertElement(vector, llvm_elem, index_u32, "");
9905 vector = try self.wip.insertElement(vector, llvm_elem, index_u32, "");
93709906 }
93719907 return vector;
93729908 },
......@@ -9375,48 +9911,47 @@ pub const FuncGen = struct {
93759911 const struct_obj = mod.typeToStruct(result_ty).?;
93769912 assert(struct_obj.haveLayout());
93779913 const big_bits = struct_obj.backing_int_ty.bitSize(mod);
9378 const int_llvm_ty = self.context.intType(@as(c_uint, @intCast(big_bits)));
9914 const int_ty = try o.builder.intType(@intCast(big_bits));
93799915 const fields = struct_obj.fields.values();
93809916 comptime assert(Type.packed_struct_layout_version == 2);
9381 var running_int: *llvm.Value = int_llvm_ty.constNull();
9917 var running_int = try o.builder.intValue(int_ty, 0);
93829918 var running_bits: u16 = 0;
93839919 for (elements, 0..) |elem, i| {
93849920 const field = fields[i];
93859921 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
93869922
93879923 const non_int_val = try self.resolveInst(elem);
9388 const ty_bit_size = @as(u16, @intCast(field.ty.bitSize(mod)));
9389 const small_int_ty = self.context.intType(ty_bit_size);
9924 const ty_bit_size: u16 = @intCast(field.ty.bitSize(mod));
9925 const small_int_ty = try o.builder.intType(ty_bit_size);
93909926 const small_int_val = if (field.ty.isPtrAtRuntime(mod))
9391 self.builder.buildPtrToInt(non_int_val, small_int_ty, "")
9927 try self.wip.cast(.ptrtoint, non_int_val, small_int_ty, "")
93929928 else
9393 self.builder.buildBitCast(non_int_val, small_int_ty, "");
9394 const shift_rhs = int_llvm_ty.constInt(running_bits, .False);
9929 try self.wip.cast(.bitcast, non_int_val, small_int_ty, "");
9930 const shift_rhs = try o.builder.intValue(int_ty, running_bits);
93959931 // If the field is as large as the entire packed struct, this
93969932 // zext would go from, e.g. i16 to i16. This is legal with
93979933 // constZExtOrBitCast but not legal with constZExt.
9398 const extended_int_val = self.builder.buildZExtOrBitCast(small_int_val, int_llvm_ty, "");
9399 const shifted = self.builder.buildShl(extended_int_val, shift_rhs, "");
9400 running_int = self.builder.buildOr(running_int, shifted, "");
9934 const extended_int_val = try self.wip.conv(.unsigned, small_int_val, int_ty, "");
9935 const shifted = try self.wip.bin(.shl, extended_int_val, shift_rhs, "");
9936 running_int = try self.wip.bin(.@"or", running_int, shifted, "");
94019937 running_bits += ty_bit_size;
94029938 }
94039939 return running_int;
94049940 }
94059941
94069942 if (isByRef(result_ty, mod)) {
9407 const llvm_u32 = self.context.intType(32);
94089943 // TODO in debug builds init to undef so that the padding will be 0xaa
94099944 // even if we fully populate the fields.
9410 const alloca_inst = self.buildAlloca(llvm_result_ty, result_ty.abiAlignment(mod));
9945 const alignment = Builder.Alignment.fromByteUnits(result_ty.abiAlignment(mod));
9946 const alloca_inst = try self.buildAlloca(llvm_result_ty, alignment);
94119947
9412 var indices: [2]*llvm.Value = .{ llvm_u32.constNull(), undefined };
94139948 for (elements, 0..) |elem, i| {
94149949 if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue;
94159950
94169951 const llvm_elem = try self.resolveInst(elem);
94179952 const llvm_i = llvmField(result_ty, i, mod).?.index;
9418 indices[1] = llvm_u32.constInt(llvm_i, .False);
9419 const field_ptr = self.builder.buildInBoundsGEP(llvm_result_ty, alloca_inst, &indices, indices.len, "");
9953 const field_ptr =
9954 try self.wip.gepStruct(llvm_result_ty, alloca_inst, llvm_i, "");
94209955 const field_ptr_ty = try mod.ptrType(.{
94219956 .child = self.typeOf(elem).toIntern(),
94229957 .flags = .{
......@@ -9425,18 +9960,18 @@ pub const FuncGen = struct {
94259960 ),
94269961 },
94279962 });
9428 try self.store(field_ptr, field_ptr_ty, llvm_elem, .NotAtomic);
9963 try self.store(field_ptr, field_ptr_ty, llvm_elem, .none);
94299964 }
94309965
94319966 return alloca_inst;
94329967 } else {
9433 var result = llvm_result_ty.getUndef();
9968 var result = try o.builder.poisonValue(llvm_result_ty);
94349969 for (elements, 0..) |elem, i| {
94359970 if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue;
94369971
94379972 const llvm_elem = try self.resolveInst(elem);
94389973 const llvm_i = llvmField(result_ty, i, mod).?.index;
9439 result = self.builder.buildInsertValue(result, llvm_elem, llvm_i, "");
9974 result = try self.wip.insertValue(result, llvm_elem, &.{llvm_i}, "");
94409975 }
94419976 return result;
94429977 }
......@@ -9445,7 +9980,9 @@ pub const FuncGen = struct {
94459980 assert(isByRef(result_ty, mod));
94469981
94479982 const llvm_usize = try o.lowerType(Type.usize);
9448 const alloca_inst = self.buildAlloca(llvm_result_ty, result_ty.abiAlignment(mod));
9983 const usize_zero = try o.builder.intValue(llvm_usize, 0);
9984 const alignment = Builder.Alignment.fromByteUnits(result_ty.abiAlignment(mod));
9985 const alloca_inst = try self.buildAlloca(llvm_result_ty, alignment);
94499986
94509987 const array_info = result_ty.arrayInfo(mod);
94519988 const elem_ptr_ty = try mod.ptrType(.{
......@@ -9453,26 +9990,21 @@ pub const FuncGen = struct {
94539990 });
94549991
94559992 for (elements, 0..) |elem, i| {
9456 const indices: [2]*llvm.Value = .{
9457 llvm_usize.constNull(),
9458 llvm_usize.constInt(@as(c_uint, @intCast(i)), .False),
9459 };
9460 const elem_ptr = self.builder.buildInBoundsGEP(llvm_result_ty, alloca_inst, &indices, indices.len, "");
9993 const elem_ptr = try self.wip.gep(.inbounds, llvm_result_ty, alloca_inst, &.{
9994 usize_zero, try o.builder.intValue(llvm_usize, i),
9995 }, "");
94619996 const llvm_elem = try self.resolveInst(elem);
9462 try self.store(elem_ptr, elem_ptr_ty, llvm_elem, .NotAtomic);
9997 try self.store(elem_ptr, elem_ptr_ty, llvm_elem, .none);
94639998 }
94649999 if (array_info.sentinel) |sent_val| {
9465 const indices: [2]*llvm.Value = .{
9466 llvm_usize.constNull(),
9467 llvm_usize.constInt(@as(c_uint, @intCast(array_info.len)), .False),
9468 };
9469 const elem_ptr = self.builder.buildInBoundsGEP(llvm_result_ty, alloca_inst, &indices, indices.len, "");
10000 const elem_ptr = try self.wip.gep(.inbounds, llvm_result_ty, alloca_inst, &.{
10001 usize_zero, try o.builder.intValue(llvm_usize, array_info.len),
10002 }, "");
947010003 const llvm_elem = try self.resolveValue(.{
947110004 .ty = array_info.elem_type,
947210005 .val = sent_val,
947310006 });
9474
9475 try self.store(elem_ptr, elem_ptr_ty, llvm_elem, .NotAtomic);
10007 try self.store(elem_ptr, elem_ptr_ty, llvm_elem.toValue(), .none);
947610008 }
947710009
947810010 return alloca_inst;
......@@ -9481,7 +10013,7 @@ pub const FuncGen = struct {
948110013 }
948210014 }
948310015
9484 fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
10016 fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
948510017 const o = self.dg.object;
948610018 const mod = o.module;
948710019 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -9493,16 +10025,15 @@ pub const FuncGen = struct {
949310025
949410026 if (union_obj.layout == .Packed) {
949510027 const big_bits = union_ty.bitSize(mod);
9496 const int_llvm_ty = self.context.intType(@as(c_uint, @intCast(big_bits)));
10028 const int_llvm_ty = try o.builder.intType(@intCast(big_bits));
949710029 const field = union_obj.fields.values()[extra.field_index];
949810030 const non_int_val = try self.resolveInst(extra.init);
9499 const ty_bit_size = @as(u16, @intCast(field.ty.bitSize(mod)));
9500 const small_int_ty = self.context.intType(ty_bit_size);
10031 const small_int_ty = try o.builder.intType(@intCast(field.ty.bitSize(mod)));
950110032 const small_int_val = if (field.ty.isPtrAtRuntime(mod))
9502 self.builder.buildPtrToInt(non_int_val, small_int_ty, "")
10033 try self.wip.cast(.ptrtoint, non_int_val, small_int_ty, "")
950310034 else
9504 self.builder.buildBitCast(non_int_val, small_int_ty, "");
9505 return self.builder.buildZExtOrBitCast(small_int_val, int_llvm_ty, "");
10035 try self.wip.cast(.bitcast, non_int_val, small_int_ty, "");
10036 return self.wip.conv(.unsigned, small_int_val, int_llvm_ty, "");
950610037 }
950710038
950810039 const tag_int = blk: {
......@@ -9515,106 +10046,96 @@ pub const FuncGen = struct {
951510046 };
951610047 if (layout.payload_size == 0) {
951710048 if (layout.tag_size == 0) {
9518 return null;
10049 return .none;
951910050 }
952010051 assert(!isByRef(union_ty, mod));
9521 return union_llvm_ty.constInt(tag_int, .False);
10052 return o.builder.intValue(union_llvm_ty, tag_int);
952210053 }
952310054 assert(isByRef(union_ty, mod));
952410055 // The llvm type of the alloca will be the named LLVM union type, and will not
952510056 // necessarily match the format that we need, depending on which tag is active.
952610057 // We must construct the correct unnamed struct type here, in order to then set
952710058 // the fields appropriately.
9528 const result_ptr = self.buildAlloca(union_llvm_ty, layout.abi_align);
10059 const alignment = Builder.Alignment.fromByteUnits(layout.abi_align);
10060 const result_ptr = try self.buildAlloca(union_llvm_ty, alignment);
952910061 const llvm_payload = try self.resolveInst(extra.init);
953010062 assert(union_obj.haveFieldTypes());
953110063 const field = union_obj.fields.values()[extra.field_index];
953210064 const field_llvm_ty = try o.lowerType(field.ty);
953310065 const field_size = field.ty.abiSize(mod);
953410066 const field_align = field.normalAlignment(mod);
10067 const llvm_usize = try o.lowerType(Type.usize);
10068 const usize_zero = try o.builder.intValue(llvm_usize, 0);
10069 const i32_zero = try o.builder.intValue(.i32, 0);
953510070
953610071 const llvm_union_ty = t: {
9537 const payload = p: {
10072 const payload_ty = p: {
953810073 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) {
9539 const padding_len = @as(c_uint, @intCast(layout.payload_size));
9540 break :p self.context.intType(8).arrayType(padding_len);
10074 const padding_len = layout.payload_size;
10075 break :p try o.builder.arrayType(padding_len, .i8);
954110076 }
954210077 if (field_size == layout.payload_size) {
954310078 break :p field_llvm_ty;
954410079 }
9545 const padding_len = @as(c_uint, @intCast(layout.payload_size - field_size));
9546 const fields: [2]*llvm.Type = .{
9547 field_llvm_ty, self.context.intType(8).arrayType(padding_len),
9548 };
9549 break :p self.context.structType(&fields, fields.len, .True);
10080 const padding_len = layout.payload_size - field_size;
10081 break :p try o.builder.structType(.@"packed", &.{
10082 field_llvm_ty, try o.builder.arrayType(padding_len, .i8),
10083 });
955010084 };
9551 if (layout.tag_size == 0) {
9552 const fields: [1]*llvm.Type = .{payload};
9553 break :t self.context.structType(&fields, fields.len, .False);
9554 }
9555 const tag_llvm_ty = try o.lowerType(union_obj.tag_ty);
9556 var fields: [3]*llvm.Type = undefined;
9557 var fields_len: c_uint = 2;
10085 if (layout.tag_size == 0) break :t try o.builder.structType(.normal, &.{payload_ty});
10086 const tag_ty = try o.lowerType(union_obj.tag_ty);
10087 var fields: [3]Builder.Type = undefined;
10088 var fields_len: usize = 2;
955810089 if (layout.tag_align >= layout.payload_align) {
9559 fields = .{ tag_llvm_ty, payload, undefined };
10090 fields = .{ tag_ty, payload_ty, undefined };
956010091 } else {
9561 fields = .{ payload, tag_llvm_ty, undefined };
10092 fields = .{ payload_ty, tag_ty, undefined };
956210093 }
956310094 if (layout.padding != 0) {
9564 fields[2] = self.context.intType(8).arrayType(layout.padding);
9565 fields_len = 3;
10095 fields[fields_len] = try o.builder.arrayType(layout.padding, .i8);
10096 fields_len += 1;
956610097 }
9567 break :t self.context.structType(&fields, fields_len, .False);
10098 break :t try o.builder.structType(.normal, fields[0..fields_len]);
956810099 };
956910100
957010101 // Now we follow the layout as expressed above with GEP instructions to set the
957110102 // tag and the payload.
9572 const index_type = self.context.intType(32);
9573
957410103 const field_ptr_ty = try mod.ptrType(.{
957510104 .child = field.ty.toIntern(),
9576 .flags = .{
9577 .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_align),
9578 },
10105 .flags = .{ .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_align) },
957910106 });
958010107 if (layout.tag_size == 0) {
9581 const indices: [3]*llvm.Value = .{
9582 index_type.constNull(),
9583 index_type.constNull(),
9584 index_type.constNull(),
9585 };
9586 const len: c_uint = if (field_size == layout.payload_size) 2 else 3;
9587 const field_ptr = self.builder.buildInBoundsGEP(llvm_union_ty, result_ptr, &indices, len, "");
9588 try self.store(field_ptr, field_ptr_ty, llvm_payload, .NotAtomic);
10108 const indices = [3]Builder.Value{ usize_zero, i32_zero, i32_zero };
10109 const len: usize = if (field_size == layout.payload_size) 2 else 3;
10110 const field_ptr =
10111 try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, indices[0..len], "");
10112 try self.store(field_ptr, field_ptr_ty, llvm_payload, .none);
958910113 return result_ptr;
959010114 }
959110115
959210116 {
9593 const indices: [3]*llvm.Value = .{
9594 index_type.constNull(),
9595 index_type.constInt(@intFromBool(layout.tag_align >= layout.payload_align), .False),
9596 index_type.constNull(),
9597 };
9598 const len: c_uint = if (field_size == layout.payload_size) 2 else 3;
9599 const field_ptr = self.builder.buildInBoundsGEP(llvm_union_ty, result_ptr, &indices, len, "");
9600 try self.store(field_ptr, field_ptr_ty, llvm_payload, .NotAtomic);
10117 const payload_index = @intFromBool(layout.tag_align >= layout.payload_align);
10118 const indices: [3]Builder.Value =
10119 .{ usize_zero, try o.builder.intValue(.i32, payload_index), i32_zero };
10120 const len: usize = if (field_size == layout.payload_size) 2 else 3;
10121 const field_ptr =
10122 try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, indices[0..len], "");
10123 try self.store(field_ptr, field_ptr_ty, llvm_payload, .none);
960110124 }
960210125 {
9603 const indices: [2]*llvm.Value = .{
9604 index_type.constNull(),
9605 index_type.constInt(@intFromBool(layout.tag_align < layout.payload_align), .False),
9606 };
9607 const field_ptr = self.builder.buildInBoundsGEP(llvm_union_ty, result_ptr, &indices, indices.len, "");
9608 const tag_llvm_ty = try o.lowerType(union_obj.tag_ty);
9609 const llvm_tag = tag_llvm_ty.constInt(tag_int, .False);
9610 const store_inst = self.builder.buildStore(llvm_tag, field_ptr);
9611 store_inst.setAlignment(union_obj.tag_ty.abiAlignment(mod));
10126 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);
10127 const indices: [2]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, tag_index) };
10128 const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, &indices, "");
10129 const tag_ty = try o.lowerType(union_obj.tag_ty);
10130 const llvm_tag = try o.builder.intValue(tag_ty, tag_int);
10131 const tag_alignment = Builder.Alignment.fromByteUnits(union_obj.tag_ty.abiAlignment(mod));
10132 _ = try self.wip.store(.normal, llvm_tag, field_ptr, tag_alignment);
961210133 }
961310134
961410135 return result_ptr;
961510136 }
961610137
9617 fn airPrefetch(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
10138 fn airPrefetch(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
961810139 const o = self.dg.object;
961910140 const prefetch = self.air.instructions.items(.data)[inst].prefetch;
962010141
......@@ -9643,10 +10164,10 @@ pub const FuncGen = struct {
964310164 .powerpcle,
964410165 .powerpc64,
964510166 .powerpc64le,
9646 => return null,
10167 => return .none,
964710168 .arm, .armeb, .thumb, .thumbeb => {
964810169 switch (prefetch.rw) {
9649 .write => return null,
10170 .write => return .none,
965010171 else => {},
965110172 }
965210173 },
......@@ -9655,58 +10176,64 @@ pub const FuncGen = struct {
965510176 .data => {},
965610177 }
965710178
9658 const llvm_ptr_u8 = self.context.pointerType(0);
9659 const llvm_u32 = self.context.intType(32);
9660
966110179 const llvm_fn_name = "llvm.prefetch.p0";
9662 const fn_val = o.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {
9663 // declare void @llvm.prefetch(i8*, i32, i32, i32)
9664 const llvm_void = self.context.voidType();
9665 const param_types = [_]*llvm.Type{
9666 llvm_ptr_u8, llvm_u32, llvm_u32, llvm_u32,
9667 };
9668 const fn_type = llvm.functionType(llvm_void, &param_types, param_types.len, .False);
9669 break :blk o.llvm_module.addFunction(llvm_fn_name, fn_type);
9670 };
10180 // declare void @llvm.prefetch(i8*, i32, i32, i32)
10181 const llvm_fn_ty = try o.builder.fnType(.void, &.{ .ptr, .i32, .i32, .i32 }, .normal);
10182 const fn_val = o.llvm_module.getNamedFunction(llvm_fn_name) orelse
10183 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
967110184
967210185 const ptr = try self.resolveInst(prefetch.ptr);
967310186
967410187 const params = [_]*llvm.Value{
9675 ptr,
9676 llvm_u32.constInt(@intFromEnum(prefetch.rw), .False),
9677 llvm_u32.constInt(prefetch.locality, .False),
9678 llvm_u32.constInt(@intFromEnum(prefetch.cache), .False),
10188 ptr.toLlvm(&self.wip),
10189 (try o.builder.intConst(.i32, @intFromEnum(prefetch.rw))).toLlvm(&o.builder),
10190 (try o.builder.intConst(.i32, prefetch.locality)).toLlvm(&o.builder),
10191 (try o.builder.intConst(.i32, @intFromEnum(prefetch.cache))).toLlvm(&o.builder),
967910192 };
9680 _ = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, "");
9681 return null;
10193 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
10194 llvm_fn_ty.toLlvm(&o.builder),
10195 fn_val,
10196 &params,
10197 params.len,
10198 .C,
10199 .Auto,
10200 "",
10201 ), &self.wip);
10202 return .none;
968210203 }
968310204
9684 fn airAddrSpaceCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
10205 fn airAddrSpaceCast(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
968510206 const o = self.dg.object;
968610207 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
968710208 const inst_ty = self.typeOfIndex(inst);
968810209 const operand = try self.resolveInst(ty_op.operand);
968910210
9690 const llvm_dest_ty = try o.lowerType(inst_ty);
9691 return self.builder.buildAddrSpaceCast(operand, llvm_dest_ty, "");
10211 return self.wip.cast(.addrspacecast, operand, try o.lowerType(inst_ty), "");
969210212 }
969310213
9694 fn amdgcnWorkIntrinsic(self: *FuncGen, dimension: u32, default: u32, comptime basename: []const u8) !?*llvm.Value {
9695 const llvm_u32 = self.context.intType(32);
9696
10214 fn amdgcnWorkIntrinsic(self: *FuncGen, dimension: u32, default: u32, comptime basename: []const u8) !Builder.Value {
10215 const o = self.dg.object;
969710216 const llvm_fn_name = switch (dimension) {
969810217 0 => basename ++ ".x",
969910218 1 => basename ++ ".y",
970010219 2 => basename ++ ".z",
9701 else => return llvm_u32.constInt(default, .False),
10220 else => return o.builder.intValue(.i32, default),
970210221 };
970310222
970410223 const args: [0]*llvm.Value = .{};
9705 const llvm_fn = self.getIntrinsic(llvm_fn_name, &.{});
9706 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");
10224 const llvm_fn = try self.getIntrinsic(llvm_fn_name, &.{});
10225 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCall(
10226 (try o.builder.fnType(.i32, &.{}, .normal)).toLlvm(&o.builder),
10227 llvm_fn,
10228 &args,
10229 args.len,
10230 .Fast,
10231 .Auto,
10232 "",
10233 ), &self.wip);
970710234 }
970810235
9709 fn airWorkItemId(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
10236 fn airWorkItemId(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
971010237 const o = self.dg.object;
971110238 const target = o.module.getTarget();
971210239 assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures
......@@ -9716,37 +10243,41 @@ pub const FuncGen = struct {
971610243 return self.amdgcnWorkIntrinsic(dimension, 0, "llvm.amdgcn.workitem.id");
971710244 }
971810245
9719 fn airWorkGroupSize(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
10246 fn airWorkGroupSize(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
972010247 const o = self.dg.object;
972110248 const target = o.module.getTarget();
972210249 assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures
972310250
972410251 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
972510252 const dimension = pl_op.payload;
9726 const llvm_u32 = self.context.intType(32);
9727 if (dimension >= 3) {
9728 return llvm_u32.constInt(1, .False);
9729 }
10253 if (dimension >= 3) return o.builder.intValue(.i32, 1);
973010254
973110255 // Fetch the dispatch pointer, which points to this structure:
973210256 // https://github.com/RadeonOpenCompute/ROCR-Runtime/blob/adae6c61e10d371f7cbc3d0e94ae2c070cab18a4/src/inc/hsa.h#L2913
9733 const llvm_fn = self.getIntrinsic("llvm.amdgcn.dispatch.ptr", &.{});
10257 const llvm_fn = try self.getIntrinsic("llvm.amdgcn.dispatch.ptr", &.{});
973410258 const args: [0]*llvm.Value = .{};
9735 const dispatch_ptr = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");
9736 dispatch_ptr.setAlignment(4);
10259 const llvm_ret_ty = try o.builder.ptrType(Builder.AddrSpace.amdgpu.constant);
10260 const dispatch_ptr = (try self.wip.unimplemented(llvm_ret_ty, "")).finish(self.builder.buildCall(
10261 (try o.builder.fnType(llvm_ret_ty, &.{}, .normal)).toLlvm(&o.builder),
10262 llvm_fn,
10263 &args,
10264 args.len,
10265 .Fast,
10266 .Auto,
10267 "",
10268 ), &self.wip);
10269 o.addAttrInt(dispatch_ptr.toLlvm(&self.wip), 0, "align", 4);
973710270
973810271 // Load the work_group_* member from the struct as u16.
973910272 // Just treat the dispatch pointer as an array of u16 to keep things simple.
9740 const offset = 2 + dimension;
9741 const index = [_]*llvm.Value{llvm_u32.constInt(offset, .False)};
9742 const llvm_u16 = self.context.intType(16);
9743 const workgroup_size_ptr = self.builder.buildInBoundsGEP(llvm_u16, dispatch_ptr, &index, index.len, "");
9744 const workgroup_size = self.builder.buildLoad(llvm_u16, workgroup_size_ptr, "");
9745 workgroup_size.setAlignment(2);
9746 return workgroup_size;
10273 const workgroup_size_ptr = try self.wip.gep(.inbounds, .i16, dispatch_ptr, &.{
10274 try o.builder.intValue(try o.lowerType(Type.usize), 2 + dimension),
10275 }, "");
10276 const workgroup_size_alignment = comptime Builder.Alignment.fromByteUnits(2);
10277 return self.wip.load(.normal, .i16, workgroup_size_ptr, workgroup_size_alignment, "");
974710278 }
974810279
9749 fn airWorkGroupId(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
10280 fn airWorkGroupId(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
975010281 const o = self.dg.object;
975110282 const target = o.module.getTarget();
975210283 assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures
......@@ -9756,65 +10287,82 @@ pub const FuncGen = struct {
975610287 return self.amdgcnWorkIntrinsic(dimension, 0, "llvm.amdgcn.workgroup.id");
975710288 }
975810289
9759 fn getErrorNameTable(self: *FuncGen) !*llvm.Value {
10290 fn getErrorNameTable(self: *FuncGen) Allocator.Error!Builder.Variable.Index {
976010291 const o = self.dg.object;
9761 if (o.error_name_table) |table| {
9762 return table;
9763 }
10292 const table = o.error_name_table;
10293 if (table != .none) return table;
976410294
976510295 const mod = o.module;
976610296 const slice_ty = Type.slice_const_u8_sentinel_0;
976710297 const slice_alignment = slice_ty.abiAlignment(mod);
9768 const llvm_slice_ptr_ty = self.context.pointerType(0); // TODO: Address space
10298 const undef_init = try o.builder.undefConst(.ptr); // TODO: Address space
976910299
9770 const error_name_table_global = o.llvm_module.addGlobal(llvm_slice_ptr_ty, "__zig_err_name_table");
9771 error_name_table_global.setInitializer(llvm_slice_ptr_ty.getUndef());
10300 const name = try o.builder.string("__zig_err_name_table");
10301 const error_name_table_global = o.llvm_module.addGlobal(Builder.Type.ptr.toLlvm(&o.builder), name.toSlice(&o.builder).?);
10302 error_name_table_global.setInitializer(undef_init.toLlvm(&o.builder));
977210303 error_name_table_global.setLinkage(.Private);
977310304 error_name_table_global.setGlobalConstant(.True);
977410305 error_name_table_global.setUnnamedAddr(.True);
977510306 error_name_table_global.setAlignment(slice_alignment);
977610307
9777 o.error_name_table = error_name_table_global;
9778 return error_name_table_global;
10308 var global = Builder.Global{
10309 .linkage = .private,
10310 .unnamed_addr = .unnamed_addr,
10311 .type = .ptr,
10312 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
10313 };
10314 var variable = Builder.Variable{
10315 .global = @enumFromInt(o.builder.globals.count()),
10316 .mutability = .constant,
10317 .init = undef_init,
10318 .alignment = Builder.Alignment.fromByteUnits(slice_alignment),
10319 };
10320 try o.builder.llvm.globals.append(o.gpa, error_name_table_global);
10321 _ = try o.builder.addGlobal(name, global);
10322 try o.builder.variables.append(o.gpa, variable);
10323
10324 o.error_name_table = global.kind.variable;
10325 return global.kind.variable;
977910326 }
978010327
978110328 /// Assumes the optional is not pointer-like and payload has bits.
9782 fn optIsNonNull(
10329 fn optCmpNull(
978310330 self: *FuncGen,
9784 opt_llvm_ty: *llvm.Type,
9785 opt_handle: *llvm.Value,
10331 cond: Builder.IntegerCondition,
10332 opt_llvm_ty: Builder.Type,
10333 opt_handle: Builder.Value,
978610334 is_by_ref: bool,
9787 ) *llvm.Value {
9788 const non_null_llvm_ty = self.context.intType(8);
10335 ) Allocator.Error!Builder.Value {
10336 const o = self.dg.object;
978910337 const field = b: {
979010338 if (is_by_ref) {
9791 const field_ptr = self.builder.buildStructGEP(opt_llvm_ty, opt_handle, 1, "");
9792 break :b self.builder.buildLoad(non_null_llvm_ty, field_ptr, "");
10339 const field_ptr = try self.wip.gepStruct(opt_llvm_ty, opt_handle, 1, "");
10340 break :b try self.wip.load(.normal, .i8, field_ptr, .default, "");
979310341 }
9794 break :b self.builder.buildExtractValue(opt_handle, 1, "");
10342 break :b try self.wip.extractValue(opt_handle, &.{1}, "");
979510343 };
979610344 comptime assert(optional_layout_version == 3);
979710345
9798 return self.builder.buildICmp(.NE, field, non_null_llvm_ty.constInt(0, .False), "");
10346 return self.wip.icmp(cond, field, try o.builder.intValue(.i8, 0), "");
979910347 }
980010348
980110349 /// Assumes the optional is not pointer-like and payload has bits.
980210350 fn optPayloadHandle(
980310351 fg: *FuncGen,
9804 opt_llvm_ty: *llvm.Type,
9805 opt_handle: *llvm.Value,
10352 opt_llvm_ty: Builder.Type,
10353 opt_handle: Builder.Value,
980610354 opt_ty: Type,
980710355 can_elide_load: bool,
9808 ) !*llvm.Value {
10356 ) !Builder.Value {
980910357 const o = fg.dg.object;
981010358 const mod = o.module;
981110359 const payload_ty = opt_ty.optionalChild(mod);
981210360
981310361 if (isByRef(opt_ty, mod)) {
981410362 // We have a pointer and we need to return a pointer to the first field.
9815 const payload_ptr = fg.builder.buildStructGEP(opt_llvm_ty, opt_handle, 0, "");
10363 const payload_ptr = try fg.wip.gepStruct(opt_llvm_ty, opt_handle, 0, "");
981610364
9817 const payload_alignment = payload_ty.abiAlignment(mod);
10365 const payload_alignment = Builder.Alignment.fromByteUnits(payload_ty.abiAlignment(mod));
981810366 if (isByRef(payload_ty, mod)) {
981910367 if (can_elide_load)
982010368 return payload_ptr;
......@@ -9822,55 +10370,51 @@ pub const FuncGen = struct {
982210370 return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, false);
982310371 }
982410372 const payload_llvm_ty = try o.lowerType(payload_ty);
9825 const load_inst = fg.builder.buildLoad(payload_llvm_ty, payload_ptr, "");
9826 load_inst.setAlignment(payload_alignment);
9827 return load_inst;
10373 return fg.wip.load(.normal, payload_llvm_ty, payload_ptr, payload_alignment, "");
982810374 }
982910375
983010376 assert(!isByRef(payload_ty, mod));
9831 return fg.builder.buildExtractValue(opt_handle, 0, "");
10377 return fg.wip.extractValue(opt_handle, &.{0}, "");
983210378 }
983310379
983410380 fn buildOptional(
983510381 self: *FuncGen,
983610382 optional_ty: Type,
9837 payload: *llvm.Value,
9838 non_null_bit: *llvm.Value,
9839 ) !?*llvm.Value {
10383 payload: Builder.Value,
10384 non_null_bit: Builder.Value,
10385 ) !Builder.Value {
984010386 const o = self.dg.object;
984110387 const optional_llvm_ty = try o.lowerType(optional_ty);
9842 const non_null_field = self.builder.buildZExt(non_null_bit, self.context.intType(8), "");
10388 const non_null_field = try self.wip.cast(.zext, non_null_bit, .i8, "");
984310389 const mod = o.module;
984410390
984510391 if (isByRef(optional_ty, mod)) {
9846 const payload_alignment = optional_ty.abiAlignment(mod);
9847 const alloca_inst = self.buildAlloca(optional_llvm_ty, payload_alignment);
10392 const payload_alignment = Builder.Alignment.fromByteUnits(optional_ty.abiAlignment(mod));
10393 const alloca_inst = try self.buildAlloca(optional_llvm_ty, payload_alignment);
984810394
984910395 {
9850 const field_ptr = self.builder.buildStructGEP(optional_llvm_ty, alloca_inst, 0, "");
9851 const store_inst = self.builder.buildStore(payload, field_ptr);
9852 store_inst.setAlignment(payload_alignment);
10396 const field_ptr = try self.wip.gepStruct(optional_llvm_ty, alloca_inst, 0, "");
10397 _ = try self.wip.store(.normal, payload, field_ptr, payload_alignment);
985310398 }
985410399 {
9855 const field_ptr = self.builder.buildStructGEP(optional_llvm_ty, alloca_inst, 1, "");
9856 const store_inst = self.builder.buildStore(non_null_field, field_ptr);
9857 store_inst.setAlignment(1);
10400 const non_null_alignment = comptime Builder.Alignment.fromByteUnits(1);
10401 const field_ptr = try self.wip.gepStruct(optional_llvm_ty, alloca_inst, 1, "");
10402 _ = try self.wip.store(.normal, non_null_field, field_ptr, non_null_alignment);
985810403 }
985910404
986010405 return alloca_inst;
986110406 }
986210407
9863 const partial = self.builder.buildInsertValue(optional_llvm_ty.getUndef(), payload, 0, "");
9864 return self.builder.buildInsertValue(partial, non_null_field, 1, "");
10408 return self.wip.buildAggregate(optional_llvm_ty, &.{ payload, non_null_field }, "");
986510409 }
986610410
986710411 fn fieldPtr(
986810412 self: *FuncGen,
986910413 inst: Air.Inst.Index,
9870 struct_ptr: *llvm.Value,
10414 struct_ptr: Builder.Value,
987110415 struct_ptr_ty: Type,
987210416 field_index: u32,
9873 ) !?*llvm.Value {
10417 ) !Builder.Value {
987410418 const o = self.dg.object;
987510419 const mod = o.module;
987610420 const struct_ty = struct_ptr_ty.childType(mod);
......@@ -9892,26 +10436,25 @@ pub const FuncGen = struct {
989210436 // Offset our operand pointer by the correct number of bytes.
989310437 const byte_offset = struct_ty.packedStructFieldByteOffset(field_index, mod);
989410438 if (byte_offset == 0) return struct_ptr;
9895 const byte_llvm_ty = self.context.intType(8);
9896 const llvm_usize = try o.lowerType(Type.usize);
9897 const llvm_index = llvm_usize.constInt(byte_offset, .False);
9898 const indices: [1]*llvm.Value = .{llvm_index};
9899 return self.builder.buildInBoundsGEP(byte_llvm_ty, struct_ptr, &indices, indices.len, "");
10439 const usize_ty = try o.lowerType(Type.usize);
10440 const llvm_index = try o.builder.intValue(usize_ty, byte_offset);
10441 return self.wip.gep(.inbounds, .i8, struct_ptr, &.{llvm_index}, "");
990010442 },
990110443 else => {
990210444 const struct_llvm_ty = try o.lowerPtrElemTy(struct_ty);
990310445
990410446 if (llvmField(struct_ty, field_index, mod)) |llvm_field| {
9905 return self.builder.buildStructGEP(struct_llvm_ty, struct_ptr, llvm_field.index, "");
10447 return self.wip.gepStruct(struct_llvm_ty, struct_ptr, llvm_field.index, "");
990610448 } else {
990710449 // If we found no index then this means this is a zero sized field at the
990810450 // end of the struct. Treat our struct pointer as an array of two and get
990910451 // the index to the element at index `1` to get a pointer to the end of
991010452 // the struct.
9911 const llvm_u32 = self.context.intType(32);
9912 const llvm_index = llvm_u32.constInt(@intFromBool(struct_ty.hasRuntimeBitsIgnoreComptime(mod)), .False);
9913 const indices: [1]*llvm.Value = .{llvm_index};
9914 return self.builder.buildInBoundsGEP(struct_llvm_ty, struct_ptr, &indices, indices.len, "");
10453 const llvm_index = try o.builder.intValue(
10454 try o.lowerType(Type.usize),
10455 @intFromBool(struct_ty.hasRuntimeBitsIgnoreComptime(mod)),
10456 );
10457 return self.wip.gep(.inbounds, struct_llvm_ty, struct_ptr, &.{llvm_index}, "");
991510458 }
991610459 },
991710460 },
......@@ -9920,126 +10463,128 @@ pub const FuncGen = struct {
992010463 if (layout.payload_size == 0 or struct_ty.containerLayout(mod) == .Packed) return struct_ptr;
992110464 const payload_index = @intFromBool(layout.tag_align >= layout.payload_align);
992210465 const union_llvm_ty = try o.lowerType(struct_ty);
9923 const union_field_ptr = self.builder.buildStructGEP(union_llvm_ty, struct_ptr, payload_index, "");
9924 return union_field_ptr;
10466 return self.wip.gepStruct(union_llvm_ty, struct_ptr, payload_index, "");
992510467 },
992610468 else => unreachable,
992710469 }
992810470 }
992910471
9930 fn getIntrinsic(fg: *FuncGen, name: []const u8, types: []const *llvm.Type) *llvm.Value {
10472 fn getIntrinsic(
10473 fg: *FuncGen,
10474 name: []const u8,
10475 types: []const Builder.Type,
10476 ) Allocator.Error!*llvm.Value {
10477 const o = fg.dg.object;
993110478 const id = llvm.lookupIntrinsicID(name.ptr, name.len);
993210479 assert(id != 0);
9933 const o = fg.dg.object;
9934 return o.llvm_module.getIntrinsicDeclaration(id, types.ptr, types.len);
10480 const llvm_types = try o.gpa.alloc(*llvm.Type, types.len);
10481 defer o.gpa.free(llvm_types);
10482 for (llvm_types, types) |*llvm_type, ty| llvm_type.* = ty.toLlvm(&o.builder);
10483 return o.llvm_module.getIntrinsicDeclaration(id, llvm_types.ptr, llvm_types.len);
993510484 }
993610485
993710486 /// Load a by-ref type by constructing a new alloca and performing a memcpy.
993810487 fn loadByRef(
993910488 fg: *FuncGen,
9940 ptr: *llvm.Value,
10489 ptr: Builder.Value,
994110490 pointee_type: Type,
9942 ptr_alignment: u32,
10491 ptr_alignment: Builder.Alignment,
994310492 is_volatile: bool,
9944 ) !*llvm.Value {
10493 ) !Builder.Value {
994510494 const o = fg.dg.object;
994610495 const mod = o.module;
994710496 const pointee_llvm_ty = try o.lowerType(pointee_type);
9948 const result_align = @max(ptr_alignment, pointee_type.abiAlignment(mod));
9949 const result_ptr = fg.buildAlloca(pointee_llvm_ty, result_align);
9950 const llvm_usize = fg.context.intType(Type.usize.intInfo(mod).bits);
10497 const result_align = Builder.Alignment.fromByteUnits(
10498 @max(ptr_alignment.toByteUnits() orelse 0, pointee_type.abiAlignment(mod)),
10499 );
10500 const result_ptr = try fg.buildAlloca(pointee_llvm_ty, result_align);
10501 const usize_ty = try o.lowerType(Type.usize);
995110502 const size_bytes = pointee_type.abiSize(mod);
9952 _ = fg.builder.buildMemCpy(
9953 result_ptr,
9954 result_align,
9955 ptr,
9956 ptr_alignment,
9957 llvm_usize.constInt(size_bytes, .False),
10503 _ = (try fg.wip.unimplemented(.void, "")).finish(fg.builder.buildMemCpy(
10504 result_ptr.toLlvm(&fg.wip),
10505 @intCast(result_align.toByteUnits() orelse 0),
10506 ptr.toLlvm(&fg.wip),
10507 @intCast(ptr_alignment.toByteUnits() orelse 0),
10508 (try o.builder.intConst(usize_ty, size_bytes)).toLlvm(&o.builder),
995810509 is_volatile,
9959 );
10510 ), &fg.wip);
996010511 return result_ptr;
996110512 }
996210513
996310514 /// This function always performs a copy. For isByRef=true types, it creates a new
996410515 /// alloca and copies the value into it, then returns the alloca instruction.
996510516 /// For isByRef=false types, it creates a load instruction and returns it.
9966 fn load(self: *FuncGen, ptr: *llvm.Value, ptr_ty: Type) !?*llvm.Value {
10517 fn load(self: *FuncGen, ptr: Builder.Value, ptr_ty: Type) !Builder.Value {
996710518 const o = self.dg.object;
996810519 const mod = o.module;
996910520 const info = ptr_ty.ptrInfo(mod);
997010521 const elem_ty = info.child.toType();
9971 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return null;
10522 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none;
997210523
9973 const ptr_alignment = @as(u32, @intCast(info.flags.alignment.toByteUnitsOptional() orelse
9974 elem_ty.abiAlignment(mod)));
9975 const ptr_volatile = llvm.Bool.fromBool(info.flags.is_volatile);
10524 const ptr_alignment = Builder.Alignment.fromByteUnits(
10525 info.flags.alignment.toByteUnitsOptional() orelse elem_ty.abiAlignment(mod),
10526 );
10527 const ptr_kind: Builder.MemoryAccessKind = switch (info.flags.is_volatile) {
10528 false => .normal,
10529 true => .@"volatile",
10530 };
997610531
997710532 assert(info.flags.vector_index != .runtime);
997810533 if (info.flags.vector_index != .none) {
9979 const index_u32 = self.context.intType(32).constInt(@intFromEnum(info.flags.vector_index), .False);
10534 const index_u32 = try o.builder.intValue(.i32, @intFromEnum(info.flags.vector_index));
998010535 const vec_elem_ty = try o.lowerType(elem_ty);
9981 const vec_ty = vec_elem_ty.vectorType(info.packed_offset.host_size);
9982
9983 const loaded_vector = self.builder.buildLoad(vec_ty, ptr, "");
9984 loaded_vector.setAlignment(ptr_alignment);
9985 loaded_vector.setVolatile(ptr_volatile);
10536 const vec_ty = try o.builder.vectorType(.normal, info.packed_offset.host_size, vec_elem_ty);
998610537
9987 return self.builder.buildExtractElement(loaded_vector, index_u32, "");
10538 const loaded_vector = try self.wip.load(ptr_kind, vec_ty, ptr, ptr_alignment, "");
10539 return self.wip.extractElement(loaded_vector, index_u32, "");
998810540 }
998910541
999010542 if (info.packed_offset.host_size == 0) {
999110543 if (isByRef(elem_ty, mod)) {
999210544 return self.loadByRef(ptr, elem_ty, ptr_alignment, info.flags.is_volatile);
999310545 }
9994 const elem_llvm_ty = try o.lowerType(elem_ty);
9995 const llvm_inst = self.builder.buildLoad(elem_llvm_ty, ptr, "");
9996 llvm_inst.setAlignment(ptr_alignment);
9997 llvm_inst.setVolatile(ptr_volatile);
9998 return llvm_inst;
10546 return self.wip.load(ptr_kind, try o.lowerType(elem_ty), ptr, ptr_alignment, "");
999910547 }
1000010548
10001 const int_elem_ty = self.context.intType(info.packed_offset.host_size * 8);
10002 const containing_int = self.builder.buildLoad(int_elem_ty, ptr, "");
10003 containing_int.setAlignment(ptr_alignment);
10004 containing_int.setVolatile(ptr_volatile);
10549 const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8));
10550 const containing_int = try self.wip.load(ptr_kind, containing_int_ty, ptr, ptr_alignment, "");
1000510551
10006 const elem_bits = @as(c_uint, @intCast(ptr_ty.childType(mod).bitSize(mod)));
10007 const shift_amt = containing_int.typeOf().constInt(info.packed_offset.bit_offset, .False);
10008 const shifted_value = self.builder.buildLShr(containing_int, shift_amt, "");
10552 const elem_bits = ptr_ty.childType(mod).bitSize(mod);
10553 const shift_amt = try o.builder.intValue(containing_int_ty, info.packed_offset.bit_offset);
10554 const shifted_value = try self.wip.bin(.lshr, containing_int, shift_amt, "");
1000910555 const elem_llvm_ty = try o.lowerType(elem_ty);
1001010556
1001110557 if (isByRef(elem_ty, mod)) {
10012 const result_align = elem_ty.abiAlignment(mod);
10013 const result_ptr = self.buildAlloca(elem_llvm_ty, result_align);
10558 const result_align = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
10559 const result_ptr = try self.buildAlloca(elem_llvm_ty, result_align);
1001410560
10015 const same_size_int = self.context.intType(elem_bits);
10016 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
10017 const store_inst = self.builder.buildStore(truncated_int, result_ptr);
10018 store_inst.setAlignment(result_align);
10561 const same_size_int = try o.builder.intType(@intCast(elem_bits));
10562 const truncated_int = try self.wip.cast(.trunc, shifted_value, same_size_int, "");
10563 _ = try self.wip.store(.normal, truncated_int, result_ptr, result_align);
1001910564 return result_ptr;
1002010565 }
1002110566
1002210567 if (elem_ty.zigTypeTag(mod) == .Float or elem_ty.zigTypeTag(mod) == .Vector) {
10023 const same_size_int = self.context.intType(elem_bits);
10024 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
10025 return self.builder.buildBitCast(truncated_int, elem_llvm_ty, "");
10568 const same_size_int = try o.builder.intType(@intCast(elem_bits));
10569 const truncated_int = try self.wip.cast(.trunc, shifted_value, same_size_int, "");
10570 return self.wip.cast(.bitcast, truncated_int, elem_llvm_ty, "");
1002610571 }
1002710572
1002810573 if (elem_ty.isPtrAtRuntime(mod)) {
10029 const same_size_int = self.context.intType(elem_bits);
10030 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
10031 return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, "");
10574 const same_size_int = try o.builder.intType(@intCast(elem_bits));
10575 const truncated_int = try self.wip.cast(.trunc, shifted_value, same_size_int, "");
10576 return self.wip.cast(.inttoptr, truncated_int, elem_llvm_ty, "");
1003210577 }
1003310578
10034 return self.builder.buildTrunc(shifted_value, elem_llvm_ty, "");
10579 return self.wip.cast(.trunc, shifted_value, elem_llvm_ty, "");
1003510580 }
1003610581
1003710582 fn store(
1003810583 self: *FuncGen,
10039 ptr: *llvm.Value,
10584 ptr: Builder.Value,
1004010585 ptr_ty: Type,
10041 elem: *llvm.Value,
10042 ordering: llvm.AtomicOrdering,
10586 elem: Builder.Value,
10587 ordering: Builder.AtomicOrdering,
1004310588 ) !void {
1004410589 const o = self.dg.object;
1004510590 const mod = o.module;
......@@ -10048,124 +10593,115 @@ pub const FuncGen = struct {
1004810593 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) {
1004910594 return;
1005010595 }
10051 const ptr_alignment = ptr_ty.ptrAlignment(mod);
10052 const ptr_volatile = llvm.Bool.fromBool(info.flags.is_volatile);
10596 const ptr_alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
10597 const ptr_kind: Builder.MemoryAccessKind = switch (info.flags.is_volatile) {
10598 false => .normal,
10599 true => .@"volatile",
10600 };
1005310601
1005410602 assert(info.flags.vector_index != .runtime);
1005510603 if (info.flags.vector_index != .none) {
10056 const index_u32 = self.context.intType(32).constInt(@intFromEnum(info.flags.vector_index), .False);
10604 const index_u32 = try o.builder.intValue(.i32, @intFromEnum(info.flags.vector_index));
1005710605 const vec_elem_ty = try o.lowerType(elem_ty);
10058 const vec_ty = vec_elem_ty.vectorType(info.packed_offset.host_size);
10606 const vec_ty = try o.builder.vectorType(.normal, info.packed_offset.host_size, vec_elem_ty);
1005910607
10060 const loaded_vector = self.builder.buildLoad(vec_ty, ptr, "");
10061 loaded_vector.setAlignment(ptr_alignment);
10062 loaded_vector.setVolatile(ptr_volatile);
10608 const loaded_vector = try self.wip.load(ptr_kind, vec_ty, ptr, ptr_alignment, "");
1006310609
10064 const modified_vector = self.builder.buildInsertElement(loaded_vector, elem, index_u32, "");
10610 const modified_vector = try self.wip.insertElement(loaded_vector, elem, index_u32, "");
1006510611
10066 const store_inst = self.builder.buildStore(modified_vector, ptr);
10067 assert(ordering == .NotAtomic);
10068 store_inst.setAlignment(ptr_alignment);
10069 store_inst.setVolatile(ptr_volatile);
10612 assert(ordering == .none);
10613 _ = try self.wip.store(ptr_kind, modified_vector, ptr, ptr_alignment);
1007010614 return;
1007110615 }
1007210616
1007310617 if (info.packed_offset.host_size != 0) {
10074 const int_elem_ty = self.context.intType(info.packed_offset.host_size * 8);
10075 const containing_int = self.builder.buildLoad(int_elem_ty, ptr, "");
10076 assert(ordering == .NotAtomic);
10077 containing_int.setAlignment(ptr_alignment);
10078 containing_int.setVolatile(ptr_volatile);
10079 const elem_bits = @as(c_uint, @intCast(ptr_ty.childType(mod).bitSize(mod)));
10080 const containing_int_ty = containing_int.typeOf();
10081 const shift_amt = containing_int_ty.constInt(info.packed_offset.bit_offset, .False);
10618 const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8));
10619 assert(ordering == .none);
10620 const containing_int =
10621 try self.wip.load(ptr_kind, containing_int_ty, ptr, ptr_alignment, "");
10622 const elem_bits = ptr_ty.childType(mod).bitSize(mod);
10623 const shift_amt = try o.builder.intConst(containing_int_ty, info.packed_offset.bit_offset);
1008210624 // Convert to equally-sized integer type in order to perform the bit
1008310625 // operations on the value to store
10084 const value_bits_type = self.context.intType(elem_bits);
10626 const value_bits_type = try o.builder.intType(@intCast(elem_bits));
1008510627 const value_bits = if (elem_ty.isPtrAtRuntime(mod))
10086 self.builder.buildPtrToInt(elem, value_bits_type, "")
10628 try self.wip.cast(.ptrtoint, elem, value_bits_type, "")
1008710629 else
10088 self.builder.buildBitCast(elem, value_bits_type, "");
10089
10090 var mask_val = value_bits_type.constAllOnes();
10091 mask_val = mask_val.constZExt(containing_int_ty);
10092 mask_val = mask_val.constShl(shift_amt);
10093 mask_val = mask_val.constNot();
10094
10095 const anded_containing_int = self.builder.buildAnd(containing_int, mask_val, "");
10096 const extended_value = self.builder.buildZExt(value_bits, containing_int_ty, "");
10097 const shifted_value = self.builder.buildShl(extended_value, shift_amt, "");
10098 const ored_value = self.builder.buildOr(shifted_value, anded_containing_int, "");
10099
10100 const store_inst = self.builder.buildStore(ored_value, ptr);
10101 assert(ordering == .NotAtomic);
10102 store_inst.setAlignment(ptr_alignment);
10103 store_inst.setVolatile(ptr_volatile);
10630 try self.wip.cast(.bitcast, elem, value_bits_type, "");
10631
10632 var mask_val = try o.builder.intConst(value_bits_type, -1);
10633 mask_val = try o.builder.castConst(.zext, mask_val, containing_int_ty);
10634 mask_val = try o.builder.binConst(.shl, mask_val, shift_amt);
10635 mask_val =
10636 try o.builder.binConst(.xor, mask_val, try o.builder.intConst(containing_int_ty, -1));
10637
10638 const anded_containing_int =
10639 try self.wip.bin(.@"and", containing_int, mask_val.toValue(), "");
10640 const extended_value = try self.wip.cast(.zext, value_bits, containing_int_ty, "");
10641 const shifted_value = try self.wip.bin(.shl, extended_value, shift_amt.toValue(), "");
10642 const ored_value = try self.wip.bin(.@"or", shifted_value, anded_containing_int, "");
10643
10644 assert(ordering == .none);
10645 _ = try self.wip.store(ptr_kind, ored_value, ptr, ptr_alignment);
1010410646 return;
1010510647 }
1010610648 if (!isByRef(elem_ty, mod)) {
10107 const store_inst = self.builder.buildStore(elem, ptr);
10108 store_inst.setOrdering(ordering);
10109 store_inst.setAlignment(ptr_alignment);
10110 store_inst.setVolatile(ptr_volatile);
10649 _ = try self.wip.storeAtomic(ptr_kind, elem, ptr, self.sync_scope, ordering, ptr_alignment);
1011110650 return;
1011210651 }
10113 assert(ordering == .NotAtomic);
10652 assert(ordering == .none);
1011410653 const size_bytes = elem_ty.abiSize(mod);
10115 _ = self.builder.buildMemCpy(
10116 ptr,
10117 ptr_alignment,
10118 elem,
10654 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy(
10655 ptr.toLlvm(&self.wip),
10656 @intCast(ptr_alignment.toByteUnits() orelse 0),
10657 elem.toLlvm(&self.wip),
1011910658 elem_ty.abiAlignment(mod),
10120 self.context.intType(Type.usize.intInfo(mod).bits).constInt(size_bytes, .False),
10659 (try o.builder.intConst(try o.lowerType(Type.usize), size_bytes)).toLlvm(&o.builder),
1012110660 info.flags.is_volatile,
10122 );
10661 ), &self.wip);
1012310662 }
1012410663
10125 fn valgrindMarkUndef(fg: *FuncGen, ptr: *llvm.Value, len: *llvm.Value) void {
10664 fn valgrindMarkUndef(fg: *FuncGen, ptr: Builder.Value, len: Builder.Value) Allocator.Error!void {
1012610665 const VG_USERREQ__MAKE_MEM_UNDEFINED = 1296236545;
1012710666 const o = fg.dg.object;
10128 const target = o.module.getTarget();
10129 const usize_llvm_ty = fg.context.intType(target.ptrBitWidth());
10130 const zero = usize_llvm_ty.constInt(0, .False);
10131 const req = usize_llvm_ty.constInt(VG_USERREQ__MAKE_MEM_UNDEFINED, .False);
10132 const ptr_as_usize = fg.builder.buildPtrToInt(ptr, usize_llvm_ty, "");
10133 _ = valgrindClientRequest(fg, zero, req, ptr_as_usize, len, zero, zero, zero);
10667 const usize_ty = try o.lowerType(Type.usize);
10668 const zero = try o.builder.intValue(usize_ty, 0);
10669 const req = try o.builder.intValue(usize_ty, VG_USERREQ__MAKE_MEM_UNDEFINED);
10670 const ptr_as_usize = try fg.wip.cast(.ptrtoint, ptr, usize_ty, "");
10671 _ = try valgrindClientRequest(fg, zero, req, ptr_as_usize, len, zero, zero, zero);
1013410672 }
1013510673
1013610674 fn valgrindClientRequest(
1013710675 fg: *FuncGen,
10138 default_value: *llvm.Value,
10139 request: *llvm.Value,
10140 a1: *llvm.Value,
10141 a2: *llvm.Value,
10142 a3: *llvm.Value,
10143 a4: *llvm.Value,
10144 a5: *llvm.Value,
10145 ) *llvm.Value {
10676 default_value: Builder.Value,
10677 request: Builder.Value,
10678 a1: Builder.Value,
10679 a2: Builder.Value,
10680 a3: Builder.Value,
10681 a4: Builder.Value,
10682 a5: Builder.Value,
10683 ) Allocator.Error!Builder.Value {
1014610684 const o = fg.dg.object;
1014710685 const mod = o.module;
1014810686 const target = mod.getTarget();
1014910687 if (!target_util.hasValgrindSupport(target)) return default_value;
1015010688
10151 const usize_llvm_ty = fg.context.intType(target.ptrBitWidth());
10152 const usize_alignment = @as(c_uint, @intCast(Type.usize.abiSize(mod)));
10689 const llvm_usize = try o.lowerType(Type.usize);
10690 const usize_alignment = Builder.Alignment.fromByteUnits(Type.usize.abiAlignment(mod));
1015310691
10154 const array_llvm_ty = usize_llvm_ty.arrayType(6);
10155 const array_ptr = fg.valgrind_client_request_array orelse a: {
10156 const array_ptr = fg.buildAlloca(array_llvm_ty, usize_alignment);
10692 const array_llvm_ty = try o.builder.arrayType(6, llvm_usize);
10693 const array_ptr = if (fg.valgrind_client_request_array == .none) a: {
10694 const array_ptr = try fg.buildAlloca(array_llvm_ty, usize_alignment);
1015710695 fg.valgrind_client_request_array = array_ptr;
1015810696 break :a array_ptr;
10159 };
10160 const array_elements = [_]*llvm.Value{ request, a1, a2, a3, a4, a5 };
10161 const zero = usize_llvm_ty.constInt(0, .False);
10697 } else fg.valgrind_client_request_array;
10698 const array_elements = [_]Builder.Value{ request, a1, a2, a3, a4, a5 };
10699 const zero = try o.builder.intValue(llvm_usize, 0);
1016210700 for (array_elements, 0..) |elem, i| {
10163 const indexes = [_]*llvm.Value{
10164 zero, usize_llvm_ty.constInt(@as(c_uint, @intCast(i)), .False),
10165 };
10166 const elem_ptr = fg.builder.buildInBoundsGEP(array_llvm_ty, array_ptr, &indexes, indexes.len, "");
10167 const store_inst = fg.builder.buildStore(elem, elem_ptr);
10168 store_inst.setAlignment(usize_alignment);
10701 const elem_ptr = try fg.wip.gep(.inbounds, array_llvm_ty, array_ptr, &.{
10702 zero, try o.builder.intValue(llvm_usize, i),
10703 }, "");
10704 _ = try fg.wip.store(.normal, elem, elem_ptr, usize_alignment);
1016910705 }
1017010706
1017110707 const arch_specific: struct {
......@@ -10199,10 +10735,9 @@ pub const FuncGen = struct {
1019910735 else => unreachable,
1020010736 };
1020110737
10202 const array_ptr_as_usize = fg.builder.buildPtrToInt(array_ptr, usize_llvm_ty, "");
10203 const args = [_]*llvm.Value{ array_ptr_as_usize, default_value };
10204 const param_types = [_]*llvm.Type{ usize_llvm_ty, usize_llvm_ty };
10205 const fn_llvm_ty = llvm.functionType(usize_llvm_ty, &param_types, args.len, .False);
10738 const fn_llvm_ty = (try o.builder.fnType(llvm_usize, &(.{llvm_usize} ** 2), .normal)).toLlvm(&o.builder);
10739 const array_ptr_as_usize = try fg.wip.cast(.ptrtoint, array_ptr, llvm_usize, "");
10740 const args = [_]*llvm.Value{ array_ptr_as_usize.toLlvm(&fg.wip), default_value.toLlvm(&fg.wip) };
1020610741 const asm_fn = llvm.getInlineAsm(
1020710742 fn_llvm_ty,
1020810743 arch_specific.template.ptr,
......@@ -10215,14 +10750,9 @@ pub const FuncGen = struct {
1021510750 .False, // can throw
1021610751 );
1021710752
10218 const call = fg.builder.buildCall(
10219 fn_llvm_ty,
10220 asm_fn,
10221 &args,
10222 args.len,
10223 .C,
10224 .Auto,
10225 "",
10753 const call = (try fg.wip.unimplemented(llvm_usize, "")).finish(
10754 fg.builder.buildCall(fn_llvm_ty, asm_fn, &args, args.len, .C, .Auto, ""),
10755 &fg.wip,
1022610756 );
1022710757 return call;
1022810758 }
......@@ -10432,14 +10962,14 @@ fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void {
1043210962 }
1043310963}
1043410964
10435fn toLlvmAtomicOrdering(atomic_order: std.builtin.AtomicOrder) llvm.AtomicOrdering {
10965fn toLlvmAtomicOrdering(atomic_order: std.builtin.AtomicOrder) Builder.AtomicOrdering {
1043610966 return switch (atomic_order) {
10437 .Unordered => .Unordered,
10438 .Monotonic => .Monotonic,
10439 .Acquire => .Acquire,
10440 .Release => .Release,
10441 .AcqRel => .AcquireRelease,
10442 .SeqCst => .SequentiallyConsistent,
10967 .Unordered => .unordered,
10968 .Monotonic => .monotonic,
10969 .Acquire => .acquire,
10970 .Release => .release,
10971 .AcqRel => .acq_rel,
10972 .SeqCst => .seq_cst,
1044310973 };
1044410974}
1044510975
......@@ -10494,45 +11024,67 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca
1049411024}
1049511025
1049611026/// Convert a zig-address space to an llvm address space.
10497fn toLlvmAddressSpace(address_space: std.builtin.AddressSpace, target: std.Target) c_uint {
11027fn toLlvmAddressSpace(address_space: std.builtin.AddressSpace, target: std.Target) Builder.AddrSpace {
11028 for (llvmAddrSpaceInfo(target)) |info| if (info.zig == address_space) return info.llvm;
11029 unreachable;
11030}
11031
11032const AddrSpaceInfo = struct {
11033 zig: ?std.builtin.AddressSpace,
11034 llvm: Builder.AddrSpace,
11035 non_integral: bool = false,
11036 size: ?u16 = null,
11037 abi: ?u16 = null,
11038 pref: ?u16 = null,
11039 idx: ?u16 = null,
11040 force_in_data_layout: bool = false,
11041};
11042fn llvmAddrSpaceInfo(target: std.Target) []const AddrSpaceInfo {
1049811043 return switch (target.cpu.arch) {
10499 .x86, .x86_64 => switch (address_space) {
10500 .generic => llvm.address_space.default,
10501 .gs => llvm.address_space.x86.gs,
10502 .fs => llvm.address_space.x86.fs,
10503 .ss => llvm.address_space.x86.ss,
10504 else => unreachable,
11044 .x86, .x86_64 => &.{
11045 .{ .zig = .generic, .llvm = .default },
11046 .{ .zig = .gs, .llvm = Builder.AddrSpace.x86.gs },
11047 .{ .zig = .fs, .llvm = Builder.AddrSpace.x86.fs },
11048 .{ .zig = .ss, .llvm = Builder.AddrSpace.x86.ss },
11049 .{ .zig = null, .llvm = Builder.AddrSpace.x86.ptr32_sptr, .size = 32, .abi = 32, .force_in_data_layout = true },
11050 .{ .zig = null, .llvm = Builder.AddrSpace.x86.ptr32_uptr, .size = 32, .abi = 32, .force_in_data_layout = true },
11051 .{ .zig = null, .llvm = Builder.AddrSpace.x86.ptr64, .size = 64, .abi = 64, .force_in_data_layout = true },
1050511052 },
10506 .nvptx, .nvptx64 => switch (address_space) {
10507 .generic => llvm.address_space.default,
10508 .global => llvm.address_space.nvptx.global,
10509 .constant => llvm.address_space.nvptx.constant,
10510 .param => llvm.address_space.nvptx.param,
10511 .shared => llvm.address_space.nvptx.shared,
10512 .local => llvm.address_space.nvptx.local,
10513 else => unreachable,
11053 .nvptx, .nvptx64 => &.{
11054 .{ .zig = .generic, .llvm = .default },
11055 .{ .zig = .global, .llvm = Builder.AddrSpace.nvptx.global },
11056 .{ .zig = .constant, .llvm = Builder.AddrSpace.nvptx.constant },
11057 .{ .zig = .param, .llvm = Builder.AddrSpace.nvptx.param },
11058 .{ .zig = .shared, .llvm = Builder.AddrSpace.nvptx.shared },
11059 .{ .zig = .local, .llvm = Builder.AddrSpace.nvptx.local },
1051411060 },
10515 .amdgcn => switch (address_space) {
10516 .generic => llvm.address_space.amdgpu.flat,
10517 .global => llvm.address_space.amdgpu.global,
10518 .constant => llvm.address_space.amdgpu.constant,
10519 .shared => llvm.address_space.amdgpu.local,
10520 .local => llvm.address_space.amdgpu.private,
10521 else => unreachable,
11061 .amdgcn => &.{
11062 .{ .zig = .generic, .llvm = Builder.AddrSpace.amdgpu.flat, .force_in_data_layout = true },
11063 .{ .zig = .global, .llvm = Builder.AddrSpace.amdgpu.global, .force_in_data_layout = true },
11064 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.region, .size = 32, .abi = 32 },
11065 .{ .zig = .shared, .llvm = Builder.AddrSpace.amdgpu.local, .size = 32, .abi = 32 },
11066 .{ .zig = .constant, .llvm = Builder.AddrSpace.amdgpu.constant, .force_in_data_layout = true },
11067 .{ .zig = .local, .llvm = Builder.AddrSpace.amdgpu.private, .size = 32, .abi = 32 },
11068 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.constant_32bit, .size = 32, .abi = 32 },
11069 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.buffer_fat_pointer, .non_integral = true },
1052211070 },
10523 .avr => switch (address_space) {
10524 .generic => llvm.address_space.default,
10525 .flash => llvm.address_space.avr.flash,
10526 .flash1 => llvm.address_space.avr.flash1,
10527 .flash2 => llvm.address_space.avr.flash2,
10528 .flash3 => llvm.address_space.avr.flash3,
10529 .flash4 => llvm.address_space.avr.flash4,
10530 .flash5 => llvm.address_space.avr.flash5,
10531 else => unreachable,
11071 .avr => &.{
11072 .{ .zig = .generic, .llvm = .default, .abi = 8 },
11073 .{ .zig = .flash, .llvm = Builder.AddrSpace.avr.flash, .abi = 8 },
11074 .{ .zig = .flash1, .llvm = Builder.AddrSpace.avr.flash1, .abi = 8 },
11075 .{ .zig = .flash2, .llvm = Builder.AddrSpace.avr.flash2, .abi = 8 },
11076 .{ .zig = .flash3, .llvm = Builder.AddrSpace.avr.flash3, .abi = 8 },
11077 .{ .zig = .flash4, .llvm = Builder.AddrSpace.avr.flash4, .abi = 8 },
11078 .{ .zig = .flash5, .llvm = Builder.AddrSpace.avr.flash5, .abi = 8 },
1053211079 },
10533 else => switch (address_space) {
10534 .generic => llvm.address_space.default,
10535 else => unreachable,
11080 .wasm32, .wasm64 => &.{
11081 .{ .zig = .generic, .llvm = .default, .force_in_data_layout = true },
11082 .{ .zig = null, .llvm = Builder.AddrSpace.wasm.variable, .non_integral = true },
11083 .{ .zig = null, .llvm = Builder.AddrSpace.wasm.externref, .non_integral = true, .size = 8, .abi = 8 },
11084 .{ .zig = null, .llvm = Builder.AddrSpace.wasm.funcref, .non_integral = true, .size = 8, .abi = 8 },
11085 },
11086 else => &.{
11087 .{ .zig = .generic, .llvm = .default },
1053611088 },
1053711089 };
1053811090}
......@@ -10541,30 +11093,30 @@ fn toLlvmAddressSpace(address_space: std.builtin.AddressSpace, target: std.Targe
1054111093/// different address, space and then cast back to the generic address space.
1054211094/// For example, on GPUs local variable declarations must be generated into the local address space.
1054311095/// This function returns the address space local values should be generated into.
10544fn llvmAllocaAddressSpace(target: std.Target) c_uint {
11096fn llvmAllocaAddressSpace(target: std.Target) Builder.AddrSpace {
1054511097 return switch (target.cpu.arch) {
1054611098 // On amdgcn, locals should be generated into the private address space.
1054711099 // To make Zig not impossible to use, these are then converted to addresses in the
1054811100 // generic address space and treates as regular pointers. This is the way that HIP also does it.
10549 .amdgcn => llvm.address_space.amdgpu.private,
10550 else => llvm.address_space.default,
11101 .amdgcn => Builder.AddrSpace.amdgpu.private,
11102 else => .default,
1055111103 };
1055211104}
1055311105
1055411106/// On some targets, global values that are in the generic address space must be generated into a
1055511107/// different address space, and then cast back to the generic address space.
10556fn llvmDefaultGlobalAddressSpace(target: std.Target) c_uint {
11108fn llvmDefaultGlobalAddressSpace(target: std.Target) Builder.AddrSpace {
1055711109 return switch (target.cpu.arch) {
1055811110 // On amdgcn, globals must be explicitly allocated and uploaded so that the program can access
1055911111 // them.
10560 .amdgcn => llvm.address_space.amdgpu.global,
10561 else => llvm.address_space.default,
11112 .amdgcn => Builder.AddrSpace.amdgpu.global,
11113 else => .default,
1056211114 };
1056311115}
1056411116
1056511117/// Return the actual address space that a value should be stored in if its a global address space.
1056611118/// When a value is placed in the resulting address space, it needs to be cast back into wanted_address_space.
10567fn toLlvmGlobalAddressSpace(wanted_address_space: std.builtin.AddressSpace, target: std.Target) c_uint {
11119fn toLlvmGlobalAddressSpace(wanted_address_space: std.builtin.AddressSpace, target: std.Target) Builder.AddrSpace {
1056811120 return switch (wanted_address_space) {
1056911121 .generic => llvmDefaultGlobalAddressSpace(target),
1057011122 else => |as| toLlvmAddressSpace(as, target),
......@@ -10694,28 +11246,20 @@ fn firstParamSRetSystemV(ty: Type, mod: *Module) bool {
1069411246/// In order to support the C calling convention, some return types need to be lowered
1069511247/// completely differently in the function prototype to honor the C ABI, and then
1069611248/// be effectively bitcasted to the actual return type.
10697fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) !*llvm.Type {
11249fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type {
1069811250 const mod = o.module;
1069911251 const return_type = fn_info.return_type.toType();
1070011252 if (!return_type.hasRuntimeBitsIgnoreComptime(mod)) {
1070111253 // If the return type is an error set or an error union, then we make this
1070211254 // anyerror return type instead, so that it can be coerced into a function
1070311255 // pointer type which has anyerror as the return type.
10704 if (return_type.isError(mod)) {
10705 return o.lowerType(Type.anyerror);
10706 } else {
10707 return o.context.voidType();
10708 }
11256 return if (return_type.isError(mod)) Builder.Type.err_int else .void;
1070911257 }
1071011258 const target = mod.getTarget();
1071111259 switch (fn_info.cc) {
10712 .Unspecified, .Inline => {
10713 if (isByRef(return_type, mod)) {
10714 return o.context.voidType();
10715 } else {
10716 return o.lowerType(return_type);
10717 }
10718 },
11260 .Unspecified,
11261 .Inline,
11262 => return if (isByRef(return_type, mod)) .void else o.lowerType(return_type),
1071911263 .C => {
1072011264 switch (target.cpu.arch) {
1072111265 .mips, .mipsel => return o.lowerType(return_type),
......@@ -10729,50 +11273,37 @@ fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) !*llvm.Type {
1072911273 }
1073011274 const classes = wasm_c_abi.classifyType(return_type, mod);
1073111275 if (classes[0] == .indirect or classes[0] == .none) {
10732 return o.context.voidType();
11276 return .void;
1073311277 }
1073411278
1073511279 assert(classes[0] == .direct and classes[1] == .none);
1073611280 const scalar_type = wasm_c_abi.scalarType(return_type, mod);
10737 const abi_size = scalar_type.abiSize(mod);
10738 return o.context.intType(@as(c_uint, @intCast(abi_size * 8)));
11281 return o.builder.intType(@intCast(scalar_type.abiSize(mod) * 8));
1073911282 },
1074011283 .aarch64, .aarch64_be => {
1074111284 switch (aarch64_c_abi.classifyType(return_type, mod)) {
10742 .memory => return o.context.voidType(),
11285 .memory => return .void,
1074311286 .float_array => return o.lowerType(return_type),
1074411287 .byval => return o.lowerType(return_type),
10745 .integer => {
10746 const bit_size = return_type.bitSize(mod);
10747 return o.context.intType(@as(c_uint, @intCast(bit_size)));
10748 },
10749 .double_integer => return o.context.intType(64).arrayType(2),
11288 .integer => return o.builder.intType(@intCast(return_type.bitSize(mod))),
11289 .double_integer => return o.builder.arrayType(2, .i64),
1075011290 }
1075111291 },
1075211292 .arm, .armeb => {
1075311293 switch (arm_c_abi.classifyType(return_type, mod, .ret)) {
10754 .memory, .i64_array => return o.context.voidType(),
10755 .i32_array => |len| if (len == 1) {
10756 return o.context.intType(32);
10757 } else {
10758 return o.context.voidType();
10759 },
11294 .memory, .i64_array => return .void,
11295 .i32_array => |len| return if (len == 1) .i32 else .void,
1076011296 .byval => return o.lowerType(return_type),
1076111297 }
1076211298 },
1076311299 .riscv32, .riscv64 => {
1076411300 switch (riscv_c_abi.classifyType(return_type, mod)) {
10765 .memory => return o.context.voidType(),
11301 .memory => return .void,
1076611302 .integer => {
10767 const bit_size = return_type.bitSize(mod);
10768 return o.context.intType(@as(c_uint, @intCast(bit_size)));
11303 return o.builder.intType(@intCast(return_type.bitSize(mod)));
1076911304 },
1077011305 .double_integer => {
10771 var llvm_types_buffer: [2]*llvm.Type = .{
10772 o.context.intType(64),
10773 o.context.intType(64),
10774 };
10775 return o.context.structType(&llvm_types_buffer, 2, .False);
11306 return o.builder.structType(.normal, &.{ .i64, .i64 });
1077611307 },
1077711308 .byval => return o.lowerType(return_type),
1077811309 }
......@@ -10783,18 +11314,12 @@ fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) !*llvm.Type {
1078311314 },
1078411315 .Win64 => return lowerWin64FnRetTy(o, fn_info),
1078511316 .SysV => return lowerSystemVFnRetTy(o, fn_info),
10786 .Stdcall => {
10787 if (isScalar(mod, return_type)) {
10788 return o.lowerType(return_type);
10789 } else {
10790 return o.context.voidType();
10791 }
10792 },
11317 .Stdcall => return if (isScalar(mod, return_type)) o.lowerType(return_type) else .void,
1079311318 else => return o.lowerType(return_type),
1079411319 }
1079511320}
1079611321
10797fn lowerWin64FnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) !*llvm.Type {
11322fn lowerWin64FnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type {
1079811323 const mod = o.module;
1079911324 const return_type = fn_info.return_type.toType();
1080011325 switch (x86_64_abi.classifyWindows(return_type, mod)) {
......@@ -10802,53 +11327,48 @@ fn lowerWin64FnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) !*llvm.Type {
1080211327 if (isScalar(mod, return_type)) {
1080311328 return o.lowerType(return_type);
1080411329 } else {
10805 const abi_size = return_type.abiSize(mod);
10806 return o.context.intType(@as(c_uint, @intCast(abi_size * 8)));
11330 return o.builder.intType(@intCast(return_type.abiSize(mod) * 8));
1080711331 }
1080811332 },
10809 .win_i128 => return o.context.intType(64).vectorType(2),
10810 .memory => return o.context.voidType(),
11333 .win_i128 => return o.builder.vectorType(.normal, 2, .i64),
11334 .memory => return .void,
1081111335 .sse => return o.lowerType(return_type),
1081211336 else => unreachable,
1081311337 }
1081411338}
1081511339
10816fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) !*llvm.Type {
11340fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type {
1081711341 const mod = o.module;
1081811342 const return_type = fn_info.return_type.toType();
1081911343 if (isScalar(mod, return_type)) {
1082011344 return o.lowerType(return_type);
1082111345 }
1082211346 const classes = x86_64_abi.classifySystemV(return_type, mod, .ret);
10823 if (classes[0] == .memory) {
10824 return o.context.voidType();
10825 }
10826 var llvm_types_buffer: [8]*llvm.Type = undefined;
10827 var llvm_types_index: u32 = 0;
11347 if (classes[0] == .memory) return .void;
11348 var types_index: u32 = 0;
11349 var types_buffer: [8]Builder.Type = undefined;
1082811350 for (classes) |class| {
1082911351 switch (class) {
1083011352 .integer => {
10831 llvm_types_buffer[llvm_types_index] = o.context.intType(64);
10832 llvm_types_index += 1;
11353 types_buffer[types_index] = .i64;
11354 types_index += 1;
1083311355 },
1083411356 .sse, .sseup => {
10835 llvm_types_buffer[llvm_types_index] = o.context.doubleType();
10836 llvm_types_index += 1;
11357 types_buffer[types_index] = .double;
11358 types_index += 1;
1083711359 },
1083811360 .float => {
10839 llvm_types_buffer[llvm_types_index] = o.context.floatType();
10840 llvm_types_index += 1;
11361 types_buffer[types_index] = .float;
11362 types_index += 1;
1084111363 },
1084211364 .float_combine => {
10843 llvm_types_buffer[llvm_types_index] = o.context.floatType().vectorType(2);
10844 llvm_types_index += 1;
11365 types_buffer[types_index] = try o.builder.vectorType(.normal, 2, .float);
11366 types_index += 1;
1084511367 },
1084611368 .x87 => {
10847 if (llvm_types_index != 0 or classes[2] != .none) {
10848 return o.context.voidType();
10849 }
10850 llvm_types_buffer[llvm_types_index] = o.context.x86FP80Type();
10851 llvm_types_index += 1;
11369 if (types_index != 0 or classes[2] != .none) return .void;
11370 types_buffer[types_index] = .x86_fp80;
11371 types_index += 1;
1085211372 },
1085311373 .x87up => continue,
1085411374 .complex_x87 => {
......@@ -10860,10 +11380,9 @@ fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) !*llvm.Type
1086011380 }
1086111381 }
1086211382 if (classes[0] == .integer and classes[1] == .none) {
10863 const abi_size = return_type.abiSize(mod);
10864 return o.context.intType(@as(c_uint, @intCast(abi_size * 8)));
11383 return o.builder.intType(@intCast(return_type.abiSize(mod) * 8));
1086511384 }
10866 return o.context.structType(&llvm_types_buffer, llvm_types_index, .False);
11385 return o.builder.structType(.normal, types_buffer[0..types_index]);
1086711386}
1086811387
1086911388const ParamTypeIterator = struct {
......@@ -10871,8 +11390,8 @@ const ParamTypeIterator = struct {
1087111390 fn_info: InternPool.Key.FuncType,
1087211391 zig_index: u32,
1087311392 llvm_index: u32,
10874 llvm_types_len: u32,
10875 llvm_types_buffer: [8]*llvm.Type,
11393 types_len: u32,
11394 types_buffer: [8]Builder.Type,
1087611395 byval_attr: bool,
1087711396
1087811397 const Lowering = union(enum) {
......@@ -10889,7 +11408,7 @@ const ParamTypeIterator = struct {
1088911408 i64_array: u8,
1089011409 };
1089111410
10892 pub fn next(it: *ParamTypeIterator) ?Lowering {
11411 pub fn next(it: *ParamTypeIterator) Allocator.Error!?Lowering {
1089311412 if (it.zig_index >= it.fn_info.param_types.len) return null;
1089411413 const mod = it.object.module;
1089511414 const ip = &mod.intern_pool;
......@@ -10899,7 +11418,7 @@ const ParamTypeIterator = struct {
1089911418 }
1090011419
1090111420 /// `airCall` uses this instead of `next` so that it can take into account variadic functions.
10902 pub fn nextCall(it: *ParamTypeIterator, fg: *FuncGen, args: []const Air.Inst.Ref) ?Lowering {
11421 pub fn nextCall(it: *ParamTypeIterator, fg: *FuncGen, args: []const Air.Inst.Ref) Allocator.Error!?Lowering {
1090311422 const mod = it.object.module;
1090411423 const ip = &mod.intern_pool;
1090511424 if (it.zig_index >= it.fn_info.param_types.len) {
......@@ -10913,7 +11432,7 @@ const ParamTypeIterator = struct {
1091311432 }
1091411433 }
1091511434
10916 fn nextInner(it: *ParamTypeIterator, ty: Type) ?Lowering {
11435 fn nextInner(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering {
1091711436 const mod = it.object.module;
1091811437 const target = mod.getTarget();
1091911438
......@@ -10968,8 +11487,8 @@ const ParamTypeIterator = struct {
1096811487 .float_array => |len| return Lowering{ .float_array = len },
1096911488 .byval => return .byval,
1097011489 .integer => {
10971 it.llvm_types_len = 1;
10972 it.llvm_types_buffer[0] = it.object.context.intType(64);
11490 it.types_len = 1;
11491 it.types_buffer[0] = .i64;
1097311492 return .multiple_llvm_types;
1097411493 },
1097511494 .double_integer => return Lowering{ .i64_array = 2 },
......@@ -11063,7 +11582,7 @@ const ParamTypeIterator = struct {
1106311582 }
1106411583 }
1106511584
11066 fn nextSystemV(it: *ParamTypeIterator, ty: Type) ?Lowering {
11585 fn nextSystemV(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering {
1106711586 const mod = it.object.module;
1106811587 const classes = x86_64_abi.classifySystemV(ty, mod, .arg);
1106911588 if (classes[0] == .memory) {
......@@ -11077,25 +11596,25 @@ const ParamTypeIterator = struct {
1107711596 it.llvm_index += 1;
1107811597 return .byval;
1107911598 }
11080 var llvm_types_buffer: [8]*llvm.Type = undefined;
11081 var llvm_types_index: u32 = 0;
11599 var types_index: u32 = 0;
11600 var types_buffer: [8]Builder.Type = undefined;
1108211601 for (classes) |class| {
1108311602 switch (class) {
1108411603 .integer => {
11085 llvm_types_buffer[llvm_types_index] = it.object.context.intType(64);
11086 llvm_types_index += 1;
11604 types_buffer[types_index] = .i64;
11605 types_index += 1;
1108711606 },
1108811607 .sse, .sseup => {
11089 llvm_types_buffer[llvm_types_index] = it.object.context.doubleType();
11090 llvm_types_index += 1;
11608 types_buffer[types_index] = .double;
11609 types_index += 1;
1109111610 },
1109211611 .float => {
11093 llvm_types_buffer[llvm_types_index] = it.object.context.floatType();
11094 llvm_types_index += 1;
11612 types_buffer[types_index] = .float;
11613 types_index += 1;
1109511614 },
1109611615 .float_combine => {
11097 llvm_types_buffer[llvm_types_index] = it.object.context.floatType().vectorType(2);
11098 llvm_types_index += 1;
11616 types_buffer[types_index] = try it.object.builder.vectorType(.normal, 2, .float);
11617 types_index += 1;
1109911618 },
1110011619 .x87 => {
1110111620 it.zig_index += 1;
......@@ -11117,9 +11636,9 @@ const ParamTypeIterator = struct {
1111711636 it.llvm_index += 1;
1111811637 return .abi_sized_int;
1111911638 }
11120 it.llvm_types_buffer = llvm_types_buffer;
11121 it.llvm_types_len = llvm_types_index;
11122 it.llvm_index += llvm_types_index;
11639 it.types_len = types_index;
11640 it.types_buffer = types_buffer;
11641 it.llvm_index += types_index;
1112311642 it.zig_index += 1;
1112411643 return .multiple_llvm_types;
1112511644 }
......@@ -11131,8 +11650,8 @@ fn iterateParamTypes(object: *Object, fn_info: InternPool.Key.FuncType) ParamTyp
1113111650 .fn_info = fn_info,
1113211651 .zig_index = 0,
1113311652 .llvm_index = 0,
11134 .llvm_types_buffer = undefined,
11135 .llvm_types_len = 0,
11653 .types_len = 0,
11654 .types_buffer = undefined,
1113611655 .byval_attr = false,
1113711656 };
1113811657}
......@@ -11355,23 +11874,23 @@ const AnnotatedDITypePtr = enum(usize) {
1135511874 fn initFwd(di_type: *llvm.DIType) AnnotatedDITypePtr {
1135611875 const addr = @intFromPtr(di_type);
1135711876 assert(@as(u1, @truncate(addr)) == 0);
11358 return @as(AnnotatedDITypePtr, @enumFromInt(addr | 1));
11877 return @enumFromInt(addr | 1);
1135911878 }
1136011879
1136111880 fn initFull(di_type: *llvm.DIType) AnnotatedDITypePtr {
1136211881 const addr = @intFromPtr(di_type);
11363 return @as(AnnotatedDITypePtr, @enumFromInt(addr));
11882 return @enumFromInt(addr);
1136411883 }
1136511884
1136611885 fn init(di_type: *llvm.DIType, resolve: Object.DebugResolveStatus) AnnotatedDITypePtr {
1136711886 const addr = @intFromPtr(di_type);
1136811887 const bit = @intFromBool(resolve == .fwd);
11369 return @as(AnnotatedDITypePtr, @enumFromInt(addr | bit));
11888 return @enumFromInt(addr | bit);
1137011889 }
1137111890
1137211891 fn toDIType(self: AnnotatedDITypePtr) *llvm.DIType {
1137311892 const fixed_addr = @intFromEnum(self) & ~@as(usize, 1);
11374 return @as(*llvm.DIType, @ptrFromInt(fixed_addr));
11893 return @ptrFromInt(fixed_addr);
1137511894 }
1137611895
1137711896 fn isFwdOnly(self: AnnotatedDITypePtr) bool {
......@@ -11401,56 +11920,39 @@ fn compilerRtIntBits(bits: u16) u16 {
1140111920}
1140211921
1140311922fn buildAllocaInner(
11404 context: *llvm.Context,
11405 builder: *llvm.Builder,
11406 llvm_func: *llvm.Value,
11923 wip: *Builder.WipFunction,
1140711924 di_scope_non_null: bool,
11408 llvm_ty: *llvm.Type,
11409 maybe_alignment: ?c_uint,
11925 llvm_ty: Builder.Type,
11926 alignment: Builder.Alignment,
1141011927 target: std.Target,
11411) *llvm.Value {
11928) Allocator.Error!Builder.Value {
1141211929 const address_space = llvmAllocaAddressSpace(target);
1141311930
1141411931 const alloca = blk: {
11415 const prev_block = builder.getInsertBlock();
11416 const prev_debug_location = builder.getCurrentDebugLocation2();
11932 const prev_cursor = wip.cursor;
11933 const prev_debug_location = wip.llvm.builder.getCurrentDebugLocation2();
1141711934 defer {
11418 builder.positionBuilderAtEnd(prev_block);
11419 if (di_scope_non_null) {
11420 builder.setCurrentDebugLocation2(prev_debug_location);
11421 }
11422 }
11423
11424 const entry_block = llvm_func.getFirstBasicBlock().?;
11425 if (entry_block.getFirstInstruction()) |first_inst| {
11426 builder.positionBuilder(entry_block, first_inst);
11427 } else {
11428 builder.positionBuilderAtEnd(entry_block);
11935 wip.cursor = prev_cursor;
11936 if (wip.cursor.block == .entry) wip.cursor.instruction += 1;
11937 if (di_scope_non_null) wip.llvm.builder.setCurrentDebugLocation2(prev_debug_location);
1142911938 }
11430 builder.clearCurrentDebugLocation();
1143111939
11432 break :blk builder.buildAllocaInAddressSpace(llvm_ty, address_space, "");
11940 wip.cursor = .{ .block = .entry };
11941 wip.llvm.builder.clearCurrentDebugLocation();
11942 break :blk try wip.alloca(.normal, llvm_ty, .none, alignment, address_space, "");
1143311943 };
1143411944
11435 if (maybe_alignment) |alignment| {
11436 alloca.setAlignment(alignment);
11437 }
11438
1143911945 // The pointer returned from this function should have the generic address space,
1144011946 // if this isn't the case then cast it to the generic address space.
11441 if (address_space != llvm.address_space.default) {
11442 return builder.buildAddrSpaceCast(alloca, context.pointerType(llvm.address_space.default), "");
11443 }
11444
11445 return alloca;
11947 return wip.conv(.unneeded, alloca, .ptr, "");
1144611948}
1144711949
1144811950fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u1 {
11449 return @intFromBool(Type.anyerror.abiAlignment(mod) > payload_ty.abiAlignment(mod));
11951 return @intFromBool(Type.err_int.abiAlignment(mod) > payload_ty.abiAlignment(mod));
1145011952}
1145111953
1145211954fn errUnionErrorOffset(payload_ty: Type, mod: *Module) u1 {
11453 return @intFromBool(Type.anyerror.abiAlignment(mod) <= payload_ty.abiAlignment(mod));
11955 return @intFromBool(Type.err_int.abiAlignment(mod) <= payload_ty.abiAlignment(mod));
1145411956}
1145511957
1145611958/// Returns true for asm constraint (e.g. "=*m", "=r") if it accepts a memory location
src/codegen/llvm/Builder.zig created+7931
......@@ -0,0 +1,7931 @@
1gpa: Allocator,
2use_lib_llvm: bool,
3strip: bool,
4
5llvm: if (build_options.have_llvm) struct {
6 context: *llvm.Context,
7 module: ?*llvm.Module = null,
8 target: ?*llvm.Target = null,
9 di_builder: ?*llvm.DIBuilder = null,
10 di_compile_unit: ?*llvm.DICompileUnit = null,
11 types: std.ArrayListUnmanaged(*llvm.Type) = .{},
12 globals: std.ArrayListUnmanaged(*llvm.Value) = .{},
13 constants: std.ArrayListUnmanaged(*llvm.Value) = .{},
14} else void,
15
16source_filename: String,
17data_layout: String,
18target_triple: String,
19
20string_map: std.AutoArrayHashMapUnmanaged(void, void),
21string_bytes: std.ArrayListUnmanaged(u8),
22string_indices: std.ArrayListUnmanaged(u32),
23
24types: std.AutoArrayHashMapUnmanaged(String, Type),
25next_unnamed_type: String,
26next_unique_type_id: std.AutoHashMapUnmanaged(String, u32),
27type_map: std.AutoArrayHashMapUnmanaged(void, void),
28type_items: std.ArrayListUnmanaged(Type.Item),
29type_extra: std.ArrayListUnmanaged(u32),
30
31globals: std.AutoArrayHashMapUnmanaged(String, Global),
32next_unnamed_global: String,
33next_replaced_global: String,
34next_unique_global_id: std.AutoHashMapUnmanaged(String, u32),
35aliases: std.ArrayListUnmanaged(Alias),
36variables: std.ArrayListUnmanaged(Variable),
37functions: std.ArrayListUnmanaged(Function),
38
39constant_map: std.AutoArrayHashMapUnmanaged(void, void),
40constant_items: std.MultiArrayList(Constant.Item),
41constant_extra: std.ArrayListUnmanaged(u32),
42constant_limbs: std.ArrayListUnmanaged(std.math.big.Limb),
43
44pub const expected_fields_len = 32;
45pub const expected_gep_indices_len = 8;
46pub const expected_cases_len = 8;
47pub const expected_incoming_len = 8;
48
49pub const Options = struct {
50 allocator: Allocator,
51 use_lib_llvm: bool = false,
52 strip: bool = true,
53 name: []const u8 = &.{},
54 target: std.Target = builtin.target,
55 triple: []const u8 = &.{},
56};
57
58pub const String = enum(u32) {
59 none = std.math.maxInt(u31),
60 empty,
61 _,
62
63 pub fn isAnon(self: String) bool {
64 assert(self != .none);
65 return self.toIndex() == null;
66 }
67
68 pub fn toSlice(self: String, b: *const Builder) ?[:0]const u8 {
69 const index = self.toIndex() orelse return null;
70 const start = b.string_indices.items[index];
71 const end = b.string_indices.items[index + 1];
72 return b.string_bytes.items[start .. end - 1 :0];
73 }
74
75 const FormatData = struct {
76 string: String,
77 builder: *const Builder,
78 };
79 fn format(
80 data: FormatData,
81 comptime fmt_str: []const u8,
82 _: std.fmt.FormatOptions,
83 writer: anytype,
84 ) @TypeOf(writer).Error!void {
85 if (comptime std.mem.indexOfNone(u8, fmt_str, "@\"")) |_|
86 @compileError("invalid format string: '" ++ fmt_str ++ "'");
87 assert(data.string != .none);
88 const slice = data.string.toSlice(data.builder) orelse
89 return writer.print("{d}", .{@intFromEnum(data.string)});
90 const full_slice = slice[0 .. slice.len + comptime @intFromBool(
91 std.mem.indexOfScalar(u8, fmt_str, '@') != null,
92 )];
93 const need_quotes = (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) or
94 !isValidIdentifier(full_slice);
95 if (need_quotes) try writer.writeByte('"');
96 for (full_slice) |character| switch (character) {
97 '\\' => try writer.writeAll("\\\\"),
98 ' '...'"' - 1, '"' + 1...'\\' - 1, '\\' + 1...'~' => try writer.writeByte(character),
99 else => try writer.print("\\{X:0>2}", .{character}),
100 };
101 if (need_quotes) try writer.writeByte('"');
102 }
103 pub fn fmt(self: String, builder: *const Builder) std.fmt.Formatter(format) {
104 return .{ .data = .{ .string = self, .builder = builder } };
105 }
106
107 fn fromIndex(index: ?usize) String {
108 return @enumFromInt(@as(u32, @intCast((index orelse return .none) +
109 @intFromEnum(String.empty))));
110 }
111 fn toIndex(self: String) ?usize {
112 return std.math.sub(u32, @intFromEnum(self), @intFromEnum(String.empty)) catch null;
113 }
114
115 const Adapter = struct {
116 builder: *const Builder,
117 pub fn hash(_: Adapter, key: []const u8) u32 {
118 return @truncate(std.hash.Wyhash.hash(0, key));
119 }
120 pub fn eql(ctx: Adapter, lhs_key: []const u8, _: void, rhs_index: usize) bool {
121 return std.mem.eql(u8, lhs_key, String.fromIndex(rhs_index).toSlice(ctx.builder).?);
122 }
123 };
124};
125
126pub const Type = enum(u32) {
127 void,
128 half,
129 bfloat,
130 float,
131 double,
132 fp128,
133 x86_fp80,
134 ppc_fp128,
135 x86_amx,
136 x86_mmx,
137 label,
138 token,
139 metadata,
140
141 i1,
142 i8,
143 i16,
144 i29,
145 i32,
146 i64,
147 i80,
148 i128,
149 ptr,
150
151 none = std.math.maxInt(u32),
152 _,
153
154 pub const err_int = Type.i16;
155
156 pub const Tag = enum(u4) {
157 simple,
158 function,
159 vararg_function,
160 integer,
161 pointer,
162 target,
163 vector,
164 scalable_vector,
165 small_array,
166 array,
167 structure,
168 packed_structure,
169 named_structure,
170 };
171
172 pub const Simple = enum {
173 void,
174 half,
175 bfloat,
176 float,
177 double,
178 fp128,
179 x86_fp80,
180 ppc_fp128,
181 x86_amx,
182 x86_mmx,
183 label,
184 token,
185 metadata,
186 };
187
188 pub const Function = struct {
189 ret: Type,
190 params_len: u32,
191 //params: [params_len]Value,
192
193 pub const Kind = enum { normal, vararg };
194 };
195
196 pub const Target = extern struct {
197 name: String,
198 types_len: u32,
199 ints_len: u32,
200 //types: [types_len]Type,
201 //ints: [ints_len]u32,
202 };
203
204 pub const Vector = extern struct {
205 len: u32,
206 child: Type,
207
208 fn length(self: Vector) u32 {
209 return self.len;
210 }
211
212 pub const Kind = enum { normal, scalable };
213 };
214
215 pub const Array = extern struct {
216 len_lo: u32,
217 len_hi: u32,
218 child: Type,
219
220 fn length(self: Array) u64 {
221 return @as(u64, self.len_hi) << 32 | self.len_lo;
222 }
223 };
224
225 pub const Structure = struct {
226 fields_len: u32,
227 //fields: [fields_len]Type,
228
229 pub const Kind = enum { normal, @"packed" };
230 };
231
232 pub const NamedStructure = struct {
233 id: String,
234 body: Type,
235 };
236
237 pub const Item = packed struct(u32) {
238 tag: Tag,
239 data: ExtraIndex,
240
241 pub const ExtraIndex = u28;
242 };
243
244 pub fn tag(self: Type, builder: *const Builder) Tag {
245 return builder.type_items.items[@intFromEnum(self)].tag;
246 }
247
248 pub fn unnamedTag(self: Type, builder: *const Builder) Tag {
249 const item = builder.type_items.items[@intFromEnum(self)];
250 return switch (item.tag) {
251 .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body
252 .unnamedTag(builder),
253 else => item.tag,
254 };
255 }
256
257 pub fn scalarTag(self: Type, builder: *const Builder) Tag {
258 const item = builder.type_items.items[@intFromEnum(self)];
259 return switch (item.tag) {
260 .vector, .scalable_vector => builder.typeExtraData(Type.Vector, item.data)
261 .child.tag(builder),
262 else => item.tag,
263 };
264 }
265
266 pub fn isFloatingPoint(self: Type) bool {
267 return switch (self) {
268 .half, .bfloat, .float, .double, .fp128, .x86_fp80, .ppc_fp128 => true,
269 else => false,
270 };
271 }
272
273 pub fn isInteger(self: Type, builder: *const Builder) bool {
274 return switch (self) {
275 .i1, .i8, .i16, .i29, .i32, .i64, .i80, .i128 => true,
276 else => switch (self.tag(builder)) {
277 .integer => true,
278 else => false,
279 },
280 };
281 }
282
283 pub fn isPointer(self: Type, builder: *const Builder) bool {
284 return switch (self) {
285 .ptr => true,
286 else => switch (self.tag(builder)) {
287 .pointer => true,
288 else => false,
289 },
290 };
291 }
292
293 pub fn isFunction(self: Type, builder: *const Builder) bool {
294 return switch (self.tag(builder)) {
295 .function, .vararg_function => true,
296 else => false,
297 };
298 }
299
300 pub fn functionKind(self: Type, builder: *const Builder) Type.Function.Kind {
301 return switch (self.tag(builder)) {
302 .function => .normal,
303 .vararg_function => .vararg,
304 else => unreachable,
305 };
306 }
307
308 pub fn functionParameters(self: Type, builder: *const Builder) []const Type {
309 const item = builder.type_items.items[@intFromEnum(self)];
310 switch (item.tag) {
311 .function,
312 .vararg_function,
313 => {
314 var extra = builder.typeExtraDataTrail(Type.Function, item.data);
315 return extra.trail.next(extra.data.params_len, Type, builder);
316 },
317 else => unreachable,
318 }
319 }
320
321 pub fn functionReturn(self: Type, builder: *const Builder) Type {
322 const item = builder.type_items.items[@intFromEnum(self)];
323 switch (item.tag) {
324 .function,
325 .vararg_function,
326 => return builder.typeExtraData(Type.Function, item.data).ret,
327 else => unreachable,
328 }
329 }
330
331 pub fn isVector(self: Type, builder: *const Builder) bool {
332 return switch (self.tag(builder)) {
333 .vector, .scalable_vector => true,
334 else => false,
335 };
336 }
337
338 pub fn vectorKind(self: Type, builder: *const Builder) Type.Vector.Kind {
339 return switch (self.tag(builder)) {
340 .vector => .normal,
341 .scalable_vector => .scalable,
342 else => unreachable,
343 };
344 }
345
346 pub fn isStruct(self: Type, builder: *const Builder) bool {
347 return switch (self.tag(builder)) {
348 .structure, .packed_structure, .named_structure => true,
349 else => false,
350 };
351 }
352
353 pub fn structKind(self: Type, builder: *const Builder) Type.Structure.Kind {
354 return switch (self.unnamedTag(builder)) {
355 .structure => .normal,
356 .packed_structure => .@"packed",
357 else => unreachable,
358 };
359 }
360
361 pub fn isAggregate(self: Type, builder: *const Builder) bool {
362 return switch (self.tag(builder)) {
363 .small_array, .array, .structure, .packed_structure, .named_structure => true,
364 else => false,
365 };
366 }
367
368 pub fn scalarBits(self: Type, builder: *const Builder) u24 {
369 return switch (self) {
370 .void, .label, .token, .metadata, .none, .x86_amx => unreachable,
371 .i1 => 1,
372 .i8 => 8,
373 .half, .bfloat, .i16 => 16,
374 .i29 => 29,
375 .float, .i32 => 32,
376 .double, .i64, .x86_mmx => 64,
377 .x86_fp80, .i80 => 80,
378 .fp128, .ppc_fp128, .i128 => 128,
379 .ptr => @panic("TODO: query data layout"),
380 _ => {
381 const item = builder.type_items.items[@intFromEnum(self)];
382 return switch (item.tag) {
383 .simple,
384 .function,
385 .vararg_function,
386 => unreachable,
387 .integer => @intCast(item.data),
388 .pointer => @panic("TODO: query data layout"),
389 .target => unreachable,
390 .vector,
391 .scalable_vector,
392 => builder.typeExtraData(Type.Vector, item.data).child.scalarBits(builder),
393 .small_array,
394 .array,
395 .structure,
396 .packed_structure,
397 .named_structure,
398 => unreachable,
399 };
400 },
401 };
402 }
403
404 pub fn childType(self: Type, builder: *const Builder) Type {
405 const item = builder.type_items.items[@intFromEnum(self)];
406 return switch (item.tag) {
407 .vector,
408 .scalable_vector,
409 .small_array,
410 => builder.typeExtraData(Type.Vector, item.data).child,
411 .array => builder.typeExtraData(Type.Array, item.data).child,
412 .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body,
413 else => unreachable,
414 };
415 }
416
417 pub fn scalarType(self: Type, builder: *const Builder) Type {
418 if (self.isFloatingPoint()) return self;
419 const item = builder.type_items.items[@intFromEnum(self)];
420 return switch (item.tag) {
421 .integer,
422 .pointer,
423 => self,
424 .vector,
425 .scalable_vector,
426 => builder.typeExtraData(Type.Vector, item.data).child,
427 else => unreachable,
428 };
429 }
430
431 pub fn changeScalar(self: Type, scalar: Type, builder: *Builder) Allocator.Error!Type {
432 try builder.ensureUnusedTypeCapacity(1, Type.Vector, 0);
433 return self.changeScalarAssumeCapacity(scalar, builder);
434 }
435
436 pub fn changeScalarAssumeCapacity(self: Type, scalar: Type, builder: *Builder) Type {
437 if (self.isFloatingPoint()) return scalar;
438 const item = builder.type_items.items[@intFromEnum(self)];
439 return switch (item.tag) {
440 .integer,
441 .pointer,
442 => scalar,
443 inline .vector,
444 .scalable_vector,
445 => |kind| builder.vectorTypeAssumeCapacity(
446 switch (kind) {
447 .vector => .normal,
448 .scalable_vector => .scalable,
449 else => unreachable,
450 },
451 builder.typeExtraData(Type.Vector, item.data).len,
452 scalar,
453 ),
454 else => unreachable,
455 };
456 }
457
458 pub fn vectorLen(self: Type, builder: *const Builder) u32 {
459 const item = builder.type_items.items[@intFromEnum(self)];
460 return switch (item.tag) {
461 .vector,
462 .scalable_vector,
463 => builder.typeExtraData(Type.Vector, item.data).len,
464 else => unreachable,
465 };
466 }
467
468 pub fn changeLength(self: Type, len: u32, builder: *Builder) Allocator.Error!Type {
469 try builder.ensureUnusedTypeCapacity(1, Type.Array, 0);
470 return self.changeLengthAssumeCapacity(len, builder);
471 }
472
473 pub fn changeLengthAssumeCapacity(self: Type, len: u32, builder: *Builder) Type {
474 const item = builder.type_items.items[@intFromEnum(self)];
475 return switch (item.tag) {
476 inline .vector,
477 .scalable_vector,
478 => |kind| builder.vectorTypeAssumeCapacity(
479 switch (kind) {
480 .vector => .normal,
481 .scalable_vector => .scalable,
482 else => unreachable,
483 },
484 len,
485 builder.typeExtraData(Type.Vector, item.data).child,
486 ),
487 .small_array => builder.arrayTypeAssumeCapacity(
488 len,
489 builder.typeExtraData(Type.Vector, item.data).child,
490 ),
491 .array => builder.arrayTypeAssumeCapacity(
492 len,
493 builder.typeExtraData(Type.Array, item.data).child,
494 ),
495 else => unreachable,
496 };
497 }
498
499 pub fn aggregateLen(self: Type, builder: *const Builder) u64 {
500 const item = builder.type_items.items[@intFromEnum(self)];
501 return switch (item.tag) {
502 .vector,
503 .scalable_vector,
504 .small_array,
505 => builder.typeExtraData(Type.Vector, item.data).len,
506 .array => builder.typeExtraData(Type.Array, item.data).length(),
507 .structure,
508 .packed_structure,
509 => builder.typeExtraData(Type.Structure, item.data).fields_len,
510 .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body
511 .aggregateLen(builder),
512 else => unreachable,
513 };
514 }
515
516 pub fn structFields(self: Type, builder: *const Builder) []const Type {
517 const item = builder.type_items.items[@intFromEnum(self)];
518 switch (item.tag) {
519 .structure,
520 .packed_structure,
521 => {
522 var extra = builder.typeExtraDataTrail(Type.Structure, item.data);
523 return extra.trail.next(extra.data.fields_len, Type, builder);
524 },
525 .named_structure => return builder.typeExtraData(Type.NamedStructure, item.data).body
526 .structFields(builder),
527 else => unreachable,
528 }
529 }
530
531 pub fn childTypeAt(self: Type, indices: []const u32, builder: *const Builder) Type {
532 if (indices.len == 0) return self;
533 const item = builder.type_items.items[@intFromEnum(self)];
534 return switch (item.tag) {
535 .small_array => builder.typeExtraData(Type.Vector, item.data).child
536 .childTypeAt(indices[1..], builder),
537 .array => builder.typeExtraData(Type.Array, item.data).child
538 .childTypeAt(indices[1..], builder),
539 .structure,
540 .packed_structure,
541 => {
542 var extra = builder.typeExtraDataTrail(Type.Structure, item.data);
543 const fields = extra.trail.next(extra.data.fields_len, Type, builder);
544 return fields[indices[0]].childTypeAt(indices[1..], builder);
545 },
546 .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body
547 .childTypeAt(indices, builder),
548 else => unreachable,
549 };
550 }
551
552 pub fn targetLayoutType(self: Type, builder: *const Builder) Type {
553 _ = self;
554 _ = builder;
555 @panic("TODO: implement targetLayoutType");
556 }
557
558 pub fn isSized(self: Type, builder: *const Builder) Allocator.Error!bool {
559 var visited: IsSizedVisited = .{};
560 return self.isSizedVisited(&visited, builder);
561 }
562
563 const FormatData = struct {
564 type: Type,
565 builder: *const Builder,
566 };
567 fn format(
568 data: FormatData,
569 comptime fmt_str: []const u8,
570 fmt_opts: std.fmt.FormatOptions,
571 writer: anytype,
572 ) @TypeOf(writer).Error!void {
573 assert(data.type != .none);
574 if (comptime std.mem.eql(u8, fmt_str, "m")) {
575 const item = data.builder.type_items.items[@intFromEnum(data.type)];
576 switch (item.tag) {
577 .simple => try writer.writeAll(switch (@as(Simple, @enumFromInt(item.data))) {
578 .void => "isVoid",
579 .half => "f16",
580 .bfloat => "bf16",
581 .float => "f32",
582 .double => "f64",
583 .fp128 => "f128",
584 .x86_fp80 => "f80",
585 .ppc_fp128 => "ppcf128",
586 .x86_amx => "x86amx",
587 .x86_mmx => "x86mmx",
588 .label, .token => unreachable,
589 .metadata => "Metadata",
590 }),
591 .function, .vararg_function => |kind| {
592 var extra = data.builder.typeExtraDataTrail(Type.Function, item.data);
593 const params = extra.trail.next(extra.data.params_len, Type, data.builder);
594 try writer.print("f_{m}", .{extra.data.ret.fmt(data.builder)});
595 for (params) |param| try writer.print("{m}", .{param.fmt(data.builder)});
596 switch (kind) {
597 .function => {},
598 .vararg_function => try writer.writeAll("vararg"),
599 else => unreachable,
600 }
601 try writer.writeByte('f');
602 },
603 .integer => try writer.print("i{d}", .{item.data}),
604 .pointer => try writer.print("p{d}", .{item.data}),
605 .target => {
606 var extra = data.builder.typeExtraDataTrail(Type.Target, item.data);
607 const types = extra.trail.next(extra.data.types_len, Type, data.builder);
608 const ints = extra.trail.next(extra.data.ints_len, u32, data.builder);
609 try writer.print("t{s}", .{extra.data.name.toSlice(data.builder).?});
610 for (types) |ty| try writer.print("_{m}", .{ty.fmt(data.builder)});
611 for (ints) |int| try writer.print("_{d}", .{int});
612 try writer.writeByte('t');
613 },
614 .vector, .scalable_vector => |kind| {
615 const extra = data.builder.typeExtraData(Type.Vector, item.data);
616 try writer.print("{s}v{d}{m}", .{
617 switch (kind) {
618 .vector => "",
619 .scalable_vector => "nx",
620 else => unreachable,
621 },
622 extra.len,
623 extra.child.fmt(data.builder),
624 });
625 },
626 inline .small_array, .array => |kind| {
627 const extra = data.builder.typeExtraData(switch (kind) {
628 .small_array => Type.Vector,
629 .array => Type.Array,
630 else => unreachable,
631 }, item.data);
632 try writer.print("a{d}{m}", .{ extra.length(), extra.child.fmt(data.builder) });
633 },
634 .structure, .packed_structure => {
635 var extra = data.builder.typeExtraDataTrail(Type.Structure, item.data);
636 const fields = extra.trail.next(extra.data.fields_len, Type, data.builder);
637 try writer.writeAll("sl_");
638 for (fields) |field| try writer.print("{m}", .{field.fmt(data.builder)});
639 try writer.writeByte('s');
640 },
641 .named_structure => {
642 const extra = data.builder.typeExtraData(Type.NamedStructure, item.data);
643 try writer.writeAll("s_");
644 if (extra.id.toSlice(data.builder)) |id| try writer.writeAll(id);
645 },
646 }
647 return;
648 }
649 if (std.enums.tagName(Type, data.type)) |name| return writer.writeAll(name);
650 const item = data.builder.type_items.items[@intFromEnum(data.type)];
651 switch (item.tag) {
652 .simple => unreachable,
653 .function, .vararg_function => |kind| {
654 var extra = data.builder.typeExtraDataTrail(Type.Function, item.data);
655 const params = extra.trail.next(extra.data.params_len, Type, data.builder);
656 if (!comptime std.mem.eql(u8, fmt_str, ">"))
657 try writer.print("{%} ", .{extra.data.ret.fmt(data.builder)});
658 if (!comptime std.mem.eql(u8, fmt_str, "<")) {
659 try writer.writeByte('(');
660 for (params, 0..) |param, index| {
661 if (index > 0) try writer.writeAll(", ");
662 try writer.print("{%}", .{param.fmt(data.builder)});
663 }
664 switch (kind) {
665 .function => {},
666 .vararg_function => {
667 if (params.len > 0) try writer.writeAll(", ");
668 try writer.writeAll("...");
669 },
670 else => unreachable,
671 }
672 try writer.writeByte(')');
673 }
674 },
675 .integer => try writer.print("i{d}", .{item.data}),
676 .pointer => try writer.print("ptr{}", .{@as(AddrSpace, @enumFromInt(item.data))}),
677 .target => {
678 var extra = data.builder.typeExtraDataTrail(Type.Target, item.data);
679 const types = extra.trail.next(extra.data.types_len, Type, data.builder);
680 const ints = extra.trail.next(extra.data.ints_len, u32, data.builder);
681 try writer.print(
682 \\target({"}
683 , .{extra.data.name.fmt(data.builder)});
684 for (types) |ty| try writer.print(", {%}", .{ty.fmt(data.builder)});
685 for (ints) |int| try writer.print(", {d}", .{int});
686 try writer.writeByte(')');
687 },
688 .vector, .scalable_vector => |kind| {
689 const extra = data.builder.typeExtraData(Type.Vector, item.data);
690 try writer.print("<{s}{d} x {%}>", .{
691 switch (kind) {
692 .vector => "",
693 .scalable_vector => "vscale x ",
694 else => unreachable,
695 },
696 extra.len,
697 extra.child.fmt(data.builder),
698 });
699 },
700 inline .small_array, .array => |kind| {
701 const extra = data.builder.typeExtraData(switch (kind) {
702 .small_array => Type.Vector,
703 .array => Type.Array,
704 else => unreachable,
705 }, item.data);
706 try writer.print("[{d} x {%}]", .{ extra.length(), extra.child.fmt(data.builder) });
707 },
708 .structure, .packed_structure => |kind| {
709 var extra = data.builder.typeExtraDataTrail(Type.Structure, item.data);
710 const fields = extra.trail.next(extra.data.fields_len, Type, data.builder);
711 switch (kind) {
712 .structure => {},
713 .packed_structure => try writer.writeByte('<'),
714 else => unreachable,
715 }
716 try writer.writeAll("{ ");
717 for (fields, 0..) |field, index| {
718 if (index > 0) try writer.writeAll(", ");
719 try writer.print("{%}", .{field.fmt(data.builder)});
720 }
721 try writer.writeAll(" }");
722 switch (kind) {
723 .structure => {},
724 .packed_structure => try writer.writeByte('>'),
725 else => unreachable,
726 }
727 },
728 .named_structure => {
729 const extra = data.builder.typeExtraData(Type.NamedStructure, item.data);
730 if (comptime std.mem.eql(u8, fmt_str, "%")) try writer.print("%{}", .{
731 extra.id.fmt(data.builder),
732 }) else switch (extra.body) {
733 .none => try writer.writeAll("opaque"),
734 else => try format(.{
735 .type = extra.body,
736 .builder = data.builder,
737 }, fmt_str, fmt_opts, writer),
738 }
739 },
740 }
741 }
742 pub fn fmt(self: Type, builder: *const Builder) std.fmt.Formatter(format) {
743 return .{ .data = .{ .type = self, .builder = builder } };
744 }
745
746 pub fn toLlvm(self: Type, builder: *const Builder) *llvm.Type {
747 assert(builder.useLibLlvm());
748 return builder.llvm.types.items[@intFromEnum(self)];
749 }
750
751 const IsSizedVisited = std.AutoHashMapUnmanaged(Type, void);
752 fn isSizedVisited(
753 self: Type,
754 visited: *IsSizedVisited,
755 builder: *const Builder,
756 ) Allocator.Error!bool {
757 return switch (self) {
758 .void,
759 .label,
760 .token,
761 .metadata,
762 => false,
763 .half,
764 .bfloat,
765 .float,
766 .double,
767 .fp128,
768 .x86_fp80,
769 .ppc_fp128,
770 .x86_amx,
771 .x86_mmx,
772 .i1,
773 .i8,
774 .i16,
775 .i29,
776 .i32,
777 .i64,
778 .i80,
779 .i128,
780 .ptr,
781 => true,
782 .none => unreachable,
783 _ => {
784 const item = builder.type_items.items[@intFromEnum(self)];
785 return switch (item.tag) {
786 .simple => unreachable,
787 .function,
788 .vararg_function,
789 => false,
790 .integer,
791 .pointer,
792 => true,
793 .target => self.targetLayoutType(builder).isSizedVisited(visited, builder),
794 .vector,
795 .scalable_vector,
796 .small_array,
797 => builder.typeExtraData(Type.Vector, item.data)
798 .child.isSizedVisited(visited, builder),
799 .array => builder.typeExtraData(Type.Array, item.data)
800 .child.isSizedVisited(visited, builder),
801 .structure,
802 .packed_structure,
803 => {
804 if (try visited.fetchPut(builder.gpa, self, {})) |_| return false;
805
806 var extra = builder.typeExtraDataTrail(Type.Structure, item.data);
807 const fields = extra.trail.next(extra.data.fields_len, Type, builder);
808 for (fields) |field| {
809 if (field.isVector(builder) and field.vectorKind(builder) == .scalable)
810 return false;
811 if (!try field.isSizedVisited(visited, builder))
812 return false;
813 }
814 return true;
815 },
816 .named_structure => {
817 const body = builder.typeExtraData(Type.NamedStructure, item.data).body;
818 return body != .none and try body.isSizedVisited(visited, builder);
819 },
820 };
821 },
822 };
823 }
824};
825
826pub const Linkage = enum {
827 external,
828 private,
829 internal,
830 available_externally,
831 linkonce,
832 weak,
833 common,
834 appending,
835 extern_weak,
836 linkonce_odr,
837 weak_odr,
838
839 pub fn format(
840 self: Linkage,
841 comptime _: []const u8,
842 _: std.fmt.FormatOptions,
843 writer: anytype,
844 ) @TypeOf(writer).Error!void {
845 if (self != .external) try writer.print(" {s}", .{@tagName(self)});
846 }
847};
848
849pub const Preemption = enum {
850 dso_preemptable,
851 dso_local,
852 implicit_dso_local,
853
854 pub fn format(
855 self: Preemption,
856 comptime _: []const u8,
857 _: std.fmt.FormatOptions,
858 writer: anytype,
859 ) @TypeOf(writer).Error!void {
860 if (self == .dso_local) try writer.print(" {s}", .{@tagName(self)});
861 }
862};
863
864pub const Visibility = enum {
865 default,
866 hidden,
867 protected,
868
869 pub fn format(
870 self: Visibility,
871 comptime _: []const u8,
872 _: std.fmt.FormatOptions,
873 writer: anytype,
874 ) @TypeOf(writer).Error!void {
875 if (self != .default) try writer.print(" {s}", .{@tagName(self)});
876 }
877};
878
879pub const DllStorageClass = enum {
880 default,
881 dllimport,
882 dllexport,
883
884 pub fn format(
885 self: DllStorageClass,
886 comptime _: []const u8,
887 _: std.fmt.FormatOptions,
888 writer: anytype,
889 ) @TypeOf(writer).Error!void {
890 if (self != .default) try writer.print(" {s}", .{@tagName(self)});
891 }
892};
893
894pub const ThreadLocal = enum {
895 default,
896 generaldynamic,
897 localdynamic,
898 initialexec,
899 localexec,
900
901 pub fn format(
902 self: ThreadLocal,
903 comptime _: []const u8,
904 _: std.fmt.FormatOptions,
905 writer: anytype,
906 ) @TypeOf(writer).Error!void {
907 if (self == .default) return;
908 try writer.writeAll(" thread_local");
909 if (self != .generaldynamic) {
910 try writer.writeByte('(');
911 try writer.writeAll(@tagName(self));
912 try writer.writeByte(')');
913 }
914 }
915};
916
917pub const UnnamedAddr = enum {
918 default,
919 unnamed_addr,
920 local_unnamed_addr,
921
922 pub fn format(
923 self: UnnamedAddr,
924 comptime _: []const u8,
925 _: std.fmt.FormatOptions,
926 writer: anytype,
927 ) @TypeOf(writer).Error!void {
928 if (self != .default) try writer.print(" {s}", .{@tagName(self)});
929 }
930};
931
932pub const AddrSpace = enum(u24) {
933 default,
934 _,
935
936 // See llvm/lib/Target/X86/X86.h
937 pub const x86 = struct {
938 pub const gs: AddrSpace = @enumFromInt(256);
939 pub const fs: AddrSpace = @enumFromInt(257);
940 pub const ss: AddrSpace = @enumFromInt(258);
941
942 pub const ptr32_sptr: AddrSpace = @enumFromInt(270);
943 pub const ptr32_uptr: AddrSpace = @enumFromInt(271);
944 pub const ptr64: AddrSpace = @enumFromInt(272);
945 };
946 pub const x86_64 = x86;
947
948 // See llvm/lib/Target/AVR/AVR.h
949 pub const avr = struct {
950 pub const flash: AddrSpace = @enumFromInt(1);
951 pub const flash1: AddrSpace = @enumFromInt(2);
952 pub const flash2: AddrSpace = @enumFromInt(3);
953 pub const flash3: AddrSpace = @enumFromInt(4);
954 pub const flash4: AddrSpace = @enumFromInt(5);
955 pub const flash5: AddrSpace = @enumFromInt(6);
956 };
957
958 // See llvm/lib/Target/NVPTX/NVPTX.h
959 pub const nvptx = struct {
960 pub const generic: AddrSpace = @enumFromInt(0);
961 pub const global: AddrSpace = @enumFromInt(1);
962 pub const constant: AddrSpace = @enumFromInt(2);
963 pub const shared: AddrSpace = @enumFromInt(3);
964 pub const param: AddrSpace = @enumFromInt(4);
965 pub const local: AddrSpace = @enumFromInt(5);
966 };
967
968 // See llvm/lib/Target/AMDGPU/AMDGPU.h
969 pub const amdgpu = struct {
970 pub const flat: AddrSpace = @enumFromInt(0);
971 pub const global: AddrSpace = @enumFromInt(1);
972 pub const region: AddrSpace = @enumFromInt(2);
973 pub const local: AddrSpace = @enumFromInt(3);
974 pub const constant: AddrSpace = @enumFromInt(4);
975 pub const private: AddrSpace = @enumFromInt(5);
976 pub const constant_32bit: AddrSpace = @enumFromInt(6);
977 pub const buffer_fat_pointer: AddrSpace = @enumFromInt(7);
978 pub const param_d: AddrSpace = @enumFromInt(6);
979 pub const param_i: AddrSpace = @enumFromInt(7);
980 pub const constant_buffer_0: AddrSpace = @enumFromInt(8);
981 pub const constant_buffer_1: AddrSpace = @enumFromInt(9);
982 pub const constant_buffer_2: AddrSpace = @enumFromInt(10);
983 pub const constant_buffer_3: AddrSpace = @enumFromInt(11);
984 pub const constant_buffer_4: AddrSpace = @enumFromInt(12);
985 pub const constant_buffer_5: AddrSpace = @enumFromInt(13);
986 pub const constant_buffer_6: AddrSpace = @enumFromInt(14);
987 pub const constant_buffer_7: AddrSpace = @enumFromInt(15);
988 pub const constant_buffer_8: AddrSpace = @enumFromInt(16);
989 pub const constant_buffer_9: AddrSpace = @enumFromInt(17);
990 pub const constant_buffer_10: AddrSpace = @enumFromInt(18);
991 pub const constant_buffer_11: AddrSpace = @enumFromInt(19);
992 pub const constant_buffer_12: AddrSpace = @enumFromInt(20);
993 pub const constant_buffer_13: AddrSpace = @enumFromInt(21);
994 pub const constant_buffer_14: AddrSpace = @enumFromInt(22);
995 pub const constant_buffer_15: AddrSpace = @enumFromInt(23);
996 };
997
998 // See llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h
999 pub const wasm = struct {
1000 pub const variable: AddrSpace = @enumFromInt(1);
1001 pub const externref: AddrSpace = @enumFromInt(10);
1002 pub const funcref: AddrSpace = @enumFromInt(20);
1003 };
1004
1005 pub fn format(
1006 self: AddrSpace,
1007 comptime prefix: []const u8,
1008 _: std.fmt.FormatOptions,
1009 writer: anytype,
1010 ) @TypeOf(writer).Error!void {
1011 if (self != .default) try writer.print("{s} addrspace({d})", .{ prefix, @intFromEnum(self) });
1012 }
1013};
1014
1015pub const ExternallyInitialized = enum {
1016 default,
1017 externally_initialized,
1018
1019 pub fn format(
1020 self: ExternallyInitialized,
1021 comptime _: []const u8,
1022 _: std.fmt.FormatOptions,
1023 writer: anytype,
1024 ) @TypeOf(writer).Error!void {
1025 if (self == .default) return;
1026 try writer.writeByte(' ');
1027 try writer.writeAll(@tagName(self));
1028 }
1029};
1030
1031pub const Alignment = enum(u6) {
1032 default = std.math.maxInt(u6),
1033 _,
1034
1035 pub fn fromByteUnits(bytes: u64) Alignment {
1036 if (bytes == 0) return .default;
1037 assert(std.math.isPowerOfTwo(bytes));
1038 assert(bytes <= 1 << 32);
1039 return @enumFromInt(@ctz(bytes));
1040 }
1041
1042 pub fn toByteUnits(self: Alignment) ?u64 {
1043 return if (self == .default) null else @as(u64, 1) << @intFromEnum(self);
1044 }
1045
1046 pub fn format(
1047 self: Alignment,
1048 comptime prefix: []const u8,
1049 _: std.fmt.FormatOptions,
1050 writer: anytype,
1051 ) @TypeOf(writer).Error!void {
1052 try writer.print("{s} align {d}", .{ prefix, self.toByteUnits() orelse return });
1053 }
1054};
1055
1056pub const Global = struct {
1057 linkage: Linkage = .external,
1058 preemption: Preemption = .dso_preemptable,
1059 visibility: Visibility = .default,
1060 dll_storage_class: DllStorageClass = .default,
1061 unnamed_addr: UnnamedAddr = .default,
1062 addr_space: AddrSpace = .default,
1063 externally_initialized: ExternallyInitialized = .default,
1064 type: Type,
1065 partition: String = .none,
1066 kind: union(enum) {
1067 alias: Alias.Index,
1068 variable: Variable.Index,
1069 function: Function.Index,
1070 replaced: Global.Index,
1071 },
1072
1073 pub const Index = enum(u32) {
1074 none = std.math.maxInt(u32),
1075 _,
1076
1077 pub fn unwrap(self: Index, builder: *const Builder) Index {
1078 var cur = self;
1079 while (true) {
1080 const replacement = cur.getReplacement(builder);
1081 if (replacement == .none) return cur;
1082 cur = replacement;
1083 }
1084 }
1085
1086 pub fn eql(self: Index, other: Index, builder: *const Builder) bool {
1087 return self.unwrap(builder) == other.unwrap(builder);
1088 }
1089
1090 pub fn name(self: Index, builder: *const Builder) String {
1091 return builder.globals.keys()[@intFromEnum(self.unwrap(builder))];
1092 }
1093
1094 pub fn ptr(self: Index, builder: *Builder) *Global {
1095 return &builder.globals.values()[@intFromEnum(self.unwrap(builder))];
1096 }
1097
1098 pub fn ptrConst(self: Index, builder: *const Builder) *const Global {
1099 return &builder.globals.values()[@intFromEnum(self.unwrap(builder))];
1100 }
1101
1102 pub fn typeOf(self: Index, builder: *const Builder) Type {
1103 return self.ptrConst(builder).type;
1104 }
1105
1106 pub fn toConst(self: Index) Constant {
1107 return @enumFromInt(@intFromEnum(Constant.first_global) + @intFromEnum(self));
1108 }
1109
1110 pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {
1111 assert(builder.useLibLlvm());
1112 return builder.llvm.globals.items[@intFromEnum(self.unwrap(builder))];
1113 }
1114
1115 const FormatData = struct {
1116 global: Index,
1117 builder: *const Builder,
1118 };
1119 fn format(
1120 data: FormatData,
1121 comptime _: []const u8,
1122 _: std.fmt.FormatOptions,
1123 writer: anytype,
1124 ) @TypeOf(writer).Error!void {
1125 try writer.print("@{}", .{
1126 data.global.unwrap(data.builder).name(data.builder).fmt(data.builder),
1127 });
1128 }
1129 pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(format) {
1130 return .{ .data = .{ .global = self, .builder = builder } };
1131 }
1132
1133 pub fn rename(self: Index, new_name: String, builder: *Builder) Allocator.Error!void {
1134 try builder.ensureUnusedGlobalCapacity(new_name);
1135 self.renameAssumeCapacity(new_name, builder);
1136 }
1137
1138 pub fn takeName(self: Index, other: Index, builder: *Builder) Allocator.Error!void {
1139 try builder.ensureUnusedGlobalCapacity(.empty);
1140 self.takeNameAssumeCapacity(other, builder);
1141 }
1142
1143 pub fn replace(self: Index, other: Index, builder: *Builder) Allocator.Error!void {
1144 try builder.ensureUnusedGlobalCapacity(.empty);
1145 self.replaceAssumeCapacity(other, builder);
1146 }
1147
1148 fn renameAssumeCapacity(self: Index, new_name: String, builder: *Builder) void {
1149 const old_name = self.name(builder);
1150 if (new_name == old_name) return;
1151 const index = @intFromEnum(self.unwrap(builder));
1152 if (builder.useLibLlvm())
1153 builder.llvm.globals.appendAssumeCapacity(builder.llvm.globals.items[index]);
1154 _ = builder.addGlobalAssumeCapacity(new_name, builder.globals.values()[index]);
1155 if (builder.useLibLlvm()) _ = builder.llvm.globals.pop();
1156 builder.globals.swapRemoveAt(index);
1157 self.updateName(builder);
1158 if (!old_name.isAnon()) return;
1159 builder.next_unnamed_global = @enumFromInt(@intFromEnum(builder.next_unnamed_global) - 1);
1160 if (builder.next_unnamed_global == old_name) return;
1161 builder.getGlobal(builder.next_unnamed_global).?.renameAssumeCapacity(old_name, builder);
1162 }
1163
1164 fn takeNameAssumeCapacity(self: Index, other: Index, builder: *Builder) void {
1165 const other_name = other.name(builder);
1166 other.renameAssumeCapacity(.empty, builder);
1167 self.renameAssumeCapacity(other_name, builder);
1168 }
1169
1170 fn updateName(self: Index, builder: *const Builder) void {
1171 if (!builder.useLibLlvm()) return;
1172 const index = @intFromEnum(self.unwrap(builder));
1173 const name_slice = self.name(builder).toSlice(builder) orelse "";
1174 builder.llvm.globals.items[index].setValueName2(name_slice.ptr, name_slice.len);
1175 }
1176
1177 fn replaceAssumeCapacity(self: Index, other: Index, builder: *Builder) void {
1178 if (self.eql(other, builder)) return;
1179 builder.next_replaced_global = @enumFromInt(@intFromEnum(builder.next_replaced_global) - 1);
1180 self.renameAssumeCapacity(builder.next_replaced_global, builder);
1181 if (builder.useLibLlvm()) {
1182 const self_llvm = self.toLlvm(builder);
1183 self_llvm.replaceAllUsesWith(other.toLlvm(builder));
1184 switch (self.ptr(builder).kind) {
1185 .alias,
1186 .variable,
1187 => self_llvm.deleteGlobal(),
1188 .function => self_llvm.deleteFunction(),
1189 .replaced => unreachable,
1190 }
1191 }
1192 self.ptr(builder).kind = .{ .replaced = other.unwrap(builder) };
1193 }
1194
1195 fn getReplacement(self: Index, builder: *const Builder) Index {
1196 return switch (builder.globals.values()[@intFromEnum(self)].kind) {
1197 .replaced => |replacement| replacement,
1198 else => .none,
1199 };
1200 }
1201 };
1202
1203 pub fn updateAttributes(self: *Global) void {
1204 switch (self.linkage) {
1205 .private, .internal => {
1206 self.visibility = .default;
1207 self.dll_storage_class = .default;
1208 self.preemption = .implicit_dso_local;
1209 },
1210 .extern_weak => if (self.preemption == .implicit_dso_local) {
1211 self.preemption = .dso_local;
1212 },
1213 else => switch (self.visibility) {
1214 .default => if (self.preemption == .implicit_dso_local) {
1215 self.preemption = .dso_local;
1216 },
1217 else => self.preemption = .implicit_dso_local,
1218 },
1219 }
1220 }
1221};
1222
1223pub const Alias = struct {
1224 global: Global.Index,
1225 thread_local: ThreadLocal = .default,
1226 init: Constant = .no_init,
1227
1228 pub const Index = enum(u32) {
1229 none = std.math.maxInt(u32),
1230 _,
1231
1232 pub fn getAliasee(self: Index, builder: *const Builder) Global.Index {
1233 const aliasee = self.ptrConst(builder).init.getBase(builder);
1234 assert(aliasee != .none);
1235 return aliasee;
1236 }
1237
1238 pub fn ptr(self: Index, builder: *Builder) *Alias {
1239 return &builder.aliases.items[@intFromEnum(self)];
1240 }
1241
1242 pub fn ptrConst(self: Index, builder: *const Builder) *const Alias {
1243 return &builder.aliases.items[@intFromEnum(self)];
1244 }
1245
1246 pub fn typeOf(self: Index, builder: *const Builder) Type {
1247 return self.ptrConst(builder).global.typeOf(builder);
1248 }
1249
1250 pub fn toConst(self: Index, builder: *const Builder) Constant {
1251 return self.ptrConst(builder).global.toConst();
1252 }
1253
1254 pub fn toValue(self: Index, builder: *const Builder) Value {
1255 return self.toConst(builder).toValue();
1256 }
1257
1258 pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {
1259 return self.ptrConst(builder).global.toLlvm(builder);
1260 }
1261 };
1262};
1263
1264pub const Variable = struct {
1265 global: Global.Index,
1266 thread_local: ThreadLocal = .default,
1267 mutability: enum { global, constant } = .global,
1268 init: Constant = .no_init,
1269 section: String = .none,
1270 alignment: Alignment = .default,
1271
1272 pub const Index = enum(u32) {
1273 none = std.math.maxInt(u32),
1274 _,
1275
1276 pub fn ptr(self: Index, builder: *Builder) *Variable {
1277 return &builder.variables.items[@intFromEnum(self)];
1278 }
1279
1280 pub fn ptrConst(self: Index, builder: *const Builder) *const Variable {
1281 return &builder.variables.items[@intFromEnum(self)];
1282 }
1283
1284 pub fn typeOf(self: Index, builder: *const Builder) Type {
1285 return self.ptrConst(builder).global.typeOf(builder);
1286 }
1287
1288 pub fn toConst(self: Index, builder: *const Builder) Constant {
1289 return self.ptrConst(builder).global.toConst();
1290 }
1291
1292 pub fn toValue(self: Index, builder: *const Builder) Value {
1293 return self.toConst(builder).toValue();
1294 }
1295
1296 pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {
1297 return self.ptrConst(builder).global.toLlvm(builder);
1298 }
1299 };
1300};
1301
1302pub const Function = struct {
1303 global: Global.Index,
1304 section: String = .none,
1305 alignment: Alignment = .default,
1306 blocks: []const Block = &.{},
1307 instructions: std.MultiArrayList(Instruction) = .{},
1308 names: [*]const String = &[0]String{},
1309 metadata: ?[*]const Metadata = null,
1310 extra: []const u32 = &.{},
1311
1312 pub const Index = enum(u32) {
1313 none = std.math.maxInt(u32),
1314 _,
1315
1316 pub fn ptr(self: Index, builder: *Builder) *Function {
1317 return &builder.functions.items[@intFromEnum(self)];
1318 }
1319
1320 pub fn ptrConst(self: Index, builder: *const Builder) *const Function {
1321 return &builder.functions.items[@intFromEnum(self)];
1322 }
1323
1324 pub fn typeOf(self: Index, builder: *const Builder) Type {
1325 return self.ptrConst(builder).global.typeOf(builder);
1326 }
1327
1328 pub fn toConst(self: Index, builder: *const Builder) Constant {
1329 return self.ptrConst(builder).global.toConst();
1330 }
1331
1332 pub fn toValue(self: Index, builder: *const Builder) Value {
1333 return self.toConst(builder).toValue();
1334 }
1335
1336 pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {
1337 return self.ptrConst(builder).global.toLlvm(builder);
1338 }
1339 };
1340
1341 pub const Block = struct {
1342 instruction: Instruction.Index,
1343
1344 pub const Index = WipFunction.Block.Index;
1345 };
1346
1347 pub const Instruction = struct {
1348 tag: Tag,
1349 data: u32,
1350
1351 pub const Tag = enum(u8) {
1352 add,
1353 @"add nsw",
1354 @"add nuw",
1355 @"add nuw nsw",
1356 addrspacecast,
1357 alloca,
1358 @"alloca inalloca",
1359 @"and",
1360 arg,
1361 ashr,
1362 @"ashr exact",
1363 bitcast,
1364 block,
1365 br,
1366 br_cond,
1367 extractelement,
1368 extractvalue,
1369 fadd,
1370 @"fadd fast",
1371 @"fcmp false",
1372 @"fcmp fast false",
1373 @"fcmp fast oeq",
1374 @"fcmp fast oge",
1375 @"fcmp fast ogt",
1376 @"fcmp fast ole",
1377 @"fcmp fast olt",
1378 @"fcmp fast one",
1379 @"fcmp fast ord",
1380 @"fcmp fast true",
1381 @"fcmp fast ueq",
1382 @"fcmp fast uge",
1383 @"fcmp fast ugt",
1384 @"fcmp fast ule",
1385 @"fcmp fast ult",
1386 @"fcmp fast une",
1387 @"fcmp fast uno",
1388 @"fcmp oeq",
1389 @"fcmp oge",
1390 @"fcmp ogt",
1391 @"fcmp ole",
1392 @"fcmp olt",
1393 @"fcmp one",
1394 @"fcmp ord",
1395 @"fcmp true",
1396 @"fcmp ueq",
1397 @"fcmp uge",
1398 @"fcmp ugt",
1399 @"fcmp ule",
1400 @"fcmp ult",
1401 @"fcmp une",
1402 @"fcmp uno",
1403 fdiv,
1404 @"fdiv fast",
1405 fence,
1406 fmul,
1407 @"fmul fast",
1408 fneg,
1409 @"fneg fast",
1410 fpext,
1411 fptosi,
1412 fptoui,
1413 fptrunc,
1414 frem,
1415 @"frem fast",
1416 fsub,
1417 @"fsub fast",
1418 getelementptr,
1419 @"getelementptr inbounds",
1420 @"icmp eq",
1421 @"icmp ne",
1422 @"icmp sge",
1423 @"icmp sgt",
1424 @"icmp sle",
1425 @"icmp slt",
1426 @"icmp uge",
1427 @"icmp ugt",
1428 @"icmp ule",
1429 @"icmp ult",
1430 insertelement,
1431 insertvalue,
1432 inttoptr,
1433 @"llvm.maxnum.",
1434 @"llvm.minnum.",
1435 @"llvm.sadd.sat.",
1436 @"llvm.smax.",
1437 @"llvm.smin.",
1438 @"llvm.smul.fix.sat.",
1439 @"llvm.sshl.sat.",
1440 @"llvm.ssub.sat.",
1441 @"llvm.uadd.sat.",
1442 @"llvm.umax.",
1443 @"llvm.umin.",
1444 @"llvm.umul.fix.sat.",
1445 @"llvm.ushl.sat.",
1446 @"llvm.usub.sat.",
1447 load,
1448 @"load atomic",
1449 @"load atomic volatile",
1450 @"load volatile",
1451 lshr,
1452 @"lshr exact",
1453 mul,
1454 @"mul nsw",
1455 @"mul nuw",
1456 @"mul nuw nsw",
1457 @"or",
1458 phi,
1459 @"phi fast",
1460 ptrtoint,
1461 ret,
1462 @"ret void",
1463 sdiv,
1464 @"sdiv exact",
1465 select,
1466 @"select fast",
1467 sext,
1468 shl,
1469 @"shl nsw",
1470 @"shl nuw",
1471 @"shl nuw nsw",
1472 shufflevector,
1473 sitofp,
1474 srem,
1475 store,
1476 @"store atomic",
1477 @"store atomic volatile",
1478 @"store volatile",
1479 sub,
1480 @"sub nsw",
1481 @"sub nuw",
1482 @"sub nuw nsw",
1483 @"switch",
1484 trunc,
1485 udiv,
1486 @"udiv exact",
1487 urem,
1488 uitofp,
1489 unimplemented,
1490 @"unreachable",
1491 va_arg,
1492 xor,
1493 zext,
1494 };
1495
1496 pub const Index = enum(u32) {
1497 none = std.math.maxInt(u31),
1498 _,
1499
1500 pub fn name(self: Instruction.Index, function: *const Function) String {
1501 return function.names[@intFromEnum(self)];
1502 }
1503
1504 pub fn toValue(self: Instruction.Index) Value {
1505 return @enumFromInt(@intFromEnum(self));
1506 }
1507
1508 pub fn isTerminatorWip(self: Instruction.Index, wip: *const WipFunction) bool {
1509 return switch (wip.instructions.items(.tag)[@intFromEnum(self)]) {
1510 .br,
1511 .br_cond,
1512 .ret,
1513 .@"ret void",
1514 .@"unreachable",
1515 => true,
1516 else => false,
1517 };
1518 }
1519
1520 pub fn hasResultWip(self: Instruction.Index, wip: *const WipFunction) bool {
1521 return switch (wip.instructions.items(.tag)[@intFromEnum(self)]) {
1522 .br,
1523 .br_cond,
1524 .fence,
1525 .ret,
1526 .@"ret void",
1527 .store,
1528 .@"store atomic",
1529 .@"store atomic volatile",
1530 .@"store volatile",
1531 .@"unreachable",
1532 => false,
1533 else => true,
1534 };
1535 }
1536
1537 pub fn typeOfWip(self: Instruction.Index, wip: *const WipFunction) Type {
1538 const instruction = wip.instructions.get(@intFromEnum(self));
1539 return switch (instruction.tag) {
1540 .add,
1541 .@"add nsw",
1542 .@"add nuw",
1543 .@"add nuw nsw",
1544 .@"and",
1545 .ashr,
1546 .@"ashr exact",
1547 .fadd,
1548 .@"fadd fast",
1549 .fdiv,
1550 .@"fdiv fast",
1551 .fmul,
1552 .@"fmul fast",
1553 .frem,
1554 .@"frem fast",
1555 .fsub,
1556 .@"fsub fast",
1557 .@"llvm.maxnum.",
1558 .@"llvm.minnum.",
1559 .@"llvm.sadd.sat.",
1560 .@"llvm.smax.",
1561 .@"llvm.smin.",
1562 .@"llvm.smul.fix.sat.",
1563 .@"llvm.sshl.sat.",
1564 .@"llvm.ssub.sat.",
1565 .@"llvm.uadd.sat.",
1566 .@"llvm.umax.",
1567 .@"llvm.umin.",
1568 .@"llvm.umul.fix.sat.",
1569 .@"llvm.ushl.sat.",
1570 .@"llvm.usub.sat.",
1571 .lshr,
1572 .@"lshr exact",
1573 .mul,
1574 .@"mul nsw",
1575 .@"mul nuw",
1576 .@"mul nuw nsw",
1577 .@"or",
1578 .sdiv,
1579 .@"sdiv exact",
1580 .shl,
1581 .@"shl nsw",
1582 .@"shl nuw",
1583 .@"shl nuw nsw",
1584 .srem,
1585 .sub,
1586 .@"sub nsw",
1587 .@"sub nuw",
1588 .@"sub nuw nsw",
1589 .udiv,
1590 .@"udiv exact",
1591 .urem,
1592 .xor,
1593 => wip.extraData(Binary, instruction.data).lhs.typeOfWip(wip),
1594 .addrspacecast,
1595 .bitcast,
1596 .fpext,
1597 .fptosi,
1598 .fptoui,
1599 .fptrunc,
1600 .inttoptr,
1601 .ptrtoint,
1602 .sext,
1603 .sitofp,
1604 .trunc,
1605 .uitofp,
1606 .zext,
1607 => wip.extraData(Cast, instruction.data).type,
1608 .alloca,
1609 .@"alloca inalloca",
1610 => wip.builder.ptrTypeAssumeCapacity(
1611 wip.extraData(Alloca, instruction.data).info.addr_space,
1612 ),
1613 .arg => wip.function.typeOf(wip.builder)
1614 .functionParameters(wip.builder)[instruction.data],
1615 .block => .label,
1616 .br,
1617 .br_cond,
1618 .fence,
1619 .ret,
1620 .@"ret void",
1621 .store,
1622 .@"store atomic",
1623 .@"store atomic volatile",
1624 .@"store volatile",
1625 .@"switch",
1626 .@"unreachable",
1627 => .none,
1628 .extractelement => wip.extraData(ExtractElement, instruction.data)
1629 .val.typeOfWip(wip).childType(wip.builder),
1630 .extractvalue => {
1631 var extra = wip.extraDataTrail(ExtractValue, instruction.data);
1632 const indices = extra.trail.next(extra.data.indices_len, u32, wip);
1633 return extra.data.val.typeOfWip(wip).childTypeAt(indices, wip.builder);
1634 },
1635 .@"fcmp false",
1636 .@"fcmp fast false",
1637 .@"fcmp fast oeq",
1638 .@"fcmp fast oge",
1639 .@"fcmp fast ogt",
1640 .@"fcmp fast ole",
1641 .@"fcmp fast olt",
1642 .@"fcmp fast one",
1643 .@"fcmp fast ord",
1644 .@"fcmp fast true",
1645 .@"fcmp fast ueq",
1646 .@"fcmp fast uge",
1647 .@"fcmp fast ugt",
1648 .@"fcmp fast ule",
1649 .@"fcmp fast ult",
1650 .@"fcmp fast une",
1651 .@"fcmp fast uno",
1652 .@"fcmp oeq",
1653 .@"fcmp oge",
1654 .@"fcmp ogt",
1655 .@"fcmp ole",
1656 .@"fcmp olt",
1657 .@"fcmp one",
1658 .@"fcmp ord",
1659 .@"fcmp true",
1660 .@"fcmp ueq",
1661 .@"fcmp uge",
1662 .@"fcmp ugt",
1663 .@"fcmp ule",
1664 .@"fcmp ult",
1665 .@"fcmp une",
1666 .@"fcmp uno",
1667 .@"icmp eq",
1668 .@"icmp ne",
1669 .@"icmp sge",
1670 .@"icmp sgt",
1671 .@"icmp sle",
1672 .@"icmp slt",
1673 .@"icmp uge",
1674 .@"icmp ugt",
1675 .@"icmp ule",
1676 .@"icmp ult",
1677 => wip.extraData(Binary, instruction.data).lhs.typeOfWip(wip)
1678 .changeScalarAssumeCapacity(.i1, wip.builder),
1679 .fneg,
1680 .@"fneg fast",
1681 => @as(Value, @enumFromInt(instruction.data)).typeOfWip(wip),
1682 .getelementptr,
1683 .@"getelementptr inbounds",
1684 => {
1685 var extra = wip.extraDataTrail(GetElementPtr, instruction.data);
1686 const indices = extra.trail.next(extra.data.indices_len, Value, wip);
1687 const base_ty = extra.data.base.typeOfWip(wip);
1688 if (!base_ty.isVector(wip.builder)) for (indices) |index| {
1689 const index_ty = index.typeOfWip(wip);
1690 if (!index_ty.isVector(wip.builder)) continue;
1691 return index_ty.changeScalarAssumeCapacity(base_ty, wip.builder);
1692 };
1693 return base_ty;
1694 },
1695 .insertelement => wip.extraData(InsertElement, instruction.data).val.typeOfWip(wip),
1696 .insertvalue => wip.extraData(InsertValue, instruction.data).val.typeOfWip(wip),
1697 .load,
1698 .@"load atomic",
1699 .@"load atomic volatile",
1700 .@"load volatile",
1701 => wip.extraData(Load, instruction.data).type,
1702 .phi,
1703 .@"phi fast",
1704 => wip.extraData(Phi, instruction.data).type,
1705 .select,
1706 .@"select fast",
1707 => wip.extraData(Select, instruction.data).lhs.typeOfWip(wip),
1708 .shufflevector => {
1709 const extra = wip.extraData(ShuffleVector, instruction.data);
1710 return extra.lhs.typeOfWip(wip).changeLengthAssumeCapacity(
1711 extra.mask.typeOfWip(wip).vectorLen(wip.builder),
1712 wip.builder,
1713 );
1714 },
1715 .unimplemented => @enumFromInt(instruction.data),
1716 .va_arg => wip.extraData(VaArg, instruction.data).type,
1717 };
1718 }
1719
1720 pub fn typeOf(
1721 self: Instruction.Index,
1722 function_index: Function.Index,
1723 builder: *Builder,
1724 ) Type {
1725 const function = function_index.ptrConst(builder);
1726 const instruction = function.instructions.get(@intFromEnum(self));
1727 return switch (instruction.tag) {
1728 .add,
1729 .@"add nsw",
1730 .@"add nuw",
1731 .@"add nuw nsw",
1732 .@"and",
1733 .ashr,
1734 .@"ashr exact",
1735 .fadd,
1736 .@"fadd fast",
1737 .fdiv,
1738 .@"fdiv fast",
1739 .fmul,
1740 .@"fmul fast",
1741 .frem,
1742 .@"frem fast",
1743 .fsub,
1744 .@"fsub fast",
1745 .@"llvm.maxnum.",
1746 .@"llvm.minnum.",
1747 .@"llvm.sadd.sat.",
1748 .@"llvm.smax.",
1749 .@"llvm.smin.",
1750 .@"llvm.smul.fix.sat.",
1751 .@"llvm.sshl.sat.",
1752 .@"llvm.ssub.sat.",
1753 .@"llvm.uadd.sat.",
1754 .@"llvm.umax.",
1755 .@"llvm.umin.",
1756 .@"llvm.umul.fix.sat.",
1757 .@"llvm.ushl.sat.",
1758 .@"llvm.usub.sat.",
1759 .lshr,
1760 .@"lshr exact",
1761 .mul,
1762 .@"mul nsw",
1763 .@"mul nuw",
1764 .@"mul nuw nsw",
1765 .@"or",
1766 .sdiv,
1767 .@"sdiv exact",
1768 .shl,
1769 .@"shl nsw",
1770 .@"shl nuw",
1771 .@"shl nuw nsw",
1772 .srem,
1773 .sub,
1774 .@"sub nsw",
1775 .@"sub nuw",
1776 .@"sub nuw nsw",
1777 .udiv,
1778 .@"udiv exact",
1779 .urem,
1780 .xor,
1781 => function.extraData(Binary, instruction.data).lhs.typeOf(function_index, builder),
1782 .addrspacecast,
1783 .bitcast,
1784 .fpext,
1785 .fptosi,
1786 .fptoui,
1787 .fptrunc,
1788 .inttoptr,
1789 .ptrtoint,
1790 .sext,
1791 .sitofp,
1792 .trunc,
1793 .uitofp,
1794 .zext,
1795 => function.extraData(Cast, instruction.data).type,
1796 .alloca,
1797 .@"alloca inalloca",
1798 => builder.ptrTypeAssumeCapacity(
1799 function.extraData(Alloca, instruction.data).info.addr_space,
1800 ),
1801 .arg => function.global.typeOf(builder)
1802 .functionParameters(builder)[instruction.data],
1803 .block => .label,
1804 .br,
1805 .br_cond,
1806 .fence,
1807 .ret,
1808 .@"ret void",
1809 .store,
1810 .@"store atomic",
1811 .@"store atomic volatile",
1812 .@"store volatile",
1813 .@"switch",
1814 .@"unreachable",
1815 => .none,
1816 .extractelement => function.extraData(ExtractElement, instruction.data)
1817 .val.typeOf(function_index, builder).childType(builder),
1818 .extractvalue => {
1819 var extra = function.extraDataTrail(ExtractValue, instruction.data);
1820 const indices = extra.trail.next(extra.data.indices_len, u32, function);
1821 return extra.data.val.typeOf(function_index, builder)
1822 .childTypeAt(indices, builder);
1823 },
1824 .@"fcmp false",
1825 .@"fcmp fast false",
1826 .@"fcmp fast oeq",
1827 .@"fcmp fast oge",
1828 .@"fcmp fast ogt",
1829 .@"fcmp fast ole",
1830 .@"fcmp fast olt",
1831 .@"fcmp fast one",
1832 .@"fcmp fast ord",
1833 .@"fcmp fast true",
1834 .@"fcmp fast ueq",
1835 .@"fcmp fast uge",
1836 .@"fcmp fast ugt",
1837 .@"fcmp fast ule",
1838 .@"fcmp fast ult",
1839 .@"fcmp fast une",
1840 .@"fcmp fast uno",
1841 .@"fcmp oeq",
1842 .@"fcmp oge",
1843 .@"fcmp ogt",
1844 .@"fcmp ole",
1845 .@"fcmp olt",
1846 .@"fcmp one",
1847 .@"fcmp ord",
1848 .@"fcmp true",
1849 .@"fcmp ueq",
1850 .@"fcmp uge",
1851 .@"fcmp ugt",
1852 .@"fcmp ule",
1853 .@"fcmp ult",
1854 .@"fcmp une",
1855 .@"fcmp uno",
1856 .@"icmp eq",
1857 .@"icmp ne",
1858 .@"icmp sge",
1859 .@"icmp sgt",
1860 .@"icmp sle",
1861 .@"icmp slt",
1862 .@"icmp uge",
1863 .@"icmp ugt",
1864 .@"icmp ule",
1865 .@"icmp ult",
1866 => function.extraData(Binary, instruction.data).lhs.typeOf(function_index, builder)
1867 .changeScalarAssumeCapacity(.i1, builder),
1868 .fneg,
1869 .@"fneg fast",
1870 => @as(Value, @enumFromInt(instruction.data)).typeOf(function_index, builder),
1871 .getelementptr,
1872 .@"getelementptr inbounds",
1873 => {
1874 var extra = function.extraDataTrail(GetElementPtr, instruction.data);
1875 const indices = extra.trail.next(extra.data.indices_len, Value, function);
1876 const base_ty = extra.data.base.typeOf(function_index, builder);
1877 if (!base_ty.isVector(builder)) for (indices) |index| {
1878 const index_ty = index.typeOf(function_index, builder);
1879 if (!index_ty.isVector(builder)) continue;
1880 return index_ty.changeScalarAssumeCapacity(base_ty, builder);
1881 };
1882 return base_ty;
1883 },
1884 .insertelement => function.extraData(InsertElement, instruction.data)
1885 .val.typeOf(function_index, builder),
1886 .insertvalue => function.extraData(InsertValue, instruction.data)
1887 .val.typeOf(function_index, builder),
1888 .load,
1889 .@"load atomic",
1890 .@"load atomic volatile",
1891 .@"load volatile",
1892 => function.extraData(Load, instruction.data).type,
1893 .phi,
1894 .@"phi fast",
1895 => function.extraData(Phi, instruction.data).type,
1896 .select,
1897 .@"select fast",
1898 => function.extraData(Select, instruction.data).lhs.typeOf(function_index, builder),
1899 .shufflevector => {
1900 const extra = function.extraData(ShuffleVector, instruction.data);
1901 return extra.lhs.typeOf(function_index, builder).changeLengthAssumeCapacity(
1902 extra.mask.typeOf(function_index, builder).vectorLen(builder),
1903 builder,
1904 );
1905 },
1906 .unimplemented => @enumFromInt(instruction.data),
1907 .va_arg => function.extraData(VaArg, instruction.data).type,
1908 };
1909 }
1910
1911 const FormatData = struct {
1912 instruction: Instruction.Index,
1913 function: Function.Index,
1914 builder: *Builder,
1915 };
1916 fn format(
1917 data: FormatData,
1918 comptime fmt_str: []const u8,
1919 _: std.fmt.FormatOptions,
1920 writer: anytype,
1921 ) @TypeOf(writer).Error!void {
1922 if (comptime std.mem.indexOfNone(u8, fmt_str, ", %")) |_|
1923 @compileError("invalid format string: '" ++ fmt_str ++ "'");
1924 if (comptime std.mem.indexOfScalar(u8, fmt_str, ',') != null) {
1925 if (data.instruction == .none) return;
1926 try writer.writeByte(',');
1927 }
1928 if (comptime std.mem.indexOfScalar(u8, fmt_str, ' ') != null) {
1929 if (data.instruction == .none) return;
1930 try writer.writeByte(' ');
1931 }
1932 if (comptime std.mem.indexOfScalar(u8, fmt_str, '%') != null) try writer.print(
1933 "{%} ",
1934 .{data.instruction.typeOf(data.function, data.builder).fmt(data.builder)},
1935 );
1936 assert(data.instruction != .none);
1937 try writer.print("%{}", .{
1938 data.instruction.name(data.function.ptrConst(data.builder)).fmt(data.builder),
1939 });
1940 }
1941 pub fn fmt(
1942 self: Instruction.Index,
1943 function: Function.Index,
1944 builder: *Builder,
1945 ) std.fmt.Formatter(format) {
1946 return .{ .data = .{ .instruction = self, .function = function, .builder = builder } };
1947 }
1948
1949 pub fn toLlvm(self: Instruction.Index, wip: *const WipFunction) *llvm.Value {
1950 assert(wip.builder.useLibLlvm());
1951 return wip.llvm.instructions.items[@intFromEnum(self)];
1952 }
1953
1954 fn llvmName(self: Instruction.Index, wip: *const WipFunction) [*:0]const u8 {
1955 return if (wip.builder.strip)
1956 ""
1957 else
1958 wip.names.items[@intFromEnum(self)].toSlice(wip.builder).?;
1959 }
1960 };
1961
1962 pub const ExtraIndex = u32;
1963
1964 pub const BrCond = struct {
1965 cond: Value,
1966 then: Block.Index,
1967 @"else": Block.Index,
1968 };
1969
1970 pub const Switch = struct {
1971 val: Value,
1972 default: Block.Index,
1973 cases_len: u32,
1974 //case_vals: [cases_len]Constant,
1975 //case_blocks: [cases_len]Block.Index,
1976 };
1977
1978 pub const Binary = struct {
1979 lhs: Value,
1980 rhs: Value,
1981 };
1982
1983 pub const ExtractElement = struct {
1984 val: Value,
1985 index: Value,
1986 };
1987
1988 pub const InsertElement = struct {
1989 val: Value,
1990 elem: Value,
1991 index: Value,
1992 };
1993
1994 pub const ShuffleVector = struct {
1995 lhs: Value,
1996 rhs: Value,
1997 mask: Value,
1998 };
1999
2000 pub const ExtractValue = struct {
2001 val: Value,
2002 indices_len: u32,
2003 //indices: [indices_len]u32,
2004 };
2005
2006 pub const InsertValue = struct {
2007 val: Value,
2008 elem: Value,
2009 indices_len: u32,
2010 //indices: [indices_len]u32,
2011 };
2012
2013 pub const Alloca = struct {
2014 type: Type,
2015 len: Value,
2016 info: Info,
2017
2018 pub const Kind = enum { normal, inalloca };
2019 pub const Info = packed struct(u32) {
2020 alignment: Alignment,
2021 addr_space: AddrSpace,
2022 _: u2 = undefined,
2023 };
2024 };
2025
2026 pub const Load = struct {
2027 type: Type,
2028 ptr: Value,
2029 info: MemoryAccessInfo,
2030 };
2031
2032 pub const Store = struct {
2033 val: Value,
2034 ptr: Value,
2035 info: MemoryAccessInfo,
2036 };
2037
2038 pub const GetElementPtr = struct {
2039 type: Type,
2040 base: Value,
2041 indices_len: u32,
2042 //indices: [indices_len]Value,
2043
2044 pub const Kind = Constant.GetElementPtr.Kind;
2045 };
2046
2047 pub const Cast = struct {
2048 val: Value,
2049 type: Type,
2050
2051 pub const Signedness = Constant.Cast.Signedness;
2052 };
2053
2054 pub const Phi = struct {
2055 type: Type,
2056 //incoming_vals: [block.incoming]Value,
2057 //incoming_blocks: [block.incoming]Block.Index,
2058 };
2059
2060 pub const Select = struct {
2061 cond: Value,
2062 lhs: Value,
2063 rhs: Value,
2064 };
2065
2066 pub const VaArg = struct {
2067 list: Value,
2068 type: Type,
2069 };
2070 };
2071
2072 pub fn deinit(self: *Function, gpa: Allocator) void {
2073 gpa.free(self.extra);
2074 if (self.metadata) |metadata| gpa.free(metadata[0..self.instructions.len]);
2075 gpa.free(self.names[0..self.instructions.len]);
2076 self.instructions.deinit(gpa);
2077 self.* = undefined;
2078 }
2079
2080 pub fn arg(self: *const Function, index: u32) Value {
2081 const argument = self.instructions.get(index);
2082 assert(argument.tag == .arg);
2083 assert(argument.data == index);
2084
2085 const argument_index: Instruction.Index = @enumFromInt(index);
2086 return argument_index.toValue();
2087 }
2088
2089 const ExtraDataTrail = struct {
2090 index: Instruction.ExtraIndex,
2091
2092 fn nextMut(self: *ExtraDataTrail, len: u32, comptime Item: type, function: *Function) []Item {
2093 const items: []Item = @ptrCast(function.extra[self.index..][0..len]);
2094 self.index += @intCast(len);
2095 return items;
2096 }
2097
2098 fn next(
2099 self: *ExtraDataTrail,
2100 len: u32,
2101 comptime Item: type,
2102 function: *const Function,
2103 ) []const Item {
2104 const items: []const Item = @ptrCast(function.extra[self.index..][0..len]);
2105 self.index += @intCast(len);
2106 return items;
2107 }
2108 };
2109
2110 fn extraDataTrail(
2111 self: *const Function,
2112 comptime T: type,
2113 index: Instruction.ExtraIndex,
2114 ) struct { data: T, trail: ExtraDataTrail } {
2115 var result: T = undefined;
2116 const fields = @typeInfo(T).Struct.fields;
2117 inline for (fields, self.extra[index..][0..fields.len]) |field, value|
2118 @field(result, field.name) = switch (field.type) {
2119 u32 => value,
2120 Alignment, AtomicOrdering, Block.Index, Type, Value => @enumFromInt(value),
2121 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),
2122 else => @compileError("bad field type: " ++ @typeName(field.type)),
2123 };
2124 return .{
2125 .data = result,
2126 .trail = .{ .index = index + @as(Type.Item.ExtraIndex, @intCast(fields.len)) },
2127 };
2128 }
2129
2130 fn extraData(self: *const Function, comptime T: type, index: Instruction.ExtraIndex) T {
2131 return self.extraDataTrail(T, index).data;
2132 }
2133};
2134
2135pub const WipFunction = struct {
2136 builder: *Builder,
2137 function: Function.Index,
2138 llvm: if (build_options.have_llvm) struct {
2139 builder: *llvm.Builder,
2140 blocks: std.ArrayListUnmanaged(*llvm.BasicBlock),
2141 instructions: std.ArrayListUnmanaged(*llvm.Value),
2142 } else void,
2143 cursor: Cursor,
2144 blocks: std.ArrayListUnmanaged(Block),
2145 instructions: std.MultiArrayList(Instruction),
2146 names: std.ArrayListUnmanaged(String),
2147 metadata: std.ArrayListUnmanaged(Metadata),
2148 extra: std.ArrayListUnmanaged(u32),
2149
2150 pub const Cursor = struct { block: Block.Index, instruction: u32 = 0 };
2151
2152 pub const Block = struct {
2153 name: String,
2154 incoming: u32,
2155 branches: u32 = 0,
2156 instructions: std.ArrayListUnmanaged(Instruction.Index),
2157
2158 const Index = enum(u32) {
2159 entry,
2160 _,
2161
2162 pub fn ptr(self: Index, wip: *WipFunction) *Block {
2163 return &wip.blocks.items[@intFromEnum(self)];
2164 }
2165
2166 pub fn ptrConst(self: Index, wip: *const WipFunction) *const Block {
2167 return &wip.blocks.items[@intFromEnum(self)];
2168 }
2169
2170 pub fn toInst(self: Index, function: *const Function) Instruction.Index {
2171 return function.blocks[@intFromEnum(self)].instruction;
2172 }
2173
2174 pub fn toLlvm(self: Index, wip: *const WipFunction) *llvm.BasicBlock {
2175 assert(wip.builder.useLibLlvm());
2176 return wip.llvm.blocks.items[@intFromEnum(self)];
2177 }
2178 };
2179 };
2180
2181 pub const Instruction = Function.Instruction;
2182
2183 pub fn init(builder: *Builder, function: Function.Index) Allocator.Error!WipFunction {
2184 if (builder.useLibLlvm()) {
2185 const llvm_function = function.toLlvm(builder);
2186 while (llvm_function.getFirstBasicBlock()) |bb| bb.deleteBasicBlock();
2187 }
2188
2189 var self = WipFunction{
2190 .builder = builder,
2191 .function = function,
2192 .llvm = if (builder.useLibLlvm()) .{
2193 .builder = builder.llvm.context.createBuilder(),
2194 .blocks = .{},
2195 .instructions = .{},
2196 } else undefined,
2197 .cursor = undefined,
2198 .blocks = .{},
2199 .instructions = .{},
2200 .names = .{},
2201 .metadata = .{},
2202 .extra = .{},
2203 };
2204 errdefer self.deinit();
2205
2206 const params_len = function.typeOf(self.builder).functionParameters(self.builder).len;
2207 try self.ensureUnusedExtraCapacity(params_len, NoExtra, 0);
2208 try self.instructions.ensureUnusedCapacity(self.builder.gpa, params_len);
2209 if (!self.builder.strip) try self.names.ensureUnusedCapacity(self.builder.gpa, params_len);
2210 if (self.builder.useLibLlvm())
2211 try self.llvm.instructions.ensureUnusedCapacity(self.builder.gpa, params_len);
2212 for (0..params_len) |param_index| {
2213 self.instructions.appendAssumeCapacity(.{ .tag = .arg, .data = @intCast(param_index) });
2214 if (!self.builder.strip) self.names.appendAssumeCapacity(.empty); // TODO: param names
2215 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
2216 function.toLlvm(self.builder).getParam(@intCast(param_index)),
2217 );
2218 }
2219
2220 return self;
2221 }
2222
2223 pub fn arg(self: *const WipFunction, index: u32) Value {
2224 const argument = self.instructions.get(index);
2225 assert(argument.tag == .arg);
2226 assert(argument.data == index);
2227
2228 const argument_index: Instruction.Index = @enumFromInt(index);
2229 return argument_index.toValue();
2230 }
2231
2232 pub fn block(self: *WipFunction, incoming: u32, name: []const u8) Allocator.Error!Block.Index {
2233 try self.blocks.ensureUnusedCapacity(self.builder.gpa, 1);
2234 if (self.builder.useLibLlvm()) try self.llvm.blocks.ensureUnusedCapacity(self.builder.gpa, 1);
2235
2236 const index: Block.Index = @enumFromInt(self.blocks.items.len);
2237 const final_name = if (self.builder.strip) .empty else try self.builder.string(name);
2238 self.blocks.appendAssumeCapacity(.{
2239 .name = final_name,
2240 .incoming = incoming,
2241 .instructions = .{},
2242 });
2243 if (self.builder.useLibLlvm()) self.llvm.blocks.appendAssumeCapacity(
2244 self.builder.llvm.context.appendBasicBlock(
2245 self.function.toLlvm(self.builder),
2246 final_name.toSlice(self.builder).?,
2247 ),
2248 );
2249 return index;
2250 }
2251
2252 pub fn ret(self: *WipFunction, val: Value) Allocator.Error!Instruction.Index {
2253 assert(val.typeOfWip(self) == self.function.typeOf(self.builder).functionReturn(self.builder));
2254 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
2255 const instruction = try self.addInst(null, .{ .tag = .ret, .data = @intFromEnum(val) });
2256 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
2257 self.llvm.builder.buildRet(val.toLlvm(self)),
2258 );
2259 return instruction;
2260 }
2261
2262 pub fn retVoid(self: *WipFunction) Allocator.Error!Instruction.Index {
2263 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
2264 const instruction = try self.addInst(null, .{ .tag = .@"ret void", .data = undefined });
2265 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
2266 self.llvm.builder.buildRetVoid(),
2267 );
2268 return instruction;
2269 }
2270
2271 pub fn br(self: *WipFunction, dest: Block.Index) Allocator.Error!Instruction.Index {
2272 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
2273 const instruction = try self.addInst(null, .{ .tag = .br, .data = @intFromEnum(dest) });
2274 dest.ptr(self).branches += 1;
2275 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
2276 self.llvm.builder.buildBr(dest.toLlvm(self)),
2277 );
2278 return instruction;
2279 }
2280
2281 pub fn brCond(
2282 self: *WipFunction,
2283 cond: Value,
2284 then: Block.Index,
2285 @"else": Block.Index,
2286 ) Allocator.Error!Instruction.Index {
2287 assert(cond.typeOfWip(self) == .i1);
2288 try self.ensureUnusedExtraCapacity(1, Instruction.BrCond, 0);
2289 const instruction = try self.addInst(null, .{
2290 .tag = .br_cond,
2291 .data = self.addExtraAssumeCapacity(Instruction.BrCond{
2292 .cond = cond,
2293 .then = then,
2294 .@"else" = @"else",
2295 }),
2296 });
2297 then.ptr(self).branches += 1;
2298 @"else".ptr(self).branches += 1;
2299 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
2300 self.llvm.builder.buildCondBr(cond.toLlvm(self), then.toLlvm(self), @"else".toLlvm(self)),
2301 );
2302 return instruction;
2303 }
2304
2305 pub const WipSwitch = struct {
2306 index: u32,
2307 instruction: Instruction.Index,
2308
2309 pub fn addCase(
2310 self: *WipSwitch,
2311 val: Constant,
2312 dest: Block.Index,
2313 wip: *WipFunction,
2314 ) Allocator.Error!void {
2315 const instruction = wip.instructions.get(@intFromEnum(self.instruction));
2316 var extra = wip.extraDataTrail(Instruction.Switch, instruction.data);
2317 assert(val.typeOf(wip.builder) == extra.data.val.typeOfWip(wip));
2318 extra.trail.nextMut(extra.data.cases_len, Constant, wip)[self.index] = val;
2319 extra.trail.nextMut(extra.data.cases_len, Block.Index, wip)[self.index] = dest;
2320 self.index += 1;
2321 dest.ptr(wip).branches += 1;
2322 if (wip.builder.useLibLlvm())
2323 self.instruction.toLlvm(wip).addCase(val.toLlvm(wip.builder), dest.toLlvm(wip));
2324 }
2325
2326 pub fn finish(self: WipSwitch, wip: *WipFunction) void {
2327 const instruction = wip.instructions.get(@intFromEnum(self.instruction));
2328 const extra = wip.extraData(Instruction.Switch, instruction.data);
2329 assert(self.index == extra.cases_len);
2330 }
2331 };
2332
2333 pub fn @"switch"(
2334 self: *WipFunction,
2335 val: Value,
2336 default: Block.Index,
2337 cases_len: u32,
2338 ) Allocator.Error!WipSwitch {
2339 try self.ensureUnusedExtraCapacity(1, Instruction.Switch, cases_len * 2);
2340 const instruction = try self.addInst(null, .{
2341 .tag = .@"switch",
2342 .data = self.addExtraAssumeCapacity(Instruction.Switch{
2343 .val = val,
2344 .default = default,
2345 .cases_len = cases_len,
2346 }),
2347 });
2348 _ = self.extra.addManyAsSliceAssumeCapacity(cases_len * 2);
2349 default.ptr(self).branches += 1;
2350 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
2351 self.llvm.builder.buildSwitch(val.toLlvm(self), default.toLlvm(self), @intCast(cases_len)),
2352 );
2353 return .{ .index = 0, .instruction = instruction };
2354 }
2355
2356 pub fn @"unreachable"(self: *WipFunction) Allocator.Error!Instruction.Index {
2357 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
2358 const instruction = try self.addInst(null, .{ .tag = .@"unreachable", .data = undefined });
2359 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
2360 self.llvm.builder.buildUnreachable(),
2361 );
2362 return instruction;
2363 }
2364
2365 pub fn un(
2366 self: *WipFunction,
2367 tag: Instruction.Tag,
2368 val: Value,
2369 name: []const u8,
2370 ) Allocator.Error!Value {
2371 switch (tag) {
2372 .fneg,
2373 .@"fneg fast",
2374 => assert(val.typeOfWip(self).scalarType(self.builder).isFloatingPoint()),
2375 else => unreachable,
2376 }
2377 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
2378 const instruction = try self.addInst(name, .{ .tag = tag, .data = @intFromEnum(val) });
2379 if (self.builder.useLibLlvm()) {
2380 switch (tag) {
2381 .fneg => self.llvm.builder.setFastMath(false),
2382 .@"fneg fast" => self.llvm.builder.setFastMath(true),
2383 else => unreachable,
2384 }
2385 self.llvm.instructions.appendAssumeCapacity(switch (tag) {
2386 .fneg, .@"fneg fast" => &llvm.Builder.buildFNeg,
2387 else => unreachable,
2388 }(self.llvm.builder, val.toLlvm(self), instruction.llvmName(self)));
2389 }
2390 return instruction.toValue();
2391 }
2392
2393 pub fn not(self: *WipFunction, val: Value, name: []const u8) Allocator.Error!Value {
2394 const ty = val.typeOfWip(self);
2395 const all_ones = try self.builder.splatValue(
2396 ty,
2397 try self.builder.intConst(ty.scalarType(self.builder), -1),
2398 );
2399 return self.bin(.xor, val, all_ones, name);
2400 }
2401
2402 pub fn neg(self: *WipFunction, val: Value, name: []const u8) Allocator.Error!Value {
2403 return self.bin(.sub, try self.builder.zeroInitValue(val.typeOfWip(self)), val, name);
2404 }
2405
2406 pub fn bin(
2407 self: *WipFunction,
2408 tag: Instruction.Tag,
2409 lhs: Value,
2410 rhs: Value,
2411 name: []const u8,
2412 ) Allocator.Error!Value {
2413 switch (tag) {
2414 .add,
2415 .@"add nsw",
2416 .@"add nuw",
2417 .@"and",
2418 .ashr,
2419 .@"ashr exact",
2420 .fadd,
2421 .@"fadd fast",
2422 .fdiv,
2423 .@"fdiv fast",
2424 .fmul,
2425 .@"fmul fast",
2426 .frem,
2427 .@"frem fast",
2428 .fsub,
2429 .@"fsub fast",
2430 .@"llvm.maxnum.",
2431 .@"llvm.minnum.",
2432 .@"llvm.sadd.sat.",
2433 .@"llvm.smax.",
2434 .@"llvm.smin.",
2435 .@"llvm.smul.fix.sat.",
2436 .@"llvm.sshl.sat.",
2437 .@"llvm.ssub.sat.",
2438 .@"llvm.uadd.sat.",
2439 .@"llvm.umax.",
2440 .@"llvm.umin.",
2441 .@"llvm.umul.fix.sat.",
2442 .@"llvm.ushl.sat.",
2443 .@"llvm.usub.sat.",
2444 .lshr,
2445 .@"lshr exact",
2446 .mul,
2447 .@"mul nsw",
2448 .@"mul nuw",
2449 .@"or",
2450 .sdiv,
2451 .@"sdiv exact",
2452 .shl,
2453 .@"shl nsw",
2454 .@"shl nuw",
2455 .srem,
2456 .sub,
2457 .@"sub nsw",
2458 .@"sub nuw",
2459 .udiv,
2460 .@"udiv exact",
2461 .urem,
2462 .xor,
2463 => assert(lhs.typeOfWip(self) == rhs.typeOfWip(self)),
2464 else => unreachable,
2465 }
2466 try self.ensureUnusedExtraCapacity(1, Instruction.Binary, 0);
2467 const instruction = try self.addInst(name, .{
2468 .tag = tag,
2469 .data = self.addExtraAssumeCapacity(Instruction.Binary{ .lhs = lhs, .rhs = rhs }),
2470 });
2471 if (self.builder.useLibLlvm()) {
2472 switch (tag) {
2473 .fadd,
2474 .fdiv,
2475 .fmul,
2476 .frem,
2477 .fsub,
2478 => self.llvm.builder.setFastMath(false),
2479 .@"fadd fast",
2480 .@"fdiv fast",
2481 .@"fmul fast",
2482 .@"frem fast",
2483 .@"fsub fast",
2484 => self.llvm.builder.setFastMath(true),
2485 else => {},
2486 }
2487 self.llvm.instructions.appendAssumeCapacity(switch (tag) {
2488 .add => &llvm.Builder.buildAdd,
2489 .@"add nsw" => &llvm.Builder.buildNSWAdd,
2490 .@"add nuw" => &llvm.Builder.buildNUWAdd,
2491 .@"and" => &llvm.Builder.buildAnd,
2492 .ashr => &llvm.Builder.buildAShr,
2493 .@"ashr exact" => &llvm.Builder.buildAShrExact,
2494 .fadd, .@"fadd fast" => &llvm.Builder.buildFAdd,
2495 .fdiv, .@"fdiv fast" => &llvm.Builder.buildFDiv,
2496 .fmul, .@"fmul fast" => &llvm.Builder.buildFMul,
2497 .frem, .@"frem fast" => &llvm.Builder.buildFRem,
2498 .fsub, .@"fsub fast" => &llvm.Builder.buildFSub,
2499 .@"llvm.maxnum." => &llvm.Builder.buildMaxNum,
2500 .@"llvm.minnum." => &llvm.Builder.buildMinNum,
2501 .@"llvm.sadd.sat." => &llvm.Builder.buildSAddSat,
2502 .@"llvm.smax." => &llvm.Builder.buildSMax,
2503 .@"llvm.smin." => &llvm.Builder.buildSMin,
2504 .@"llvm.smul.fix.sat." => &llvm.Builder.buildSMulFixSat,
2505 .@"llvm.sshl.sat." => &llvm.Builder.buildSShlSat,
2506 .@"llvm.ssub.sat." => &llvm.Builder.buildSSubSat,
2507 .@"llvm.uadd.sat." => &llvm.Builder.buildUAddSat,
2508 .@"llvm.umax." => &llvm.Builder.buildUMax,
2509 .@"llvm.umin." => &llvm.Builder.buildUMin,
2510 .@"llvm.umul.fix.sat." => &llvm.Builder.buildUMulFixSat,
2511 .@"llvm.ushl.sat." => &llvm.Builder.buildUShlSat,
2512 .@"llvm.usub.sat." => &llvm.Builder.buildUSubSat,
2513 .lshr => &llvm.Builder.buildLShr,
2514 .@"lshr exact" => &llvm.Builder.buildLShrExact,
2515 .mul => &llvm.Builder.buildMul,
2516 .@"mul nsw" => &llvm.Builder.buildNSWMul,
2517 .@"mul nuw" => &llvm.Builder.buildNUWMul,
2518 .@"or" => &llvm.Builder.buildOr,
2519 .sdiv => &llvm.Builder.buildSDiv,
2520 .@"sdiv exact" => &llvm.Builder.buildExactSDiv,
2521 .shl => &llvm.Builder.buildShl,
2522 .@"shl nsw" => &llvm.Builder.buildNSWShl,
2523 .@"shl nuw" => &llvm.Builder.buildNUWShl,
2524 .srem => &llvm.Builder.buildSRem,
2525 .sub => &llvm.Builder.buildSub,
2526 .@"sub nsw" => &llvm.Builder.buildNSWSub,
2527 .@"sub nuw" => &llvm.Builder.buildNUWSub,
2528 .udiv => &llvm.Builder.buildUDiv,
2529 .@"udiv exact" => &llvm.Builder.buildExactUDiv,
2530 .urem => &llvm.Builder.buildURem,
2531 .xor => &llvm.Builder.buildXor,
2532 else => unreachable,
2533 }(self.llvm.builder, lhs.toLlvm(self), rhs.toLlvm(self), instruction.llvmName(self)));
2534 }
2535 return instruction.toValue();
2536 }
2537
2538 pub fn extractElement(
2539 self: *WipFunction,
2540 val: Value,
2541 index: Value,
2542 name: []const u8,
2543 ) Allocator.Error!Value {
2544 assert(val.typeOfWip(self).isVector(self.builder));
2545 assert(index.typeOfWip(self).isInteger(self.builder));
2546 try self.ensureUnusedExtraCapacity(1, Instruction.ExtractElement, 0);
2547 const instruction = try self.addInst(name, .{
2548 .tag = .extractelement,
2549 .data = self.addExtraAssumeCapacity(Instruction.ExtractElement{
2550 .val = val,
2551 .index = index,
2552 }),
2553 });
2554 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
2555 self.llvm.builder.buildExtractElement(
2556 val.toLlvm(self),
2557 index.toLlvm(self),
2558 instruction.llvmName(self),
2559 ),
2560 );
2561 return instruction.toValue();
2562 }
2563
2564 pub fn insertElement(
2565 self: *WipFunction,
2566 val: Value,
2567 elem: Value,
2568 index: Value,
2569 name: []const u8,
2570 ) Allocator.Error!Value {
2571 assert(val.typeOfWip(self).scalarType(self.builder) == elem.typeOfWip(self));
2572 assert(index.typeOfWip(self).isInteger(self.builder));
2573 try self.ensureUnusedExtraCapacity(1, Instruction.InsertElement, 0);
2574 const instruction = try self.addInst(name, .{
2575 .tag = .insertelement,
2576 .data = self.addExtraAssumeCapacity(Instruction.InsertElement{
2577 .val = val,
2578 .elem = elem,
2579 .index = index,
2580 }),
2581 });
2582 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
2583 self.llvm.builder.buildInsertElement(
2584 val.toLlvm(self),
2585 elem.toLlvm(self),
2586 index.toLlvm(self),
2587 instruction.llvmName(self),
2588 ),
2589 );
2590 return instruction.toValue();
2591 }
2592
2593 pub fn shuffleVector(
2594 self: *WipFunction,
2595 lhs: Value,
2596 rhs: Value,
2597 mask: Value,
2598 name: []const u8,
2599 ) Allocator.Error!Value {
2600 assert(lhs.typeOfWip(self).isVector(self.builder));
2601 assert(lhs.typeOfWip(self) == rhs.typeOfWip(self));
2602 assert(mask.typeOfWip(self).scalarType(self.builder).isInteger(self.builder));
2603 _ = try self.ensureUnusedExtraCapacity(1, Instruction.ShuffleVector, 0);
2604 const instruction = try self.addInst(name, .{
2605 .tag = .shufflevector,
2606 .data = self.addExtraAssumeCapacity(Instruction.ShuffleVector{
2607 .lhs = lhs,
2608 .rhs = rhs,
2609 .mask = mask,
2610 }),
2611 });
2612 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
2613 self.llvm.builder.buildShuffleVector(
2614 lhs.toLlvm(self),
2615 rhs.toLlvm(self),
2616 mask.toLlvm(self),
2617 instruction.llvmName(self),
2618 ),
2619 );
2620 return instruction.toValue();
2621 }
2622
2623 pub fn splatVector(
2624 self: *WipFunction,
2625 ty: Type,
2626 elem: Value,
2627 name: []const u8,
2628 ) Allocator.Error!Value {
2629 const scalar_ty = try ty.changeLength(1, self.builder);
2630 const mask_ty = try ty.changeScalar(.i32, self.builder);
2631 const zero = try self.builder.intConst(.i32, 0);
2632 const poison = try self.builder.poisonValue(scalar_ty);
2633 const mask = try self.builder.splatValue(mask_ty, zero);
2634 const scalar = try self.insertElement(poison, elem, zero.toValue(), name);
2635 return self.shuffleVector(scalar, poison, mask, name);
2636 }
2637
2638 pub fn extractValue(
2639 self: *WipFunction,
2640 val: Value,
2641 indices: []const u32,
2642 name: []const u8,
2643 ) Allocator.Error!Value {
2644 assert(indices.len > 0);
2645 _ = val.typeOfWip(self).childTypeAt(indices, self.builder);
2646 try self.ensureUnusedExtraCapacity(1, Instruction.ExtractValue, indices.len);
2647 const instruction = try self.addInst(name, .{
2648 .tag = .extractvalue,
2649 .data = self.addExtraAssumeCapacity(Instruction.ExtractValue{
2650 .val = val,
2651 .indices_len = @intCast(indices.len),
2652 }),
2653 });
2654 self.extra.appendSliceAssumeCapacity(indices);
2655 if (self.builder.useLibLlvm()) {
2656 const llvm_name = instruction.llvmName(self);
2657 var cur = val.toLlvm(self);
2658 for (indices) |index|
2659 cur = self.llvm.builder.buildExtractValue(cur, @intCast(index), llvm_name);
2660 self.llvm.instructions.appendAssumeCapacity(cur);
2661 }
2662 return instruction.toValue();
2663 }
2664
2665 pub fn insertValue(
2666 self: *WipFunction,
2667 val: Value,
2668 elem: Value,
2669 indices: []const u32,
2670 name: []const u8,
2671 ) Allocator.Error!Value {
2672 assert(indices.len > 0);
2673 assert(val.typeOfWip(self).childTypeAt(indices, self.builder) == elem.typeOfWip(self));
2674 try self.ensureUnusedExtraCapacity(1, Instruction.InsertValue, indices.len);
2675 const instruction = try self.addInst(name, .{
2676 .tag = .insertvalue,
2677 .data = self.addExtraAssumeCapacity(Instruction.InsertValue{
2678 .val = val,
2679 .elem = elem,
2680 .indices_len = @intCast(indices.len),
2681 }),
2682 });
2683 self.extra.appendSliceAssumeCapacity(indices);
2684 if (self.builder.useLibLlvm()) {
2685 const ExpectedContents = [expected_gep_indices_len]*llvm.Value;
2686 var stack align(@alignOf(ExpectedContents)) =
2687 std.heap.stackFallback(@sizeOf(ExpectedContents), self.builder.gpa);
2688 const allocator = stack.get();
2689
2690 const llvm_name = instruction.llvmName(self);
2691 const llvm_vals = try allocator.alloc(*llvm.Value, indices.len);
2692 defer allocator.free(llvm_vals);
2693 llvm_vals[0] = val.toLlvm(self);
2694 for (llvm_vals[1..], llvm_vals[0 .. llvm_vals.len - 1], indices[0 .. indices.len - 1]) |
2695 *cur_val,
2696 prev_val,
2697 index,
2698 | cur_val.* = self.llvm.builder.buildExtractValue(prev_val, @intCast(index), llvm_name);
2699
2700 var depth: usize = llvm_vals.len;
2701 var cur = elem.toLlvm(self);
2702 while (depth > 0) {
2703 depth -= 1;
2704 cur = self.llvm.builder.buildInsertValue(
2705 llvm_vals[depth],
2706 cur,
2707 @intCast(indices[depth]),
2708 llvm_name,
2709 );
2710 }
2711 self.llvm.instructions.appendAssumeCapacity(cur);
2712 }
2713 return instruction.toValue();
2714 }
2715
2716 pub fn buildAggregate(
2717 self: *WipFunction,
2718 ty: Type,
2719 elems: []const Value,
2720 name: []const u8,
2721 ) Allocator.Error!Value {
2722 assert(ty.aggregateLen(self.builder) == elems.len);
2723 var cur = try self.builder.poisonValue(ty);
2724 for (elems, 0..) |elem, index|
2725 cur = try self.insertValue(cur, elem, &[_]u32{@intCast(index)}, name);
2726 return cur;
2727 }
2728
2729 pub fn alloca(
2730 self: *WipFunction,
2731 kind: Instruction.Alloca.Kind,
2732 ty: Type,
2733 len: Value,
2734 alignment: Alignment,
2735 addr_space: AddrSpace,
2736 name: []const u8,
2737 ) Allocator.Error!Value {
2738 assert(len == .none or len.typeOfWip(self).isInteger(self.builder));
2739 _ = try self.builder.ptrType(addr_space);
2740 try self.ensureUnusedExtraCapacity(1, Instruction.Alloca, 0);
2741 const instruction = try self.addInst(name, .{
2742 .tag = switch (kind) {
2743 .normal => .alloca,
2744 .inalloca => .@"alloca inalloca",
2745 },
2746 .data = self.addExtraAssumeCapacity(Instruction.Alloca{
2747 .type = ty,
2748 .len = len,
2749 .info = .{ .alignment = alignment, .addr_space = addr_space },
2750 }),
2751 });
2752 if (self.builder.useLibLlvm()) {
2753 const llvm_instruction = self.llvm.builder.buildAllocaInAddressSpace(
2754 ty.toLlvm(self.builder),
2755 @intFromEnum(addr_space),
2756 instruction.llvmName(self),
2757 );
2758 if (alignment.toByteUnits()) |a| llvm_instruction.setAlignment(@intCast(a));
2759 self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
2760 }
2761 return instruction.toValue();
2762 }
2763
2764 pub fn load(
2765 self: *WipFunction,
2766 kind: MemoryAccessKind,
2767 ty: Type,
2768 ptr: Value,
2769 alignment: Alignment,
2770 name: []const u8,
2771 ) Allocator.Error!Value {
2772 return self.loadAtomic(kind, ty, ptr, .system, .none, alignment, name);
2773 }
2774
2775 pub fn loadAtomic(
2776 self: *WipFunction,
2777 kind: MemoryAccessKind,
2778 ty: Type,
2779 ptr: Value,
2780 scope: SyncScope,
2781 ordering: AtomicOrdering,
2782 alignment: Alignment,
2783 name: []const u8,
2784 ) Allocator.Error!Value {
2785 assert(ptr.typeOfWip(self).isPointer(self.builder));
2786 try self.ensureUnusedExtraCapacity(1, Instruction.Load, 0);
2787 const instruction = try self.addInst(name, .{
2788 .tag = switch (ordering) {
2789 .none => switch (kind) {
2790 .normal => .load,
2791 .@"volatile" => .@"load volatile",
2792 },
2793 else => switch (kind) {
2794 .normal => .@"load atomic",
2795 .@"volatile" => .@"load atomic volatile",
2796 },
2797 },
2798 .data = self.addExtraAssumeCapacity(Instruction.Load{
2799 .type = ty,
2800 .ptr = ptr,
2801 .info = .{ .scope = switch (ordering) {
2802 .none => .system,
2803 else => scope,
2804 }, .ordering = ordering, .alignment = alignment },
2805 }),
2806 });
2807 if (self.builder.useLibLlvm()) {
2808 const llvm_instruction = self.llvm.builder.buildLoad(
2809 ty.toLlvm(self.builder),
2810 ptr.toLlvm(self),
2811 instruction.llvmName(self),
2812 );
2813 if (ordering != .none) llvm_instruction.setOrdering(@enumFromInt(@intFromEnum(ordering)));
2814 if (alignment.toByteUnits()) |a| llvm_instruction.setAlignment(@intCast(a));
2815 self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
2816 }
2817 return instruction.toValue();
2818 }
2819
2820 pub fn store(
2821 self: *WipFunction,
2822 kind: MemoryAccessKind,
2823 val: Value,
2824 ptr: Value,
2825 alignment: Alignment,
2826 ) Allocator.Error!Instruction.Index {
2827 return self.storeAtomic(kind, val, ptr, .system, .none, alignment);
2828 }
2829
2830 pub fn storeAtomic(
2831 self: *WipFunction,
2832 kind: MemoryAccessKind,
2833 val: Value,
2834 ptr: Value,
2835 scope: SyncScope,
2836 ordering: AtomicOrdering,
2837 alignment: Alignment,
2838 ) Allocator.Error!Instruction.Index {
2839 assert(ptr.typeOfWip(self).isPointer(self.builder));
2840 try self.ensureUnusedExtraCapacity(1, Instruction.Store, 0);
2841 const instruction = try self.addInst(null, .{
2842 .tag = switch (ordering) {
2843 .none => switch (kind) {
2844 .normal => .store,
2845 .@"volatile" => .@"store volatile",
2846 },
2847 else => switch (kind) {
2848 .normal => .@"store atomic",
2849 .@"volatile" => .@"store atomic volatile",
2850 },
2851 },
2852 .data = self.addExtraAssumeCapacity(Instruction.Store{
2853 .val = val,
2854 .ptr = ptr,
2855 .info = .{ .scope = switch (ordering) {
2856 .none => .system,
2857 else => scope,
2858 }, .ordering = ordering, .alignment = alignment },
2859 }),
2860 });
2861 if (self.builder.useLibLlvm()) {
2862 const llvm_instruction = self.llvm.builder.buildStore(val.toLlvm(self), ptr.toLlvm(self));
2863 switch (kind) {
2864 .normal => {},
2865 .@"volatile" => llvm_instruction.setVolatile(.True),
2866 }
2867 if (ordering != .none) llvm_instruction.setOrdering(@enumFromInt(@intFromEnum(ordering)));
2868 if (alignment.toByteUnits()) |a| llvm_instruction.setAlignment(@intCast(a));
2869 self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
2870 }
2871 return instruction;
2872 }
2873
2874 pub fn fence(
2875 self: *WipFunction,
2876 scope: SyncScope,
2877 ordering: AtomicOrdering,
2878 ) Allocator.Error!Instruction.Index {
2879 assert(ordering != .none);
2880 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
2881 const instruction = try self.addInst(null, .{
2882 .tag = .fence,
2883 .data = @bitCast(MemoryAccessInfo{
2884 .scope = scope,
2885 .ordering = ordering,
2886 .alignment = undefined,
2887 }),
2888 });
2889 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
2890 self.llvm.builder.buildFence(
2891 @enumFromInt(@intFromEnum(ordering)),
2892 llvm.Bool.fromBool(scope == .singlethread),
2893 "",
2894 ),
2895 );
2896 return instruction;
2897 }
2898
2899 pub fn gep(
2900 self: *WipFunction,
2901 kind: Instruction.GetElementPtr.Kind,
2902 ty: Type,
2903 base: Value,
2904 indices: []const Value,
2905 name: []const u8,
2906 ) Allocator.Error!Value {
2907 const base_ty = base.typeOfWip(self);
2908 const base_is_vector = base_ty.isVector(self.builder);
2909
2910 const VectorInfo = struct {
2911 kind: Type.Vector.Kind,
2912 len: u32,
2913
2914 fn init(vector_ty: Type, builder: *const Builder) @This() {
2915 return .{ .kind = vector_ty.vectorKind(builder), .len = vector_ty.vectorLen(builder) };
2916 }
2917 };
2918 var vector_info: ?VectorInfo =
2919 if (base_is_vector) VectorInfo.init(base_ty, self.builder) else null;
2920 for (indices) |index| {
2921 const index_ty = index.typeOfWip(self);
2922 switch (index_ty.tag(self.builder)) {
2923 .integer => {},
2924 .vector, .scalable_vector => {
2925 const index_info = VectorInfo.init(index_ty, self.builder);
2926 if (vector_info) |info|
2927 assert(std.meta.eql(info, index_info))
2928 else
2929 vector_info = index_info;
2930 },
2931 else => unreachable,
2932 }
2933 }
2934 if (!base_is_vector) if (vector_info) |info| switch (info.kind) {
2935 inline else => |vector_kind| _ = try self.builder.vectorType(
2936 vector_kind,
2937 info.len,
2938 base_ty,
2939 ),
2940 };
2941
2942 try self.ensureUnusedExtraCapacity(1, Instruction.GetElementPtr, indices.len);
2943 const instruction = try self.addInst(name, .{
2944 .tag = switch (kind) {
2945 .normal => .getelementptr,
2946 .inbounds => .@"getelementptr inbounds",
2947 },
2948 .data = self.addExtraAssumeCapacity(Instruction.GetElementPtr{
2949 .type = ty,
2950 .base = base,
2951 .indices_len = @intCast(indices.len),
2952 }),
2953 });
2954 self.extra.appendSliceAssumeCapacity(@ptrCast(indices));
2955 if (self.builder.useLibLlvm()) {
2956 const ExpectedContents = [expected_gep_indices_len]*llvm.Value;
2957 var stack align(@alignOf(ExpectedContents)) =
2958 std.heap.stackFallback(@sizeOf(ExpectedContents), self.builder.gpa);
2959 const allocator = stack.get();
2960
2961 const llvm_indices = try allocator.alloc(*llvm.Value, indices.len);
2962 defer allocator.free(llvm_indices);
2963 for (llvm_indices, indices) |*llvm_index, index| llvm_index.* = index.toLlvm(self);
2964
2965 self.llvm.instructions.appendAssumeCapacity(switch (kind) {
2966 .normal => &llvm.Builder.buildGEP,
2967 .inbounds => &llvm.Builder.buildInBoundsGEP,
2968 }(
2969 self.llvm.builder,
2970 ty.toLlvm(self.builder),
2971 base.toLlvm(self),
2972 llvm_indices.ptr,
2973 @intCast(llvm_indices.len),
2974 instruction.llvmName(self),
2975 ));
2976 }
2977 return instruction.toValue();
2978 }
2979
2980 pub fn gepStruct(
2981 self: *WipFunction,
2982 ty: Type,
2983 base: Value,
2984 index: usize,
2985 name: []const u8,
2986 ) Allocator.Error!Value {
2987 assert(ty.isStruct(self.builder));
2988 return self.gep(.inbounds, ty, base, &.{
2989 try self.builder.intValue(.i32, 0), try self.builder.intValue(.i32, index),
2990 }, name);
2991 }
2992
2993 pub fn conv(
2994 self: *WipFunction,
2995 signedness: Instruction.Cast.Signedness,
2996 val: Value,
2997 ty: Type,
2998 name: []const u8,
2999 ) Allocator.Error!Value {
3000 const val_ty = val.typeOfWip(self);
3001 if (val_ty == ty) return val;
3002 return self.cast(self.builder.convTag(Instruction.Tag, signedness, val_ty, ty), val, ty, name);
3003 }
3004
3005 pub fn cast(
3006 self: *WipFunction,
3007 tag: Instruction.Tag,
3008 val: Value,
3009 ty: Type,
3010 name: []const u8,
3011 ) Allocator.Error!Value {
3012 switch (tag) {
3013 .addrspacecast,
3014 .bitcast,
3015 .fpext,
3016 .fptosi,
3017 .fptoui,
3018 .fptrunc,
3019 .inttoptr,
3020 .ptrtoint,
3021 .sext,
3022 .sitofp,
3023 .trunc,
3024 .uitofp,
3025 .zext,
3026 => {},
3027 else => unreachable,
3028 }
3029 if (val.typeOfWip(self) == ty) return val;
3030 try self.ensureUnusedExtraCapacity(1, Instruction.Cast, 0);
3031 const instruction = try self.addInst(name, .{
3032 .tag = tag,
3033 .data = self.addExtraAssumeCapacity(Instruction.Cast{
3034 .val = val,
3035 .type = ty,
3036 }),
3037 });
3038 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(switch (tag) {
3039 .addrspacecast => &llvm.Builder.buildAddrSpaceCast,
3040 .bitcast => &llvm.Builder.buildBitCast,
3041 .fpext => &llvm.Builder.buildFPExt,
3042 .fptosi => &llvm.Builder.buildFPToSI,
3043 .fptoui => &llvm.Builder.buildFPToUI,
3044 .fptrunc => &llvm.Builder.buildFPTrunc,
3045 .inttoptr => &llvm.Builder.buildIntToPtr,
3046 .ptrtoint => &llvm.Builder.buildPtrToInt,
3047 .sext => &llvm.Builder.buildSExt,
3048 .sitofp => &llvm.Builder.buildSIToFP,
3049 .trunc => &llvm.Builder.buildTrunc,
3050 .uitofp => &llvm.Builder.buildUIToFP,
3051 .zext => &llvm.Builder.buildZExt,
3052 else => unreachable,
3053 }(self.llvm.builder, val.toLlvm(self), ty.toLlvm(self.builder), instruction.llvmName(self)));
3054 return instruction.toValue();
3055 }
3056
3057 pub fn icmp(
3058 self: *WipFunction,
3059 cond: IntegerCondition,
3060 lhs: Value,
3061 rhs: Value,
3062 name: []const u8,
3063 ) Allocator.Error!Value {
3064 return self.cmpTag(switch (cond) {
3065 inline else => |tag| @field(Instruction.Tag, "icmp " ++ @tagName(tag)),
3066 }, @intFromEnum(cond), lhs, rhs, name);
3067 }
3068
3069 pub fn fcmp(
3070 self: *WipFunction,
3071 cond: FloatCondition,
3072 lhs: Value,
3073 rhs: Value,
3074 name: []const u8,
3075 ) Allocator.Error!Value {
3076 return self.cmpTag(switch (cond) {
3077 inline else => |tag| @field(Instruction.Tag, "fcmp " ++ @tagName(tag)),
3078 }, @intFromEnum(cond), lhs, rhs, name);
3079 }
3080
3081 pub fn fcmpFast(
3082 self: *WipFunction,
3083 cond: FloatCondition,
3084 lhs: Value,
3085 rhs: Value,
3086 name: []const u8,
3087 ) Allocator.Error!Value {
3088 return self.cmpTag(switch (cond) {
3089 inline else => |tag| @field(Instruction.Tag, "fcmp fast " ++ @tagName(tag)),
3090 }, @intFromEnum(cond), lhs, rhs, name);
3091 }
3092
3093 pub const WipPhi = struct {
3094 block: Block.Index,
3095 instruction: Instruction.Index,
3096
3097 pub fn toValue(self: WipPhi) Value {
3098 return self.instruction.toValue();
3099 }
3100
3101 pub fn finish(
3102 self: WipPhi,
3103 vals: []const Value,
3104 blocks: []const Block.Index,
3105 wip: *WipFunction,
3106 ) if (build_options.have_llvm) Allocator.Error!void else void {
3107 const incoming_len = self.block.ptrConst(wip).incoming;
3108 assert(vals.len == incoming_len and blocks.len == incoming_len);
3109 const instruction = wip.instructions.get(@intFromEnum(self.instruction));
3110 var extra = wip.extraDataTrail(Instruction.Phi, instruction.data);
3111 for (vals) |val| assert(val.typeOfWip(wip) == extra.data.type);
3112 @memcpy(extra.trail.nextMut(incoming_len, Value, wip), vals);
3113 @memcpy(extra.trail.nextMut(incoming_len, Block.Index, wip), blocks);
3114 if (wip.builder.useLibLlvm()) {
3115 const ExpectedContents = extern struct {
3116 [expected_incoming_len]*llvm.Value,
3117 [expected_incoming_len]*llvm.BasicBlock,
3118 };
3119 var stack align(@alignOf(ExpectedContents)) =
3120 std.heap.stackFallback(@sizeOf(ExpectedContents), wip.builder.gpa);
3121 const allocator = stack.get();
3122
3123 const llvm_vals = try allocator.alloc(*llvm.Value, incoming_len);
3124 defer allocator.free(llvm_vals);
3125 const llvm_blocks = try allocator.alloc(*llvm.BasicBlock, incoming_len);
3126 defer allocator.free(llvm_blocks);
3127
3128 for (llvm_vals, vals) |*llvm_val, incoming_val| llvm_val.* = incoming_val.toLlvm(wip);
3129 for (llvm_blocks, blocks) |*llvm_block, incoming_block|
3130 llvm_block.* = incoming_block.toLlvm(wip);
3131 self.instruction.toLlvm(wip)
3132 .addIncoming(llvm_vals.ptr, llvm_blocks.ptr, @intCast(incoming_len));
3133 }
3134 }
3135 };
3136
3137 pub fn phi(self: *WipFunction, ty: Type, name: []const u8) Allocator.Error!WipPhi {
3138 return self.phiTag(.phi, ty, name);
3139 }
3140
3141 pub fn phiFast(self: *WipFunction, ty: Type, name: []const u8) Allocator.Error!WipPhi {
3142 return self.phiTag(.@"phi fast", ty, name);
3143 }
3144
3145 pub fn select(
3146 self: *WipFunction,
3147 cond: Value,
3148 lhs: Value,
3149 rhs: Value,
3150 name: []const u8,
3151 ) Allocator.Error!Value {
3152 return self.selectTag(.select, cond, lhs, rhs, name);
3153 }
3154
3155 pub fn selectFast(
3156 self: *WipFunction,
3157 cond: Value,
3158 lhs: Value,
3159 rhs: Value,
3160 name: []const u8,
3161 ) Allocator.Error!Value {
3162 return self.selectTag(.@"select fast", cond, lhs, rhs, name);
3163 }
3164
3165 pub fn vaArg(self: *WipFunction, list: Value, ty: Type, name: []const u8) Allocator.Error!Value {
3166 try self.ensureUnusedExtraCapacity(1, Instruction.VaArg, 0);
3167 const instruction = try self.addInst(name, .{
3168 .tag = .va_arg,
3169 .data = self.addExtraAssumeCapacity(Instruction.VaArg{
3170 .list = list,
3171 .type = ty,
3172 }),
3173 });
3174 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
3175 self.llvm.builder.buildVAArg(
3176 list.toLlvm(self),
3177 ty.toLlvm(self.builder),
3178 instruction.llvmName(self),
3179 ),
3180 );
3181 return instruction.toValue();
3182 }
3183
3184 pub const WipUnimplemented = struct {
3185 instruction: Instruction.Index,
3186
3187 pub fn finish(self: WipUnimplemented, val: *llvm.Value, wip: *WipFunction) Value {
3188 assert(wip.builder.useLibLlvm());
3189 wip.llvm.instructions.items[@intFromEnum(self.instruction)] = val;
3190 return self.instruction.toValue();
3191 }
3192 };
3193
3194 pub fn unimplemented(
3195 self: *WipFunction,
3196 ty: Type,
3197 name: []const u8,
3198 ) Allocator.Error!WipUnimplemented {
3199 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
3200 const instruction = try self.addInst(name, .{
3201 .tag = .unimplemented,
3202 .data = @intFromEnum(ty),
3203 });
3204 if (self.builder.useLibLlvm()) _ = self.llvm.instructions.addOneAssumeCapacity();
3205 return .{ .instruction = instruction };
3206 }
3207
3208 pub fn finish(self: *WipFunction) Allocator.Error!void {
3209 const gpa = self.builder.gpa;
3210 const function = self.function.ptr(self.builder);
3211 const params_len = self.function.typeOf(self.builder).functionParameters(self.builder).len;
3212 const final_instructions_len = self.blocks.items.len + self.instructions.len;
3213
3214 const blocks = try gpa.alloc(Function.Block, self.blocks.items.len);
3215 errdefer gpa.free(blocks);
3216
3217 const instructions: struct {
3218 items: []Instruction.Index,
3219
3220 fn map(instructions: @This(), val: Value) Value {
3221 if (val == .none) return .none;
3222 return switch (val.unwrap()) {
3223 .instruction => |instruction| instructions.items[
3224 @intFromEnum(instruction)
3225 ].toValue(),
3226 .constant => |constant| constant.toValue(),
3227 };
3228 }
3229 } = .{ .items = try gpa.alloc(Instruction.Index, self.instructions.len) };
3230 defer gpa.free(instructions.items);
3231
3232 const names = try gpa.alloc(String, final_instructions_len);
3233 errdefer gpa.free(names);
3234
3235 const metadata =
3236 if (self.builder.strip) null else try gpa.alloc(Metadata, final_instructions_len);
3237 errdefer if (metadata) |new_metadata| gpa.free(new_metadata);
3238
3239 var wip_extra: struct {
3240 index: Instruction.ExtraIndex = 0,
3241 items: []u32,
3242
3243 fn addExtra(wip_extra: *@This(), extra: anytype) Instruction.ExtraIndex {
3244 const result = wip_extra.index;
3245 inline for (@typeInfo(@TypeOf(extra)).Struct.fields) |field| {
3246 const value = @field(extra, field.name);
3247 wip_extra.items[wip_extra.index] = switch (field.type) {
3248 u32 => value,
3249 Alignment, AtomicOrdering, Block.Index, Type, Value => @intFromEnum(value),
3250 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),
3251 else => @compileError("bad field type: " ++ @typeName(field.type)),
3252 };
3253 wip_extra.index += 1;
3254 }
3255 return result;
3256 }
3257
3258 fn appendSlice(wip_extra: *@This(), slice: anytype) void {
3259 if (@typeInfo(@TypeOf(slice)).Pointer.child == Value) @compileError("use appendValues");
3260 const data: []const u32 = @ptrCast(slice);
3261 @memcpy(wip_extra.items[wip_extra.index..][0..data.len], data);
3262 wip_extra.index += @intCast(data.len);
3263 }
3264
3265 fn appendValues(wip_extra: *@This(), vals: []const Value, ctx: anytype) void {
3266 for (wip_extra.items[wip_extra.index..][0..vals.len], vals) |*extra, val|
3267 extra.* = @intFromEnum(ctx.map(val));
3268 wip_extra.index += @intCast(vals.len);
3269 }
3270
3271 fn finish(wip_extra: *const @This()) []const u32 {
3272 assert(wip_extra.index == wip_extra.items.len);
3273 return wip_extra.items;
3274 }
3275 } = .{ .items = try gpa.alloc(u32, self.extra.items.len) };
3276 errdefer gpa.free(wip_extra.items);
3277
3278 gpa.free(function.blocks);
3279 function.blocks = &.{};
3280 gpa.free(function.names[0..function.instructions.len]);
3281 if (function.metadata) |old_metadata| gpa.free(old_metadata[0..function.instructions.len]);
3282 function.metadata = null;
3283 gpa.free(function.extra);
3284 function.extra = &.{};
3285
3286 function.instructions.shrinkRetainingCapacity(0);
3287 try function.instructions.setCapacity(gpa, final_instructions_len);
3288 errdefer function.instructions.shrinkRetainingCapacity(0);
3289
3290 {
3291 var final_instruction_index: Instruction.Index = @enumFromInt(0);
3292 for (0..params_len) |param_index| {
3293 instructions.items[param_index] = final_instruction_index;
3294 final_instruction_index = @enumFromInt(@intFromEnum(final_instruction_index) + 1);
3295 }
3296 for (blocks, self.blocks.items) |*final_block, current_block| {
3297 assert(current_block.incoming == current_block.branches);
3298 final_block.instruction = final_instruction_index;
3299 final_instruction_index = @enumFromInt(@intFromEnum(final_instruction_index) + 1);
3300 for (current_block.instructions.items) |instruction| {
3301 instructions.items[@intFromEnum(instruction)] = final_instruction_index;
3302 final_instruction_index = @enumFromInt(@intFromEnum(final_instruction_index) + 1);
3303 }
3304 }
3305 }
3306
3307 var wip_name: struct {
3308 next_name: String = @enumFromInt(0),
3309
3310 fn map(wip_name: *@This(), old_name: String) String {
3311 if (old_name != .empty) return old_name;
3312
3313 const new_name = wip_name.next_name;
3314 wip_name.next_name = @enumFromInt(@intFromEnum(new_name) + 1);
3315 return new_name;
3316 }
3317 } = .{};
3318 for (0..params_len) |param_index| {
3319 const old_argument_index: Instruction.Index = @enumFromInt(param_index);
3320 const new_argument_index: Instruction.Index = @enumFromInt(function.instructions.len);
3321 const argument = self.instructions.get(@intFromEnum(old_argument_index));
3322 assert(argument.tag == .arg);
3323 assert(argument.data == param_index);
3324 function.instructions.appendAssumeCapacity(argument);
3325 names[@intFromEnum(new_argument_index)] = wip_name.map(
3326 if (self.builder.strip) .empty else self.names.items[@intFromEnum(old_argument_index)],
3327 );
3328 }
3329 for (self.blocks.items) |current_block| {
3330 const new_block_index: Instruction.Index = @enumFromInt(function.instructions.len);
3331 function.instructions.appendAssumeCapacity(.{
3332 .tag = .block,
3333 .data = current_block.incoming,
3334 });
3335 names[@intFromEnum(new_block_index)] = wip_name.map(current_block.name);
3336 for (current_block.instructions.items) |old_instruction_index| {
3337 const new_instruction_index: Instruction.Index =
3338 @enumFromInt(function.instructions.len);
3339 var instruction = self.instructions.get(@intFromEnum(old_instruction_index));
3340 switch (instruction.tag) {
3341 .add,
3342 .@"add nsw",
3343 .@"add nuw",
3344 .@"add nuw nsw",
3345 .@"and",
3346 .ashr,
3347 .@"ashr exact",
3348 .fadd,
3349 .@"fadd fast",
3350 .@"fcmp false",
3351 .@"fcmp fast false",
3352 .@"fcmp fast oeq",
3353 .@"fcmp fast oge",
3354 .@"fcmp fast ogt",
3355 .@"fcmp fast ole",
3356 .@"fcmp fast olt",
3357 .@"fcmp fast one",
3358 .@"fcmp fast ord",
3359 .@"fcmp fast true",
3360 .@"fcmp fast ueq",
3361 .@"fcmp fast uge",
3362 .@"fcmp fast ugt",
3363 .@"fcmp fast ule",
3364 .@"fcmp fast ult",
3365 .@"fcmp fast une",
3366 .@"fcmp fast uno",
3367 .@"fcmp oeq",
3368 .@"fcmp oge",
3369 .@"fcmp ogt",
3370 .@"fcmp ole",
3371 .@"fcmp olt",
3372 .@"fcmp one",
3373 .@"fcmp ord",
3374 .@"fcmp true",
3375 .@"fcmp ueq",
3376 .@"fcmp uge",
3377 .@"fcmp ugt",
3378 .@"fcmp ule",
3379 .@"fcmp ult",
3380 .@"fcmp une",
3381 .@"fcmp uno",
3382 .fdiv,
3383 .@"fdiv fast",
3384 .fmul,
3385 .@"fmul fast",
3386 .frem,
3387 .@"frem fast",
3388 .fsub,
3389 .@"fsub fast",
3390 .@"icmp eq",
3391 .@"icmp ne",
3392 .@"icmp sge",
3393 .@"icmp sgt",
3394 .@"icmp sle",
3395 .@"icmp slt",
3396 .@"icmp uge",
3397 .@"icmp ugt",
3398 .@"icmp ule",
3399 .@"icmp ult",
3400 .@"llvm.maxnum.",
3401 .@"llvm.minnum.",
3402 .@"llvm.sadd.sat.",
3403 .@"llvm.smax.",
3404 .@"llvm.smin.",
3405 .@"llvm.smul.fix.sat.",
3406 .@"llvm.sshl.sat.",
3407 .@"llvm.ssub.sat.",
3408 .@"llvm.uadd.sat.",
3409 .@"llvm.umax.",
3410 .@"llvm.umin.",
3411 .@"llvm.umul.fix.sat.",
3412 .@"llvm.ushl.sat.",
3413 .@"llvm.usub.sat.",
3414 .lshr,
3415 .@"lshr exact",
3416 .mul,
3417 .@"mul nsw",
3418 .@"mul nuw",
3419 .@"mul nuw nsw",
3420 .@"or",
3421 .sdiv,
3422 .@"sdiv exact",
3423 .shl,
3424 .@"shl nsw",
3425 .@"shl nuw",
3426 .@"shl nuw nsw",
3427 .srem,
3428 .sub,
3429 .@"sub nsw",
3430 .@"sub nuw",
3431 .@"sub nuw nsw",
3432 .udiv,
3433 .@"udiv exact",
3434 .urem,
3435 .xor,
3436 => {
3437 const extra = self.extraData(Instruction.Binary, instruction.data);
3438 instruction.data = wip_extra.addExtra(Instruction.Binary{
3439 .lhs = instructions.map(extra.lhs),
3440 .rhs = instructions.map(extra.rhs),
3441 });
3442 },
3443 .addrspacecast,
3444 .bitcast,
3445 .fpext,
3446 .fptosi,
3447 .fptoui,
3448 .fptrunc,
3449 .inttoptr,
3450 .ptrtoint,
3451 .sext,
3452 .sitofp,
3453 .trunc,
3454 .uitofp,
3455 .zext,
3456 => {
3457 const extra = self.extraData(Instruction.Cast, instruction.data);
3458 instruction.data = wip_extra.addExtra(Instruction.Cast{
3459 .val = instructions.map(extra.val),
3460 .type = extra.type,
3461 });
3462 },
3463 .alloca,
3464 .@"alloca inalloca",
3465 => {
3466 const extra = self.extraData(Instruction.Alloca, instruction.data);
3467 instruction.data = wip_extra.addExtra(Instruction.Alloca{
3468 .type = extra.type,
3469 .len = instructions.map(extra.len),
3470 .info = extra.info,
3471 });
3472 },
3473 .arg,
3474 .block,
3475 => unreachable,
3476 .br,
3477 .fence,
3478 .@"ret void",
3479 .unimplemented,
3480 .@"unreachable",
3481 => {},
3482 .extractelement => {
3483 const extra = self.extraData(Instruction.ExtractElement, instruction.data);
3484 instruction.data = wip_extra.addExtra(Instruction.ExtractElement{
3485 .val = instructions.map(extra.val),
3486 .index = instructions.map(extra.index),
3487 });
3488 },
3489 .br_cond => {
3490 const extra = self.extraData(Instruction.BrCond, instruction.data);
3491 instruction.data = wip_extra.addExtra(Instruction.BrCond{
3492 .cond = instructions.map(extra.cond),
3493 .then = extra.then,
3494 .@"else" = extra.@"else",
3495 });
3496 },
3497 .extractvalue => {
3498 var extra = self.extraDataTrail(Instruction.ExtractValue, instruction.data);
3499 const indices = extra.trail.next(extra.data.indices_len, u32, self);
3500 instruction.data = wip_extra.addExtra(Instruction.ExtractValue{
3501 .val = instructions.map(extra.data.val),
3502 .indices_len = extra.data.indices_len,
3503 });
3504 wip_extra.appendSlice(indices);
3505 },
3506 .fneg,
3507 .@"fneg fast",
3508 .ret,
3509 => instruction.data = @intFromEnum(instructions.map(@enumFromInt(instruction.data))),
3510 .getelementptr,
3511 .@"getelementptr inbounds",
3512 => {
3513 var extra = self.extraDataTrail(Instruction.GetElementPtr, instruction.data);
3514 const indices = extra.trail.next(extra.data.indices_len, Value, self);
3515 instruction.data = wip_extra.addExtra(Instruction.GetElementPtr{
3516 .type = extra.data.type,
3517 .base = instructions.map(extra.data.base),
3518 .indices_len = extra.data.indices_len,
3519 });
3520 wip_extra.appendValues(indices, instructions);
3521 },
3522 .insertelement => {
3523 const extra = self.extraData(Instruction.InsertElement, instruction.data);
3524 instruction.data = wip_extra.addExtra(Instruction.InsertElement{
3525 .val = instructions.map(extra.val),
3526 .elem = instructions.map(extra.elem),
3527 .index = instructions.map(extra.index),
3528 });
3529 },
3530 .insertvalue => {
3531 var extra = self.extraDataTrail(Instruction.InsertValue, instruction.data);
3532 const indices = extra.trail.next(extra.data.indices_len, u32, self);
3533 instruction.data = wip_extra.addExtra(Instruction.InsertValue{
3534 .val = instructions.map(extra.data.val),
3535 .elem = instructions.map(extra.data.elem),
3536 .indices_len = extra.data.indices_len,
3537 });
3538 wip_extra.appendSlice(indices);
3539 },
3540 .load,
3541 .@"load atomic",
3542 .@"load atomic volatile",
3543 .@"load volatile",
3544 => {
3545 const extra = self.extraData(Instruction.Load, instruction.data);
3546 instruction.data = wip_extra.addExtra(Instruction.Load{
3547 .type = extra.type,
3548 .ptr = instructions.map(extra.ptr),
3549 .info = extra.info,
3550 });
3551 },
3552 .phi,
3553 .@"phi fast",
3554 => {
3555 const incoming_len = current_block.incoming;
3556 var extra = self.extraDataTrail(Instruction.Phi, instruction.data);
3557 const incoming_vals = extra.trail.next(incoming_len, Value, self);
3558 const incoming_blocks = extra.trail.next(incoming_len, Block.Index, self);
3559 instruction.data = wip_extra.addExtra(Instruction.Phi{
3560 .type = extra.data.type,
3561 });
3562 wip_extra.appendValues(incoming_vals, instructions);
3563 wip_extra.appendSlice(incoming_blocks);
3564 },
3565 .select,
3566 .@"select fast",
3567 => {
3568 const extra = self.extraData(Instruction.Select, instruction.data);
3569 instruction.data = wip_extra.addExtra(Instruction.Select{
3570 .cond = instructions.map(extra.cond),
3571 .lhs = instructions.map(extra.lhs),
3572 .rhs = instructions.map(extra.rhs),
3573 });
3574 },
3575 .shufflevector => {
3576 const extra = self.extraData(Instruction.ShuffleVector, instruction.data);
3577 instruction.data = wip_extra.addExtra(Instruction.ShuffleVector{
3578 .lhs = instructions.map(extra.lhs),
3579 .rhs = instructions.map(extra.rhs),
3580 .mask = instructions.map(extra.mask),
3581 });
3582 },
3583 .store,
3584 .@"store atomic",
3585 .@"store atomic volatile",
3586 .@"store volatile",
3587 => {
3588 const extra = self.extraData(Instruction.Store, instruction.data);
3589 instruction.data = wip_extra.addExtra(Instruction.Store{
3590 .val = instructions.map(extra.val),
3591 .ptr = instructions.map(extra.ptr),
3592 .info = extra.info,
3593 });
3594 },
3595 .@"switch" => {
3596 var extra = self.extraDataTrail(Instruction.Switch, instruction.data);
3597 const case_vals = extra.trail.next(extra.data.cases_len, Constant, self);
3598 const case_blocks = extra.trail.next(extra.data.cases_len, Block.Index, self);
3599 instruction.data = wip_extra.addExtra(Instruction.Switch{
3600 .val = instructions.map(extra.data.val),
3601 .default = extra.data.default,
3602 .cases_len = extra.data.cases_len,
3603 });
3604 wip_extra.appendSlice(case_vals);
3605 wip_extra.appendSlice(case_blocks);
3606 },
3607 .va_arg => {
3608 const extra = self.extraData(Instruction.VaArg, instruction.data);
3609 instruction.data = wip_extra.addExtra(Instruction.VaArg{
3610 .list = instructions.map(extra.list),
3611 .type = extra.type,
3612 });
3613 },
3614 }
3615 function.instructions.appendAssumeCapacity(instruction);
3616 names[@intFromEnum(new_instruction_index)] = wip_name.map(if (self.builder.strip)
3617 if (old_instruction_index.hasResultWip(self)) .empty else .none
3618 else
3619 self.names.items[@intFromEnum(old_instruction_index)]);
3620 }
3621 }
3622
3623 assert(function.instructions.len == final_instructions_len);
3624 function.extra = wip_extra.finish();
3625 function.blocks = blocks;
3626 function.names = names.ptr;
3627 function.metadata = if (metadata) |new_metadata| new_metadata.ptr else null;
3628 }
3629
3630 pub fn deinit(self: *WipFunction) void {
3631 self.extra.deinit(self.builder.gpa);
3632 self.instructions.deinit(self.builder.gpa);
3633 for (self.blocks.items) |*b| b.instructions.deinit(self.builder.gpa);
3634 self.blocks.deinit(self.builder.gpa);
3635 if (self.builder.useLibLlvm()) self.llvm.builder.dispose();
3636 self.* = undefined;
3637 }
3638
3639 fn cmpTag(
3640 self: *WipFunction,
3641 tag: Instruction.Tag,
3642 cond: u32,
3643 lhs: Value,
3644 rhs: Value,
3645 name: []const u8,
3646 ) Allocator.Error!Value {
3647 switch (tag) {
3648 .@"fcmp false",
3649 .@"fcmp fast false",
3650 .@"fcmp fast oeq",
3651 .@"fcmp fast oge",
3652 .@"fcmp fast ogt",
3653 .@"fcmp fast ole",
3654 .@"fcmp fast olt",
3655 .@"fcmp fast one",
3656 .@"fcmp fast ord",
3657 .@"fcmp fast true",
3658 .@"fcmp fast ueq",
3659 .@"fcmp fast uge",
3660 .@"fcmp fast ugt",
3661 .@"fcmp fast ule",
3662 .@"fcmp fast ult",
3663 .@"fcmp fast une",
3664 .@"fcmp fast uno",
3665 .@"fcmp oeq",
3666 .@"fcmp oge",
3667 .@"fcmp ogt",
3668 .@"fcmp ole",
3669 .@"fcmp olt",
3670 .@"fcmp one",
3671 .@"fcmp ord",
3672 .@"fcmp true",
3673 .@"fcmp ueq",
3674 .@"fcmp uge",
3675 .@"fcmp ugt",
3676 .@"fcmp ule",
3677 .@"fcmp ult",
3678 .@"fcmp une",
3679 .@"fcmp uno",
3680 .@"icmp eq",
3681 .@"icmp ne",
3682 .@"icmp sge",
3683 .@"icmp sgt",
3684 .@"icmp sle",
3685 .@"icmp slt",
3686 .@"icmp uge",
3687 .@"icmp ugt",
3688 .@"icmp ule",
3689 .@"icmp ult",
3690 => assert(lhs.typeOfWip(self) == rhs.typeOfWip(self)),
3691 else => unreachable,
3692 }
3693 _ = try lhs.typeOfWip(self).changeScalar(.i1, self.builder);
3694 try self.ensureUnusedExtraCapacity(1, Instruction.Binary, 0);
3695 const instruction = try self.addInst(name, .{
3696 .tag = tag,
3697 .data = self.addExtraAssumeCapacity(Instruction.Binary{
3698 .lhs = lhs,
3699 .rhs = rhs,
3700 }),
3701 });
3702 if (self.builder.useLibLlvm()) {
3703 switch (tag) {
3704 .@"fcmp false",
3705 .@"fcmp oeq",
3706 .@"fcmp oge",
3707 .@"fcmp ogt",
3708 .@"fcmp ole",
3709 .@"fcmp olt",
3710 .@"fcmp one",
3711 .@"fcmp ord",
3712 .@"fcmp true",
3713 .@"fcmp ueq",
3714 .@"fcmp uge",
3715 .@"fcmp ugt",
3716 .@"fcmp ule",
3717 .@"fcmp ult",
3718 .@"fcmp une",
3719 .@"fcmp uno",
3720 => self.llvm.builder.setFastMath(false),
3721 .@"fcmp fast false",
3722 .@"fcmp fast oeq",
3723 .@"fcmp fast oge",
3724 .@"fcmp fast ogt",
3725 .@"fcmp fast ole",
3726 .@"fcmp fast olt",
3727 .@"fcmp fast one",
3728 .@"fcmp fast ord",
3729 .@"fcmp fast true",
3730 .@"fcmp fast ueq",
3731 .@"fcmp fast uge",
3732 .@"fcmp fast ugt",
3733 .@"fcmp fast ule",
3734 .@"fcmp fast ult",
3735 .@"fcmp fast une",
3736 .@"fcmp fast uno",
3737 => self.llvm.builder.setFastMath(true),
3738 .@"icmp eq",
3739 .@"icmp ne",
3740 .@"icmp sge",
3741 .@"icmp sgt",
3742 .@"icmp sle",
3743 .@"icmp slt",
3744 .@"icmp uge",
3745 .@"icmp ugt",
3746 .@"icmp ule",
3747 .@"icmp ult",
3748 => {},
3749 else => unreachable,
3750 }
3751 self.llvm.instructions.appendAssumeCapacity(switch (tag) {
3752 .@"fcmp false",
3753 .@"fcmp fast false",
3754 .@"fcmp fast oeq",
3755 .@"fcmp fast oge",
3756 .@"fcmp fast ogt",
3757 .@"fcmp fast ole",
3758 .@"fcmp fast olt",
3759 .@"fcmp fast one",
3760 .@"fcmp fast ord",
3761 .@"fcmp fast true",
3762 .@"fcmp fast ueq",
3763 .@"fcmp fast uge",
3764 .@"fcmp fast ugt",
3765 .@"fcmp fast ule",
3766 .@"fcmp fast ult",
3767 .@"fcmp fast une",
3768 .@"fcmp fast uno",
3769 .@"fcmp oeq",
3770 .@"fcmp oge",
3771 .@"fcmp ogt",
3772 .@"fcmp ole",
3773 .@"fcmp olt",
3774 .@"fcmp one",
3775 .@"fcmp ord",
3776 .@"fcmp true",
3777 .@"fcmp ueq",
3778 .@"fcmp uge",
3779 .@"fcmp ugt",
3780 .@"fcmp ule",
3781 .@"fcmp ult",
3782 .@"fcmp une",
3783 .@"fcmp uno",
3784 => self.llvm.builder.buildFCmp(
3785 @enumFromInt(cond),
3786 lhs.toLlvm(self),
3787 rhs.toLlvm(self),
3788 instruction.llvmName(self),
3789 ),
3790 .@"icmp eq",
3791 .@"icmp ne",
3792 .@"icmp sge",
3793 .@"icmp sgt",
3794 .@"icmp sle",
3795 .@"icmp slt",
3796 .@"icmp uge",
3797 .@"icmp ugt",
3798 .@"icmp ule",
3799 .@"icmp ult",
3800 => self.llvm.builder.buildICmp(
3801 @enumFromInt(cond),
3802 lhs.toLlvm(self),
3803 rhs.toLlvm(self),
3804 instruction.llvmName(self),
3805 ),
3806 else => unreachable,
3807 });
3808 }
3809 return instruction.toValue();
3810 }
3811
3812 fn phiTag(
3813 self: *WipFunction,
3814 tag: Instruction.Tag,
3815 ty: Type,
3816 name: []const u8,
3817 ) Allocator.Error!WipPhi {
3818 switch (tag) {
3819 .phi, .@"phi fast" => assert(try ty.isSized(self.builder)),
3820 else => unreachable,
3821 }
3822 const incoming = self.cursor.block.ptrConst(self).incoming;
3823 assert(incoming > 0);
3824 try self.ensureUnusedExtraCapacity(1, Instruction.Phi, incoming * 2);
3825 const instruction = try self.addInst(name, .{
3826 .tag = tag,
3827 .data = self.addExtraAssumeCapacity(Instruction.Phi{ .type = ty }),
3828 });
3829 _ = self.extra.addManyAsSliceAssumeCapacity(incoming * 2);
3830 if (self.builder.useLibLlvm()) {
3831 switch (tag) {
3832 .phi => self.llvm.builder.setFastMath(false),
3833 .@"phi fast" => self.llvm.builder.setFastMath(true),
3834 else => unreachable,
3835 }
3836 self.llvm.instructions.appendAssumeCapacity(
3837 self.llvm.builder.buildPhi(ty.toLlvm(self.builder), instruction.llvmName(self)),
3838 );
3839 }
3840 return .{ .block = self.cursor.block, .instruction = instruction };
3841 }
3842
3843 fn selectTag(
3844 self: *WipFunction,
3845 tag: Instruction.Tag,
3846 cond: Value,
3847 lhs: Value,
3848 rhs: Value,
3849 name: []const u8,
3850 ) Allocator.Error!Value {
3851 switch (tag) {
3852 .select, .@"select fast" => {
3853 assert(cond.typeOfWip(self).scalarType(self.builder) == .i1);
3854 assert(lhs.typeOfWip(self) == rhs.typeOfWip(self));
3855 },
3856 else => unreachable,
3857 }
3858 try self.ensureUnusedExtraCapacity(1, Instruction.Select, 0);
3859 const instruction = try self.addInst(name, .{
3860 .tag = tag,
3861 .data = self.addExtraAssumeCapacity(Instruction.Select{
3862 .cond = cond,
3863 .lhs = lhs,
3864 .rhs = rhs,
3865 }),
3866 });
3867 if (self.builder.useLibLlvm()) {
3868 switch (tag) {
3869 .select => self.llvm.builder.setFastMath(false),
3870 .@"select fast" => self.llvm.builder.setFastMath(true),
3871 else => unreachable,
3872 }
3873 self.llvm.instructions.appendAssumeCapacity(self.llvm.builder.buildSelect(
3874 cond.toLlvm(self),
3875 lhs.toLlvm(self),
3876 rhs.toLlvm(self),
3877 instruction.llvmName(self),
3878 ));
3879 }
3880 return instruction.toValue();
3881 }
3882
3883 fn ensureUnusedExtraCapacity(
3884 self: *WipFunction,
3885 count: usize,
3886 comptime Extra: type,
3887 trail_len: usize,
3888 ) Allocator.Error!void {
3889 try self.extra.ensureUnusedCapacity(
3890 self.builder.gpa,
3891 count * (@typeInfo(Extra).Struct.fields.len + trail_len),
3892 );
3893 }
3894
3895 fn addInst(
3896 self: *WipFunction,
3897 name: ?[]const u8,
3898 instruction: Instruction,
3899 ) Allocator.Error!Instruction.Index {
3900 const block_instructions = &self.cursor.block.ptr(self).instructions;
3901 try self.instructions.ensureUnusedCapacity(self.builder.gpa, 1);
3902 if (!self.builder.strip) try self.names.ensureUnusedCapacity(self.builder.gpa, 1);
3903 try block_instructions.ensureUnusedCapacity(self.builder.gpa, 1);
3904 if (self.builder.useLibLlvm())
3905 try self.llvm.instructions.ensureUnusedCapacity(self.builder.gpa, 1);
3906 const final_name = if (name) |n|
3907 if (self.builder.strip) .empty else try self.builder.string(n)
3908 else
3909 .none;
3910
3911 if (self.builder.useLibLlvm()) self.llvm.builder.positionBuilder(
3912 self.cursor.block.toLlvm(self),
3913 for (block_instructions.items[self.cursor.instruction..]) |instruction_index| {
3914 const llvm_instruction =
3915 self.llvm.instructions.items[@intFromEnum(instruction_index)];
3916 // TODO: remove when constant propagation is implemented
3917 if (!llvm_instruction.isConstant().toBool()) break llvm_instruction;
3918 } else null,
3919 );
3920
3921 const index: Instruction.Index = @enumFromInt(self.instructions.len);
3922 self.instructions.appendAssumeCapacity(instruction);
3923 if (!self.builder.strip) self.names.appendAssumeCapacity(final_name);
3924 block_instructions.insertAssumeCapacity(self.cursor.instruction, index);
3925 self.cursor.instruction += 1;
3926 return index;
3927 }
3928
3929 fn addExtraAssumeCapacity(self: *WipFunction, extra: anytype) Instruction.ExtraIndex {
3930 const result: Instruction.ExtraIndex = @intCast(self.extra.items.len);
3931 inline for (@typeInfo(@TypeOf(extra)).Struct.fields) |field| {
3932 const value = @field(extra, field.name);
3933 self.extra.appendAssumeCapacity(switch (field.type) {
3934 u32 => value,
3935 Alignment, AtomicOrdering, Block.Index, Type, Value => @intFromEnum(value),
3936 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),
3937 else => @compileError("bad field type: " ++ @typeName(field.type)),
3938 });
3939 }
3940 return result;
3941 }
3942
3943 const ExtraDataTrail = struct {
3944 index: Instruction.ExtraIndex,
3945
3946 fn nextMut(self: *ExtraDataTrail, len: u32, comptime Item: type, wip: *WipFunction) []Item {
3947 const items: []Item = @ptrCast(wip.extra.items[self.index..][0..len]);
3948 self.index += @intCast(len);
3949 return items;
3950 }
3951
3952 fn next(
3953 self: *ExtraDataTrail,
3954 len: u32,
3955 comptime Item: type,
3956 wip: *const WipFunction,
3957 ) []const Item {
3958 const items: []const Item = @ptrCast(wip.extra.items[self.index..][0..len]);
3959 self.index += @intCast(len);
3960 return items;
3961 }
3962 };
3963
3964 fn extraDataTrail(
3965 self: *const WipFunction,
3966 comptime T: type,
3967 index: Instruction.ExtraIndex,
3968 ) struct { data: T, trail: ExtraDataTrail } {
3969 var result: T = undefined;
3970 const fields = @typeInfo(T).Struct.fields;
3971 inline for (fields, self.extra.items[index..][0..fields.len]) |field, value|
3972 @field(result, field.name) = switch (field.type) {
3973 u32 => value,
3974 Alignment, AtomicOrdering, Block.Index, Type, Value => @enumFromInt(value),
3975 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),
3976 else => @compileError("bad field type: " ++ @typeName(field.type)),
3977 };
3978 return .{
3979 .data = result,
3980 .trail = .{ .index = index + @as(Type.Item.ExtraIndex, @intCast(fields.len)) },
3981 };
3982 }
3983
3984 fn extraData(self: *const WipFunction, comptime T: type, index: Instruction.ExtraIndex) T {
3985 return self.extraDataTrail(T, index).data;
3986 }
3987};
3988
3989pub const FloatCondition = enum(u4) {
3990 oeq = 1,
3991 ogt = 2,
3992 oge = 3,
3993 olt = 4,
3994 ole = 5,
3995 one = 6,
3996 ord = 7,
3997 uno = 8,
3998 ueq = 9,
3999 ugt = 10,
4000 uge = 11,
4001 ult = 12,
4002 ule = 13,
4003 une = 14,
4004};
4005
4006pub const IntegerCondition = enum(u6) {
4007 eq = 32,
4008 ne = 33,
4009 ugt = 34,
4010 uge = 35,
4011 ult = 36,
4012 ule = 37,
4013 sgt = 38,
4014 sge = 39,
4015 slt = 40,
4016 sle = 41,
4017};
4018
4019pub const MemoryAccessKind = enum(u1) {
4020 normal,
4021 @"volatile",
4022};
4023
4024pub const SyncScope = enum(u1) {
4025 singlethread,
4026 system,
4027
4028 pub fn format(
4029 self: SyncScope,
4030 comptime prefix: []const u8,
4031 _: std.fmt.FormatOptions,
4032 writer: anytype,
4033 ) @TypeOf(writer).Error!void {
4034 if (self != .system) try writer.print(
4035 \\{s} syncscope("{s}")
4036 , .{ prefix, @tagName(self) });
4037 }
4038};
4039
4040pub const AtomicOrdering = enum(u3) {
4041 none = 0,
4042 unordered = 1,
4043 monotonic = 2,
4044 acquire = 4,
4045 release = 5,
4046 acq_rel = 6,
4047 seq_cst = 7,
4048
4049 pub fn format(
4050 self: AtomicOrdering,
4051 comptime prefix: []const u8,
4052 _: std.fmt.FormatOptions,
4053 writer: anytype,
4054 ) @TypeOf(writer).Error!void {
4055 if (self != .none) try writer.print("{s} {s}", .{ prefix, @tagName(self) });
4056 }
4057};
4058
4059const MemoryAccessInfo = packed struct(u32) {
4060 scope: SyncScope,
4061 ordering: AtomicOrdering,
4062 alignment: Alignment,
4063 _: u22 = undefined,
4064};
4065
4066pub const FastMath = packed struct(u32) {
4067 nnan: bool = false,
4068 ninf: bool = false,
4069 nsz: bool = false,
4070 arcp: bool = false,
4071 contract: bool = false,
4072 afn: bool = false,
4073 reassoc: bool = false,
4074
4075 pub const fast = FastMath{
4076 .nnan = true,
4077 .ninf = true,
4078 .nsz = true,
4079 .arcp = true,
4080 .contract = true,
4081 .afn = true,
4082 .realloc = true,
4083 };
4084};
4085
4086pub const Constant = enum(u32) {
4087 false,
4088 true,
4089 none,
4090 no_init = 1 << 31,
4091 _,
4092
4093 const first_global: Constant = @enumFromInt(1 << 30);
4094
4095 pub const Tag = enum(u6) {
4096 positive_integer,
4097 negative_integer,
4098 half,
4099 bfloat,
4100 float,
4101 double,
4102 fp128,
4103 x86_fp80,
4104 ppc_fp128,
4105 null,
4106 none,
4107 structure,
4108 packed_structure,
4109 array,
4110 string,
4111 string_null,
4112 vector,
4113 splat,
4114 zeroinitializer,
4115 undef,
4116 poison,
4117 blockaddress,
4118 dso_local_equivalent,
4119 no_cfi,
4120 trunc,
4121 zext,
4122 sext,
4123 fptrunc,
4124 fpext,
4125 fptoui,
4126 fptosi,
4127 uitofp,
4128 sitofp,
4129 ptrtoint,
4130 inttoptr,
4131 bitcast,
4132 addrspacecast,
4133 getelementptr,
4134 @"getelementptr inbounds",
4135 icmp,
4136 fcmp,
4137 extractelement,
4138 insertelement,
4139 shufflevector,
4140 add,
4141 @"add nsw",
4142 @"add nuw",
4143 sub,
4144 @"sub nsw",
4145 @"sub nuw",
4146 mul,
4147 @"mul nsw",
4148 @"mul nuw",
4149 shl,
4150 lshr,
4151 ashr,
4152 @"and",
4153 @"or",
4154 xor,
4155 };
4156
4157 pub const Item = struct {
4158 tag: Tag,
4159 data: ExtraIndex,
4160
4161 const ExtraIndex = u32;
4162 };
4163
4164 pub const Integer = packed struct(u64) {
4165 type: Type,
4166 limbs_len: u32,
4167
4168 pub const limbs = @divExact(@bitSizeOf(Integer), @bitSizeOf(std.math.big.Limb));
4169 };
4170
4171 pub const Double = struct {
4172 lo: u32,
4173 hi: u32,
4174 };
4175
4176 pub const Fp80 = struct {
4177 lo_lo: u32,
4178 lo_hi: u32,
4179 hi: u32,
4180 };
4181
4182 pub const Fp128 = struct {
4183 lo_lo: u32,
4184 lo_hi: u32,
4185 hi_lo: u32,
4186 hi_hi: u32,
4187 };
4188
4189 pub const Aggregate = struct {
4190 type: Type,
4191 //fields: [type.aggregateLen(builder)]Constant,
4192 };
4193
4194 pub const Splat = extern struct {
4195 type: Type,
4196 value: Constant,
4197 };
4198
4199 pub const BlockAddress = extern struct {
4200 function: Function.Index,
4201 block: Function.Block.Index,
4202 };
4203
4204 pub const Cast = extern struct {
4205 val: Constant,
4206 type: Type,
4207
4208 pub const Signedness = enum { unsigned, signed, unneeded };
4209 };
4210
4211 pub const GetElementPtr = struct {
4212 type: Type,
4213 base: Constant,
4214 info: Info,
4215 //indices: [info.indices_len]Constant,
4216
4217 pub const Kind = enum { normal, inbounds };
4218 pub const InRangeIndex = enum(u16) { none = std.math.maxInt(u16), _ };
4219 pub const Info = packed struct(u32) { indices_len: u16, inrange: InRangeIndex };
4220 };
4221
4222 pub const Compare = extern struct {
4223 cond: u32,
4224 lhs: Constant,
4225 rhs: Constant,
4226 };
4227
4228 pub const ExtractElement = extern struct {
4229 val: Constant,
4230 index: Constant,
4231 };
4232
4233 pub const InsertElement = extern struct {
4234 val: Constant,
4235 elem: Constant,
4236 index: Constant,
4237 };
4238
4239 pub const ShuffleVector = extern struct {
4240 lhs: Constant,
4241 rhs: Constant,
4242 mask: Constant,
4243 };
4244
4245 pub const Binary = extern struct {
4246 lhs: Constant,
4247 rhs: Constant,
4248 };
4249
4250 pub fn unwrap(self: Constant) union(enum) {
4251 constant: u30,
4252 global: Global.Index,
4253 } {
4254 return if (@intFromEnum(self) < @intFromEnum(first_global))
4255 .{ .constant = @intCast(@intFromEnum(self)) }
4256 else
4257 .{ .global = @enumFromInt(@intFromEnum(self) - @intFromEnum(first_global)) };
4258 }
4259
4260 pub fn toValue(self: Constant) Value {
4261 return @enumFromInt(@intFromEnum(Value.first_constant) + @intFromEnum(self));
4262 }
4263
4264 pub fn typeOf(self: Constant, builder: *Builder) Type {
4265 switch (self.unwrap()) {
4266 .constant => |constant| {
4267 const item = builder.constant_items.get(constant);
4268 return switch (item.tag) {
4269 .positive_integer,
4270 .negative_integer,
4271 => @as(
4272 *align(@alignOf(std.math.big.Limb)) Integer,
4273 @ptrCast(builder.constant_limbs.items[item.data..][0..Integer.limbs]),
4274 ).type,
4275 .half => .half,
4276 .bfloat => .bfloat,
4277 .float => .float,
4278 .double => .double,
4279 .fp128 => .fp128,
4280 .x86_fp80 => .x86_fp80,
4281 .ppc_fp128 => .ppc_fp128,
4282 .null,
4283 .none,
4284 .zeroinitializer,
4285 .undef,
4286 .poison,
4287 => @enumFromInt(item.data),
4288 .structure,
4289 .packed_structure,
4290 .array,
4291 .vector,
4292 => builder.constantExtraData(Aggregate, item.data).type,
4293 .splat => builder.constantExtraData(Splat, item.data).type,
4294 .string,
4295 .string_null,
4296 => builder.arrayTypeAssumeCapacity(
4297 @as(String, @enumFromInt(item.data)).toSlice(builder).?.len +
4298 @intFromBool(item.tag == .string_null),
4299 .i8,
4300 ),
4301 .blockaddress => builder.ptrTypeAssumeCapacity(
4302 builder.constantExtraData(BlockAddress, item.data)
4303 .function.ptrConst(builder).global.ptrConst(builder).addr_space,
4304 ),
4305 .dso_local_equivalent,
4306 .no_cfi,
4307 => builder.ptrTypeAssumeCapacity(@as(Function.Index, @enumFromInt(item.data))
4308 .ptrConst(builder).global.ptrConst(builder).addr_space),
4309 .trunc,
4310 .zext,
4311 .sext,
4312 .fptrunc,
4313 .fpext,
4314 .fptoui,
4315 .fptosi,
4316 .uitofp,
4317 .sitofp,
4318 .ptrtoint,
4319 .inttoptr,
4320 .bitcast,
4321 .addrspacecast,
4322 => builder.constantExtraData(Cast, item.data).type,
4323 .getelementptr,
4324 .@"getelementptr inbounds",
4325 => {
4326 var extra = builder.constantExtraDataTrail(GetElementPtr, item.data);
4327 const indices =
4328 extra.trail.next(extra.data.info.indices_len, Constant, builder);
4329 const base_ty = extra.data.base.typeOf(builder);
4330 if (!base_ty.isVector(builder)) for (indices) |index| {
4331 const index_ty = index.typeOf(builder);
4332 if (!index_ty.isVector(builder)) continue;
4333 return index_ty.changeScalarAssumeCapacity(base_ty, builder);
4334 };
4335 return base_ty;
4336 },
4337 .icmp,
4338 .fcmp,
4339 => builder.constantExtraData(Compare, item.data).lhs.typeOf(builder)
4340 .changeScalarAssumeCapacity(.i1, builder),
4341 .extractelement => builder.constantExtraData(ExtractElement, item.data)
4342 .val.typeOf(builder).childType(builder),
4343 .insertelement => builder.constantExtraData(InsertElement, item.data)
4344 .val.typeOf(builder),
4345 .shufflevector => {
4346 const extra = builder.constantExtraData(ShuffleVector, item.data);
4347 return extra.lhs.typeOf(builder).changeLengthAssumeCapacity(
4348 extra.mask.typeOf(builder).vectorLen(builder),
4349 builder,
4350 );
4351 },
4352 .add,
4353 .@"add nsw",
4354 .@"add nuw",
4355 .sub,
4356 .@"sub nsw",
4357 .@"sub nuw",
4358 .mul,
4359 .@"mul nsw",
4360 .@"mul nuw",
4361 .shl,
4362 .lshr,
4363 .ashr,
4364 .@"and",
4365 .@"or",
4366 .xor,
4367 => builder.constantExtraData(Binary, item.data).lhs.typeOf(builder),
4368 };
4369 },
4370 .global => |global| return builder.ptrTypeAssumeCapacity(
4371 global.ptrConst(builder).addr_space,
4372 ),
4373 }
4374 }
4375
4376 pub fn isZeroInit(self: Constant, builder: *const Builder) bool {
4377 switch (self.unwrap()) {
4378 .constant => |constant| {
4379 const item = builder.constant_items.get(constant);
4380 return switch (item.tag) {
4381 .positive_integer => {
4382 const extra: *align(@alignOf(std.math.big.Limb)) Integer =
4383 @ptrCast(builder.constant_limbs.items[item.data..][0..Integer.limbs]);
4384 const limbs = builder.constant_limbs
4385 .items[item.data + Integer.limbs ..][0..extra.limbs_len];
4386 return std.mem.eql(std.math.big.Limb, limbs, &.{0});
4387 },
4388 .half, .bfloat, .float => item.data == 0,
4389 .double => {
4390 const extra = builder.constantExtraData(Constant.Double, item.data);
4391 return extra.lo == 0 and extra.hi == 0;
4392 },
4393 .fp128, .ppc_fp128 => {
4394 const extra = builder.constantExtraData(Constant.Fp128, item.data);
4395 return extra.lo_lo == 0 and extra.lo_hi == 0 and
4396 extra.hi_lo == 0 and extra.hi_hi == 0;
4397 },
4398 .x86_fp80 => {
4399 const extra = builder.constantExtraData(Constant.Fp80, item.data);
4400 return extra.lo_lo == 0 and extra.lo_hi == 0 and extra.hi == 0;
4401 },
4402 .vector => {
4403 var extra = builder.constantExtraDataTrail(Aggregate, item.data);
4404 const len: u32 = @intCast(extra.data.type.aggregateLen(builder));
4405 const vals = extra.trail.next(len, Constant, builder);
4406 for (vals) |val| if (!val.isZeroInit(builder)) return false;
4407 return true;
4408 },
4409 .null, .zeroinitializer => true,
4410 else => false,
4411 };
4412 },
4413 .global => return false,
4414 }
4415 }
4416
4417 pub fn getBase(self: Constant, builder: *const Builder) Global.Index {
4418 var cur = self;
4419 while (true) switch (cur.unwrap()) {
4420 .constant => |constant| {
4421 const item = builder.constant_items.get(constant);
4422 switch (item.tag) {
4423 .ptrtoint,
4424 .inttoptr,
4425 .bitcast,
4426 => cur = builder.constantExtraData(Cast, item.data).val,
4427 .getelementptr => cur = builder.constantExtraData(GetElementPtr, item.data).base,
4428 .add => {
4429 const extra = builder.constantExtraData(Binary, item.data);
4430 const lhs_base = extra.lhs.getBase(builder);
4431 const rhs_base = extra.rhs.getBase(builder);
4432 return if (lhs_base != .none and rhs_base != .none)
4433 .none
4434 else if (lhs_base != .none) lhs_base else rhs_base;
4435 },
4436 .sub => {
4437 const extra = builder.constantExtraData(Binary, item.data);
4438 if (extra.rhs.getBase(builder) != .none) return .none;
4439 cur = extra.lhs;
4440 },
4441 else => return .none,
4442 }
4443 },
4444 .global => |global| switch (global.ptrConst(builder).kind) {
4445 .alias => |alias| cur = alias.ptrConst(builder).init,
4446 .variable, .function => return global,
4447 .replaced => unreachable,
4448 },
4449 };
4450 }
4451
4452 const FormatData = struct {
4453 constant: Constant,
4454 builder: *Builder,
4455 };
4456 fn format(
4457 data: FormatData,
4458 comptime fmt_str: []const u8,
4459 _: std.fmt.FormatOptions,
4460 writer: anytype,
4461 ) @TypeOf(writer).Error!void {
4462 if (comptime std.mem.indexOfNone(u8, fmt_str, ", %")) |_|
4463 @compileError("invalid format string: '" ++ fmt_str ++ "'");
4464 if (comptime std.mem.indexOfScalar(u8, fmt_str, ',') != null) {
4465 if (data.constant == .no_init) return;
4466 try writer.writeByte(',');
4467 }
4468 if (comptime std.mem.indexOfScalar(u8, fmt_str, ' ') != null) {
4469 if (data.constant == .no_init) return;
4470 try writer.writeByte(' ');
4471 }
4472 if (comptime std.mem.indexOfScalar(u8, fmt_str, '%') != null)
4473 try writer.print("{%} ", .{data.constant.typeOf(data.builder).fmt(data.builder)});
4474 assert(data.constant != .no_init);
4475 if (std.enums.tagName(Constant, data.constant)) |name| return writer.writeAll(name);
4476 switch (data.constant.unwrap()) {
4477 .constant => |constant| {
4478 const item = data.builder.constant_items.get(constant);
4479 switch (item.tag) {
4480 .positive_integer,
4481 .negative_integer,
4482 => |tag| {
4483 const extra: *align(@alignOf(std.math.big.Limb)) Integer =
4484 @ptrCast(data.builder.constant_limbs.items[item.data..][0..Integer.limbs]);
4485 const limbs = data.builder.constant_limbs
4486 .items[item.data + Integer.limbs ..][0..extra.limbs_len];
4487 const bigint = std.math.big.int.Const{
4488 .limbs = limbs,
4489 .positive = tag == .positive_integer,
4490 };
4491 const ExpectedContents = extern struct {
4492 string: [(64 * 8 / std.math.log2(10)) + 2]u8,
4493 limbs: [
4494 std.math.big.int.calcToStringLimbsBufferLen(
4495 64 / @sizeOf(std.math.big.Limb),
4496 10,
4497 )
4498 ]std.math.big.Limb,
4499 };
4500 var stack align(@alignOf(ExpectedContents)) =
4501 std.heap.stackFallback(@sizeOf(ExpectedContents), data.builder.gpa);
4502 const allocator = stack.get();
4503 const str = bigint.toStringAlloc(allocator, 10, undefined) catch
4504 return writer.writeAll("...");
4505 defer allocator.free(str);
4506 try writer.writeAll(str);
4507 },
4508 .half,
4509 .bfloat,
4510 => |tag| try writer.print("0x{c}{X:0>4}", .{ @as(u8, switch (tag) {
4511 .half => 'H',
4512 .bfloat => 'R',
4513 else => unreachable,
4514 }), item.data >> switch (tag) {
4515 .half => 0,
4516 .bfloat => 16,
4517 else => unreachable,
4518 } }),
4519 .float => try writer.print("0x{X:0>16}", .{
4520 @as(u64, @bitCast(@as(f64, @as(f32, @bitCast(item.data))))),
4521 }),
4522 .double => {
4523 const extra = data.builder.constantExtraData(Double, item.data);
4524 try writer.print("0x{X:0>8}{X:0>8}", .{ extra.hi, extra.lo });
4525 },
4526 .fp128,
4527 .ppc_fp128,
4528 => |tag| {
4529 const extra = data.builder.constantExtraData(Fp128, item.data);
4530 try writer.print("0x{c}{X:0>8}{X:0>8}{X:0>8}{X:0>8}", .{
4531 @as(u8, switch (tag) {
4532 .fp128 => 'L',
4533 .ppc_fp128 => 'M',
4534 else => unreachable,
4535 }),
4536 extra.lo_hi,
4537 extra.lo_lo,
4538 extra.hi_hi,
4539 extra.hi_lo,
4540 });
4541 },
4542 .x86_fp80 => {
4543 const extra = data.builder.constantExtraData(Fp80, item.data);
4544 try writer.print("0xK{X:0>4}{X:0>8}{X:0>8}", .{
4545 extra.hi, extra.lo_hi, extra.lo_lo,
4546 });
4547 },
4548 .null,
4549 .none,
4550 .zeroinitializer,
4551 .undef,
4552 .poison,
4553 => |tag| try writer.writeAll(@tagName(tag)),
4554 .structure,
4555 .packed_structure,
4556 .array,
4557 .vector,
4558 => |tag| {
4559 var extra = data.builder.constantExtraDataTrail(Aggregate, item.data);
4560 const len: u32 = @intCast(extra.data.type.aggregateLen(data.builder));
4561 const vals = extra.trail.next(len, Constant, data.builder);
4562 try writer.writeAll(switch (tag) {
4563 .structure => "{ ",
4564 .packed_structure => "<{ ",
4565 .array => "[",
4566 .vector => "<",
4567 else => unreachable,
4568 });
4569 for (vals, 0..) |val, index| {
4570 if (index > 0) try writer.writeAll(", ");
4571 try writer.print("{%}", .{val.fmt(data.builder)});
4572 }
4573 try writer.writeAll(switch (tag) {
4574 .structure => " }",
4575 .packed_structure => " }>",
4576 .array => "]",
4577 .vector => ">",
4578 else => unreachable,
4579 });
4580 },
4581 .splat => {
4582 const extra = data.builder.constantExtraData(Splat, item.data);
4583 const len = extra.type.vectorLen(data.builder);
4584 try writer.writeByte('<');
4585 for (0..len) |index| {
4586 if (index > 0) try writer.writeAll(", ");
4587 try writer.print("{%}", .{extra.value.fmt(data.builder)});
4588 }
4589 try writer.writeByte('>');
4590 },
4591 inline .string,
4592 .string_null,
4593 => |tag| try writer.print("c{\"" ++ switch (tag) {
4594 .string => "",
4595 .string_null => "@",
4596 else => unreachable,
4597 } ++ "}", .{@as(String, @enumFromInt(item.data)).fmt(data.builder)}),
4598 .blockaddress => |tag| {
4599 const extra = data.builder.constantExtraData(BlockAddress, item.data);
4600 const function = extra.function.ptrConst(data.builder);
4601 try writer.print("{s}({}, %{d})", .{
4602 @tagName(tag),
4603 function.global.fmt(data.builder),
4604 @intFromEnum(extra.block), // TODO
4605 });
4606 },
4607 .dso_local_equivalent,
4608 .no_cfi,
4609 => |tag| {
4610 const function: Function.Index = @enumFromInt(item.data);
4611 try writer.print("{s} {}", .{
4612 @tagName(tag),
4613 function.ptrConst(data.builder).global.fmt(data.builder),
4614 });
4615 },
4616 .trunc,
4617 .zext,
4618 .sext,
4619 .fptrunc,
4620 .fpext,
4621 .fptoui,
4622 .fptosi,
4623 .uitofp,
4624 .sitofp,
4625 .ptrtoint,
4626 .inttoptr,
4627 .bitcast,
4628 .addrspacecast,
4629 => |tag| {
4630 const extra = data.builder.constantExtraData(Cast, item.data);
4631 try writer.print("{s} ({%} to {%})", .{
4632 @tagName(tag),
4633 extra.val.fmt(data.builder),
4634 extra.type.fmt(data.builder),
4635 });
4636 },
4637 .getelementptr,
4638 .@"getelementptr inbounds",
4639 => |tag| {
4640 var extra = data.builder.constantExtraDataTrail(GetElementPtr, item.data);
4641 const indices =
4642 extra.trail.next(extra.data.info.indices_len, Constant, data.builder);
4643 try writer.print("{s} ({%}, {%}", .{
4644 @tagName(tag),
4645 extra.data.type.fmt(data.builder),
4646 extra.data.base.fmt(data.builder),
4647 });
4648 for (indices) |index| try writer.print(", {%}", .{index.fmt(data.builder)});
4649 try writer.writeByte(')');
4650 },
4651 inline .icmp,
4652 .fcmp,
4653 => |tag| {
4654 const extra = data.builder.constantExtraData(Compare, item.data);
4655 try writer.print("{s} {s} ({%}, {%})", .{
4656 @tagName(tag),
4657 @tagName(@as(switch (tag) {
4658 .icmp => IntegerCondition,
4659 .fcmp => FloatCondition,
4660 else => unreachable,
4661 }, @enumFromInt(extra.cond))),
4662 extra.lhs.fmt(data.builder),
4663 extra.rhs.fmt(data.builder),
4664 });
4665 },
4666 .extractelement => |tag| {
4667 const extra = data.builder.constantExtraData(ExtractElement, item.data);
4668 try writer.print("{s} ({%}, {%})", .{
4669 @tagName(tag),
4670 extra.val.fmt(data.builder),
4671 extra.index.fmt(data.builder),
4672 });
4673 },
4674 .insertelement => |tag| {
4675 const extra = data.builder.constantExtraData(InsertElement, item.data);
4676 try writer.print("{s} ({%}, {%}, {%})", .{
4677 @tagName(tag),
4678 extra.val.fmt(data.builder),
4679 extra.elem.fmt(data.builder),
4680 extra.index.fmt(data.builder),
4681 });
4682 },
4683 .shufflevector => |tag| {
4684 const extra = data.builder.constantExtraData(ShuffleVector, item.data);
4685 try writer.print("{s} ({%}, {%}, {%})", .{
4686 @tagName(tag),
4687 extra.lhs.fmt(data.builder),
4688 extra.rhs.fmt(data.builder),
4689 extra.mask.fmt(data.builder),
4690 });
4691 },
4692 .add,
4693 .@"add nsw",
4694 .@"add nuw",
4695 .sub,
4696 .@"sub nsw",
4697 .@"sub nuw",
4698 .mul,
4699 .@"mul nsw",
4700 .@"mul nuw",
4701 .shl,
4702 .lshr,
4703 .ashr,
4704 .@"and",
4705 .@"or",
4706 .xor,
4707 => |tag| {
4708 const extra = data.builder.constantExtraData(Binary, item.data);
4709 try writer.print("{s} ({%}, {%})", .{
4710 @tagName(tag),
4711 extra.lhs.fmt(data.builder),
4712 extra.rhs.fmt(data.builder),
4713 });
4714 },
4715 }
4716 },
4717 .global => |global| try writer.print("{}", .{global.fmt(data.builder)}),
4718 }
4719 }
4720 pub fn fmt(self: Constant, builder: *Builder) std.fmt.Formatter(format) {
4721 return .{ .data = .{ .constant = self, .builder = builder } };
4722 }
4723
4724 pub fn toLlvm(self: Constant, builder: *const Builder) *llvm.Value {
4725 assert(builder.useLibLlvm());
4726 return switch (self.unwrap()) {
4727 .constant => |constant| builder.llvm.constants.items[constant],
4728 .global => |global| global.toLlvm(builder),
4729 };
4730 }
4731};
4732
4733pub const Value = enum(u32) {
4734 none = std.math.maxInt(u31),
4735 _,
4736
4737 const first_constant: Value = @enumFromInt(1 << 31);
4738
4739 pub fn unwrap(self: Value) union(enum) {
4740 instruction: Function.Instruction.Index,
4741 constant: Constant,
4742 } {
4743 return if (@intFromEnum(self) < @intFromEnum(first_constant))
4744 .{ .instruction = @enumFromInt(@intFromEnum(self)) }
4745 else
4746 .{ .constant = @enumFromInt(@intFromEnum(self) - @intFromEnum(first_constant)) };
4747 }
4748
4749 pub fn typeOfWip(self: Value, wip: *const WipFunction) Type {
4750 return switch (self.unwrap()) {
4751 .instruction => |instruction| instruction.typeOfWip(wip),
4752 .constant => |constant| constant.typeOf(wip.builder),
4753 };
4754 }
4755
4756 pub fn typeOf(self: Value, function: Function.Index, builder: *Builder) Type {
4757 return switch (self.unwrap()) {
4758 .instruction => |instruction| instruction.typeOf(function, builder),
4759 .constant => |constant| constant.typeOf(builder),
4760 };
4761 }
4762
4763 pub fn toConst(self: Value) ?Constant {
4764 return switch (self.unwrap()) {
4765 .instruction => null,
4766 .constant => |constant| constant,
4767 };
4768 }
4769
4770 const FormatData = struct {
4771 value: Value,
4772 function: Function.Index,
4773 builder: *Builder,
4774 };
4775 fn format(
4776 data: FormatData,
4777 comptime fmt_str: []const u8,
4778 fmt_opts: std.fmt.FormatOptions,
4779 writer: anytype,
4780 ) @TypeOf(writer).Error!void {
4781 switch (data.value.unwrap()) {
4782 .instruction => |instruction| try Function.Instruction.Index.format(.{
4783 .instruction = instruction,
4784 .function = data.function,
4785 .builder = data.builder,
4786 }, fmt_str, fmt_opts, writer),
4787 .constant => |constant| try Constant.format(.{
4788 .constant = constant,
4789 .builder = data.builder,
4790 }, fmt_str, fmt_opts, writer),
4791 }
4792 }
4793 pub fn fmt(self: Value, function: Function.Index, builder: *Builder) std.fmt.Formatter(format) {
4794 return .{ .data = .{ .value = self, .function = function, .builder = builder } };
4795 }
4796
4797 pub fn toLlvm(self: Value, wip: *const WipFunction) *llvm.Value {
4798 return switch (self.unwrap()) {
4799 .instruction => |instruction| instruction.toLlvm(wip),
4800 .constant => |constant| constant.toLlvm(wip.builder),
4801 };
4802 }
4803};
4804
4805pub const Metadata = enum(u32) { _ };
4806
4807pub const InitError = error{
4808 InvalidLlvmTriple,
4809} || Allocator.Error;
4810
4811pub fn init(options: Options) InitError!Builder {
4812 var self = Builder{
4813 .gpa = options.allocator,
4814 .use_lib_llvm = options.use_lib_llvm,
4815 .strip = options.strip,
4816
4817 .llvm = undefined,
4818
4819 .source_filename = .none,
4820 .data_layout = .none,
4821 .target_triple = .none,
4822
4823 .string_map = .{},
4824 .string_bytes = .{},
4825 .string_indices = .{},
4826
4827 .types = .{},
4828 .next_unnamed_type = @enumFromInt(0),
4829 .next_unique_type_id = .{},
4830 .type_map = .{},
4831 .type_items = .{},
4832 .type_extra = .{},
4833
4834 .globals = .{},
4835 .next_unnamed_global = @enumFromInt(0),
4836 .next_replaced_global = .none,
4837 .next_unique_global_id = .{},
4838 .aliases = .{},
4839 .variables = .{},
4840 .functions = .{},
4841
4842 .constant_map = .{},
4843 .constant_items = .{},
4844 .constant_extra = .{},
4845 .constant_limbs = .{},
4846 };
4847 if (self.useLibLlvm()) self.llvm = .{ .context = llvm.Context.create() };
4848 errdefer self.deinit();
4849
4850 try self.string_indices.append(self.gpa, 0);
4851 assert(try self.string("") == .empty);
4852
4853 if (options.name.len > 0) self.source_filename = try self.string(options.name);
4854 self.initializeLLVMTarget(options.target.cpu.arch);
4855 if (self.useLibLlvm()) self.llvm.module = llvm.Module.createWithName(
4856 (self.source_filename.toSlice(&self) orelse "").ptr,
4857 self.llvm.context,
4858 );
4859
4860 if (options.triple.len > 0) {
4861 self.target_triple = try self.string(options.triple);
4862
4863 if (self.useLibLlvm()) {
4864 var error_message: [*:0]const u8 = undefined;
4865 var target: *llvm.Target = undefined;
4866 if (llvm.Target.getFromTriple(
4867 self.target_triple.toSlice(&self).?,
4868 &target,
4869 &error_message,
4870 ).toBool()) {
4871 defer llvm.disposeMessage(error_message);
4872
4873 log.err("LLVM failed to parse '{s}': {s}", .{
4874 self.target_triple.toSlice(&self).?,
4875 error_message,
4876 });
4877 return InitError.InvalidLlvmTriple;
4878 }
4879 self.llvm.target = target;
4880 self.llvm.module.?.setTarget(self.target_triple.toSlice(&self).?);
4881 }
4882 }
4883
4884 {
4885 const static_len = @typeInfo(Type).Enum.fields.len - 1;
4886 try self.type_map.ensureTotalCapacity(self.gpa, static_len);
4887 try self.type_items.ensureTotalCapacity(self.gpa, static_len);
4888 if (self.useLibLlvm()) try self.llvm.types.ensureTotalCapacity(self.gpa, static_len);
4889 inline for (@typeInfo(Type.Simple).Enum.fields) |simple_field| {
4890 const result = self.getOrPutTypeNoExtraAssumeCapacity(
4891 .{ .tag = .simple, .data = simple_field.value },
4892 );
4893 assert(result.new and result.type == @field(Type, simple_field.name));
4894 if (self.useLibLlvm()) self.llvm.types.appendAssumeCapacity(
4895 @field(llvm.Context, simple_field.name ++ "Type")(self.llvm.context),
4896 );
4897 }
4898 inline for (.{ 1, 8, 16, 29, 32, 64, 80, 128 }) |bits|
4899 assert(self.intTypeAssumeCapacity(bits) ==
4900 @field(Type, std.fmt.comptimePrint("i{d}", .{bits})));
4901 inline for (.{0}) |addr_space|
4902 assert(self.ptrTypeAssumeCapacity(@enumFromInt(addr_space)) == .ptr);
4903 }
4904
4905 assert(try self.intConst(.i1, 0) == .false);
4906 assert(try self.intConst(.i1, 1) == .true);
4907 assert(try self.noneConst(.token) == .none);
4908
4909 return self;
4910}
4911
4912pub fn deinit(self: *Builder) void {
4913 self.string_map.deinit(self.gpa);
4914 self.string_bytes.deinit(self.gpa);
4915 self.string_indices.deinit(self.gpa);
4916
4917 self.types.deinit(self.gpa);
4918 self.next_unique_type_id.deinit(self.gpa);
4919 self.type_map.deinit(self.gpa);
4920 self.type_items.deinit(self.gpa);
4921 self.type_extra.deinit(self.gpa);
4922
4923 self.globals.deinit(self.gpa);
4924 self.next_unique_global_id.deinit(self.gpa);
4925 self.aliases.deinit(self.gpa);
4926 self.variables.deinit(self.gpa);
4927 for (self.functions.items) |*function| function.deinit(self.gpa);
4928 self.functions.deinit(self.gpa);
4929
4930 self.constant_map.deinit(self.gpa);
4931 self.constant_items.deinit(self.gpa);
4932 self.constant_extra.deinit(self.gpa);
4933 self.constant_limbs.deinit(self.gpa);
4934
4935 if (self.useLibLlvm()) {
4936 self.llvm.constants.deinit(self.gpa);
4937 self.llvm.globals.deinit(self.gpa);
4938 self.llvm.types.deinit(self.gpa);
4939 if (self.llvm.di_builder) |di_builder| di_builder.dispose();
4940 if (self.llvm.module) |module| module.dispose();
4941 self.llvm.context.dispose();
4942 }
4943 self.* = undefined;
4944}
4945
4946pub fn initializeLLVMTarget(self: *const Builder, arch: std.Target.Cpu.Arch) void {
4947 if (!self.useLibLlvm()) return;
4948 switch (arch) {
4949 .aarch64, .aarch64_be, .aarch64_32 => {
4950 llvm.LLVMInitializeAArch64Target();
4951 llvm.LLVMInitializeAArch64TargetInfo();
4952 llvm.LLVMInitializeAArch64TargetMC();
4953 llvm.LLVMInitializeAArch64AsmPrinter();
4954 llvm.LLVMInitializeAArch64AsmParser();
4955 },
4956 .amdgcn => {
4957 llvm.LLVMInitializeAMDGPUTarget();
4958 llvm.LLVMInitializeAMDGPUTargetInfo();
4959 llvm.LLVMInitializeAMDGPUTargetMC();
4960 llvm.LLVMInitializeAMDGPUAsmPrinter();
4961 llvm.LLVMInitializeAMDGPUAsmParser();
4962 },
4963 .thumb, .thumbeb, .arm, .armeb => {
4964 llvm.LLVMInitializeARMTarget();
4965 llvm.LLVMInitializeARMTargetInfo();
4966 llvm.LLVMInitializeARMTargetMC();
4967 llvm.LLVMInitializeARMAsmPrinter();
4968 llvm.LLVMInitializeARMAsmParser();
4969 },
4970 .avr => {
4971 llvm.LLVMInitializeAVRTarget();
4972 llvm.LLVMInitializeAVRTargetInfo();
4973 llvm.LLVMInitializeAVRTargetMC();
4974 llvm.LLVMInitializeAVRAsmPrinter();
4975 llvm.LLVMInitializeAVRAsmParser();
4976 },
4977 .bpfel, .bpfeb => {
4978 llvm.LLVMInitializeBPFTarget();
4979 llvm.LLVMInitializeBPFTargetInfo();
4980 llvm.LLVMInitializeBPFTargetMC();
4981 llvm.LLVMInitializeBPFAsmPrinter();
4982 llvm.LLVMInitializeBPFAsmParser();
4983 },
4984 .hexagon => {
4985 llvm.LLVMInitializeHexagonTarget();
4986 llvm.LLVMInitializeHexagonTargetInfo();
4987 llvm.LLVMInitializeHexagonTargetMC();
4988 llvm.LLVMInitializeHexagonAsmPrinter();
4989 llvm.LLVMInitializeHexagonAsmParser();
4990 },
4991 .lanai => {
4992 llvm.LLVMInitializeLanaiTarget();
4993 llvm.LLVMInitializeLanaiTargetInfo();
4994 llvm.LLVMInitializeLanaiTargetMC();
4995 llvm.LLVMInitializeLanaiAsmPrinter();
4996 llvm.LLVMInitializeLanaiAsmParser();
4997 },
4998 .mips, .mipsel, .mips64, .mips64el => {
4999 llvm.LLVMInitializeMipsTarget();
5000 llvm.LLVMInitializeMipsTargetInfo();
5001 llvm.LLVMInitializeMipsTargetMC();
5002 llvm.LLVMInitializeMipsAsmPrinter();
5003 llvm.LLVMInitializeMipsAsmParser();
5004 },
5005 .msp430 => {
5006 llvm.LLVMInitializeMSP430Target();
5007 llvm.LLVMInitializeMSP430TargetInfo();
5008 llvm.LLVMInitializeMSP430TargetMC();
5009 llvm.LLVMInitializeMSP430AsmPrinter();
5010 llvm.LLVMInitializeMSP430AsmParser();
5011 },
5012 .nvptx, .nvptx64 => {
5013 llvm.LLVMInitializeNVPTXTarget();
5014 llvm.LLVMInitializeNVPTXTargetInfo();
5015 llvm.LLVMInitializeNVPTXTargetMC();
5016 llvm.LLVMInitializeNVPTXAsmPrinter();
5017 // There is no LLVMInitializeNVPTXAsmParser function available.
5018 },
5019 .powerpc, .powerpcle, .powerpc64, .powerpc64le => {
5020 llvm.LLVMInitializePowerPCTarget();
5021 llvm.LLVMInitializePowerPCTargetInfo();
5022 llvm.LLVMInitializePowerPCTargetMC();
5023 llvm.LLVMInitializePowerPCAsmPrinter();
5024 llvm.LLVMInitializePowerPCAsmParser();
5025 },
5026 .riscv32, .riscv64 => {
5027 llvm.LLVMInitializeRISCVTarget();
5028 llvm.LLVMInitializeRISCVTargetInfo();
5029 llvm.LLVMInitializeRISCVTargetMC();
5030 llvm.LLVMInitializeRISCVAsmPrinter();
5031 llvm.LLVMInitializeRISCVAsmParser();
5032 },
5033 .sparc, .sparc64, .sparcel => {
5034 llvm.LLVMInitializeSparcTarget();
5035 llvm.LLVMInitializeSparcTargetInfo();
5036 llvm.LLVMInitializeSparcTargetMC();
5037 llvm.LLVMInitializeSparcAsmPrinter();
5038 llvm.LLVMInitializeSparcAsmParser();
5039 },
5040 .s390x => {
5041 llvm.LLVMInitializeSystemZTarget();
5042 llvm.LLVMInitializeSystemZTargetInfo();
5043 llvm.LLVMInitializeSystemZTargetMC();
5044 llvm.LLVMInitializeSystemZAsmPrinter();
5045 llvm.LLVMInitializeSystemZAsmParser();
5046 },
5047 .wasm32, .wasm64 => {
5048 llvm.LLVMInitializeWebAssemblyTarget();
5049 llvm.LLVMInitializeWebAssemblyTargetInfo();
5050 llvm.LLVMInitializeWebAssemblyTargetMC();
5051 llvm.LLVMInitializeWebAssemblyAsmPrinter();
5052 llvm.LLVMInitializeWebAssemblyAsmParser();
5053 },
5054 .x86, .x86_64 => {
5055 llvm.LLVMInitializeX86Target();
5056 llvm.LLVMInitializeX86TargetInfo();
5057 llvm.LLVMInitializeX86TargetMC();
5058 llvm.LLVMInitializeX86AsmPrinter();
5059 llvm.LLVMInitializeX86AsmParser();
5060 },
5061 .xtensa => {
5062 if (build_options.llvm_has_xtensa) {
5063 llvm.LLVMInitializeXtensaTarget();
5064 llvm.LLVMInitializeXtensaTargetInfo();
5065 llvm.LLVMInitializeXtensaTargetMC();
5066 llvm.LLVMInitializeXtensaAsmPrinter();
5067 llvm.LLVMInitializeXtensaAsmParser();
5068 }
5069 },
5070 .xcore => {
5071 llvm.LLVMInitializeXCoreTarget();
5072 llvm.LLVMInitializeXCoreTargetInfo();
5073 llvm.LLVMInitializeXCoreTargetMC();
5074 llvm.LLVMInitializeXCoreAsmPrinter();
5075 // There is no LLVMInitializeXCoreAsmParser function.
5076 },
5077 .m68k => {
5078 if (build_options.llvm_has_m68k) {
5079 llvm.LLVMInitializeM68kTarget();
5080 llvm.LLVMInitializeM68kTargetInfo();
5081 llvm.LLVMInitializeM68kTargetMC();
5082 llvm.LLVMInitializeM68kAsmPrinter();
5083 llvm.LLVMInitializeM68kAsmParser();
5084 }
5085 },
5086 .csky => {
5087 if (build_options.llvm_has_csky) {
5088 llvm.LLVMInitializeCSKYTarget();
5089 llvm.LLVMInitializeCSKYTargetInfo();
5090 llvm.LLVMInitializeCSKYTargetMC();
5091 // There is no LLVMInitializeCSKYAsmPrinter function.
5092 llvm.LLVMInitializeCSKYAsmParser();
5093 }
5094 },
5095 .ve => {
5096 llvm.LLVMInitializeVETarget();
5097 llvm.LLVMInitializeVETargetInfo();
5098 llvm.LLVMInitializeVETargetMC();
5099 llvm.LLVMInitializeVEAsmPrinter();
5100 llvm.LLVMInitializeVEAsmParser();
5101 },
5102 .arc => {
5103 if (build_options.llvm_has_arc) {
5104 llvm.LLVMInitializeARCTarget();
5105 llvm.LLVMInitializeARCTargetInfo();
5106 llvm.LLVMInitializeARCTargetMC();
5107 llvm.LLVMInitializeARCAsmPrinter();
5108 // There is no LLVMInitializeARCAsmParser function.
5109 }
5110 },
5111
5112 // LLVM backends that have no initialization functions.
5113 .tce,
5114 .tcele,
5115 .r600,
5116 .le32,
5117 .le64,
5118 .amdil,
5119 .amdil64,
5120 .hsail,
5121 .hsail64,
5122 .shave,
5123 .spir,
5124 .spir64,
5125 .kalimba,
5126 .renderscript32,
5127 .renderscript64,
5128 .dxil,
5129 .loongarch32,
5130 .loongarch64,
5131 => {},
5132
5133 .spu_2 => unreachable, // LLVM does not support this backend
5134 .spirv32 => unreachable, // LLVM does not support this backend
5135 .spirv64 => unreachable, // LLVM does not support this backend
5136 }
5137}
5138
5139pub fn string(self: *Builder, bytes: []const u8) Allocator.Error!String {
5140 try self.string_bytes.ensureUnusedCapacity(self.gpa, bytes.len + 1);
5141 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
5142 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
5143
5144 const gop = self.string_map.getOrPutAssumeCapacityAdapted(bytes, String.Adapter{ .builder = self });
5145 if (!gop.found_existing) {
5146 self.string_bytes.appendSliceAssumeCapacity(bytes);
5147 self.string_bytes.appendAssumeCapacity(0);
5148 self.string_indices.appendAssumeCapacity(@intCast(self.string_bytes.items.len));
5149 }
5150 return String.fromIndex(gop.index);
5151}
5152
5153pub fn stringIfExists(self: *const Builder, bytes: []const u8) ?String {
5154 return String.fromIndex(
5155 self.string_map.getIndexAdapted(bytes, String.Adapter{ .builder = self }) orelse return null,
5156 );
5157}
5158
5159pub fn fmt(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) Allocator.Error!String {
5160 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
5161 try self.string_bytes.ensureUnusedCapacity(self.gpa, std.fmt.count(fmt_str ++ .{0}, fmt_args));
5162 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
5163 return self.fmtAssumeCapacity(fmt_str, fmt_args);
5164}
5165
5166pub fn fmtAssumeCapacity(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) String {
5167 const start = self.string_bytes.items.len;
5168 self.string_bytes.writer(self.gpa).print(fmt_str ++ .{0}, fmt_args) catch unreachable;
5169 const bytes: []const u8 = self.string_bytes.items[start .. self.string_bytes.items.len - 1];
5170
5171 const gop = self.string_map.getOrPutAssumeCapacityAdapted(bytes, String.Adapter{ .builder = self });
5172 if (gop.found_existing) {
5173 self.string_bytes.shrinkRetainingCapacity(start);
5174 } else {
5175 self.string_indices.appendAssumeCapacity(@intCast(self.string_bytes.items.len));
5176 }
5177 return String.fromIndex(gop.index);
5178}
5179
5180pub fn fnType(
5181 self: *Builder,
5182 ret: Type,
5183 params: []const Type,
5184 kind: Type.Function.Kind,
5185) Allocator.Error!Type {
5186 try self.ensureUnusedTypeCapacity(1, Type.Function, params.len);
5187 return switch (kind) {
5188 inline else => |comptime_kind| self.fnTypeAssumeCapacity(ret, params, comptime_kind),
5189 };
5190}
5191
5192pub fn intType(self: *Builder, bits: u24) Allocator.Error!Type {
5193 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
5194 return self.intTypeAssumeCapacity(bits);
5195}
5196
5197pub fn ptrType(self: *Builder, addr_space: AddrSpace) Allocator.Error!Type {
5198 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
5199 return self.ptrTypeAssumeCapacity(addr_space);
5200}
5201
5202pub fn vectorType(
5203 self: *Builder,
5204 kind: Type.Vector.Kind,
5205 len: u32,
5206 child: Type,
5207) Allocator.Error!Type {
5208 try self.ensureUnusedTypeCapacity(1, Type.Vector, 0);
5209 return switch (kind) {
5210 inline else => |comptime_kind| self.vectorTypeAssumeCapacity(comptime_kind, len, child),
5211 };
5212}
5213
5214pub fn arrayType(self: *Builder, len: u64, child: Type) Allocator.Error!Type {
5215 comptime assert(@sizeOf(Type.Array) >= @sizeOf(Type.Vector));
5216 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);
5217 return self.arrayTypeAssumeCapacity(len, child);
5218}
5219
5220pub fn structType(
5221 self: *Builder,
5222 kind: Type.Structure.Kind,
5223 fields: []const Type,
5224) Allocator.Error!Type {
5225 try self.ensureUnusedTypeCapacity(1, Type.Structure, fields.len);
5226 return switch (kind) {
5227 inline else => |comptime_kind| self.structTypeAssumeCapacity(comptime_kind, fields),
5228 };
5229}
5230
5231pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type {
5232 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
5233 if (name.toSlice(self)) |id| try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len +
5234 comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)}));
5235 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
5236 try self.types.ensureUnusedCapacity(self.gpa, 1);
5237 try self.next_unique_type_id.ensureUnusedCapacity(self.gpa, 1);
5238 try self.ensureUnusedTypeCapacity(1, Type.NamedStructure, 0);
5239 return self.opaqueTypeAssumeCapacity(name);
5240}
5241
5242pub fn namedTypeSetBody(
5243 self: *Builder,
5244 named_type: Type,
5245 body_type: Type,
5246) if (build_options.have_llvm) Allocator.Error!void else void {
5247 const named_item = self.type_items.items[@intFromEnum(named_type)];
5248 self.type_extra.items[named_item.data + std.meta.fieldIndex(Type.NamedStructure, "body").?] =
5249 @intFromEnum(body_type);
5250 if (self.useLibLlvm()) {
5251 const body_item = self.type_items.items[@intFromEnum(body_type)];
5252 var body_extra = self.typeExtraDataTrail(Type.Structure, body_item.data);
5253 const body_fields = body_extra.trail.next(body_extra.data.fields_len, Type, self);
5254 const llvm_fields = try self.gpa.alloc(*llvm.Type, body_fields.len);
5255 defer self.gpa.free(llvm_fields);
5256 for (llvm_fields, body_fields) |*llvm_field, body_field| llvm_field.* = body_field.toLlvm(self);
5257 self.llvm.types.items[@intFromEnum(named_type)].structSetBody(
5258 llvm_fields.ptr,
5259 @intCast(llvm_fields.len),
5260 switch (body_item.tag) {
5261 .structure => .False,
5262 .packed_structure => .True,
5263 else => unreachable,
5264 },
5265 );
5266 }
5267}
5268
5269pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index {
5270 assert(!name.isAnon());
5271 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
5272 try self.ensureUnusedGlobalCapacity(name);
5273 return self.addGlobalAssumeCapacity(name, global);
5274}
5275
5276pub fn addGlobalAssumeCapacity(self: *Builder, name: String, global: Global) Global.Index {
5277 _ = self.ptrTypeAssumeCapacity(global.addr_space);
5278 var id = name;
5279 if (name == .empty) {
5280 id = self.next_unnamed_global;
5281 assert(id != self.next_replaced_global);
5282 self.next_unnamed_global = @enumFromInt(@intFromEnum(id) + 1);
5283 }
5284 while (true) {
5285 const global_gop = self.globals.getOrPutAssumeCapacity(id);
5286 if (!global_gop.found_existing) {
5287 global_gop.value_ptr.* = global;
5288 global_gop.value_ptr.updateAttributes();
5289 const index: Global.Index = @enumFromInt(global_gop.index);
5290 index.updateName(self);
5291 return index;
5292 }
5293
5294 const unique_gop = self.next_unique_global_id.getOrPutAssumeCapacity(name);
5295 if (!unique_gop.found_existing) unique_gop.value_ptr.* = 2;
5296 id = self.fmtAssumeCapacity("{s}.{d}", .{ name.toSlice(self).?, unique_gop.value_ptr.* });
5297 unique_gop.value_ptr.* += 1;
5298 }
5299}
5300
5301pub fn getGlobal(self: *const Builder, name: String) ?Global.Index {
5302 return @enumFromInt(self.globals.getIndex(name) orelse return null);
5303}
5304
5305pub fn intConst(self: *Builder, ty: Type, value: anytype) Allocator.Error!Constant {
5306 var limbs: [
5307 switch (@typeInfo(@TypeOf(value))) {
5308 .Int => |info| std.math.big.int.calcTwosCompLimbCount(info.bits),
5309 .ComptimeInt => std.math.big.int.calcLimbLen(value),
5310 else => @compileError("intConst expected an integral value, got " ++
5311 @typeName(@TypeOf(value))),
5312 }
5313 ]std.math.big.Limb = undefined;
5314 return self.bigIntConst(ty, std.math.big.int.Mutable.init(&limbs, value).toConst());
5315}
5316
5317pub fn intValue(self: *Builder, ty: Type, value: anytype) Allocator.Error!Value {
5318 return (try self.intConst(ty, value)).toValue();
5319}
5320
5321pub fn bigIntConst(self: *Builder, ty: Type, value: std.math.big.int.Const) Allocator.Error!Constant {
5322 try self.constant_map.ensureUnusedCapacity(self.gpa, 1);
5323 try self.constant_items.ensureUnusedCapacity(self.gpa, 1);
5324 try self.constant_limbs.ensureUnusedCapacity(self.gpa, Constant.Integer.limbs + value.limbs.len);
5325 if (self.useLibLlvm()) try self.llvm.constants.ensureUnusedCapacity(self.gpa, 1);
5326 return self.bigIntConstAssumeCapacity(ty, value);
5327}
5328
5329pub fn bigIntValue(self: *Builder, ty: Type, value: std.math.big.int.Const) Allocator.Error!Value {
5330 return (try self.bigIntConst(ty, value)).toValue();
5331}
5332
5333pub fn fpConst(self: *Builder, ty: Type, comptime val: comptime_float) Allocator.Error!Constant {
5334 return switch (ty) {
5335 .half => try self.halfConst(val),
5336 .bfloat => try self.bfloatConst(val),
5337 .float => try self.floatConst(val),
5338 .double => try self.doubleConst(val),
5339 .fp128 => try self.fp128Const(val),
5340 .x86_fp80 => try self.x86_fp80Const(val),
5341 .ppc_fp128 => try self.ppc_fp128Const(.{ val, -0.0 }),
5342 else => unreachable,
5343 };
5344}
5345
5346pub fn fpValue(self: *Builder, ty: Type, comptime value: comptime_float) Allocator.Error!Value {
5347 return (try self.fpConst(ty, value)).toValue();
5348}
5349
5350pub fn nanConst(self: *Builder, ty: Type) Allocator.Error!Constant {
5351 return switch (ty) {
5352 .half => try self.halfConst(std.math.nan(f16)),
5353 .bfloat => try self.bfloatConst(std.math.nan(f32)),
5354 .float => try self.floatConst(std.math.nan(f32)),
5355 .double => try self.doubleConst(std.math.nan(f64)),
5356 .fp128 => try self.fp128Const(std.math.nan(f128)),
5357 .x86_fp80 => try self.x86_fp80Const(std.math.nan(f80)),
5358 .ppc_fp128 => try self.ppc_fp128Const(.{std.math.nan(f64)} ** 2),
5359 else => unreachable,
5360 };
5361}
5362
5363pub fn nanValue(self: *Builder, ty: Type) Allocator.Error!Value {
5364 return (try self.nanConst(ty)).toValue();
5365}
5366
5367pub fn halfConst(self: *Builder, val: f16) Allocator.Error!Constant {
5368 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
5369 return self.halfConstAssumeCapacity(val);
5370}
5371
5372pub fn halfValue(self: *Builder, ty: Type, value: f16) Allocator.Error!Value {
5373 return (try self.halfConst(ty, value)).toValue();
5374}
5375
5376pub fn bfloatConst(self: *Builder, val: f32) Allocator.Error!Constant {
5377 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
5378 return self.bfloatConstAssumeCapacity(val);
5379}
5380
5381pub fn bfloatValue(self: *Builder, ty: Type, value: f32) Allocator.Error!Value {
5382 return (try self.bfloatConst(ty, value)).toValue();
5383}
5384
5385pub fn floatConst(self: *Builder, val: f32) Allocator.Error!Constant {
5386 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
5387 return self.floatConstAssumeCapacity(val);
5388}
5389
5390pub fn floatValue(self: *Builder, ty: Type, value: f32) Allocator.Error!Value {
5391 return (try self.floatConst(ty, value)).toValue();
5392}
5393
5394pub fn doubleConst(self: *Builder, val: f64) Allocator.Error!Constant {
5395 try self.ensureUnusedConstantCapacity(1, Constant.Double, 0);
5396 return self.doubleConstAssumeCapacity(val);
5397}
5398
5399pub fn doubleValue(self: *Builder, ty: Type, value: f64) Allocator.Error!Value {
5400 return (try self.doubleConst(ty, value)).toValue();
5401}
5402
5403pub fn fp128Const(self: *Builder, val: f128) Allocator.Error!Constant {
5404 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);
5405 return self.fp128ConstAssumeCapacity(val);
5406}
5407
5408pub fn fp128Value(self: *Builder, ty: Type, value: f128) Allocator.Error!Value {
5409 return (try self.fp128Const(ty, value)).toValue();
5410}
5411
5412pub fn x86_fp80Const(self: *Builder, val: f80) Allocator.Error!Constant {
5413 try self.ensureUnusedConstantCapacity(1, Constant.Fp80, 0);
5414 return self.x86_fp80ConstAssumeCapacity(val);
5415}
5416
5417pub fn x86_fp80Value(self: *Builder, ty: Type, value: f80) Allocator.Error!Value {
5418 return (try self.x86_fp80Const(ty, value)).toValue();
5419}
5420
5421pub fn ppc_fp128Const(self: *Builder, val: [2]f64) Allocator.Error!Constant {
5422 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);
5423 return self.ppc_fp128ConstAssumeCapacity(val);
5424}
5425
5426pub fn ppc_fp128Value(self: *Builder, ty: Type, value: [2]f64) Allocator.Error!Value {
5427 return (try self.ppc_fp128Const(ty, value)).toValue();
5428}
5429
5430pub fn nullConst(self: *Builder, ty: Type) Allocator.Error!Constant {
5431 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
5432 return self.nullConstAssumeCapacity(ty);
5433}
5434
5435pub fn nullValue(self: *Builder, ty: Type) Allocator.Error!Value {
5436 return (try self.nullConst(ty)).toValue();
5437}
5438
5439pub fn noneConst(self: *Builder, ty: Type) Allocator.Error!Constant {
5440 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
5441 return self.noneConstAssumeCapacity(ty);
5442}
5443
5444pub fn noneValue(self: *Builder, ty: Type) Allocator.Error!Value {
5445 return (try self.noneConst(ty)).toValue();
5446}
5447
5448pub fn structConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {
5449 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);
5450 return self.structConstAssumeCapacity(ty, vals);
5451}
5452
5453pub fn structValue(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Value {
5454 return (try self.structConst(ty, vals)).toValue();
5455}
5456
5457pub fn arrayConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {
5458 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);
5459 return self.arrayConstAssumeCapacity(ty, vals);
5460}
5461
5462pub fn arrayValue(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Value {
5463 return (try self.arrayConst(ty, vals)).toValue();
5464}
5465
5466pub fn stringConst(self: *Builder, val: String) Allocator.Error!Constant {
5467 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);
5468 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
5469 return self.stringConstAssumeCapacity(val);
5470}
5471
5472pub fn stringValue(self: *Builder, val: String) Allocator.Error!Value {
5473 return (try self.stringConst(val)).toValue();
5474}
5475
5476pub fn stringNullConst(self: *Builder, val: String) Allocator.Error!Constant {
5477 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);
5478 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
5479 return self.stringNullConstAssumeCapacity(val);
5480}
5481
5482pub fn stringNullValue(self: *Builder, val: String) Allocator.Error!Value {
5483 return (try self.stringNullConst(val)).toValue();
5484}
5485
5486pub fn vectorConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {
5487 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);
5488 return self.vectorConstAssumeCapacity(ty, vals);
5489}
5490
5491pub fn vectorValue(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Value {
5492 return (try self.vectorConst(ty, vals)).toValue();
5493}
5494
5495pub fn splatConst(self: *Builder, ty: Type, val: Constant) Allocator.Error!Constant {
5496 try self.ensureUnusedConstantCapacity(1, Constant.Splat, 0);
5497 return self.splatConstAssumeCapacity(ty, val);
5498}
5499
5500pub fn splatValue(self: *Builder, ty: Type, val: Constant) Allocator.Error!Value {
5501 return (try self.splatConst(ty, val)).toValue();
5502}
5503
5504pub fn zeroInitConst(self: *Builder, ty: Type) Allocator.Error!Constant {
5505 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);
5506 try self.constant_limbs.ensureUnusedCapacity(
5507 self.gpa,
5508 Constant.Integer.limbs + comptime std.math.big.int.calcLimbLen(0),
5509 );
5510 return self.zeroInitConstAssumeCapacity(ty);
5511}
5512
5513pub fn zeroInitValue(self: *Builder, ty: Type) Allocator.Error!Value {
5514 return (try self.zeroInitConst(ty)).toValue();
5515}
5516
5517pub fn undefConst(self: *Builder, ty: Type) Allocator.Error!Constant {
5518 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
5519 return self.undefConstAssumeCapacity(ty);
5520}
5521
5522pub fn undefValue(self: *Builder, ty: Type) Allocator.Error!Value {
5523 return (try self.undefConst(ty)).toValue();
5524}
5525
5526pub fn poisonConst(self: *Builder, ty: Type) Allocator.Error!Constant {
5527 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
5528 return self.poisonConstAssumeCapacity(ty);
5529}
5530
5531pub fn poisonValue(self: *Builder, ty: Type) Allocator.Error!Value {
5532 return (try self.poisonConst(ty)).toValue();
5533}
5534
5535pub fn blockAddrConst(
5536 self: *Builder,
5537 function: Function.Index,
5538 block: Function.Block.Index,
5539) Allocator.Error!Constant {
5540 try self.ensureUnusedConstantCapacity(1, Constant.BlockAddress, 0);
5541 return self.blockAddrConstAssumeCapacity(function, block);
5542}
5543
5544pub fn blockAddrValue(
5545 self: *Builder,
5546 function: Function.Index,
5547 block: Function.Block.Index,
5548) Allocator.Error!Value {
5549 return (try self.blockAddrConst(function, block)).toValue();
5550}
5551
5552pub fn dsoLocalEquivalentConst(self: *Builder, function: Function.Index) Allocator.Error!Constant {
5553 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
5554 return self.dsoLocalEquivalentConstAssumeCapacity(function);
5555}
5556
5557pub fn dsoLocalEquivalentValue(self: *Builder, function: Function.Index) Allocator.Error!Value {
5558 return (try self.dsoLocalEquivalentConst(function)).toValue();
5559}
5560
5561pub fn noCfiConst(self: *Builder, function: Function.Index) Allocator.Error!Constant {
5562 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
5563 return self.noCfiConstAssumeCapacity(function);
5564}
5565
5566pub fn noCfiValue(self: *Builder, function: Function.Index) Allocator.Error!Value {
5567 return (try self.noCfiConst(function)).toValue();
5568}
5569
5570pub fn convConst(
5571 self: *Builder,
5572 signedness: Constant.Cast.Signedness,
5573 val: Constant,
5574 ty: Type,
5575) Allocator.Error!Constant {
5576 try self.ensureUnusedConstantCapacity(1, Constant.Cast, 0);
5577 return self.convConstAssumeCapacity(signedness, val, ty);
5578}
5579
5580pub fn convValue(
5581 self: *Builder,
5582 signedness: Constant.Cast.Signedness,
5583 val: Constant,
5584 ty: Type,
5585) Allocator.Error!Value {
5586 return (try self.convConst(signedness, val, ty)).toValue();
5587}
5588
5589pub fn castConst(self: *Builder, tag: Constant.Tag, val: Constant, ty: Type) Allocator.Error!Constant {
5590 try self.ensureUnusedConstantCapacity(1, Constant.Cast, 0);
5591 return self.castConstAssumeCapacity(tag, val, ty);
5592}
5593
5594pub fn castValue(self: *Builder, tag: Constant.Tag, val: Constant, ty: Type) Allocator.Error!Value {
5595 return (try self.castConst(tag, val, ty)).toValue();
5596}
5597
5598pub fn gepConst(
5599 self: *Builder,
5600 comptime kind: Constant.GetElementPtr.Kind,
5601 ty: Type,
5602 base: Constant,
5603 inrange: ?u16,
5604 indices: []const Constant,
5605) Allocator.Error!Constant {
5606 try self.ensureUnusedTypeCapacity(1, Type.Vector, 0);
5607 try self.ensureUnusedConstantCapacity(1, Constant.GetElementPtr, indices.len);
5608 return self.gepConstAssumeCapacity(kind, ty, base, inrange, indices);
5609}
5610
5611pub fn gepValue(
5612 self: *Builder,
5613 comptime kind: Constant.GetElementPtr.Kind,
5614 ty: Type,
5615 base: Constant,
5616 inrange: ?u16,
5617 indices: []const Constant,
5618) Allocator.Error!Value {
5619 return (try self.gepConst(kind, ty, base, inrange, indices)).toValue();
5620}
5621
5622pub fn icmpConst(
5623 self: *Builder,
5624 cond: IntegerCondition,
5625 lhs: Constant,
5626 rhs: Constant,
5627) Allocator.Error!Constant {
5628 try self.ensureUnusedConstantCapacity(1, Constant.Compare, 0);
5629 return self.icmpConstAssumeCapacity(cond, lhs, rhs);
5630}
5631
5632pub fn icmpValue(
5633 self: *Builder,
5634 cond: IntegerCondition,
5635 lhs: Constant,
5636 rhs: Constant,
5637) Allocator.Error!Value {
5638 return (try self.icmpConst(cond, lhs, rhs)).toValue();
5639}
5640
5641pub fn fcmpConst(
5642 self: *Builder,
5643 cond: FloatCondition,
5644 lhs: Constant,
5645 rhs: Constant,
5646) Allocator.Error!Constant {
5647 try self.ensureUnusedConstantCapacity(1, Constant.Compare, 0);
5648 return self.icmpConstAssumeCapacity(cond, lhs, rhs);
5649}
5650
5651pub fn fcmpValue(
5652 self: *Builder,
5653 cond: FloatCondition,
5654 lhs: Constant,
5655 rhs: Constant,
5656) Allocator.Error!Value {
5657 return (try self.fcmpConst(cond, lhs, rhs)).toValue();
5658}
5659
5660pub fn extractElementConst(self: *Builder, val: Constant, index: Constant) Allocator.Error!Constant {
5661 try self.ensureUnusedConstantCapacity(1, Constant.ExtractElement, 0);
5662 return self.extractElementConstAssumeCapacity(val, index);
5663}
5664
5665pub fn extractElementValue(self: *Builder, val: Constant, index: Constant) Allocator.Error!Value {
5666 return (try self.extractElementConst(val, index)).toValue();
5667}
5668
5669pub fn insertElementConst(
5670 self: *Builder,
5671 val: Constant,
5672 elem: Constant,
5673 index: Constant,
5674) Allocator.Error!Constant {
5675 try self.ensureUnusedConstantCapacity(1, Constant.InsertElement, 0);
5676 return self.insertElementConstAssumeCapacity(val, elem, index);
5677}
5678
5679pub fn insertElementValue(
5680 self: *Builder,
5681 val: Constant,
5682 elem: Constant,
5683 index: Constant,
5684) Allocator.Error!Value {
5685 return (try self.insertElementConst(val, elem, index)).toValue();
5686}
5687
5688pub fn shuffleVectorConst(
5689 self: *Builder,
5690 lhs: Constant,
5691 rhs: Constant,
5692 mask: Constant,
5693) Allocator.Error!Constant {
5694 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);
5695 try self.ensureUnusedConstantCapacity(1, Constant.ShuffleVector, 0);
5696 return self.shuffleVectorConstAssumeCapacity(lhs, rhs, mask);
5697}
5698
5699pub fn shuffleVectorValue(
5700 self: *Builder,
5701 lhs: Constant,
5702 rhs: Constant,
5703 mask: Constant,
5704) Allocator.Error!Value {
5705 return (try self.shuffleVectorConst(lhs, rhs, mask)).toValue();
5706}
5707
5708pub fn binConst(
5709 self: *Builder,
5710 tag: Constant.Tag,
5711 lhs: Constant,
5712 rhs: Constant,
5713) Allocator.Error!Constant {
5714 try self.ensureUnusedConstantCapacity(1, Constant.Binary, 0);
5715 return self.binConstAssumeCapacity(tag, lhs, rhs);
5716}
5717
5718pub fn binValue(self: *Builder, tag: Constant.Tag, lhs: Constant, rhs: Constant) Allocator.Error!Value {
5719 return (try self.binConst(tag, lhs, rhs)).toValue();
5720}
5721
5722pub fn dump(self: *Builder) void {
5723 if (self.useLibLlvm())
5724 self.llvm.module.?.dump()
5725 else
5726 self.print(std.io.getStdErr().writer()) catch {};
5727}
5728
5729pub fn printToFile(self: *Builder, path: []const u8) Allocator.Error!bool {
5730 const path_z = try self.gpa.dupeZ(u8, path);
5731 defer self.gpa.free(path_z);
5732 return self.printToFileZ(path_z);
5733}
5734
5735pub fn printToFileZ(self: *Builder, path: [*:0]const u8) bool {
5736 if (self.useLibLlvm()) {
5737 var error_message: [*:0]const u8 = undefined;
5738 if (self.llvm.module.?.printModuleToFile(path, &error_message).toBool()) {
5739 defer llvm.disposeMessage(error_message);
5740 log.err("failed printing LLVM module to \"{s}\": {s}", .{ path, error_message });
5741 return false;
5742 }
5743 } else {
5744 var file = std.fs.cwd().createFileZ(path, .{}) catch |err| {
5745 log.err("failed printing LLVM module to \"{s}\": {s}", .{ path, @errorName(err) });
5746 return false;
5747 };
5748 defer file.close();
5749 self.print(file.writer()) catch |err| {
5750 log.err("failed printing LLVM module to \"{s}\": {s}", .{ path, @errorName(err) });
5751 return false;
5752 };
5753 }
5754 return true;
5755}
5756
5757pub fn print(self: *Builder, writer: anytype) (@TypeOf(writer).Error || Allocator.Error)!void {
5758 var bw = std.io.bufferedWriter(writer);
5759 try self.printUnbuffered(bw.writer());
5760 try bw.flush();
5761}
5762
5763pub fn printUnbuffered(
5764 self: *Builder,
5765 writer: anytype,
5766) (@TypeOf(writer).Error || Allocator.Error)!void {
5767 if (self.source_filename != .none) try writer.print(
5768 \\; ModuleID = '{s}'
5769 \\source_filename = {"}
5770 \\
5771 , .{ self.source_filename.toSlice(self).?, self.source_filename.fmt(self) });
5772 if (self.data_layout != .none) try writer.print(
5773 \\target datalayout = {"}
5774 \\
5775 , .{self.data_layout.fmt(self)});
5776 if (self.target_triple != .none) try writer.print(
5777 \\target triple = {"}
5778 \\
5779 , .{self.target_triple.fmt(self)});
5780 try writer.writeByte('\n');
5781 for (self.types.keys(), self.types.values()) |id, ty| try writer.print(
5782 \\%{} = type {}
5783 \\
5784 , .{ id.fmt(self), ty.fmt(self) });
5785 try writer.writeByte('\n');
5786 for (self.variables.items) |variable| {
5787 if (variable.global.getReplacement(self) != .none) continue;
5788 const global = variable.global.ptrConst(self);
5789 try writer.print(
5790 \\{} ={}{}{}{}{}{}{}{} {s} {%}{ }{,}
5791 \\
5792 , .{
5793 variable.global.fmt(self),
5794 global.linkage,
5795 global.preemption,
5796 global.visibility,
5797 global.dll_storage_class,
5798 variable.thread_local,
5799 global.unnamed_addr,
5800 global.addr_space,
5801 global.externally_initialized,
5802 @tagName(variable.mutability),
5803 global.type.fmt(self),
5804 variable.init.fmt(self),
5805 variable.alignment,
5806 });
5807 }
5808 try writer.writeByte('\n');
5809 for (0.., self.functions.items) |function_i, function| {
5810 const function_index: Function.Index = @enumFromInt(function_i);
5811 if (function.global.getReplacement(self) != .none) continue;
5812 const global = function.global.ptrConst(self);
5813 const params_len = global.type.functionParameters(self).len;
5814 try writer.print(
5815 \\{s}{}{}{}{} {} {}(
5816 , .{
5817 if (function.instructions.len > 0) "define" else "declare",
5818 global.linkage,
5819 global.preemption,
5820 global.visibility,
5821 global.dll_storage_class,
5822 global.type.functionReturn(self).fmt(self),
5823 function.global.fmt(self),
5824 });
5825 for (0..params_len) |arg| {
5826 if (arg > 0) try writer.writeAll(", ");
5827 if (function.instructions.len > 0)
5828 try writer.print("{%}", .{function.arg(@intCast(arg)).fmt(function_index, self)})
5829 else
5830 try writer.print("{%}", .{global.type.functionParameters(self)[arg].fmt(self)});
5831 }
5832 switch (global.type.functionKind(self)) {
5833 .normal => {},
5834 .vararg => {
5835 if (params_len > 0) try writer.writeAll(", ");
5836 try writer.writeAll("...");
5837 },
5838 }
5839 try writer.print("){}{}", .{ global.unnamed_addr, function.alignment });
5840 if (function.instructions.len > 0) {
5841 var block_incoming_len: u32 = undefined;
5842 try writer.writeAll(" {\n");
5843 for (params_len..function.instructions.len) |instruction_i| {
5844 const instruction_index: Function.Instruction.Index = @enumFromInt(instruction_i);
5845 const instruction = function.instructions.get(@intFromEnum(instruction_index));
5846 switch (instruction.tag) {
5847 .add,
5848 .@"add nsw",
5849 .@"add nuw",
5850 .@"add nuw nsw",
5851 .@"and",
5852 .ashr,
5853 .@"ashr exact",
5854 .fadd,
5855 .@"fadd fast",
5856 .@"fcmp false",
5857 .@"fcmp fast false",
5858 .@"fcmp fast oeq",
5859 .@"fcmp fast oge",
5860 .@"fcmp fast ogt",
5861 .@"fcmp fast ole",
5862 .@"fcmp fast olt",
5863 .@"fcmp fast one",
5864 .@"fcmp fast ord",
5865 .@"fcmp fast true",
5866 .@"fcmp fast ueq",
5867 .@"fcmp fast uge",
5868 .@"fcmp fast ugt",
5869 .@"fcmp fast ule",
5870 .@"fcmp fast ult",
5871 .@"fcmp fast une",
5872 .@"fcmp fast uno",
5873 .@"fcmp oeq",
5874 .@"fcmp oge",
5875 .@"fcmp ogt",
5876 .@"fcmp ole",
5877 .@"fcmp olt",
5878 .@"fcmp one",
5879 .@"fcmp ord",
5880 .@"fcmp true",
5881 .@"fcmp ueq",
5882 .@"fcmp uge",
5883 .@"fcmp ugt",
5884 .@"fcmp ule",
5885 .@"fcmp ult",
5886 .@"fcmp une",
5887 .@"fcmp uno",
5888 .fdiv,
5889 .@"fdiv fast",
5890 .fmul,
5891 .@"fmul fast",
5892 .frem,
5893 .@"frem fast",
5894 .fsub,
5895 .@"fsub fast",
5896 .@"icmp eq",
5897 .@"icmp ne",
5898 .@"icmp sge",
5899 .@"icmp sgt",
5900 .@"icmp sle",
5901 .@"icmp slt",
5902 .@"icmp uge",
5903 .@"icmp ugt",
5904 .@"icmp ule",
5905 .@"icmp ult",
5906 .lshr,
5907 .@"lshr exact",
5908 .mul,
5909 .@"mul nsw",
5910 .@"mul nuw",
5911 .@"mul nuw nsw",
5912 .@"or",
5913 .sdiv,
5914 .@"sdiv exact",
5915 .srem,
5916 .shl,
5917 .@"shl nsw",
5918 .@"shl nuw",
5919 .@"shl nuw nsw",
5920 .sub,
5921 .@"sub nsw",
5922 .@"sub nuw",
5923 .@"sub nuw nsw",
5924 .udiv,
5925 .@"udiv exact",
5926 .urem,
5927 .xor,
5928 => |tag| {
5929 const extra = function.extraData(Function.Instruction.Binary, instruction.data);
5930 try writer.print(" %{} = {s} {%}, {}\n", .{
5931 instruction_index.name(&function).fmt(self),
5932 @tagName(tag),
5933 extra.lhs.fmt(function_index, self),
5934 extra.rhs.fmt(function_index, self),
5935 });
5936 },
5937 .addrspacecast,
5938 .bitcast,
5939 .fpext,
5940 .fptosi,
5941 .fptoui,
5942 .fptrunc,
5943 .inttoptr,
5944 .ptrtoint,
5945 .sext,
5946 .sitofp,
5947 .trunc,
5948 .uitofp,
5949 .zext,
5950 => |tag| {
5951 const extra = function.extraData(Function.Instruction.Cast, instruction.data);
5952 try writer.print(" %{} = {s} {%} to {%}\n", .{
5953 instruction_index.name(&function).fmt(self),
5954 @tagName(tag),
5955 extra.val.fmt(function_index, self),
5956 extra.type.fmt(self),
5957 });
5958 },
5959 .alloca,
5960 .@"alloca inalloca",
5961 => |tag| {
5962 const extra = function.extraData(Function.Instruction.Alloca, instruction.data);
5963 try writer.print(" %{} = {s} {%}{,%}{,}{,}\n", .{
5964 instruction_index.name(&function).fmt(self),
5965 @tagName(tag),
5966 extra.type.fmt(self),
5967 extra.len.fmt(function_index, self),
5968 extra.info.alignment,
5969 extra.info.addr_space,
5970 });
5971 },
5972 .arg => unreachable,
5973 .block => {
5974 block_incoming_len = instruction.data;
5975 const name = instruction_index.name(&function);
5976 if (@intFromEnum(instruction_index) > params_len) try writer.writeByte('\n');
5977 try writer.print("{}:\n", .{name.fmt(self)});
5978 },
5979 .br => |tag| {
5980 const target: Function.Block.Index = @enumFromInt(instruction.data);
5981 try writer.print(" {s} {%}\n", .{
5982 @tagName(tag), target.toInst(&function).fmt(function_index, self),
5983 });
5984 },
5985 .br_cond => {
5986 const extra = function.extraData(Function.Instruction.BrCond, instruction.data);
5987 try writer.print(" br {%}, {%}, {%}\n", .{
5988 extra.cond.fmt(function_index, self),
5989 extra.then.toInst(&function).fmt(function_index, self),
5990 extra.@"else".toInst(&function).fmt(function_index, self),
5991 });
5992 },
5993 .extractelement => |tag| {
5994 const extra =
5995 function.extraData(Function.Instruction.ExtractElement, instruction.data);
5996 try writer.print(" %{} = {s} {%}, {%}\n", .{
5997 instruction_index.name(&function).fmt(self),
5998 @tagName(tag),
5999 extra.val.fmt(function_index, self),
6000 extra.index.fmt(function_index, self),
6001 });
6002 },
6003 .extractvalue => |tag| {
6004 var extra =
6005 function.extraDataTrail(Function.Instruction.ExtractValue, instruction.data);
6006 const indices = extra.trail.next(extra.data.indices_len, u32, &function);
6007 try writer.print(" %{} = {s} {%}", .{
6008 instruction_index.name(&function).fmt(self),
6009 @tagName(tag),
6010 extra.data.val.fmt(function_index, self),
6011 });
6012 for (indices) |index| try writer.print(", {d}", .{index});
6013 try writer.writeByte('\n');
6014 },
6015 .fence => |tag| {
6016 const info: MemoryAccessInfo = @bitCast(instruction.data);
6017 try writer.print(" {s}{}{}", .{ @tagName(tag), info.scope, info.ordering });
6018 },
6019 .fneg,
6020 .@"fneg fast",
6021 .ret,
6022 => |tag| {
6023 const val: Value = @enumFromInt(instruction.data);
6024 try writer.print(" {s} {%}\n", .{
6025 @tagName(tag),
6026 val.fmt(function_index, self),
6027 });
6028 },
6029 .getelementptr,
6030 .@"getelementptr inbounds",
6031 => |tag| {
6032 var extra = function.extraDataTrail(
6033 Function.Instruction.GetElementPtr,
6034 instruction.data,
6035 );
6036 const indices = extra.trail.next(extra.data.indices_len, Value, &function);
6037 try writer.print(" %{} = {s} {%}, {%}", .{
6038 instruction_index.name(&function).fmt(self),
6039 @tagName(tag),
6040 extra.data.type.fmt(self),
6041 extra.data.base.fmt(function_index, self),
6042 });
6043 for (indices) |index| try writer.print(", {%}", .{
6044 index.fmt(function_index, self),
6045 });
6046 try writer.writeByte('\n');
6047 },
6048 .insertelement => |tag| {
6049 const extra =
6050 function.extraData(Function.Instruction.InsertElement, instruction.data);
6051 try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
6052 instruction_index.name(&function).fmt(self),
6053 @tagName(tag),
6054 extra.val.fmt(function_index, self),
6055 extra.elem.fmt(function_index, self),
6056 extra.index.fmt(function_index, self),
6057 });
6058 },
6059 .insertvalue => |tag| {
6060 var extra =
6061 function.extraDataTrail(Function.Instruction.InsertValue, instruction.data);
6062 const indices = extra.trail.next(extra.data.indices_len, u32, &function);
6063 try writer.print(" %{} = {s} {%}, {%}", .{
6064 instruction_index.name(&function).fmt(self),
6065 @tagName(tag),
6066 extra.data.val.fmt(function_index, self),
6067 extra.data.elem.fmt(function_index, self),
6068 });
6069 for (indices) |index| try writer.print(", {d}", .{index});
6070 try writer.writeByte('\n');
6071 },
6072 .@"llvm.maxnum.",
6073 .@"llvm.minnum.",
6074 .@"llvm.sadd.sat.",
6075 .@"llvm.smax.",
6076 .@"llvm.smin.",
6077 .@"llvm.smul.fix.sat.",
6078 .@"llvm.sshl.sat.",
6079 .@"llvm.ssub.sat.",
6080 .@"llvm.uadd.sat.",
6081 .@"llvm.umax.",
6082 .@"llvm.umin.",
6083 .@"llvm.umul.fix.sat.",
6084 .@"llvm.ushl.sat.",
6085 .@"llvm.usub.sat.",
6086 => |tag| {
6087 const extra = function.extraData(Function.Instruction.Binary, instruction.data);
6088 const ty = instruction_index.typeOf(function_index, self);
6089 try writer.print(" %{} = call {%} @{s}{m}({%}, {%})\n", .{
6090 instruction_index.name(&function).fmt(self),
6091 ty.fmt(self),
6092 @tagName(tag),
6093 ty.fmt(self),
6094 extra.lhs.fmt(function_index, self),
6095 extra.rhs.fmt(function_index, self),
6096 });
6097 },
6098 .load,
6099 .@"load atomic",
6100 .@"load atomic volatile",
6101 .@"load volatile",
6102 => |tag| {
6103 const extra = function.extraData(Function.Instruction.Load, instruction.data);
6104 try writer.print(" %{} = {s} {%}, {%}{}{}{,}\n", .{
6105 instruction_index.name(&function).fmt(self),
6106 @tagName(tag),
6107 extra.type.fmt(self),
6108 extra.ptr.fmt(function_index, self),
6109 extra.info.scope,
6110 extra.info.ordering,
6111 extra.info.alignment,
6112 });
6113 },
6114 .phi,
6115 .@"phi fast",
6116 => |tag| {
6117 var extra = function.extraDataTrail(Function.Instruction.Phi, instruction.data);
6118 const vals = extra.trail.next(block_incoming_len, Value, &function);
6119 const blocks =
6120 extra.trail.next(block_incoming_len, Function.Block.Index, &function);
6121 try writer.print(" %{} = {s} {%} ", .{
6122 instruction_index.name(&function).fmt(self),
6123 @tagName(tag),
6124 vals[0].typeOf(function_index, self).fmt(self),
6125 });
6126 for (0.., vals, blocks) |incoming_index, incoming_val, incoming_block| {
6127 if (incoming_index > 0) try writer.writeAll(", ");
6128 try writer.print("[ {}, {} ]", .{
6129 incoming_val.fmt(function_index, self),
6130 incoming_block.toInst(&function).fmt(function_index, self),
6131 });
6132 }
6133 try writer.writeByte('\n');
6134 },
6135 .@"ret void",
6136 .@"unreachable",
6137 => |tag| try writer.print(" {s}\n", .{@tagName(tag)}),
6138 .select,
6139 .@"select fast",
6140 => |tag| {
6141 const extra = function.extraData(Function.Instruction.Select, instruction.data);
6142 try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
6143 instruction_index.name(&function).fmt(self),
6144 @tagName(tag),
6145 extra.cond.fmt(function_index, self),
6146 extra.lhs.fmt(function_index, self),
6147 extra.rhs.fmt(function_index, self),
6148 });
6149 },
6150 .shufflevector => |tag| {
6151 const extra =
6152 function.extraData(Function.Instruction.ShuffleVector, instruction.data);
6153 try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
6154 instruction_index.name(&function).fmt(self),
6155 @tagName(tag),
6156 extra.lhs.fmt(function_index, self),
6157 extra.rhs.fmt(function_index, self),
6158 extra.mask.fmt(function_index, self),
6159 });
6160 },
6161 .store,
6162 .@"store atomic",
6163 .@"store atomic volatile",
6164 .@"store volatile",
6165 => |tag| {
6166 const extra = function.extraData(Function.Instruction.Store, instruction.data);
6167 try writer.print(" {s} {%}, {%}{}{}{,}\n", .{
6168 @tagName(tag),
6169 extra.val.fmt(function_index, self),
6170 extra.ptr.fmt(function_index, self),
6171 extra.info.scope,
6172 extra.info.ordering,
6173 extra.info.alignment,
6174 });
6175 },
6176 .@"switch" => |tag| {
6177 var extra =
6178 function.extraDataTrail(Function.Instruction.Switch, instruction.data);
6179 const vals = extra.trail.next(extra.data.cases_len, Constant, &function);
6180 const blocks =
6181 extra.trail.next(extra.data.cases_len, Function.Block.Index, &function);
6182 try writer.print(" {s} {%}, {%} [", .{
6183 @tagName(tag),
6184 extra.data.val.fmt(function_index, self),
6185 extra.data.default.toInst(&function).fmt(function_index, self),
6186 });
6187 for (vals, blocks) |case_val, case_block| try writer.print(" {%}, {%}\n", .{
6188 case_val.fmt(self),
6189 case_block.toInst(&function).fmt(function_index, self),
6190 });
6191 try writer.writeAll(" ]\n");
6192 },
6193 .unimplemented => |tag| {
6194 const ty: Type = @enumFromInt(instruction.data);
6195 try writer.writeAll(" ");
6196 switch (ty) {
6197 .none, .void => {},
6198 else => try writer.print("%{} = ", .{
6199 instruction_index.name(&function).fmt(self),
6200 }),
6201 }
6202 try writer.print("{s} {%}\n", .{ @tagName(tag), ty.fmt(self) });
6203 },
6204 .va_arg => |tag| {
6205 const extra = function.extraData(Function.Instruction.VaArg, instruction.data);
6206 try writer.print(" %{} = {s} {%}, {%}\n", .{
6207 instruction_index.name(&function).fmt(self),
6208 @tagName(tag),
6209 extra.list.fmt(function_index, self),
6210 extra.type.fmt(self),
6211 });
6212 },
6213 }
6214 }
6215 try writer.writeByte('}');
6216 }
6217 try writer.writeAll("\n\n");
6218 }
6219}
6220
6221pub inline fn useLibLlvm(self: *const Builder) bool {
6222 return build_options.have_llvm and self.use_lib_llvm;
6223}
6224
6225const NoExtra = struct {};
6226
6227fn isValidIdentifier(id: []const u8) bool {
6228 for (id, 0..) |character, index| switch (character) {
6229 '$', '-', '.', 'A'...'Z', '_', 'a'...'z' => {},
6230 '0'...'9' => if (index == 0) return false,
6231 else => return false,
6232 };
6233 return true;
6234}
6235
6236fn ensureUnusedGlobalCapacity(self: *Builder, name: String) Allocator.Error!void {
6237 if (self.useLibLlvm()) try self.llvm.globals.ensureUnusedCapacity(self.gpa, 1);
6238 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
6239 if (name.toSlice(self)) |id| try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len +
6240 comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)}));
6241 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
6242 try self.globals.ensureUnusedCapacity(self.gpa, 1);
6243 try self.next_unique_global_id.ensureUnusedCapacity(self.gpa, 1);
6244}
6245
6246fn fnTypeAssumeCapacity(
6247 self: *Builder,
6248 ret: Type,
6249 params: []const Type,
6250 comptime kind: Type.Function.Kind,
6251) if (build_options.have_llvm) Allocator.Error!Type else Type {
6252 const tag: Type.Tag = switch (kind) {
6253 .normal => .function,
6254 .vararg => .vararg_function,
6255 };
6256 const Key = struct { ret: Type, params: []const Type };
6257 const Adapter = struct {
6258 builder: *const Builder,
6259 pub fn hash(_: @This(), key: Key) u32 {
6260 var hasher = std.hash.Wyhash.init(comptime std.hash.uint32(@intFromEnum(tag)));
6261 hasher.update(std.mem.asBytes(&key.ret));
6262 hasher.update(std.mem.sliceAsBytes(key.params));
6263 return @truncate(hasher.final());
6264 }
6265 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
6266 const rhs_data = ctx.builder.type_items.items[rhs_index];
6267 var rhs_extra = ctx.builder.typeExtraDataTrail(Type.Function, rhs_data.data);
6268 const rhs_params = rhs_extra.trail.next(rhs_extra.data.params_len, Type, ctx.builder);
6269 return rhs_data.tag == tag and lhs_key.ret == rhs_extra.data.ret and
6270 std.mem.eql(Type, lhs_key.params, rhs_params);
6271 }
6272 };
6273 const gop = self.type_map.getOrPutAssumeCapacityAdapted(
6274 Key{ .ret = ret, .params = params },
6275 Adapter{ .builder = self },
6276 );
6277 if (!gop.found_existing) {
6278 gop.key_ptr.* = {};
6279 gop.value_ptr.* = {};
6280 self.type_items.appendAssumeCapacity(.{
6281 .tag = .function,
6282 .data = self.addTypeExtraAssumeCapacity(Type.Function{
6283 .ret = ret,
6284 .params_len = @intCast(params.len),
6285 }),
6286 });
6287 self.type_extra.appendSliceAssumeCapacity(@ptrCast(params));
6288 if (self.useLibLlvm()) {
6289 const llvm_params = try self.gpa.alloc(*llvm.Type, params.len);
6290 defer self.gpa.free(llvm_params);
6291 for (llvm_params, params) |*llvm_param, param| llvm_param.* = param.toLlvm(self);
6292 self.llvm.types.appendAssumeCapacity(llvm.functionType(
6293 ret.toLlvm(self),
6294 llvm_params.ptr,
6295 @intCast(llvm_params.len),
6296 switch (kind) {
6297 .normal => .False,
6298 .vararg => .True,
6299 },
6300 ));
6301 }
6302 }
6303 return @enumFromInt(gop.index);
6304}
6305
6306fn intTypeAssumeCapacity(self: *Builder, bits: u24) Type {
6307 assert(bits > 0);
6308 const result = self.getOrPutTypeNoExtraAssumeCapacity(.{ .tag = .integer, .data = bits });
6309 if (self.useLibLlvm() and result.new)
6310 self.llvm.types.appendAssumeCapacity(self.llvm.context.intType(bits));
6311 return result.type;
6312}
6313
6314fn ptrTypeAssumeCapacity(self: *Builder, addr_space: AddrSpace) Type {
6315 const result = self.getOrPutTypeNoExtraAssumeCapacity(
6316 .{ .tag = .pointer, .data = @intFromEnum(addr_space) },
6317 );
6318 if (self.useLibLlvm() and result.new)
6319 self.llvm.types.appendAssumeCapacity(self.llvm.context.pointerType(@intFromEnum(addr_space)));
6320 return result.type;
6321}
6322
6323fn vectorTypeAssumeCapacity(
6324 self: *Builder,
6325 comptime kind: Type.Vector.Kind,
6326 len: u32,
6327 child: Type,
6328) Type {
6329 assert(child.isFloatingPoint() or child.isInteger(self) or child.isPointer(self));
6330 const tag: Type.Tag = switch (kind) {
6331 .normal => .vector,
6332 .scalable => .scalable_vector,
6333 };
6334 const Adapter = struct {
6335 builder: *const Builder,
6336 pub fn hash(_: @This(), key: Type.Vector) u32 {
6337 return @truncate(std.hash.Wyhash.hash(
6338 comptime std.hash.uint32(@intFromEnum(tag)),
6339 std.mem.asBytes(&key),
6340 ));
6341 }
6342 pub fn eql(ctx: @This(), lhs_key: Type.Vector, _: void, rhs_index: usize) bool {
6343 const rhs_data = ctx.builder.type_items.items[rhs_index];
6344 return rhs_data.tag == tag and
6345 std.meta.eql(lhs_key, ctx.builder.typeExtraData(Type.Vector, rhs_data.data));
6346 }
6347 };
6348 const data = Type.Vector{ .len = len, .child = child };
6349 const gop = self.type_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
6350 if (!gop.found_existing) {
6351 gop.key_ptr.* = {};
6352 gop.value_ptr.* = {};
6353 self.type_items.appendAssumeCapacity(.{
6354 .tag = tag,
6355 .data = self.addTypeExtraAssumeCapacity(data),
6356 });
6357 if (self.useLibLlvm()) self.llvm.types.appendAssumeCapacity(switch (kind) {
6358 .normal => llvm.Type.vectorType,
6359 .scalable => llvm.Type.scalableVectorType,
6360 }(child.toLlvm(self), @intCast(len)));
6361 }
6362 return @enumFromInt(gop.index);
6363}
6364
6365fn arrayTypeAssumeCapacity(self: *Builder, len: u64, child: Type) Type {
6366 if (std.math.cast(u32, len)) |small_len| {
6367 const Adapter = struct {
6368 builder: *const Builder,
6369 pub fn hash(_: @This(), key: Type.Vector) u32 {
6370 return @truncate(std.hash.Wyhash.hash(
6371 comptime std.hash.uint32(@intFromEnum(Type.Tag.small_array)),
6372 std.mem.asBytes(&key),
6373 ));
6374 }
6375 pub fn eql(ctx: @This(), lhs_key: Type.Vector, _: void, rhs_index: usize) bool {
6376 const rhs_data = ctx.builder.type_items.items[rhs_index];
6377 return rhs_data.tag == .small_array and
6378 std.meta.eql(lhs_key, ctx.builder.typeExtraData(Type.Vector, rhs_data.data));
6379 }
6380 };
6381 const data = Type.Vector{ .len = small_len, .child = child };
6382 const gop = self.type_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
6383 if (!gop.found_existing) {
6384 gop.key_ptr.* = {};
6385 gop.value_ptr.* = {};
6386 self.type_items.appendAssumeCapacity(.{
6387 .tag = .small_array,
6388 .data = self.addTypeExtraAssumeCapacity(data),
6389 });
6390 if (self.useLibLlvm()) self.llvm.types.appendAssumeCapacity(
6391 child.toLlvm(self).arrayType(@intCast(len)),
6392 );
6393 }
6394 return @enumFromInt(gop.index);
6395 } else {
6396 const Adapter = struct {
6397 builder: *const Builder,
6398 pub fn hash(_: @This(), key: Type.Array) u32 {
6399 return @truncate(std.hash.Wyhash.hash(
6400 comptime std.hash.uint32(@intFromEnum(Type.Tag.array)),
6401 std.mem.asBytes(&key),
6402 ));
6403 }
6404 pub fn eql(ctx: @This(), lhs_key: Type.Array, _: void, rhs_index: usize) bool {
6405 const rhs_data = ctx.builder.type_items.items[rhs_index];
6406 return rhs_data.tag == .array and
6407 std.meta.eql(lhs_key, ctx.builder.typeExtraData(Type.Array, rhs_data.data));
6408 }
6409 };
6410 const data = Type.Array{
6411 .len_lo = @truncate(len),
6412 .len_hi = @intCast(len >> 32),
6413 .child = child,
6414 };
6415 const gop = self.type_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
6416 if (!gop.found_existing) {
6417 gop.key_ptr.* = {};
6418 gop.value_ptr.* = {};
6419 self.type_items.appendAssumeCapacity(.{
6420 .tag = .array,
6421 .data = self.addTypeExtraAssumeCapacity(data),
6422 });
6423 if (self.useLibLlvm()) self.llvm.types.appendAssumeCapacity(
6424 child.toLlvm(self).arrayType(@intCast(len)),
6425 );
6426 }
6427 return @enumFromInt(gop.index);
6428 }
6429}
6430
6431fn structTypeAssumeCapacity(
6432 self: *Builder,
6433 comptime kind: Type.Structure.Kind,
6434 fields: []const Type,
6435) if (build_options.have_llvm) Allocator.Error!Type else Type {
6436 const tag: Type.Tag = switch (kind) {
6437 .normal => .structure,
6438 .@"packed" => .packed_structure,
6439 };
6440 const Adapter = struct {
6441 builder: *const Builder,
6442 pub fn hash(_: @This(), key: []const Type) u32 {
6443 return @truncate(std.hash.Wyhash.hash(
6444 comptime std.hash.uint32(@intFromEnum(tag)),
6445 std.mem.sliceAsBytes(key),
6446 ));
6447 }
6448 pub fn eql(ctx: @This(), lhs_key: []const Type, _: void, rhs_index: usize) bool {
6449 const rhs_data = ctx.builder.type_items.items[rhs_index];
6450 var rhs_extra = ctx.builder.typeExtraDataTrail(Type.Structure, rhs_data.data);
6451 const rhs_fields = rhs_extra.trail.next(rhs_extra.data.fields_len, Type, ctx.builder);
6452 return rhs_data.tag == tag and std.mem.eql(Type, lhs_key, rhs_fields);
6453 }
6454 };
6455 const gop = self.type_map.getOrPutAssumeCapacityAdapted(fields, Adapter{ .builder = self });
6456 if (!gop.found_existing) {
6457 gop.key_ptr.* = {};
6458 gop.value_ptr.* = {};
6459 self.type_items.appendAssumeCapacity(.{
6460 .tag = tag,
6461 .data = self.addTypeExtraAssumeCapacity(Type.Structure{
6462 .fields_len = @intCast(fields.len),
6463 }),
6464 });
6465 self.type_extra.appendSliceAssumeCapacity(@ptrCast(fields));
6466 if (self.useLibLlvm()) {
6467 const ExpectedContents = [expected_fields_len]*llvm.Type;
6468 var stack align(@alignOf(ExpectedContents)) =
6469 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
6470 const allocator = stack.get();
6471
6472 const llvm_fields = try allocator.alloc(*llvm.Type, fields.len);
6473 defer allocator.free(llvm_fields);
6474 for (llvm_fields, fields) |*llvm_field, field| llvm_field.* = field.toLlvm(self);
6475
6476 self.llvm.types.appendAssumeCapacity(self.llvm.context.structType(
6477 llvm_fields.ptr,
6478 @intCast(llvm_fields.len),
6479 switch (kind) {
6480 .normal => .False,
6481 .@"packed" => .True,
6482 },
6483 ));
6484 }
6485 }
6486 return @enumFromInt(gop.index);
6487}
6488
6489fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {
6490 const Adapter = struct {
6491 builder: *const Builder,
6492 pub fn hash(_: @This(), key: String) u32 {
6493 return @truncate(std.hash.Wyhash.hash(
6494 comptime std.hash.uint32(@intFromEnum(Type.Tag.named_structure)),
6495 std.mem.asBytes(&key),
6496 ));
6497 }
6498 pub fn eql(ctx: @This(), lhs_key: String, _: void, rhs_index: usize) bool {
6499 const rhs_data = ctx.builder.type_items.items[rhs_index];
6500 return rhs_data.tag == .named_structure and
6501 lhs_key == ctx.builder.typeExtraData(Type.NamedStructure, rhs_data.data).id;
6502 }
6503 };
6504 var id = name;
6505 if (name == .empty) {
6506 id = self.next_unnamed_type;
6507 assert(id != .none);
6508 self.next_unnamed_type = @enumFromInt(@intFromEnum(id) + 1);
6509 } else assert(!name.isAnon());
6510 while (true) {
6511 const type_gop = self.types.getOrPutAssumeCapacity(id);
6512 if (!type_gop.found_existing) {
6513 const gop = self.type_map.getOrPutAssumeCapacityAdapted(id, Adapter{ .builder = self });
6514 assert(!gop.found_existing);
6515 gop.key_ptr.* = {};
6516 gop.value_ptr.* = {};
6517 self.type_items.appendAssumeCapacity(.{
6518 .tag = .named_structure,
6519 .data = self.addTypeExtraAssumeCapacity(Type.NamedStructure{
6520 .id = id,
6521 .body = .none,
6522 }),
6523 });
6524 const result: Type = @enumFromInt(gop.index);
6525 type_gop.value_ptr.* = result;
6526 if (self.useLibLlvm()) self.llvm.types.appendAssumeCapacity(
6527 self.llvm.context.structCreateNamed(id.toSlice(self) orelse ""),
6528 );
6529 return result;
6530 }
6531
6532 const unique_gop = self.next_unique_type_id.getOrPutAssumeCapacity(name);
6533 if (!unique_gop.found_existing) unique_gop.value_ptr.* = 2;
6534 id = self.fmtAssumeCapacity("{s}.{d}", .{ name.toSlice(self).?, unique_gop.value_ptr.* });
6535 unique_gop.value_ptr.* += 1;
6536 }
6537}
6538
6539fn ensureUnusedTypeCapacity(
6540 self: *Builder,
6541 count: usize,
6542 comptime Extra: type,
6543 trail_len: usize,
6544) Allocator.Error!void {
6545 try self.type_map.ensureUnusedCapacity(self.gpa, count);
6546 try self.type_items.ensureUnusedCapacity(self.gpa, count);
6547 try self.type_extra.ensureUnusedCapacity(
6548 self.gpa,
6549 count * (@typeInfo(Extra).Struct.fields.len + trail_len),
6550 );
6551 if (self.useLibLlvm()) try self.llvm.types.ensureUnusedCapacity(self.gpa, count);
6552}
6553
6554fn getOrPutTypeNoExtraAssumeCapacity(self: *Builder, item: Type.Item) struct { new: bool, type: Type } {
6555 const Adapter = struct {
6556 builder: *const Builder,
6557 pub fn hash(_: @This(), key: Type.Item) u32 {
6558 return @truncate(std.hash.Wyhash.hash(
6559 comptime std.hash.uint32(@intFromEnum(Type.Tag.simple)),
6560 std.mem.asBytes(&key),
6561 ));
6562 }
6563 pub fn eql(ctx: @This(), lhs_key: Type.Item, _: void, rhs_index: usize) bool {
6564 const lhs_bits: u32 = @bitCast(lhs_key);
6565 const rhs_bits: u32 = @bitCast(ctx.builder.type_items.items[rhs_index]);
6566 return lhs_bits == rhs_bits;
6567 }
6568 };
6569 const gop = self.type_map.getOrPutAssumeCapacityAdapted(item, Adapter{ .builder = self });
6570 if (!gop.found_existing) {
6571 gop.key_ptr.* = {};
6572 gop.value_ptr.* = {};
6573 self.type_items.appendAssumeCapacity(item);
6574 }
6575 return .{ .new = !gop.found_existing, .type = @enumFromInt(gop.index) };
6576}
6577
6578fn addTypeExtraAssumeCapacity(self: *Builder, extra: anytype) Type.Item.ExtraIndex {
6579 const result: Type.Item.ExtraIndex = @intCast(self.type_extra.items.len);
6580 inline for (@typeInfo(@TypeOf(extra)).Struct.fields) |field| {
6581 const value = @field(extra, field.name);
6582 self.type_extra.appendAssumeCapacity(switch (field.type) {
6583 u32 => value,
6584 String, Type => @intFromEnum(value),
6585 else => @compileError("bad field type: " ++ @typeName(field.type)),
6586 });
6587 }
6588 return result;
6589}
6590
6591const TypeExtraDataTrail = struct {
6592 index: Type.Item.ExtraIndex,
6593
6594 fn nextMut(self: *TypeExtraDataTrail, len: u32, comptime Item: type, builder: *Builder) []Item {
6595 const items: []Item = @ptrCast(builder.type_extra.items[self.index..][0..len]);
6596 self.index += @intCast(len);
6597 return items;
6598 }
6599
6600 fn next(
6601 self: *TypeExtraDataTrail,
6602 len: u32,
6603 comptime Item: type,
6604 builder: *const Builder,
6605 ) []const Item {
6606 const items: []const Item = @ptrCast(builder.type_extra.items[self.index..][0..len]);
6607 self.index += @intCast(len);
6608 return items;
6609 }
6610};
6611
6612fn typeExtraDataTrail(
6613 self: *const Builder,
6614 comptime T: type,
6615 index: Type.Item.ExtraIndex,
6616) struct { data: T, trail: TypeExtraDataTrail } {
6617 var result: T = undefined;
6618 const fields = @typeInfo(T).Struct.fields;
6619 inline for (fields, self.type_extra.items[index..][0..fields.len]) |field, value|
6620 @field(result, field.name) = switch (field.type) {
6621 u32 => value,
6622 String, Type => @enumFromInt(value),
6623 else => @compileError("bad field type: " ++ @typeName(field.type)),
6624 };
6625 return .{
6626 .data = result,
6627 .trail = .{ .index = index + @as(Type.Item.ExtraIndex, @intCast(fields.len)) },
6628 };
6629}
6630
6631fn typeExtraData(self: *const Builder, comptime T: type, index: Type.Item.ExtraIndex) T {
6632 return self.typeExtraDataTrail(T, index).data;
6633}
6634
6635fn bigIntConstAssumeCapacity(
6636 self: *Builder,
6637 ty: Type,
6638 value: std.math.big.int.Const,
6639) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
6640 const type_item = self.type_items.items[@intFromEnum(ty)];
6641 assert(type_item.tag == .integer);
6642 const bits = type_item.data;
6643
6644 const ExpectedContents = extern struct {
6645 limbs: [64 / @sizeOf(std.math.big.Limb)]std.math.big.Limb,
6646 llvm_limbs: if (build_options.have_llvm) [64 / @sizeOf(u64)]u64 else void,
6647 };
6648 var stack align(@alignOf(ExpectedContents)) =
6649 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
6650 const allocator = stack.get();
6651
6652 var limbs: []std.math.big.Limb = &.{};
6653 defer allocator.free(limbs);
6654 const canonical_value = if (value.fitsInTwosComp(.signed, bits)) value else canon: {
6655 assert(value.fitsInTwosComp(.unsigned, bits));
6656 limbs = try allocator.alloc(std.math.big.Limb, std.math.big.int.calcTwosCompLimbCount(bits));
6657 var temp_value = std.math.big.int.Mutable.init(limbs, 0);
6658 temp_value.truncate(value, .signed, bits);
6659 break :canon temp_value.toConst();
6660 };
6661 assert(canonical_value.fitsInTwosComp(.signed, bits));
6662
6663 const ExtraPtr = *align(@alignOf(std.math.big.Limb)) Constant.Integer;
6664 const Key = struct { tag: Constant.Tag, type: Type, limbs: []const std.math.big.Limb };
6665 const tag: Constant.Tag = switch (canonical_value.positive) {
6666 true => .positive_integer,
6667 false => .negative_integer,
6668 };
6669 const Adapter = struct {
6670 builder: *const Builder,
6671 pub fn hash(_: @This(), key: Key) u32 {
6672 var hasher = std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(key.tag)));
6673 hasher.update(std.mem.asBytes(&key.type));
6674 hasher.update(std.mem.sliceAsBytes(key.limbs));
6675 return @truncate(hasher.final());
6676 }
6677 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
6678 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
6679 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
6680 const rhs_extra: ExtraPtr =
6681 @ptrCast(ctx.builder.constant_limbs.items[rhs_data..][0..Constant.Integer.limbs]);
6682 const rhs_limbs = ctx.builder.constant_limbs
6683 .items[rhs_data + Constant.Integer.limbs ..][0..rhs_extra.limbs_len];
6684 return lhs_key.type == rhs_extra.type and
6685 std.mem.eql(std.math.big.Limb, lhs_key.limbs, rhs_limbs);
6686 }
6687 };
6688
6689 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(
6690 Key{ .tag = tag, .type = ty, .limbs = canonical_value.limbs },
6691 Adapter{ .builder = self },
6692 );
6693 if (!gop.found_existing) {
6694 gop.key_ptr.* = {};
6695 gop.value_ptr.* = {};
6696 self.constant_items.appendAssumeCapacity(.{
6697 .tag = tag,
6698 .data = @intCast(self.constant_limbs.items.len),
6699 });
6700 const extra: ExtraPtr =
6701 @ptrCast(self.constant_limbs.addManyAsArrayAssumeCapacity(Constant.Integer.limbs));
6702 extra.* = .{ .type = ty, .limbs_len = @intCast(canonical_value.limbs.len) };
6703 self.constant_limbs.appendSliceAssumeCapacity(canonical_value.limbs);
6704 if (self.useLibLlvm()) {
6705 const llvm_type = ty.toLlvm(self);
6706 if (canonical_value.to(c_longlong)) |small| {
6707 self.llvm.constants.appendAssumeCapacity(llvm_type.constInt(@bitCast(small), .True));
6708 } else |_| if (canonical_value.to(c_ulonglong)) |small| {
6709 self.llvm.constants.appendAssumeCapacity(llvm_type.constInt(small, .False));
6710 } else |_| {
6711 const llvm_limbs = try allocator.alloc(u64, std.math.divCeil(
6712 usize,
6713 if (canonical_value.positive) canonical_value.bitCountAbs() else bits,
6714 @bitSizeOf(u64),
6715 ) catch unreachable);
6716 defer allocator.free(llvm_limbs);
6717 var limb_index: usize = 0;
6718 var borrow: std.math.big.Limb = 0;
6719 for (llvm_limbs) |*result_limb| {
6720 var llvm_limb: u64 = 0;
6721 inline for (0..Constant.Integer.limbs) |shift| {
6722 const limb = if (limb_index < canonical_value.limbs.len)
6723 canonical_value.limbs[limb_index]
6724 else
6725 0;
6726 limb_index += 1;
6727 llvm_limb |= @as(u64, limb) << shift * @bitSizeOf(std.math.big.Limb);
6728 }
6729 if (!canonical_value.positive) {
6730 const overflow = @subWithOverflow(borrow, llvm_limb);
6731 llvm_limb = overflow[0];
6732 borrow -%= overflow[1];
6733 assert(borrow == 0 or borrow == std.math.maxInt(u64));
6734 }
6735 result_limb.* = llvm_limb;
6736 }
6737 self.llvm.constants.appendAssumeCapacity(
6738 llvm_type.constIntOfArbitraryPrecision(@intCast(llvm_limbs.len), llvm_limbs.ptr),
6739 );
6740 }
6741 }
6742 }
6743 return @enumFromInt(gop.index);
6744}
6745
6746fn halfConstAssumeCapacity(self: *Builder, val: f16) Constant {
6747 const result = self.getOrPutConstantNoExtraAssumeCapacity(
6748 .{ .tag = .half, .data = @as(u16, @bitCast(val)) },
6749 );
6750 if (self.useLibLlvm() and result.new) self.llvm.constants.appendAssumeCapacity(
6751 if (std.math.isSignalNan(val))
6752 Type.i16.toLlvm(self).constInt(@as(u16, @bitCast(val)), .False)
6753 .constBitCast(Type.half.toLlvm(self))
6754 else
6755 Type.half.toLlvm(self).constReal(val),
6756 );
6757 return result.constant;
6758}
6759
6760fn bfloatConstAssumeCapacity(self: *Builder, val: f32) Constant {
6761 assert(@as(u16, @truncate(@as(u32, @bitCast(val)))) == 0);
6762 const result = self.getOrPutConstantNoExtraAssumeCapacity(
6763 .{ .tag = .bfloat, .data = @bitCast(val) },
6764 );
6765 if (self.useLibLlvm() and result.new) self.llvm.constants.appendAssumeCapacity(
6766 if (std.math.isSignalNan(val))
6767 Type.i16.toLlvm(self).constInt(@as(u32, @bitCast(val)) >> 16, .False)
6768 .constBitCast(Type.bfloat.toLlvm(self))
6769 else
6770 Type.bfloat.toLlvm(self).constReal(val),
6771 );
6772
6773 if (self.useLibLlvm() and result.new)
6774 self.llvm.constants.appendAssumeCapacity(Type.bfloat.toLlvm(self).constReal(val));
6775 return result.constant;
6776}
6777
6778fn floatConstAssumeCapacity(self: *Builder, val: f32) Constant {
6779 const result = self.getOrPutConstantNoExtraAssumeCapacity(
6780 .{ .tag = .float, .data = @bitCast(val) },
6781 );
6782 if (self.useLibLlvm() and result.new) self.llvm.constants.appendAssumeCapacity(
6783 if (std.math.isSignalNan(val))
6784 Type.i32.toLlvm(self).constInt(@as(u32, @bitCast(val)), .False)
6785 .constBitCast(Type.float.toLlvm(self))
6786 else
6787 Type.float.toLlvm(self).constReal(val),
6788 );
6789 return result.constant;
6790}
6791
6792fn doubleConstAssumeCapacity(self: *Builder, val: f64) Constant {
6793 const Adapter = struct {
6794 builder: *const Builder,
6795 pub fn hash(_: @This(), key: f64) u32 {
6796 return @truncate(std.hash.Wyhash.hash(
6797 comptime std.hash.uint32(@intFromEnum(Constant.Tag.double)),
6798 std.mem.asBytes(&key),
6799 ));
6800 }
6801 pub fn eql(ctx: @This(), lhs_key: f64, _: void, rhs_index: usize) bool {
6802 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .double) return false;
6803 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
6804 const rhs_extra = ctx.builder.constantExtraData(Constant.Double, rhs_data);
6805 return @as(u64, @bitCast(lhs_key)) == @as(u64, rhs_extra.hi) << 32 | rhs_extra.lo;
6806 }
6807 };
6808 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self });
6809 if (!gop.found_existing) {
6810 gop.key_ptr.* = {};
6811 gop.value_ptr.* = {};
6812 self.constant_items.appendAssumeCapacity(.{
6813 .tag = .double,
6814 .data = self.addConstantExtraAssumeCapacity(Constant.Double{
6815 .lo = @truncate(@as(u64, @bitCast(val))),
6816 .hi = @intCast(@as(u64, @bitCast(val)) >> 32),
6817 }),
6818 });
6819 if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
6820 if (std.math.isSignalNan(val))
6821 Type.i64.toLlvm(self).constInt(@as(u64, @bitCast(val)), .False)
6822 .constBitCast(Type.double.toLlvm(self))
6823 else
6824 Type.double.toLlvm(self).constReal(val),
6825 );
6826 }
6827 return @enumFromInt(gop.index);
6828}
6829
6830fn fp128ConstAssumeCapacity(self: *Builder, val: f128) Constant {
6831 const Adapter = struct {
6832 builder: *const Builder,
6833 pub fn hash(_: @This(), key: f128) u32 {
6834 return @truncate(std.hash.Wyhash.hash(
6835 comptime std.hash.uint32(@intFromEnum(Constant.Tag.fp128)),
6836 std.mem.asBytes(&key),
6837 ));
6838 }
6839 pub fn eql(ctx: @This(), lhs_key: f128, _: void, rhs_index: usize) bool {
6840 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .fp128) return false;
6841 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
6842 const rhs_extra = ctx.builder.constantExtraData(Constant.Fp128, rhs_data);
6843 return @as(u128, @bitCast(lhs_key)) == @as(u128, rhs_extra.hi_hi) << 96 |
6844 @as(u128, rhs_extra.hi_lo) << 64 | @as(u128, rhs_extra.lo_hi) << 32 | rhs_extra.lo_lo;
6845 }
6846 };
6847 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self });
6848 if (!gop.found_existing) {
6849 gop.key_ptr.* = {};
6850 gop.value_ptr.* = {};
6851 self.constant_items.appendAssumeCapacity(.{
6852 .tag = .fp128,
6853 .data = self.addConstantExtraAssumeCapacity(Constant.Fp128{
6854 .lo_lo = @truncate(@as(u128, @bitCast(val))),
6855 .lo_hi = @truncate(@as(u128, @bitCast(val)) >> 32),
6856 .hi_lo = @truncate(@as(u128, @bitCast(val)) >> 64),
6857 .hi_hi = @intCast(@as(u128, @bitCast(val)) >> 96),
6858 }),
6859 });
6860 if (self.useLibLlvm()) {
6861 const llvm_limbs = [_]u64{
6862 @truncate(@as(u128, @bitCast(val))),
6863 @intCast(@as(u128, @bitCast(val)) >> 64),
6864 };
6865 self.llvm.constants.appendAssumeCapacity(
6866 Type.i128.toLlvm(self)
6867 .constIntOfArbitraryPrecision(@intCast(llvm_limbs.len), &llvm_limbs)
6868 .constBitCast(Type.fp128.toLlvm(self)),
6869 );
6870 }
6871 }
6872 return @enumFromInt(gop.index);
6873}
6874
6875fn x86_fp80ConstAssumeCapacity(self: *Builder, val: f80) Constant {
6876 const Adapter = struct {
6877 builder: *const Builder,
6878 pub fn hash(_: @This(), key: f80) u32 {
6879 return @truncate(std.hash.Wyhash.hash(
6880 comptime std.hash.uint32(@intFromEnum(Constant.Tag.x86_fp80)),
6881 std.mem.asBytes(&key)[0..10],
6882 ));
6883 }
6884 pub fn eql(ctx: @This(), lhs_key: f80, _: void, rhs_index: usize) bool {
6885 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .x86_fp80) return false;
6886 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
6887 const rhs_extra = ctx.builder.constantExtraData(Constant.Fp80, rhs_data);
6888 return @as(u80, @bitCast(lhs_key)) == @as(u80, rhs_extra.hi) << 64 |
6889 @as(u80, rhs_extra.lo_hi) << 32 | rhs_extra.lo_lo;
6890 }
6891 };
6892 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self });
6893 if (!gop.found_existing) {
6894 gop.key_ptr.* = {};
6895 gop.value_ptr.* = {};
6896 self.constant_items.appendAssumeCapacity(.{
6897 .tag = .x86_fp80,
6898 .data = self.addConstantExtraAssumeCapacity(Constant.Fp80{
6899 .lo_lo = @truncate(@as(u80, @bitCast(val))),
6900 .lo_hi = @truncate(@as(u80, @bitCast(val)) >> 32),
6901 .hi = @intCast(@as(u80, @bitCast(val)) >> 64),
6902 }),
6903 });
6904 if (self.useLibLlvm()) {
6905 const llvm_limbs = [_]u64{
6906 @truncate(@as(u80, @bitCast(val))),
6907 @intCast(@as(u80, @bitCast(val)) >> 64),
6908 };
6909 self.llvm.constants.appendAssumeCapacity(
6910 Type.i80.toLlvm(self)
6911 .constIntOfArbitraryPrecision(@intCast(llvm_limbs.len), &llvm_limbs)
6912 .constBitCast(Type.x86_fp80.toLlvm(self)),
6913 );
6914 }
6915 }
6916 return @enumFromInt(gop.index);
6917}
6918
6919fn ppc_fp128ConstAssumeCapacity(self: *Builder, val: [2]f64) Constant {
6920 const Adapter = struct {
6921 builder: *const Builder,
6922 pub fn hash(_: @This(), key: [2]f64) u32 {
6923 return @truncate(std.hash.Wyhash.hash(
6924 comptime std.hash.uint32(@intFromEnum(Constant.Tag.ppc_fp128)),
6925 std.mem.asBytes(&key),
6926 ));
6927 }
6928 pub fn eql(ctx: @This(), lhs_key: [2]f64, _: void, rhs_index: usize) bool {
6929 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .ppc_fp128) return false;
6930 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
6931 const rhs_extra = ctx.builder.constantExtraData(Constant.Fp128, rhs_data);
6932 return @as(u64, @bitCast(lhs_key[0])) == @as(u64, rhs_extra.lo_hi) << 32 | rhs_extra.lo_lo and
6933 @as(u64, @bitCast(lhs_key[1])) == @as(u64, rhs_extra.hi_hi) << 32 | rhs_extra.hi_lo;
6934 }
6935 };
6936 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self });
6937 if (!gop.found_existing) {
6938 gop.key_ptr.* = {};
6939 gop.value_ptr.* = {};
6940 self.constant_items.appendAssumeCapacity(.{
6941 .tag = .ppc_fp128,
6942 .data = self.addConstantExtraAssumeCapacity(Constant.Fp128{
6943 .lo_lo = @truncate(@as(u64, @bitCast(val[0]))),
6944 .lo_hi = @intCast(@as(u64, @bitCast(val[0])) >> 32),
6945 .hi_lo = @truncate(@as(u64, @bitCast(val[1]))),
6946 .hi_hi = @intCast(@as(u64, @bitCast(val[1])) >> 32),
6947 }),
6948 });
6949 if (self.useLibLlvm()) {
6950 const llvm_limbs: *const [2]u64 = @ptrCast(&val);
6951 self.llvm.constants.appendAssumeCapacity(
6952 Type.i128.toLlvm(self)
6953 .constIntOfArbitraryPrecision(@intCast(llvm_limbs.len), llvm_limbs)
6954 .constBitCast(Type.ppc_fp128.toLlvm(self)),
6955 );
6956 }
6957 }
6958 return @enumFromInt(gop.index);
6959}
6960
6961fn nullConstAssumeCapacity(self: *Builder, ty: Type) Constant {
6962 assert(self.type_items.items[@intFromEnum(ty)].tag == .pointer);
6963 const result = self.getOrPutConstantNoExtraAssumeCapacity(
6964 .{ .tag = .null, .data = @intFromEnum(ty) },
6965 );
6966 if (self.useLibLlvm() and result.new)
6967 self.llvm.constants.appendAssumeCapacity(ty.toLlvm(self).constNull());
6968 return result.constant;
6969}
6970
6971fn noneConstAssumeCapacity(self: *Builder, ty: Type) Constant {
6972 assert(ty == .token);
6973 const result = self.getOrPutConstantNoExtraAssumeCapacity(
6974 .{ .tag = .none, .data = @intFromEnum(ty) },
6975 );
6976 if (self.useLibLlvm() and result.new)
6977 self.llvm.constants.appendAssumeCapacity(ty.toLlvm(self).constNull());
6978 return result.constant;
6979}
6980
6981fn structConstAssumeCapacity(
6982 self: *Builder,
6983 ty: Type,
6984 vals: []const Constant,
6985) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
6986 const type_item = self.type_items.items[@intFromEnum(ty)];
6987 var extra = self.typeExtraDataTrail(Type.Structure, switch (type_item.tag) {
6988 .structure, .packed_structure => type_item.data,
6989 .named_structure => data: {
6990 const body_ty = self.typeExtraData(Type.NamedStructure, type_item.data).body;
6991 const body_item = self.type_items.items[@intFromEnum(body_ty)];
6992 switch (body_item.tag) {
6993 .structure, .packed_structure => break :data body_item.data,
6994 else => unreachable,
6995 }
6996 },
6997 else => unreachable,
6998 });
6999 const fields = extra.trail.next(extra.data.fields_len, Type, self);
7000 for (fields, vals) |field, val| assert(field == val.typeOf(self));
7001
7002 for (vals) |val| {
7003 if (!val.isZeroInit(self)) break;
7004 } else return self.zeroInitConstAssumeCapacity(ty);
7005
7006 const tag: Constant.Tag = switch (ty.unnamedTag(self)) {
7007 .structure => .structure,
7008 .packed_structure => .packed_structure,
7009 else => unreachable,
7010 };
7011 const result = self.getOrPutConstantAggregateAssumeCapacity(tag, ty, vals);
7012 if (self.useLibLlvm() and result.new) {
7013 const ExpectedContents = [expected_fields_len]*llvm.Value;
7014 var stack align(@alignOf(ExpectedContents)) =
7015 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
7016 const allocator = stack.get();
7017
7018 const llvm_vals = try allocator.alloc(*llvm.Value, vals.len);
7019 defer allocator.free(llvm_vals);
7020 for (llvm_vals, vals) |*llvm_val, val| llvm_val.* = val.toLlvm(self);
7021
7022 self.llvm.constants.appendAssumeCapacity(
7023 ty.toLlvm(self).constNamedStruct(llvm_vals.ptr, @intCast(llvm_vals.len)),
7024 );
7025 }
7026 return result.constant;
7027}
7028
7029fn arrayConstAssumeCapacity(
7030 self: *Builder,
7031 ty: Type,
7032 vals: []const Constant,
7033) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
7034 const type_item = self.type_items.items[@intFromEnum(ty)];
7035 const type_extra: struct { len: u64, child: Type } = switch (type_item.tag) {
7036 inline .small_array, .array => |kind| extra: {
7037 const extra = self.typeExtraData(switch (kind) {
7038 .small_array => Type.Vector,
7039 .array => Type.Array,
7040 else => unreachable,
7041 }, type_item.data);
7042 break :extra .{ .len = extra.length(), .child = extra.child };
7043 },
7044 else => unreachable,
7045 };
7046 assert(type_extra.len == vals.len);
7047 for (vals) |val| assert(type_extra.child == val.typeOf(self));
7048
7049 for (vals) |val| {
7050 if (!val.isZeroInit(self)) break;
7051 } else return self.zeroInitConstAssumeCapacity(ty);
7052
7053 const result = self.getOrPutConstantAggregateAssumeCapacity(.array, ty, vals);
7054 if (self.useLibLlvm() and result.new) {
7055 const ExpectedContents = [expected_fields_len]*llvm.Value;
7056 var stack align(@alignOf(ExpectedContents)) =
7057 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
7058 const allocator = stack.get();
7059
7060 const llvm_vals = try allocator.alloc(*llvm.Value, vals.len);
7061 defer allocator.free(llvm_vals);
7062 for (llvm_vals, vals) |*llvm_val, val| llvm_val.* = val.toLlvm(self);
7063
7064 self.llvm.constants.appendAssumeCapacity(
7065 type_extra.child.toLlvm(self).constArray(llvm_vals.ptr, @intCast(llvm_vals.len)),
7066 );
7067 }
7068 return result.constant;
7069}
7070
7071fn stringConstAssumeCapacity(self: *Builder, val: String) Constant {
7072 const slice = val.toSlice(self).?;
7073 const ty = self.arrayTypeAssumeCapacity(slice.len, .i8);
7074 if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty);
7075 const result = self.getOrPutConstantNoExtraAssumeCapacity(
7076 .{ .tag = .string, .data = @intFromEnum(val) },
7077 );
7078 if (self.useLibLlvm() and result.new) self.llvm.constants.appendAssumeCapacity(
7079 self.llvm.context.constString(slice.ptr, @intCast(slice.len), .True),
7080 );
7081 return result.constant;
7082}
7083
7084fn stringNullConstAssumeCapacity(self: *Builder, val: String) Constant {
7085 const slice = val.toSlice(self).?;
7086 const ty = self.arrayTypeAssumeCapacity(slice.len + 1, .i8);
7087 if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty);
7088 const result = self.getOrPutConstantNoExtraAssumeCapacity(
7089 .{ .tag = .string_null, .data = @intFromEnum(val) },
7090 );
7091 if (self.useLibLlvm() and result.new) self.llvm.constants.appendAssumeCapacity(
7092 self.llvm.context.constString(slice.ptr, @intCast(slice.len + 1), .True),
7093 );
7094 return result.constant;
7095}
7096
7097fn vectorConstAssumeCapacity(
7098 self: *Builder,
7099 ty: Type,
7100 vals: []const Constant,
7101) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
7102 assert(ty.isVector(self));
7103 assert(ty.vectorLen(self) == vals.len);
7104 for (vals) |val| assert(ty.childType(self) == val.typeOf(self));
7105
7106 for (vals[1..]) |val| {
7107 if (vals[0] != val) break;
7108 } else return self.splatConstAssumeCapacity(ty, vals[0]);
7109 for (vals) |val| {
7110 if (!val.isZeroInit(self)) break;
7111 } else return self.zeroInitConstAssumeCapacity(ty);
7112
7113 const result = self.getOrPutConstantAggregateAssumeCapacity(.vector, ty, vals);
7114 if (self.useLibLlvm() and result.new) {
7115 const ExpectedContents = [expected_fields_len]*llvm.Value;
7116 var stack align(@alignOf(ExpectedContents)) =
7117 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
7118 const allocator = stack.get();
7119
7120 const llvm_vals = try allocator.alloc(*llvm.Value, vals.len);
7121 defer allocator.free(llvm_vals);
7122 for (llvm_vals, vals) |*llvm_val, val| llvm_val.* = val.toLlvm(self);
7123
7124 self.llvm.constants.appendAssumeCapacity(
7125 llvm.constVector(llvm_vals.ptr, @intCast(llvm_vals.len)),
7126 );
7127 }
7128 return result.constant;
7129}
7130
7131fn splatConstAssumeCapacity(
7132 self: *Builder,
7133 ty: Type,
7134 val: Constant,
7135) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
7136 assert(ty.scalarType(self) == val.typeOf(self));
7137
7138 if (!ty.isVector(self)) return val;
7139 if (val.isZeroInit(self)) return self.zeroInitConstAssumeCapacity(ty);
7140
7141 const Adapter = struct {
7142 builder: *const Builder,
7143 pub fn hash(_: @This(), key: Constant.Splat) u32 {
7144 return @truncate(std.hash.Wyhash.hash(
7145 comptime std.hash.uint32(@intFromEnum(Constant.Tag.splat)),
7146 std.mem.asBytes(&key),
7147 ));
7148 }
7149 pub fn eql(ctx: @This(), lhs_key: Constant.Splat, _: void, rhs_index: usize) bool {
7150 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .splat) return false;
7151 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
7152 const rhs_extra = ctx.builder.constantExtraData(Constant.Splat, rhs_data);
7153 return std.meta.eql(lhs_key, rhs_extra);
7154 }
7155 };
7156 const data = Constant.Splat{ .type = ty, .value = val };
7157 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
7158 if (!gop.found_existing) {
7159 gop.key_ptr.* = {};
7160 gop.value_ptr.* = {};
7161 self.constant_items.appendAssumeCapacity(.{
7162 .tag = .splat,
7163 .data = self.addConstantExtraAssumeCapacity(data),
7164 });
7165 if (self.useLibLlvm()) {
7166 const ExpectedContents = [expected_fields_len]*llvm.Value;
7167 var stack align(@alignOf(ExpectedContents)) =
7168 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
7169 const allocator = stack.get();
7170
7171 const llvm_vals = try allocator.alloc(*llvm.Value, ty.vectorLen(self));
7172 defer allocator.free(llvm_vals);
7173 @memset(llvm_vals, val.toLlvm(self));
7174
7175 self.llvm.constants.appendAssumeCapacity(
7176 llvm.constVector(llvm_vals.ptr, @intCast(llvm_vals.len)),
7177 );
7178 }
7179 }
7180 return @enumFromInt(gop.index);
7181}
7182
7183fn zeroInitConstAssumeCapacity(self: *Builder, ty: Type) Constant {
7184 switch (ty) {
7185 inline .half,
7186 .bfloat,
7187 .float,
7188 .double,
7189 .fp128,
7190 .x86_fp80,
7191 => |tag| return @field(Builder, @tagName(tag) ++ "ConstAssumeCapacity")(self, 0.0),
7192 .ppc_fp128 => return self.ppc_fp128ConstAssumeCapacity(.{ 0.0, 0.0 }),
7193 .token => return .none,
7194 .i1 => return .false,
7195 else => switch (self.type_items.items[@intFromEnum(ty)].tag) {
7196 .simple,
7197 .function,
7198 .vararg_function,
7199 => unreachable,
7200 .integer => {
7201 var limbs: [std.math.big.int.calcLimbLen(0)]std.math.big.Limb = undefined;
7202 const bigint = std.math.big.int.Mutable.init(&limbs, 0);
7203 return self.bigIntConstAssumeCapacity(ty, bigint.toConst()) catch unreachable;
7204 },
7205 .pointer => return self.nullConstAssumeCapacity(ty),
7206 .target,
7207 .vector,
7208 .scalable_vector,
7209 .small_array,
7210 .array,
7211 .structure,
7212 .packed_structure,
7213 .named_structure,
7214 => {},
7215 },
7216 }
7217 const result = self.getOrPutConstantNoExtraAssumeCapacity(
7218 .{ .tag = .zeroinitializer, .data = @intFromEnum(ty) },
7219 );
7220 if (self.useLibLlvm() and result.new)
7221 self.llvm.constants.appendAssumeCapacity(ty.toLlvm(self).constNull());
7222 return result.constant;
7223}
7224
7225fn undefConstAssumeCapacity(self: *Builder, ty: Type) Constant {
7226 switch (self.type_items.items[@intFromEnum(ty)].tag) {
7227 .simple => switch (ty) {
7228 .void, .label => unreachable,
7229 else => {},
7230 },
7231 .function, .vararg_function => unreachable,
7232 else => {},
7233 }
7234 const result = self.getOrPutConstantNoExtraAssumeCapacity(
7235 .{ .tag = .undef, .data = @intFromEnum(ty) },
7236 );
7237 if (self.useLibLlvm() and result.new)
7238 self.llvm.constants.appendAssumeCapacity(ty.toLlvm(self).getUndef());
7239 return result.constant;
7240}
7241
7242fn poisonConstAssumeCapacity(self: *Builder, ty: Type) Constant {
7243 switch (self.type_items.items[@intFromEnum(ty)].tag) {
7244 .simple => switch (ty) {
7245 .void, .label => unreachable,
7246 else => {},
7247 },
7248 .function, .vararg_function => unreachable,
7249 else => {},
7250 }
7251 const result = self.getOrPutConstantNoExtraAssumeCapacity(
7252 .{ .tag = .poison, .data = @intFromEnum(ty) },
7253 );
7254 if (self.useLibLlvm() and result.new)
7255 self.llvm.constants.appendAssumeCapacity(ty.toLlvm(self).getPoison());
7256 return result.constant;
7257}
7258
7259fn blockAddrConstAssumeCapacity(
7260 self: *Builder,
7261 function: Function.Index,
7262 block: Function.Block.Index,
7263) Constant {
7264 const Adapter = struct {
7265 builder: *const Builder,
7266 pub fn hash(_: @This(), key: Constant.BlockAddress) u32 {
7267 return @truncate(std.hash.Wyhash.hash(
7268 comptime std.hash.uint32(@intFromEnum(Constant.Tag.blockaddress)),
7269 std.mem.asBytes(&key),
7270 ));
7271 }
7272 pub fn eql(ctx: @This(), lhs_key: Constant.BlockAddress, _: void, rhs_index: usize) bool {
7273 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .blockaddress) return false;
7274 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
7275 const rhs_extra = ctx.builder.constantExtraData(Constant.BlockAddress, rhs_data);
7276 return std.meta.eql(lhs_key, rhs_extra);
7277 }
7278 };
7279 const data = Constant.BlockAddress{ .function = function, .block = block };
7280 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
7281 if (!gop.found_existing) {
7282 gop.key_ptr.* = {};
7283 gop.value_ptr.* = {};
7284 self.constant_items.appendAssumeCapacity(.{
7285 .tag = .blockaddress,
7286 .data = self.addConstantExtraAssumeCapacity(data),
7287 });
7288 if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
7289 function.toLlvm(self).blockAddress(block.toValue(self, function).toLlvm(self, function)),
7290 );
7291 }
7292 return @enumFromInt(gop.index);
7293}
7294
7295fn dsoLocalEquivalentConstAssumeCapacity(self: *Builder, function: Function.Index) Constant {
7296 const result = self.getOrPutConstantNoExtraAssumeCapacity(
7297 .{ .tag = .dso_local_equivalent, .data = @intFromEnum(function) },
7298 );
7299 if (self.useLibLlvm() and result.new) self.llvm.constants.appendAssumeCapacity(undefined);
7300 return result.constant;
7301}
7302
7303fn noCfiConstAssumeCapacity(self: *Builder, function: Function.Index) Constant {
7304 const result = self.getOrPutConstantNoExtraAssumeCapacity(
7305 .{ .tag = .no_cfi, .data = @intFromEnum(function) },
7306 );
7307 if (self.useLibLlvm() and result.new) self.llvm.constants.appendAssumeCapacity(undefined);
7308 return result.constant;
7309}
7310
7311fn convTag(
7312 self: *Builder,
7313 comptime Tag: type,
7314 signedness: Constant.Cast.Signedness,
7315 val_ty: Type,
7316 ty: Type,
7317) Tag {
7318 assert(val_ty != ty);
7319 return switch (val_ty.scalarTag(self)) {
7320 .simple => switch (ty.scalarTag(self)) {
7321 .simple => switch (std.math.order(val_ty.scalarBits(self), ty.scalarBits(self))) {
7322 .lt => .fpext,
7323 .eq => unreachable,
7324 .gt => .fptrunc,
7325 },
7326 .integer => switch (signedness) {
7327 .unsigned => .fptoui,
7328 .signed => .fptosi,
7329 .unneeded => unreachable,
7330 },
7331 else => unreachable,
7332 },
7333 .integer => switch (ty.scalarTag(self)) {
7334 .simple => switch (signedness) {
7335 .unsigned => .uitofp,
7336 .signed => .sitofp,
7337 .unneeded => unreachable,
7338 },
7339 .integer => switch (std.math.order(val_ty.scalarBits(self), ty.scalarBits(self))) {
7340 .lt => switch (signedness) {
7341 .unsigned => .zext,
7342 .signed => .sext,
7343 .unneeded => unreachable,
7344 },
7345 .eq => unreachable,
7346 .gt => .trunc,
7347 },
7348 .pointer => .inttoptr,
7349 else => unreachable,
7350 },
7351 .pointer => switch (ty.scalarTag(self)) {
7352 .integer => .ptrtoint,
7353 .pointer => .addrspacecast,
7354 else => unreachable,
7355 },
7356 else => unreachable,
7357 };
7358}
7359
7360fn convConstAssumeCapacity(
7361 self: *Builder,
7362 signedness: Constant.Cast.Signedness,
7363 val: Constant,
7364 ty: Type,
7365) Constant {
7366 const val_ty = val.typeOf(self);
7367 if (val_ty == ty) return val;
7368 return self.castConstAssumeCapacity(self.convTag(Constant.Tag, signedness, val_ty, ty), val, ty);
7369}
7370
7371fn castConstAssumeCapacity(self: *Builder, tag: Constant.Tag, val: Constant, ty: Type) Constant {
7372 const Key = struct { tag: Constant.Tag, cast: Constant.Cast };
7373 const Adapter = struct {
7374 builder: *const Builder,
7375 pub fn hash(_: @This(), key: Key) u32 {
7376 return @truncate(std.hash.Wyhash.hash(
7377 std.hash.uint32(@intFromEnum(key.tag)),
7378 std.mem.asBytes(&key.cast),
7379 ));
7380 }
7381 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
7382 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
7383 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
7384 const rhs_extra = ctx.builder.constantExtraData(Constant.Cast, rhs_data);
7385 return std.meta.eql(lhs_key.cast, rhs_extra);
7386 }
7387 };
7388 const data = Key{ .tag = tag, .cast = .{ .val = val, .type = ty } };
7389 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
7390 if (!gop.found_existing) {
7391 gop.key_ptr.* = {};
7392 gop.value_ptr.* = {};
7393 self.constant_items.appendAssumeCapacity(.{
7394 .tag = tag,
7395 .data = self.addConstantExtraAssumeCapacity(data.cast),
7396 });
7397 if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(switch (tag) {
7398 .trunc => &llvm.Value.constTrunc,
7399 .zext => &llvm.Value.constZExt,
7400 .sext => &llvm.Value.constSExt,
7401 .fptrunc => &llvm.Value.constFPTrunc,
7402 .fpext => &llvm.Value.constFPExt,
7403 .fptoui => &llvm.Value.constFPToUI,
7404 .fptosi => &llvm.Value.constFPToSI,
7405 .uitofp => &llvm.Value.constUIToFP,
7406 .sitofp => &llvm.Value.constSIToFP,
7407 .ptrtoint => &llvm.Value.constPtrToInt,
7408 .inttoptr => &llvm.Value.constIntToPtr,
7409 .bitcast => &llvm.Value.constBitCast,
7410 else => unreachable,
7411 }(val.toLlvm(self), ty.toLlvm(self)));
7412 }
7413 return @enumFromInt(gop.index);
7414}
7415
7416fn gepConstAssumeCapacity(
7417 self: *Builder,
7418 comptime kind: Constant.GetElementPtr.Kind,
7419 ty: Type,
7420 base: Constant,
7421 inrange: ?u16,
7422 indices: []const Constant,
7423) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
7424 const tag: Constant.Tag = switch (kind) {
7425 .normal => .getelementptr,
7426 .inbounds => .@"getelementptr inbounds",
7427 };
7428 const base_ty = base.typeOf(self);
7429 const base_is_vector = base_ty.isVector(self);
7430
7431 const VectorInfo = struct {
7432 kind: Type.Vector.Kind,
7433 len: u32,
7434
7435 fn init(vector_ty: Type, builder: *const Builder) @This() {
7436 return .{ .kind = vector_ty.vectorKind(builder), .len = vector_ty.vectorLen(builder) };
7437 }
7438 };
7439 var vector_info: ?VectorInfo = if (base_is_vector) VectorInfo.init(base_ty, self) else null;
7440 for (indices) |index| {
7441 const index_ty = index.typeOf(self);
7442 switch (index_ty.tag(self)) {
7443 .integer => {},
7444 .vector, .scalable_vector => {
7445 const index_info = VectorInfo.init(index_ty, self);
7446 if (vector_info) |info|
7447 assert(std.meta.eql(info, index_info))
7448 else
7449 vector_info = index_info;
7450 },
7451 else => unreachable,
7452 }
7453 }
7454 if (!base_is_vector) if (vector_info) |info| switch (info.kind) {
7455 inline else => |vector_kind| _ = self.vectorTypeAssumeCapacity(vector_kind, info.len, base_ty),
7456 };
7457
7458 const Key = struct {
7459 type: Type,
7460 base: Constant,
7461 inrange: Constant.GetElementPtr.InRangeIndex,
7462 indices: []const Constant,
7463 };
7464 const Adapter = struct {
7465 builder: *const Builder,
7466 pub fn hash(_: @This(), key: Key) u32 {
7467 var hasher = std.hash.Wyhash.init(comptime std.hash.uint32(@intFromEnum(tag)));
7468 hasher.update(std.mem.asBytes(&key.type));
7469 hasher.update(std.mem.asBytes(&key.base));
7470 hasher.update(std.mem.asBytes(&key.inrange));
7471 hasher.update(std.mem.sliceAsBytes(key.indices));
7472 return @truncate(hasher.final());
7473 }
7474 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
7475 if (ctx.builder.constant_items.items(.tag)[rhs_index] != tag) return false;
7476 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
7477 var rhs_extra = ctx.builder.constantExtraDataTrail(Constant.GetElementPtr, rhs_data);
7478 const rhs_indices =
7479 rhs_extra.trail.next(rhs_extra.data.info.indices_len, Constant, ctx.builder);
7480 return lhs_key.type == rhs_extra.data.type and lhs_key.base == rhs_extra.data.base and
7481 lhs_key.inrange == rhs_extra.data.info.inrange and
7482 std.mem.eql(Constant, lhs_key.indices, rhs_indices);
7483 }
7484 };
7485 const data = Key{
7486 .type = ty,
7487 .base = base,
7488 .inrange = if (inrange) |index| @enumFromInt(index) else .none,
7489 .indices = indices,
7490 };
7491 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
7492 if (!gop.found_existing) {
7493 gop.key_ptr.* = {};
7494 gop.value_ptr.* = {};
7495 self.constant_items.appendAssumeCapacity(.{
7496 .tag = tag,
7497 .data = self.addConstantExtraAssumeCapacity(Constant.GetElementPtr{
7498 .type = ty,
7499 .base = base,
7500 .info = .{ .indices_len = @intCast(indices.len), .inrange = data.inrange },
7501 }),
7502 });
7503 self.constant_extra.appendSliceAssumeCapacity(@ptrCast(indices));
7504 if (self.useLibLlvm()) {
7505 const ExpectedContents = [expected_gep_indices_len]*llvm.Value;
7506 var stack align(@alignOf(ExpectedContents)) =
7507 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
7508 const allocator = stack.get();
7509
7510 const llvm_indices = try allocator.alloc(*llvm.Value, indices.len);
7511 defer allocator.free(llvm_indices);
7512 for (llvm_indices, indices) |*llvm_index, index| llvm_index.* = index.toLlvm(self);
7513
7514 self.llvm.constants.appendAssumeCapacity(switch (kind) {
7515 .normal => llvm.Type.constGEP,
7516 .inbounds => llvm.Type.constInBoundsGEP,
7517 }(ty.toLlvm(self), base.toLlvm(self), llvm_indices.ptr, @intCast(llvm_indices.len)));
7518 }
7519 }
7520 return @enumFromInt(gop.index);
7521}
7522
7523fn icmpConstAssumeCapacity(
7524 self: *Builder,
7525 cond: IntegerCondition,
7526 lhs: Constant,
7527 rhs: Constant,
7528) Constant {
7529 const Adapter = struct {
7530 builder: *const Builder,
7531 pub fn hash(_: @This(), key: Constant.Compare) u32 {
7532 return @truncate(std.hash.Wyhash.hash(
7533 std.hash.uint32(@intFromEnum(Constant.tag.icmp)),
7534 std.mem.asBytes(&key),
7535 ));
7536 }
7537 pub fn eql(ctx: @This(), lhs_key: Constant.Compare, _: void, rhs_index: usize) bool {
7538 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .icmp) return false;
7539 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
7540 const rhs_extra = ctx.builder.constantExtraData(Constant.Compare, rhs_data);
7541 return std.meta.eql(lhs_key, rhs_extra);
7542 }
7543 };
7544 const data = Constant.Compare{ .cond = @intFromEnum(cond), .lhs = lhs, .rhs = rhs };
7545 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
7546 if (!gop.found_existing) {
7547 gop.key_ptr.* = {};
7548 gop.value_ptr.* = {};
7549 self.constant_items.appendAssumeCapacity(.{
7550 .tag = .icmp,
7551 .data = self.addConstantExtraAssumeCapacity(data),
7552 });
7553 if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
7554 llvm.constICmp(@enumFromInt(@intFromEnum(cond)), lhs.toLlvm(self), rhs.toLlvm(self)),
7555 );
7556 }
7557 return @enumFromInt(gop.index);
7558}
7559
7560fn fcmpConstAssumeCapacity(
7561 self: *Builder,
7562 cond: FloatCondition,
7563 lhs: Constant,
7564 rhs: Constant,
7565) Constant {
7566 const Adapter = struct {
7567 builder: *const Builder,
7568 pub fn hash(_: @This(), key: Constant.Compare) u32 {
7569 return @truncate(std.hash.Wyhash.hash(
7570 std.hash.uint32(@intFromEnum(Constant.tag.fcmp)),
7571 std.mem.asBytes(&key),
7572 ));
7573 }
7574 pub fn eql(ctx: @This(), lhs_key: Constant.Compare, _: void, rhs_index: usize) bool {
7575 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .fcmp) return false;
7576 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
7577 const rhs_extra = ctx.builder.constantExtraData(Constant.Compare, rhs_data);
7578 return std.meta.eql(lhs_key, rhs_extra);
7579 }
7580 };
7581 const data = Constant.Compare{ .cond = @intFromEnum(cond), .lhs = lhs, .rhs = rhs };
7582 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
7583 if (!gop.found_existing) {
7584 gop.key_ptr.* = {};
7585 gop.value_ptr.* = {};
7586 self.constant_items.appendAssumeCapacity(.{
7587 .tag = .fcmp,
7588 .data = self.addConstantExtraAssumeCapacity(data),
7589 });
7590 if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
7591 llvm.constFCmp(@enumFromInt(@intFromEnum(cond)), lhs.toLlvm(self), rhs.toLlvm(self)),
7592 );
7593 }
7594 return @enumFromInt(gop.index);
7595}
7596
7597fn extractElementConstAssumeCapacity(
7598 self: *Builder,
7599 val: Constant,
7600 index: Constant,
7601) Constant {
7602 const Adapter = struct {
7603 builder: *const Builder,
7604 pub fn hash(_: @This(), key: Constant.ExtractElement) u32 {
7605 return @truncate(std.hash.Wyhash.hash(
7606 comptime std.hash.uint32(@intFromEnum(Constant.Tag.extractelement)),
7607 std.mem.asBytes(&key),
7608 ));
7609 }
7610 pub fn eql(ctx: @This(), lhs_key: Constant.ExtractElement, _: void, rhs_index: usize) bool {
7611 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .extractelement) return false;
7612 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
7613 const rhs_extra = ctx.builder.constantExtraData(Constant.ExtractElement, rhs_data);
7614 return std.meta.eql(lhs_key, rhs_extra);
7615 }
7616 };
7617 const data = Constant.ExtractElement{ .val = val, .index = index };
7618 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
7619 if (!gop.found_existing) {
7620 gop.key_ptr.* = {};
7621 gop.value_ptr.* = {};
7622 self.constant_items.appendAssumeCapacity(.{
7623 .tag = .extractelement,
7624 .data = self.addConstantExtraAssumeCapacity(data),
7625 });
7626 if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
7627 val.toLlvm(self).constExtractElement(index.toLlvm(self)),
7628 );
7629 }
7630 return @enumFromInt(gop.index);
7631}
7632
7633fn insertElementConstAssumeCapacity(
7634 self: *Builder,
7635 val: Constant,
7636 elem: Constant,
7637 index: Constant,
7638) Constant {
7639 const Adapter = struct {
7640 builder: *const Builder,
7641 pub fn hash(_: @This(), key: Constant.InsertElement) u32 {
7642 return @truncate(std.hash.Wyhash.hash(
7643 comptime std.hash.uint32(@intFromEnum(Constant.Tag.insertelement)),
7644 std.mem.asBytes(&key),
7645 ));
7646 }
7647 pub fn eql(ctx: @This(), lhs_key: Constant.InsertElement, _: void, rhs_index: usize) bool {
7648 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .insertelement) return false;
7649 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
7650 const rhs_extra = ctx.builder.constantExtraData(Constant.InsertElement, rhs_data);
7651 return std.meta.eql(lhs_key, rhs_extra);
7652 }
7653 };
7654 const data = Constant.InsertElement{ .val = val, .elem = elem, .index = index };
7655 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
7656 if (!gop.found_existing) {
7657 gop.key_ptr.* = {};
7658 gop.value_ptr.* = {};
7659 self.constant_items.appendAssumeCapacity(.{
7660 .tag = .insertelement,
7661 .data = self.addConstantExtraAssumeCapacity(data),
7662 });
7663 if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
7664 val.toLlvm(self).constInsertElement(elem.toLlvm(self), index.toLlvm(self)),
7665 );
7666 }
7667 return @enumFromInt(gop.index);
7668}
7669
7670fn shuffleVectorConstAssumeCapacity(
7671 self: *Builder,
7672 lhs: Constant,
7673 rhs: Constant,
7674 mask: Constant,
7675) Constant {
7676 assert(lhs.typeOf(self).isVector(self.builder));
7677 assert(lhs.typeOf(self) == rhs.typeOf(self));
7678 assert(mask.typeOf(self).scalarType(self).isInteger(self));
7679 _ = lhs.typeOf(self).changeLengthAssumeCapacity(mask.typeOf(self).vectorLen(self), self);
7680 const Adapter = struct {
7681 builder: *const Builder,
7682 pub fn hash(_: @This(), key: Constant.ShuffleVector) u32 {
7683 return @truncate(std.hash.Wyhash.hash(
7684 comptime std.hash.uint32(@intFromEnum(Constant.Tag.shufflevector)),
7685 std.mem.asBytes(&key),
7686 ));
7687 }
7688 pub fn eql(ctx: @This(), lhs_key: Constant.ShuffleVector, _: void, rhs_index: usize) bool {
7689 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .shufflevector) return false;
7690 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
7691 const rhs_extra = ctx.builder.constantExtraData(Constant.ShuffleVector, rhs_data);
7692 return std.meta.eql(lhs_key, rhs_extra);
7693 }
7694 };
7695 const data = Constant.ShuffleVector{ .lhs = lhs, .rhs = rhs, .mask = mask };
7696 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
7697 if (!gop.found_existing) {
7698 gop.key_ptr.* = {};
7699 gop.value_ptr.* = {};
7700 self.constant_items.appendAssumeCapacity(.{
7701 .tag = .shufflevector,
7702 .data = self.addConstantExtraAssumeCapacity(data),
7703 });
7704 if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
7705 lhs.toLlvm(self).constShuffleVector(rhs.toLlvm(self), mask.toLlvm(self)),
7706 );
7707 }
7708 return @enumFromInt(gop.index);
7709}
7710
7711fn binConstAssumeCapacity(
7712 self: *Builder,
7713 tag: Constant.Tag,
7714 lhs: Constant,
7715 rhs: Constant,
7716) Constant {
7717 switch (tag) {
7718 .add,
7719 .@"add nsw",
7720 .@"add nuw",
7721 .sub,
7722 .@"sub nsw",
7723 .@"sub nuw",
7724 .mul,
7725 .@"mul nsw",
7726 .@"mul nuw",
7727 .shl,
7728 .lshr,
7729 .ashr,
7730 .@"and",
7731 .@"or",
7732 .xor,
7733 => {},
7734 else => unreachable,
7735 }
7736 const Key = struct { tag: Constant.Tag, bin: Constant.Binary };
7737 const Adapter = struct {
7738 builder: *const Builder,
7739 pub fn hash(_: @This(), key: Key) u32 {
7740 return @truncate(std.hash.Wyhash.hash(
7741 std.hash.uint32(@intFromEnum(key.tag)),
7742 std.mem.asBytes(&key.bin),
7743 ));
7744 }
7745 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
7746 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
7747 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
7748 const rhs_extra = ctx.builder.constantExtraData(Constant.Binary, rhs_data);
7749 return std.meta.eql(lhs_key.bin, rhs_extra);
7750 }
7751 };
7752 const data = Key{ .tag = tag, .bin = .{ .lhs = lhs, .rhs = rhs } };
7753 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
7754 if (!gop.found_existing) {
7755 gop.key_ptr.* = {};
7756 gop.value_ptr.* = {};
7757 self.constant_items.appendAssumeCapacity(.{
7758 .tag = tag,
7759 .data = self.addConstantExtraAssumeCapacity(data.bin),
7760 });
7761 if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(switch (tag) {
7762 .add => &llvm.Value.constAdd,
7763 .sub => &llvm.Value.constSub,
7764 .mul => &llvm.Value.constMul,
7765 .shl => &llvm.Value.constShl,
7766 .lshr => &llvm.Value.constLShr,
7767 .ashr => &llvm.Value.constAShr,
7768 .@"and" => &llvm.Value.constAnd,
7769 .@"or" => &llvm.Value.constOr,
7770 .xor => &llvm.Value.constXor,
7771 else => unreachable,
7772 }(lhs.toLlvm(self), rhs.toLlvm(self)));
7773 }
7774 return @enumFromInt(gop.index);
7775}
7776
7777fn ensureUnusedConstantCapacity(
7778 self: *Builder,
7779 count: usize,
7780 comptime Extra: type,
7781 trail_len: usize,
7782) Allocator.Error!void {
7783 try self.constant_map.ensureUnusedCapacity(self.gpa, count);
7784 try self.constant_items.ensureUnusedCapacity(self.gpa, count);
7785 try self.constant_extra.ensureUnusedCapacity(
7786 self.gpa,
7787 count * (@typeInfo(Extra).Struct.fields.len + trail_len),
7788 );
7789 if (self.useLibLlvm()) try self.llvm.constants.ensureUnusedCapacity(self.gpa, count);
7790}
7791
7792fn getOrPutConstantNoExtraAssumeCapacity(
7793 self: *Builder,
7794 item: Constant.Item,
7795) struct { new: bool, constant: Constant } {
7796 const Adapter = struct {
7797 builder: *const Builder,
7798 pub fn hash(_: @This(), key: Constant.Item) u32 {
7799 return @truncate(std.hash.Wyhash.hash(
7800 std.hash.uint32(@intFromEnum(key.tag)),
7801 std.mem.asBytes(&key.data),
7802 ));
7803 }
7804 pub fn eql(ctx: @This(), lhs_key: Constant.Item, _: void, rhs_index: usize) bool {
7805 return std.meta.eql(lhs_key, ctx.builder.constant_items.get(rhs_index));
7806 }
7807 };
7808 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(item, Adapter{ .builder = self });
7809 if (!gop.found_existing) {
7810 gop.key_ptr.* = {};
7811 gop.value_ptr.* = {};
7812 self.constant_items.appendAssumeCapacity(item);
7813 }
7814 return .{ .new = !gop.found_existing, .constant = @enumFromInt(gop.index) };
7815}
7816
7817fn getOrPutConstantAggregateAssumeCapacity(
7818 self: *Builder,
7819 tag: Constant.Tag,
7820 ty: Type,
7821 vals: []const Constant,
7822) struct { new: bool, constant: Constant } {
7823 switch (tag) {
7824 .structure, .packed_structure, .array, .vector => {},
7825 else => unreachable,
7826 }
7827 const Key = struct { tag: Constant.Tag, type: Type, vals: []const Constant };
7828 const Adapter = struct {
7829 builder: *const Builder,
7830 pub fn hash(_: @This(), key: Key) u32 {
7831 var hasher = std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(key.tag)));
7832 hasher.update(std.mem.asBytes(&key.type));
7833 hasher.update(std.mem.sliceAsBytes(key.vals));
7834 return @truncate(hasher.final());
7835 }
7836 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
7837 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
7838 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
7839 var rhs_extra = ctx.builder.constantExtraDataTrail(Constant.Aggregate, rhs_data);
7840 if (lhs_key.type != rhs_extra.data.type) return false;
7841 const rhs_vals = rhs_extra.trail.next(@intCast(lhs_key.vals.len), Constant, ctx.builder);
7842 return std.mem.eql(Constant, lhs_key.vals, rhs_vals);
7843 }
7844 };
7845 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(
7846 Key{ .tag = tag, .type = ty, .vals = vals },
7847 Adapter{ .builder = self },
7848 );
7849 if (!gop.found_existing) {
7850 gop.key_ptr.* = {};
7851 gop.value_ptr.* = {};
7852 self.constant_items.appendAssumeCapacity(.{
7853 .tag = tag,
7854 .data = self.addConstantExtraAssumeCapacity(Constant.Aggregate{ .type = ty }),
7855 });
7856 self.constant_extra.appendSliceAssumeCapacity(@ptrCast(vals));
7857 }
7858 return .{ .new = !gop.found_existing, .constant = @enumFromInt(gop.index) };
7859}
7860
7861fn addConstantExtraAssumeCapacity(self: *Builder, extra: anytype) Constant.Item.ExtraIndex {
7862 const result: Constant.Item.ExtraIndex = @intCast(self.constant_extra.items.len);
7863 inline for (@typeInfo(@TypeOf(extra)).Struct.fields) |field| {
7864 const value = @field(extra, field.name);
7865 self.constant_extra.appendAssumeCapacity(switch (field.type) {
7866 u32 => value,
7867 Type, Constant, Function.Index, Function.Block.Index => @intFromEnum(value),
7868 Constant.GetElementPtr.Info => @bitCast(value),
7869 else => @compileError("bad field type: " ++ @typeName(field.type)),
7870 });
7871 }
7872 return result;
7873}
7874
7875const ConstantExtraDataTrail = struct {
7876 index: Constant.Item.ExtraIndex,
7877
7878 fn nextMut(self: *ConstantExtraDataTrail, len: u32, comptime Item: type, builder: *Builder) []Item {
7879 const items: []Item = @ptrCast(builder.constant_extra.items[self.index..][0..len]);
7880 self.index += @intCast(len);
7881 return items;
7882 }
7883
7884 fn next(
7885 self: *ConstantExtraDataTrail,
7886 len: u32,
7887 comptime Item: type,
7888 builder: *const Builder,
7889 ) []const Item {
7890 const items: []const Item = @ptrCast(builder.constant_extra.items[self.index..][0..len]);
7891 self.index += @intCast(len);
7892 return items;
7893 }
7894};
7895
7896fn constantExtraDataTrail(
7897 self: *const Builder,
7898 comptime T: type,
7899 index: Constant.Item.ExtraIndex,
7900) struct { data: T, trail: ConstantExtraDataTrail } {
7901 var result: T = undefined;
7902 const fields = @typeInfo(T).Struct.fields;
7903 inline for (fields, self.constant_extra.items[index..][0..fields.len]) |field, value|
7904 @field(result, field.name) = switch (field.type) {
7905 u32 => value,
7906 Type, Constant, Function.Index, Function.Block.Index => @enumFromInt(value),
7907 Constant.GetElementPtr.Info => @bitCast(value),
7908 else => @compileError("bad field type: " ++ @typeName(field.type)),
7909 };
7910 return .{
7911 .data = result,
7912 .trail = .{ .index = index + @as(Constant.Item.ExtraIndex, @intCast(fields.len)) },
7913 };
7914}
7915
7916fn constantExtraData(self: *const Builder, comptime T: type, index: Constant.Item.ExtraIndex) T {
7917 return self.constantExtraDataTrail(T, index).data;
7918}
7919
7920const assert = std.debug.assert;
7921const build_options = @import("build_options");
7922const builtin = @import("builtin");
7923const llvm = if (build_options.have_llvm)
7924 @import("bindings.zig")
7925else
7926 @compileError("LLVM unavailable");
7927const log = std.log.scoped(.llvm);
7928const std = @import("std");
7929
7930const Allocator = std.mem.Allocator;
7931const Builder = @This();
src/codegen/llvm/bindings.zig+186-92
......@@ -40,21 +40,42 @@ pub const Context = opaque {
4040 pub const halfType = LLVMHalfTypeInContext;
4141 extern fn LLVMHalfTypeInContext(C: *Context) *Type;
4242
43 pub const bfloatType = LLVMBFloatTypeInContext;
44 extern fn LLVMBFloatTypeInContext(C: *Context) *Type;
45
4346 pub const floatType = LLVMFloatTypeInContext;
4447 extern fn LLVMFloatTypeInContext(C: *Context) *Type;
4548
4649 pub const doubleType = LLVMDoubleTypeInContext;
4750 extern fn LLVMDoubleTypeInContext(C: *Context) *Type;
4851
49 pub const x86FP80Type = LLVMX86FP80TypeInContext;
50 extern fn LLVMX86FP80TypeInContext(C: *Context) *Type;
51
5252 pub const fp128Type = LLVMFP128TypeInContext;
5353 extern fn LLVMFP128TypeInContext(C: *Context) *Type;
5454
55 pub const x86_fp80Type = LLVMX86FP80TypeInContext;
56 extern fn LLVMX86FP80TypeInContext(C: *Context) *Type;
57
58 pub const ppc_fp128Type = LLVMPPCFP128TypeInContext;
59 extern fn LLVMPPCFP128TypeInContext(C: *Context) *Type;
60
61 pub const x86_amxType = LLVMX86AMXTypeInContext;
62 extern fn LLVMX86AMXTypeInContext(C: *Context) *Type;
63
64 pub const x86_mmxType = LLVMX86MMXTypeInContext;
65 extern fn LLVMX86MMXTypeInContext(C: *Context) *Type;
66
5567 pub const voidType = LLVMVoidTypeInContext;
5668 extern fn LLVMVoidTypeInContext(C: *Context) *Type;
5769
70 pub const labelType = LLVMLabelTypeInContext;
71 extern fn LLVMLabelTypeInContext(C: *Context) *Type;
72
73 pub const tokenType = LLVMTokenTypeInContext;
74 extern fn LLVMTokenTypeInContext(C: *Context) *Type;
75
76 pub const metadataType = LLVMMetadataTypeInContext;
77 extern fn LLVMMetadataTypeInContext(C: *Context) *Type;
78
5879 pub const structType = LLVMStructTypeInContext;
5980 extern fn LLVMStructTypeInContext(
6081 C: *Context,
......@@ -114,9 +135,6 @@ pub const Value = opaque {
114135 pub const getNextInstruction = LLVMGetNextInstruction;
115136 extern fn LLVMGetNextInstruction(Inst: *Value) ?*Value;
116137
117 pub const typeOf = LLVMTypeOf;
118 extern fn LLVMTypeOf(Val: *Value) *Type;
119
120138 pub const setGlobalConstant = LLVMSetGlobalConstant;
121139 extern fn LLVMSetGlobalConstant(GlobalVar: *Value, IsConstant: Bool) void;
122140
......@@ -147,36 +165,135 @@ pub const Value = opaque {
147165 pub const setAliasee = LLVMAliasSetAliasee;
148166 extern fn LLVMAliasSetAliasee(Alias: *Value, Aliasee: *Value) void;
149167
150 pub const constBitCast = LLVMConstBitCast;
151 extern fn LLVMConstBitCast(ConstantVal: *Value, ToType: *Type) *Value;
168 pub const constZExtOrBitCast = LLVMConstZExtOrBitCast;
169 extern fn LLVMConstZExtOrBitCast(ConstantVal: *Value, ToType: *Type) *Value;
152170
153 pub const constIntToPtr = LLVMConstIntToPtr;
154 extern fn LLVMConstIntToPtr(ConstantVal: *Value, ToType: *Type) *Value;
171 pub const constNeg = LLVMConstNeg;
172 extern fn LLVMConstNeg(ConstantVal: *Value) *Value;
155173
156 pub const constPtrToInt = LLVMConstPtrToInt;
157 extern fn LLVMConstPtrToInt(ConstantVal: *Value, ToType: *Type) *Value;
174 pub const constNSWNeg = LLVMConstNSWNeg;
175 extern fn LLVMConstNSWNeg(ConstantVal: *Value) *Value;
158176
159 pub const constShl = LLVMConstShl;
160 extern fn LLVMConstShl(LHSConstant: *Value, RHSConstant: *Value) *Value;
177 pub const constNUWNeg = LLVMConstNUWNeg;
178 extern fn LLVMConstNUWNeg(ConstantVal: *Value) *Value;
179
180 pub const constNot = LLVMConstNot;
181 extern fn LLVMConstNot(ConstantVal: *Value) *Value;
182
183 pub const constAdd = LLVMConstAdd;
184 extern fn LLVMConstAdd(LHSConstant: *Value, RHSConstant: *Value) *Value;
185
186 pub const constNSWAdd = LLVMConstNSWAdd;
187 extern fn LLVMConstNSWAdd(LHSConstant: *Value, RHSConstant: *Value) *Value;
188
189 pub const constNUWAdd = LLVMConstNUWAdd;
190 extern fn LLVMConstNUWAdd(LHSConstant: *Value, RHSConstant: *Value) *Value;
191
192 pub const constSub = LLVMConstSub;
193 extern fn LLVMConstSub(LHSConstant: *Value, RHSConstant: *Value) *Value;
194
195 pub const constNSWSub = LLVMConstNSWSub;
196 extern fn LLVMConstNSWSub(LHSConstant: *Value, RHSConstant: *Value) *Value;
197
198 pub const constNUWSub = LLVMConstNUWSub;
199 extern fn LLVMConstNUWSub(LHSConstant: *Value, RHSConstant: *Value) *Value;
200
201 pub const constMul = LLVMConstMul;
202 extern fn LLVMConstMul(LHSConstant: *Value, RHSConstant: *Value) *Value;
203
204 pub const constNSWMul = LLVMConstNSWMul;
205 extern fn LLVMConstNSWMul(LHSConstant: *Value, RHSConstant: *Value) *Value;
206
207 pub const constNUWMul = LLVMConstNUWMul;
208 extern fn LLVMConstNUWMul(LHSConstant: *Value, RHSConstant: *Value) *Value;
209
210 pub const constAnd = LLVMConstAnd;
211 extern fn LLVMConstAnd(LHSConstant: *Value, RHSConstant: *Value) *Value;
161212
162213 pub const constOr = LLVMConstOr;
163214 extern fn LLVMConstOr(LHSConstant: *Value, RHSConstant: *Value) *Value;
164215
216 pub const constXor = LLVMConstXor;
217 extern fn LLVMConstXor(LHSConstant: *Value, RHSConstant: *Value) *Value;
218
219 pub const constShl = LLVMConstShl;
220 extern fn LLVMConstShl(LHSConstant: *Value, RHSConstant: *Value) *Value;
221
222 pub const constLShr = LLVMConstLShr;
223 extern fn LLVMConstLShr(LHSConstant: *Value, RHSConstant: *Value) *Value;
224
225 pub const constAShr = LLVMConstAShr;
226 extern fn LLVMConstAShr(LHSConstant: *Value, RHSConstant: *Value) *Value;
227
228 pub const constTrunc = LLVMConstTrunc;
229 extern fn LLVMConstTrunc(ConstantVal: *Value, ToType: *Type) *Value;
230
231 pub const constSExt = LLVMConstSExt;
232 extern fn LLVMConstSExt(ConstantVal: *Value, ToType: *Type) *Value;
233
165234 pub const constZExt = LLVMConstZExt;
166235 extern fn LLVMConstZExt(ConstantVal: *Value, ToType: *Type) *Value;
167236
168 pub const constZExtOrBitCast = LLVMConstZExtOrBitCast;
169 extern fn LLVMConstZExtOrBitCast(ConstantVal: *Value, ToType: *Type) *Value;
237 pub const constFPTrunc = LLVMConstFPTrunc;
238 extern fn LLVMConstFPTrunc(ConstantVal: *Value, ToType: *Type) *Value;
170239
171 pub const constNot = LLVMConstNot;
172 extern fn LLVMConstNot(ConstantVal: *Value) *Value;
240 pub const constFPExt = LLVMConstFPExt;
241 extern fn LLVMConstFPExt(ConstantVal: *Value, ToType: *Type) *Value;
173242
174 pub const constAdd = LLVMConstAdd;
175 extern fn LLVMConstAdd(LHSConstant: *Value, RHSConstant: *Value) *Value;
243 pub const constUIToFP = LLVMConstUIToFP;
244 extern fn LLVMConstUIToFP(ConstantVal: *Value, ToType: *Type) *Value;
245
246 pub const constSIToFP = LLVMConstSIToFP;
247 extern fn LLVMConstSIToFP(ConstantVal: *Value, ToType: *Type) *Value;
248
249 pub const constFPToUI = LLVMConstFPToUI;
250 extern fn LLVMConstFPToUI(ConstantVal: *Value, ToType: *Type) *Value;
251
252 pub const constFPToSI = LLVMConstFPToSI;
253 extern fn LLVMConstFPToSI(ConstantVal: *Value, ToType: *Type) *Value;
254
255 pub const constPtrToInt = LLVMConstPtrToInt;
256 extern fn LLVMConstPtrToInt(ConstantVal: *Value, ToType: *Type) *Value;
257
258 pub const constIntToPtr = LLVMConstIntToPtr;
259 extern fn LLVMConstIntToPtr(ConstantVal: *Value, ToType: *Type) *Value;
260
261 pub const constBitCast = LLVMConstBitCast;
262 extern fn LLVMConstBitCast(ConstantVal: *Value, ToType: *Type) *Value;
176263
177264 pub const constAddrSpaceCast = LLVMConstAddrSpaceCast;
178265 extern fn LLVMConstAddrSpaceCast(ConstantVal: *Value, ToType: *Type) *Value;
179266
267 pub const constSelect = LLVMConstSelect;
268 extern fn LLVMConstSelect(
269 ConstantCondition: *Value,
270 ConstantIfTrue: *Value,
271 ConstantIfFalse: *Value,
272 ) *Value;
273
274 pub const constExtractElement = LLVMConstExtractElement;
275 extern fn LLVMConstExtractElement(VectorConstant: *Value, IndexConstant: *Value) *Value;
276
277 pub const constInsertElement = LLVMConstInsertElement;
278 extern fn LLVMConstInsertElement(
279 VectorConstant: *Value,
280 ElementValueConstant: *Value,
281 IndexConstant: *Value,
282 ) *Value;
283
284 pub const constShuffleVector = LLVMConstShuffleVector;
285 extern fn LLVMConstShuffleVector(
286 VectorAConstant: *Value,
287 VectorBConstant: *Value,
288 MaskConstant: *Value,
289 ) *Value;
290
291 pub const isConstant = LLVMIsConstant;
292 extern fn LLVMIsConstant(Val: *Value) Bool;
293
294 pub const blockAddress = LLVMBlockAddress;
295 extern fn LLVMBlockAddress(F: *Value, BB: *BasicBlock) *Value;
296
180297 pub const setWeak = LLVMSetWeak;
181298 extern fn LLVMSetWeak(CmpXchgInst: *Value, IsWeak: Bool) void;
182299
......@@ -186,6 +303,9 @@ pub const Value = opaque {
186303 pub const setVolatile = LLVMSetVolatile;
187304 extern fn LLVMSetVolatile(MemoryAccessInst: *Value, IsVolatile: Bool) void;
188305
306 pub const setAtomicSingleThread = LLVMSetAtomicSingleThread;
307 extern fn LLVMSetAtomicSingleThread(AtomicInst: *Value, SingleThread: Bool) void;
308
189309 pub const setAlignment = LLVMSetAlignment;
190310 extern fn LLVMSetAlignment(V: *Value, Bytes: c_uint) void;
191311
......@@ -231,17 +351,9 @@ pub const Value = opaque {
231351 pub const addCase = LLVMAddCase;
232352 extern fn LLVMAddCase(Switch: *Value, OnVal: *Value, Dest: *BasicBlock) void;
233353
234 pub inline fn isPoison(Val: *Value) bool {
235 return LLVMIsPoison(Val).toBool();
236 }
237 extern fn LLVMIsPoison(Val: *Value) Bool;
238
239354 pub const replaceAllUsesWith = LLVMReplaceAllUsesWith;
240355 extern fn LLVMReplaceAllUsesWith(OldVal: *Value, NewVal: *Value) void;
241356
242 pub const globalGetValueType = LLVMGlobalGetValueType;
243 extern fn LLVMGlobalGetValueType(Global: *Value) *Type;
244
245357 pub const getLinkage = LLVMGetLinkage;
246358 extern fn LLVMGetLinkage(Global: *Value) Linkage;
247359
......@@ -259,6 +371,9 @@ pub const Value = opaque {
259371
260372 pub const attachMetaData = ZigLLVMAttachMetaData;
261373 extern fn ZigLLVMAttachMetaData(GlobalVar: *Value, DIG: *DIGlobalVariableExpression) void;
374
375 pub const dump = LLVMDumpValue;
376 extern fn LLVMDumpValue(Val: *Value) void;
262377};
263378
264379pub const Type = opaque {
......@@ -290,12 +405,18 @@ pub const Type = opaque {
290405 pub const getUndef = LLVMGetUndef;
291406 extern fn LLVMGetUndef(Ty: *Type) *Value;
292407
408 pub const getPoison = LLVMGetPoison;
409 extern fn LLVMGetPoison(Ty: *Type) *Value;
410
293411 pub const arrayType = LLVMArrayType;
294412 extern fn LLVMArrayType(ElementType: *Type, ElementCount: c_uint) *Type;
295413
296414 pub const vectorType = LLVMVectorType;
297415 extern fn LLVMVectorType(ElementType: *Type, ElementCount: c_uint) *Type;
298416
417 pub const scalableVectorType = LLVMScalableVectorType;
418 extern fn LLVMScalableVectorType(ElementType: *Type, ElementCount: c_uint) *Type;
419
299420 pub const structSetBody = LLVMStructSetBody;
300421 extern fn LLVMStructSetBody(
301422 StructTy: *Type,
......@@ -304,23 +425,13 @@ pub const Type = opaque {
304425 Packed: Bool,
305426 ) void;
306427
307 pub const structGetTypeAtIndex = LLVMStructGetTypeAtIndex;
308 extern fn LLVMStructGetTypeAtIndex(StructTy: *Type, i: c_uint) *Type;
309
310 pub const getTypeKind = LLVMGetTypeKind;
311 extern fn LLVMGetTypeKind(Ty: *Type) TypeKind;
312
313 pub const getElementType = LLVMGetElementType;
314 extern fn LLVMGetElementType(Ty: *Type) *Type;
315
316 pub const countStructElementTypes = LLVMCountStructElementTypes;
317 extern fn LLVMCountStructElementTypes(StructTy: *Type) c_uint;
318
319 pub const isOpaqueStruct = LLVMIsOpaqueStruct;
320 extern fn LLVMIsOpaqueStruct(StructTy: *Type) Bool;
321
322 pub const isSized = LLVMTypeIsSized;
323 extern fn LLVMTypeIsSized(Ty: *Type) Bool;
428 pub const constGEP = LLVMConstGEP2;
429 extern fn LLVMConstGEP2(
430 Ty: *Type,
431 ConstantVal: *Value,
432 ConstantIndices: [*]const *Value,
433 NumIndices: c_uint,
434 ) *Value;
324435
325436 pub const constInBoundsGEP = LLVMConstInBoundsGEP2;
326437 extern fn LLVMConstInBoundsGEP2(
......@@ -329,6 +440,9 @@ pub const Type = opaque {
329440 ConstantIndices: [*]const *Value,
330441 NumIndices: c_uint,
331442 ) *Value;
443
444 pub const dump = LLVMDumpType;
445 extern fn LLVMDumpType(Ty: *Type) void;
332446};
333447
334448pub const Module = opaque {
......@@ -439,15 +553,18 @@ pub const VerifierFailureAction = enum(c_int) {
439553 ReturnStatus,
440554};
441555
442pub const constNeg = LLVMConstNeg;
443extern fn LLVMConstNeg(ConstantVal: *Value) *Value;
444
445556pub const constVector = LLVMConstVector;
446557extern fn LLVMConstVector(
447558 ScalarConstantVals: [*]*Value,
448559 Size: c_uint,
449560) *Value;
450561
562pub const constICmp = LLVMConstICmp;
563extern fn LLVMConstICmp(Predicate: IntPredicate, LHSConstant: *Value, RHSConstant: *Value) *Value;
564
565pub const constFCmp = LLVMConstFCmp;
566extern fn LLVMConstFCmp(Predicate: RealPredicate, LHSConstant: *Value, RHSConstant: *Value) *Value;
567
451568pub const getEnumAttributeKindForName = LLVMGetEnumAttributeKindForName;
452569extern fn LLVMGetEnumAttributeKindForName(Name: [*]const u8, SLen: usize) c_uint;
453570
......@@ -484,7 +601,7 @@ pub const Builder = opaque {
484601 extern fn LLVMPositionBuilder(
485602 Builder: *Builder,
486603 Block: *BasicBlock,
487 Instr: *Value,
604 Instr: ?*Value,
488605 ) void;
489606
490607 pub const positionBuilderAtEnd = LLVMPositionBuilderAtEnd;
......@@ -678,6 +795,16 @@ pub const Builder = opaque {
678795 pub const buildBitCast = LLVMBuildBitCast;
679796 extern fn LLVMBuildBitCast(*Builder, Val: *Value, DestTy: *Type, Name: [*:0]const u8) *Value;
680797
798 pub const buildGEP = LLVMBuildGEP2;
799 extern fn LLVMBuildGEP2(
800 B: *Builder,
801 Ty: *Type,
802 Pointer: *Value,
803 Indices: [*]const *Value,
804 NumIndices: c_uint,
805 Name: [*:0]const u8,
806 ) *Value;
807
681808 pub const buildInBoundsGEP = LLVMBuildInBoundsGEP2;
682809 extern fn LLVMBuildInBoundsGEP2(
683810 B: *Builder,
......@@ -731,14 +858,6 @@ pub const Builder = opaque {
731858 Name: [*:0]const u8,
732859 ) *Value;
733860
734 pub const buildVectorSplat = LLVMBuildVectorSplat;
735 extern fn LLVMBuildVectorSplat(
736 *Builder,
737 ElementCount: c_uint,
738 EltVal: *Value,
739 Name: [*:0]const u8,
740 ) *Value;
741
742861 pub const buildPtrToInt = LLVMBuildPtrToInt;
743862 extern fn LLVMBuildPtrToInt(
744863 *Builder,
......@@ -755,15 +874,6 @@ pub const Builder = opaque {
755874 Name: [*:0]const u8,
756875 ) *Value;
757876
758 pub const buildStructGEP = LLVMBuildStructGEP2;
759 extern fn LLVMBuildStructGEP2(
760 B: *Builder,
761 Ty: *Type,
762 Pointer: *Value,
763 Idx: c_uint,
764 Name: [*:0]const u8,
765 ) *Value;
766
767877 pub const buildTrunc = LLVMBuildTrunc;
768878 extern fn LLVMBuildTrunc(
769879 *Builder,
......@@ -1019,9 +1129,6 @@ pub const RealPredicate = enum(c_uint) {
10191129pub const BasicBlock = opaque {
10201130 pub const deleteBasicBlock = LLVMDeleteBasicBlock;
10211131 extern fn LLVMDeleteBasicBlock(BB: *BasicBlock) void;
1022
1023 pub const getFirstInstruction = LLVMGetFirstInstruction;
1024 extern fn LLVMGetFirstInstruction(BB: *BasicBlock) ?*Value;
10251132};
10261133
10271134pub const TargetMachine = opaque {
......@@ -1071,6 +1178,9 @@ pub const TargetData = opaque {
10711178
10721179 pub const abiSizeOfType = LLVMABISizeOfType;
10731180 extern fn LLVMABISizeOfType(TD: *TargetData, Ty: *Type) c_ulonglong;
1181
1182 pub const stringRep = LLVMCopyStringRepOfTargetData;
1183 extern fn LLVMCopyStringRepOfTargetData(TD: *TargetData) [*:0]const u8;
10741184};
10751185
10761186pub const CodeModel = enum(c_int) {
......@@ -1440,29 +1550,6 @@ pub const AtomicRMWBinOp = enum(c_int) {
14401550 FMin,
14411551};
14421552
1443pub const TypeKind = enum(c_int) {
1444 Void,
1445 Half,
1446 Float,
1447 Double,
1448 X86_FP80,
1449 FP128,
1450 PPC_FP128,
1451 Label,
1452 Integer,
1453 Function,
1454 Struct,
1455 Array,
1456 Pointer,
1457 Vector,
1458 Metadata,
1459 X86_MMX,
1460 Token,
1461 ScalableVector,
1462 BFloat,
1463 X86_AMX,
1464};
1465
14661553pub const CallConv = enum(c_uint) {
14671554 C = 0,
14681555 Fast = 8,
......@@ -1588,6 +1675,13 @@ pub const address_space = struct {
15881675 pub const constant_buffer_14: c_uint = 22;
15891676 pub const constant_buffer_15: c_uint = 23;
15901677 };
1678
1679 // See llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypetilities.h
1680 pub const wasm = struct {
1681 pub const variable: c_uint = 1;
1682 pub const externref: c_uint = 10;
1683 pub const funcref: c_uint = 20;
1684 };
15911685};
15921686
15931687pub const DIEnumerator = opaque {};
src/link.zig+1
......@@ -110,6 +110,7 @@ pub const Options = struct {
110110 /// other objects.
111111 /// Otherwise (depending on `use_lld`) this link code directly outputs and updates the final binary.
112112 use_llvm: bool,
113 use_lib_llvm: bool,
113114 link_libc: bool,
114115 link_libcpp: bool,
115116 link_libunwind: bool,
src/main.zig+8
......@@ -439,6 +439,8 @@ const usage_build_generic =
439439 \\ -fno-unwind-tables Never produce unwind table entries
440440 \\ -fLLVM Force using LLVM as the codegen backend
441441 \\ -fno-LLVM Prevent using LLVM as the codegen backend
442 \\ -flibLLVM Force using the LLVM API in the codegen backend
443 \\ -fno-libLLVM Prevent using the LLVM API in the codegen backend
442444 \\ -fClang Force using Clang as the C/C++ compilation backend
443445 \\ -fno-Clang Prevent using Clang as the C/C++ compilation backend
444446 \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error
......@@ -821,6 +823,7 @@ fn buildOutputType(
821823 var stack_size_override: ?u64 = null;
822824 var image_base_override: ?u64 = null;
823825 var use_llvm: ?bool = null;
826 var use_lib_llvm: ?bool = null;
824827 var use_lld: ?bool = null;
825828 var use_clang: ?bool = null;
826829 var link_eh_frame_hdr = false;
......@@ -1261,6 +1264,10 @@ fn buildOutputType(
12611264 use_llvm = true;
12621265 } else if (mem.eql(u8, arg, "-fno-LLVM")) {
12631266 use_llvm = false;
1267 } else if (mem.eql(u8, arg, "-flibLLVM")) {
1268 use_lib_llvm = true;
1269 } else if (mem.eql(u8, arg, "-fno-libLLVM")) {
1270 use_lib_llvm = false;
12641271 } else if (mem.eql(u8, arg, "-fLLD")) {
12651272 use_lld = true;
12661273 } else if (mem.eql(u8, arg, "-fno-LLD")) {
......@@ -3119,6 +3126,7 @@ fn buildOutputType(
31193126 .want_tsan = want_tsan,
31203127 .want_compiler_rt = want_compiler_rt,
31213128 .use_llvm = use_llvm,
3129 .use_lib_llvm = use_lib_llvm,
31223130 .use_lld = use_lld,
31233131 .use_clang = use_clang,
31243132 .hash_style = hash_style,
src/zig_llvm.cpp-4
......@@ -560,10 +560,6 @@ LLVMValueRef ZigLLVMBuildUShlSat(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRe
560560 return wrap(call_inst);
561561}
562562
563LLVMValueRef LLVMBuildVectorSplat(LLVMBuilderRef B, unsigned elem_count, LLVMValueRef V, const char *Name) {
564 return wrap(unwrap(B)->CreateVectorSplat(elem_count, unwrap(V), Name));
565}
566
567563void ZigLLVMFnSetSubprogram(LLVMValueRef fn, ZigLLVMDISubprogram *subprogram) {
568564 assert( isa<Function>(unwrap(fn)) );
569565 Function *unwrapped_function = reinterpret_cast<Function*>(unwrap(fn));