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 {...@@ -1357,8 +1357,6 @@ pub const Target = struct {
1357 }1357 }
1358 };1358 };
13591359
1360 pub const stack_align = 16;
1361
1362 pub fn zigTriple(self: Target, allocator: mem.Allocator) ![]u8 {1360 pub fn zigTriple(self: Target, allocator: mem.Allocator) ![]u8 {
1363 return std.zig.CrossTarget.fromTarget(self).zigTriple(allocator);1361 return std.zig.CrossTarget.fromTarget(self).zigTriple(allocator);
1364 }1362 }
...@@ -1833,7 +1831,7 @@ pub const Target = struct {...@@ -1833,7 +1831,7 @@ pub const Target = struct {
1833 };1831 };
1834 }1832 }
18351833
1836 pub fn ptrBitWidth(target: std.Target) u16 {1834 pub fn ptrBitWidth(target: Target) u16 {
1837 switch (target.abi) {1835 switch (target.abi) {
1838 .gnux32, .muslx32, .gnuabin32, .gnuilp32 => return 32,1836 .gnux32, .muslx32, .gnuabin32, .gnuilp32 => return 32,
1839 .gnuabi64 => return 64,1837 .gnuabi64 => return 64,
...@@ -1910,6 +1908,43 @@ pub const Target = struct {...@@ -1910,6 +1908,43 @@ pub const Target = struct {
1910 }1908 }
1911 }1909 }
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
1913 /// Default signedness of `char` for the native C compiler for this target1948 /// Default signedness of `char` for the native C compiler for this target
1914 /// Note that char signedness is implementation-defined and many compilers provide1949 /// Note that char signedness is implementation-defined and many compilers provide
1915 /// an option to override the default signedness e.g. GCC's -funsigned-char / -fsigned-char1950 /// an option to override the default signedness e.g. GCC's -funsigned-char / -fsigned-char
...@@ -2428,7 +2463,7 @@ pub const Target = struct {...@@ -2428,7 +2463,7 @@ pub const Target = struct {
2428 else => {},2463 else => {},
2429 },2464 },
2430 .avr => switch (c_type) {2465 .avr => switch (c_type) {
2431 .int, .uint, .long, .ulong, .float, .longdouble => return 1,2466 .char, .int, .uint, .long, .ulong, .float, .longdouble => return 1,
2432 .short, .ushort => return 2,2467 .short, .ushort => return 2,
2433 .double => return 4,2468 .double => return 4,
2434 .longlong, .ulonglong => return 8,2469 .longlong, .ulonglong => return 8,
lib/test_runner.zig+1-1
...@@ -136,7 +136,7 @@ fn mainTerminal() void {...@@ -136,7 +136,7 @@ fn mainTerminal() void {
136 const have_tty = progress.terminal != null and136 const have_tty = progress.terminal != null and
137 (progress.supports_ansi_escape_codes or progress.is_windows_terminal);137 (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;
140 // TODO this is on the next line (using `undefined` above) because otherwise zig incorrectly140 // TODO this is on the next line (using `undefined` above) because otherwise zig incorrectly
141 // ignores the alignment of the slice.141 // ignores the alignment of the slice.
142 async_frame_buffer = &[_]u8{};142 async_frame_buffer = &[_]u8{};
src/Compilation.zig+5-1
...@@ -538,6 +538,7 @@ pub const InitOptions = struct {...@@ -538,6 +538,7 @@ pub const InitOptions = struct {
538 want_lto: ?bool = null,538 want_lto: ?bool = null,
539 want_unwind_tables: ?bool = null,539 want_unwind_tables: ?bool = null,
540 use_llvm: ?bool = null,540 use_llvm: ?bool = null,
541 use_lib_llvm: ?bool = null,
541 use_lld: ?bool = null,542 use_lld: ?bool = null,
542 use_clang: ?bool = null,543 use_clang: ?bool = null,
543 single_threaded: ?bool = null,544 single_threaded: ?bool = null,
...@@ -753,7 +754,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -753,7 +754,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
753 const root_name = try arena.dupeZ(u8, options.root_name);754 const root_name = try arena.dupeZ(u8, options.root_name);
754755
755 // Make a decision on whether to use LLVM or our own backend.756 // 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: {
757 if (options.use_llvm) |explicit|759 if (options.use_llvm) |explicit|
758 break :blk explicit;760 break :blk explicit;
759761
...@@ -1161,6 +1163,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1161,6 +1163,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1161 hash.add(valgrind);1163 hash.add(valgrind);
1162 hash.add(single_threaded);1164 hash.add(single_threaded);
1163 hash.add(use_llvm);1165 hash.add(use_llvm);
1166 hash.add(use_lib_llvm);
1164 hash.add(dll_export_fns);1167 hash.add(dll_export_fns);
1165 hash.add(options.is_test);1168 hash.add(options.is_test);
1166 hash.add(options.test_evented_io);1169 hash.add(options.test_evented_io);
...@@ -1444,6 +1447,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1444,6 +1447,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1444 .optimize_mode = options.optimize_mode,1447 .optimize_mode = options.optimize_mode,
1445 .use_lld = use_lld,1448 .use_lld = use_lld,
1446 .use_llvm = use_llvm,1449 .use_llvm = use_llvm,
1450 .use_lib_llvm = use_lib_llvm,
1447 .link_libc = link_libc,1451 .link_libc = link_libc,
1448 .link_libcpp = link_libcpp,1452 .link_libcpp = link_libcpp,
1449 .link_libunwind = link_libunwind,1453 .link_libunwind = link_libunwind,
src/Module.zig+4-8
...@@ -835,10 +835,6 @@ pub const Decl = struct {...@@ -835,10 +835,6 @@ pub const Decl = struct {
835 assert(decl.has_tv);835 assert(decl.has_tv);
836 return @as(u32, @intCast(decl.alignment.toByteUnitsOptional() orelse decl.ty.abiAlignment(mod)));836 return @as(u32, @intCast(decl.alignment.toByteUnitsOptional() orelse decl.ty.abiAlignment(mod)));
837 }837 }
838
839 pub fn intern(decl: *Decl, mod: *Module) Allocator.Error!void {
840 decl.val = (try decl.val.intern(decl.ty, mod)).toValue();
841 }
842};838};
843839
844/// This state is attached to every Decl when Module emit_h is non-null.840/// 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 {...@@ -4204,7 +4200,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
4204 try wip_captures.finalize();4200 try wip_captures.finalize();
4205 for (comptime_mutable_decls.items) |decl_index| {4201 for (comptime_mutable_decls.items) |decl_index| {
4206 const decl = mod.declPtr(decl_index);4202 const decl = mod.declPtr(decl_index);
4207 try decl.intern(mod);4203 _ = try decl.internValue(mod);
4208 }4204 }
4209 new_decl.analysis = .complete;4205 new_decl.analysis = .complete;
4210 } else |err| switch (err) {4206 } else |err| switch (err) {
...@@ -4315,7 +4311,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -4315,7 +4311,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
4315 try wip_captures.finalize();4311 try wip_captures.finalize();
4316 for (comptime_mutable_decls.items) |ct_decl_index| {4312 for (comptime_mutable_decls.items) |ct_decl_index| {
4317 const ct_decl = mod.declPtr(ct_decl_index);4313 const ct_decl = mod.declPtr(ct_decl_index);
4318 try ct_decl.intern(mod);4314 _ = try ct_decl.internValue(mod);
4319 }4315 }
4320 const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = 0 };4316 const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = 0 };
4321 const section_src: LazySrcLoc = .{ .node_offset_var_decl_section = 0 };4317 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...@@ -5362,7 +5358,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
5362 try wip_captures.finalize();5358 try wip_captures.finalize();
5363 for (comptime_mutable_decls.items) |ct_decl_index| {5359 for (comptime_mutable_decls.items) |ct_decl_index| {
5364 const ct_decl = mod.declPtr(ct_decl_index);5360 const ct_decl = mod.declPtr(ct_decl_index);
5365 try ct_decl.intern(mod);5361 _ = try ct_decl.internValue(mod);
5366 }5362 }
53675363
5368 // Copy the block into place and mark that as the main block.5364 // 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 {...@@ -6369,7 +6365,7 @@ pub fn markDeclAlive(mod: *Module, decl: *Decl) Allocator.Error!void {
6369 if (decl.alive) return;6365 if (decl.alive) return;
6370 decl.alive = true;6366 decl.alive = true;
63716367
6372 try decl.intern(mod);6368 _ = try decl.internValue(mod);
63736369
6374 // This is the first time we are marking this Decl alive. We must6370 // This is the first time we are marking this Decl alive. We must
6375 // therefore recurse into its value and mark any Decl it references6371 // 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...@@ -3899,7 +3899,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
3899 try mod.declareDeclDependency(sema.owner_decl_index, decl_index);3899 try mod.declareDeclDependency(sema.owner_decl_index, decl_index);
39003900
3901 const decl = mod.declPtr(decl_index);3901 const decl = mod.declPtr(decl_index);
3902 if (iac.is_const) try decl.intern(mod);3902 if (iac.is_const) _ = try decl.internValue(mod);
3903 const final_elem_ty = decl.ty;3903 const final_elem_ty = decl.ty;
3904 const final_ptr_ty = try mod.ptrType(.{3904 const final_ptr_ty = try mod.ptrType(.{
3905 .child = final_elem_ty.toIntern(),3905 .child = final_elem_ty.toIntern(),
...@@ -33577,7 +33577,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi...@@ -33577,7 +33577,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
33577 try wip_captures.finalize();33577 try wip_captures.finalize();
33578 for (comptime_mutable_decls.items) |ct_decl_index| {33578 for (comptime_mutable_decls.items) |ct_decl_index| {
33579 const ct_decl = mod.declPtr(ct_decl_index);33579 const ct_decl = mod.declPtr(ct_decl_index);
33580 try ct_decl.intern(mod);33580 _ = try ct_decl.internValue(mod);
33581 }33581 }
33582 } else {33582 } else {
33583 if (fields_bit_sum > std.math.maxInt(u16)) {33583 if (fields_bit_sum > std.math.maxInt(u16)) {
...@@ -34645,7 +34645,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -34645,7 +34645,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
34645 try wip_captures.finalize();34645 try wip_captures.finalize();
34646 for (comptime_mutable_decls.items) |ct_decl_index| {34646 for (comptime_mutable_decls.items) |ct_decl_index| {
34647 const ct_decl = mod.declPtr(ct_decl_index);34647 const ct_decl = mod.declPtr(ct_decl_index);
34648 try ct_decl.intern(mod);34648 _ = try ct_decl.internValue(mod);
34649 }34649 }
3465034650
34651 struct_obj.have_field_inits = true;34651 struct_obj.have_field_inits = true;
...@@ -34744,7 +34744,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -34744,7 +34744,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
34744 try wip_captures.finalize();34744 try wip_captures.finalize();
34745 for (comptime_mutable_decls.items) |ct_decl_index| {34745 for (comptime_mutable_decls.items) |ct_decl_index| {
34746 const ct_decl = mod.declPtr(ct_decl_index);34746 const ct_decl = mod.declPtr(ct_decl_index);
34747 try ct_decl.intern(mod);34747 _ = try ct_decl.internValue(mod);
34748 }34748 }
3474934749
34750 try union_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len);34750 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;...@@ -7,7 +7,11 @@ const math = std.math;
7const native_endian = builtin.cpu.arch.endian();7const native_endian = builtin.cpu.arch.endian();
8const DW = std.dwarf;8const 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");
11const link = @import("../link.zig");15const link = @import("../link.zig");
12const Compilation = @import("../Compilation.zig");16const Compilation = @import("../Compilation.zig");
13const build_options = @import("build_options");17const build_options = @import("build_options");
...@@ -34,7 +38,7 @@ const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev;...@@ -34,7 +38,7 @@ const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev;
3438
35const Error = error{ OutOfMemory, CodegenFail };39const 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 {
38 var llvm_triple = std.ArrayList(u8).init(allocator);42 var llvm_triple = std.ArrayList(u8).init(allocator);
39 defer llvm_triple.deinit();43 defer llvm_triple.deinit();
4044
...@@ -207,7 +211,7 @@ pub fn targetTriple(allocator: Allocator, target: std.Target) ![:0]u8 {...@@ -207,7 +211,7 @@ pub fn targetTriple(allocator: Allocator, target: std.Target) ![:0]u8 {
207 };211 };
208 try llvm_triple.appendSlice(llvm_abi);212 try llvm_triple.appendSlice(llvm_abi);
209213
210 return llvm_triple.toOwnedSliceSentinel(0);214 return llvm_triple.toOwnedSlice();
211}215}
212216
213pub fn targetOs(os_tag: std.Target.Os.Tag) llvm.OSType {217pub fn targetOs(os_tag: std.Target.Os.Tag) llvm.OSType {
...@@ -327,17 +331,363 @@ pub fn supportsTailCall(target: std.Target) bool {...@@ -327,17 +331,363 @@ pub fn supportsTailCall(target: std.Target) bool {
327 }331 }
328}332}
329333
330/// TODO can this be done with simpler logic / different API binding?334const DataLayoutBuilder = struct {
331fn deleteLlvmGlobal(llvm_global: *llvm.Value) void {335 target: std.Target,
332 if (llvm_global.globalGetValueType().getTypeKind() == .Function) {336
333 llvm_global.deleteFunction();337 pub fn format(
334 return;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});
335 }684 }
336 return llvm_global.deleteGlobal();685};
337}
338686
339pub const Object = struct {687pub const Object = struct {
340 gpa: Allocator,688 gpa: Allocator,
689 builder: Builder,
690
341 module: *Module,691 module: *Module,
342 llvm_module: *llvm.Module,692 llvm_module: *llvm.Module,
343 di_builder: ?*llvm.DIBuilder,693 di_builder: ?*llvm.DIBuilder,
...@@ -347,7 +697,6 @@ pub const Object = struct {...@@ -347,7 +697,6 @@ pub const Object = struct {
347 /// - *Module.Decl (Non-Fn) => *DIGlobalVariable697 /// - *Module.Decl (Non-Fn) => *DIGlobalVariable
348 di_map: std.AutoHashMapUnmanaged(*const anyopaque, *llvm.DINode),698 di_map: std.AutoHashMapUnmanaged(*const anyopaque, *llvm.DINode),
349 di_compile_unit: ?*llvm.DICompileUnit,699 di_compile_unit: ?*llvm.DICompileUnit,
350 context: *llvm.Context,
351 target_machine: *llvm.TargetMachine,700 target_machine: *llvm.TargetMachine,
352 target_data: *llvm.TargetData,701 target_data: *llvm.TargetData,
353 target: std.Target,702 target: std.Target,
...@@ -359,9 +708,9 @@ pub const Object = struct {...@@ -359,9 +708,9 @@ pub const Object = struct {
359 /// version of the name and incorrectly get function not found in the llvm module.708 /// version of the name and incorrectly get function not found in the llvm module.
360 /// * it works for functions not all globals.709 /// * it works for functions not all globals.
361 /// Therefore, this table keeps track of the mapping.710 /// 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),
363 /// Serves the same purpose as `decl_map` but only used for the `is_named_enum_value` instruction.712 /// 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),
365 /// Maps Zig types to LLVM types. The table memory is backed by the GPA of714 /// Maps Zig types to LLVM types. The table memory is backed by the GPA of
366 /// the compiler.715 /// the compiler.
367 /// TODO when InternPool garbage collection is implemented, this map needs716 /// TODO when InternPool garbage collection is implemented, this map needs
...@@ -371,16 +720,16 @@ pub const Object = struct {...@@ -371,16 +720,16 @@ pub const Object = struct {
371 /// The LLVM global table which holds the names corresponding to Zig errors.720 /// The LLVM global table which holds the names corresponding to Zig errors.
372 /// Note that the values are not added until flushModule, when all errors in721 /// Note that the values are not added until flushModule, when all errors in
373 /// the compilation are known.722 /// the compilation are known.
374 error_name_table: ?*llvm.Value,723 error_name_table: Builder.Variable.Index,
375 /// This map is usually very close to empty. It tracks only the cases when a724 /// This map is usually very close to empty. It tracks only the cases when a
376 /// second extern Decl could not be emitted with the correct name due to a725 /// second extern Decl could not be emitted with the correct name due to a
377 /// name collision.726 /// name collision.
378 extern_collisions: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void),727 extern_collisions: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void),
379728
380 /// Memoizes a null `?usize` value.729 /// 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
385 /// This is an ArrayHashMap as opposed to a HashMap because in `flushModule` we734 /// This is an ArrayHashMap as opposed to a HashMap because in `flushModule` we
386 /// want to iterate over it while adding entries to it.735 /// want to iterate over it while adding entries to it.
...@@ -394,138 +743,137 @@ pub const Object = struct {...@@ -394,138 +743,137 @@ pub const Object = struct {
394 }743 }
395744
396 pub fn init(gpa: Allocator, options: link.Options) !Object {745 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
405 const llvm_target_triple = try targetTriple(gpa, options.target);746 const llvm_target_triple = try targetTriple(gpa, options.target);
406 defer gpa.free(llvm_target_triple);747 defer gpa.free(llvm_target_triple);
407748
408 var error_message: [*:0]const u8 = undefined;749 var builder = try Builder.init(.{
409 var target: *llvm.Target = undefined;750 .allocator = gpa,
410 if (llvm.Target.getFromTriple(llvm_target_triple.ptr, &target, &error_message).toBool()) {751 .use_lib_llvm = options.use_lib_llvm,
411 defer llvm.disposeMessage(error_message);752 .strip = options.strip,
412753 .name = options.root_name,
413 log.err("LLVM failed to parse '{s}': {s}", .{ llvm_target_triple, error_message });754 .target = options.target,
414 return error.InvalidLlvmTriple;755 .triple = llvm_target_triple,
415 }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);777 // We fully resolve all paths at this point to avoid lack of source line info in stack
418 var opt_di_builder: ?*llvm.DIBuilder = null;778 // traces or lack of debugging information which, if relative paths were used, would
419 errdefer if (opt_di_builder) |di_builder| di_builder.dispose();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) {812 const reloc_mode: llvm.RelocMode = if (options.pic)
424 switch (options.target.ofmt) {813 .PIC
425 .coff => llvm_module.addModuleCodeViewFlag(),814 else if (options.link_mode == .Dynamic)
426 else => llvm_module.addModuleDebugInfoFlag(options.dwarf_format == std.dwarf.Format.@"64"),815 llvm.RelocMode.DynamicNoPIC
427 }816 else
428 const di_builder = llvm_module.createDIBuilder(true);817 .Static;
429 opt_di_builder = di_builder;818
430819 const code_model: llvm.CodeModel = switch (options.machine_code_model) {
431 // Don't use the version string here; LLVM misparses it when it820 .default => .Default,
432 // includes the git revision.821 .tiny => .Tiny,
433 const producer = try std.fmt.allocPrintZ(gpa, "zig {d}.{d}.{d}", .{822 .small => .Small,
434 build_options.semver.major,823 .kernel => .Kernel,
435 build_options.semver.minor,824 .medium => .Medium,
436 build_options.semver.patch,825 .large => .Large,
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
453 };826 };
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)828 // TODO handle float ABI better- it should depend on the ABI portion of std.Target
476 .PIC829 const float_abi: llvm.ABIType = .Default;
477 else if (options.link_mode == .Dynamic)830
478 llvm.RelocMode.DynamicNoPIC831 target_machine = llvm.TargetMachine.create(
479 else832 builder.llvm.target.?,
480 .Static;833 builder.target_triple.toSlice(&builder).?,
481834 if (options.target.cpu.model.llvm_name) |s| s.ptr else null,
482 const code_model: llvm.CodeModel = switch (options.machine_code_model) {835 options.llvm_cpu_features,
483 .default => .Default,836 opt_level,
484 .tiny => .Tiny,837 reloc_mode,
485 .small => .Small,838 code_model,
486 .kernel => .Kernel,839 options.function_sections,
487 .medium => .Medium,840 float_abi,
488 .large => .Large,841 if (target_util.llvmMachineAbi(options.target)) |s| s.ptr else null,
489 };842 );
843 errdefer target_machine.dispose();
490844
491 // TODO handle float ABI better- it should depend on the ABI portion of std.Target845 target_data = target_machine.createTargetDataLayout();
492 const float_abi: llvm.ABIType = .Default;846 errdefer target_data.dispose();
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();
507847
508 const target_data = target_machine.createTargetDataLayout();848 builder.llvm.module.?.setModuleDataLayout(target_data);
509 errdefer target_data.dispose();
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();854 if (options.opt_bisect_limit >= 0) {
514 if (options.pie) llvm_module.setModulePIELevel();855 builder.llvm.context.setOptBisectLimit(std.math.lossyCast(c_int, options.opt_bisect_limit));
515 if (code_model != .Default) llvm_module.setModuleCodeModel(code_model);856 }
516857
517 if (options.opt_bisect_limit >= 0) {858 builder.data_layout = try builder.fmt("{}", .{DataLayoutBuilder{ .target = options.target }});
518 context.setOptBisectLimit(std.math.lossyCast(c_int, options.opt_bisect_limit));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 }
519 }867 }
520868
521 return Object{869 return .{
522 .gpa = gpa,870 .gpa = gpa,
871 .builder = builder,
523 .module = options.module.?,872 .module = options.module.?,
524 .llvm_module = llvm_module,873 .llvm_module = builder.llvm.module.?,
525 .di_map = .{},874 .di_map = .{},
526 .di_builder = opt_di_builder,875 .di_builder = builder.llvm.di_builder,
527 .di_compile_unit = di_compile_unit,876 .di_compile_unit = builder.llvm.di_compile_unit,
528 .context = context,
529 .target_machine = target_machine,877 .target_machine = target_machine,
530 .target_data = target_data,878 .target_data = target_data,
531 .target = options.target,879 .target = options.target,
...@@ -533,22 +881,17 @@ pub const Object = struct {...@@ -533,22 +881,17 @@ pub const Object = struct {
533 .named_enum_map = .{},881 .named_enum_map = .{},
534 .type_map = .{},882 .type_map = .{},
535 .di_type_map = .{},883 .di_type_map = .{},
536 .error_name_table = null,884 .error_name_table = .none,
537 .extern_collisions = .{},885 .extern_collisions = .{},
538 .null_opt_addr = null,886 .null_opt_usize = .no_init,
539 };887 };
540 }888 }
541889
542 pub fn deinit(self: *Object, gpa: Allocator) void {890 pub fn deinit(self: *Object, gpa: Allocator) void {
543 if (self.di_builder) |dib| {891 self.di_map.deinit(gpa);
544 dib.dispose();892 self.di_type_map.deinit(gpa);
545 self.di_map.deinit(gpa);
546 self.di_type_map.deinit(gpa);
547 }
548 self.target_data.dispose();893 self.target_data.dispose();
549 self.target_machine.dispose();894 self.target_machine.dispose();
550 self.llvm_module.dispose();
551 self.context.dispose();
552 self.decl_map.deinit(gpa);895 self.decl_map.deinit(gpa);
553 self.named_enum_map.deinit(gpa);896 self.named_enum_map.deinit(gpa);
554 self.type_map.deinit(gpa);897 self.type_map.deinit(gpa);
...@@ -572,85 +915,108 @@ pub const Object = struct {...@@ -572,85 +915,108 @@ pub const Object = struct {
572 return slice.ptr;915 return slice.ptr;
573 }916 }
574917
575 fn genErrorNameTable(o: *Object) !void {918 fn genErrorNameTable(o: *Object) Allocator.Error!void {
576 // If o.error_name_table is null, there was no instruction that actually referenced the error table.919 // 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
579 const mod = o.module;923 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
592 const error_name_list = mod.global_error_set.keys();925 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);
594 defer mod.gpa.free(llvm_errors);927 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);
597 for (llvm_errors[1..], error_name_list[1..]) |*llvm_error, name_nts| {937 for (llvm_errors[1..], error_name_list[1..]) |*llvm_error, name_nts| {
598 const name = mod.intern_pool.stringToSlice(name_nts);938 const name = try o.builder.string(mod.intern_pool.stringToSlice(name_nts));
599 const str_init = o.context.constString(name.ptr, @as(c_uint, @intCast(name.len)), .False);939 const str_init = try o.builder.stringNullConst(name);
600 const str_global = o.llvm_module.addGlobal(str_init.typeOf(), "");940 const str_ty = str_init.typeOf(&o.builder);
601 str_global.setInitializer(str_init);941 const str_llvm_global = o.llvm_module.addGlobal(str_ty.toLlvm(&o.builder), "");
602 str_global.setLinkage(.Private);942 str_llvm_global.setInitializer(str_init.toLlvm(&o.builder));
603 str_global.setGlobalConstant(.True);943 str_llvm_global.setLinkage(.Private);
604 str_global.setUnnamedAddr(.True);944 str_llvm_global.setGlobalConstant(.True);
605 str_global.setAlignment(1);945 str_llvm_global.setUnnamedAddr(.True);
606946 str_llvm_global.setAlignment(1);
607 const slice_fields = [_]*llvm.Value{947
608 str_global,948 var str_global = Builder.Global{
609 llvm_usize_ty.constInt(name.len, .False),949 .linkage = .private,
950 .unnamed_addr = .unnamed_addr,
951 .type = str_ty,
952 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
610 };953 };
611 llvm_error.* = llvm_slice_ty.constNamedStruct(&slice_fields, slice_fields.len);954 var str_variable = Builder.Variable{
612 }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(), "");970 const error_name_table_init = try o.builder.arrayConst(llvm_table_ty, llvm_errors);
617 error_name_table_global.setInitializer(error_name_table_init);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));
618 error_name_table_global.setLinkage(.Private);973 error_name_table_global.setLinkage(.Private);
619 error_name_table_global.setGlobalConstant(.True);974 error_name_table_global.setGlobalConstant(.True);
620 error_name_table_global.setUnnamedAddr(.True);975 error_name_table_global.setUnnamedAddr(.True);
621 error_name_table_global.setAlignment(slice_alignment); // TODO: Dont hardcode976 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
623 const error_name_table_ptr = error_name_table_global;994 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);
625 }997 }
626998
627 fn genCmpLtErrorsLenFunction(object: *Object) !void {999 fn genCmpLtErrorsLenFunction(o: *Object) !void {
628 // If there is no such function in the module, it means the source code does not need it.1000 // 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;1001 const name = o.builder.stringIfExists(lt_errors_fn_name) orelse return;
630 const mod = object.module;1002 const llvm_fn = o.builder.getGlobal(name) orelse return;
1003 const mod = o.module;
631 const errors_len = mod.global_error_set.count();1004 const errors_len = mod.global_error_set.count();
6321005
633 // Delete previous implementation. We replace it with every flush() because the1006 var wip = try Builder.WipFunction.init(&o.builder, llvm_fn.ptrConst(&o.builder).kind.function);
634 // total number of errors may have changed.1007 defer wip.deinit();
635 while (llvm_fn.getFirstBasicBlock()) |bb| {1008 wip.cursor = .{ .block = try wip.block(0, "Entry") };
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();
6441009
645 // Example source of the following LLVM IR:1010 // Example source of the following LLVM IR:
646 // fn __zig_lt_errors_len(index: u16) bool {1011 // fn __zig_lt_errors_len(index: u16) bool {
647 // return index < total_errors_len;1012 // return index < total_errors_len;
648 // }1013 // }
6491014
650 const lhs = llvm_fn.getParam(0);1015 const lhs = wip.arg(0);
651 const rhs = lhs.typeOf().constInt(errors_len, .False);1016 const rhs = try o.builder.intValue(Builder.Type.err_int, errors_len);
652 const is_lt = builder.buildICmp(.ULT, lhs, rhs, "");1017 const is_lt = try wip.icmp(.ult, lhs, rhs, "");
653 _ = builder.buildRet(is_lt);1018 _ = try wip.ret(is_lt);
1019 try wip.finish();
654 }1020 }
6551021
656 fn genModuleLevelAssembly(object: *Object) !void {1022 fn genModuleLevelAssembly(object: *Object) !void {
...@@ -671,34 +1037,28 @@ pub const Object = struct {...@@ -671,34 +1037,28 @@ pub const Object = struct {
6711037
672 // This map has externs with incorrect symbol names.1038 // This map has externs with incorrect symbol names.
673 for (object.extern_collisions.keys()) |decl_index| {1039 for (object.extern_collisions.keys()) |decl_index| {
674 const entry = object.decl_map.getEntry(decl_index) orelse continue;1040 const global = object.decl_map.get(decl_index) orelse continue;
675 const llvm_global = entry.value_ptr.*;
676 // Same logic as below but for externs instead of exports.1041 // Same logic as below but for externs instead of exports.
677 const decl = mod.declPtr(decl_index);1042 const decl_name = object.builder.stringIfExists(mod.intern_pool.stringToSlice(mod.declPtr(decl_index).name)) orelse continue;
678 const other_global = object.getLlvmGlobal(mod.intern_pool.stringToSlice(decl.name)) orelse continue;1043 const other_global = object.builder.getGlobal(decl_name) orelse continue;
679 if (other_global == llvm_global) continue;1044 if (other_global.eql(global, &object.builder)) continue;
6801045
681 llvm_global.replaceAllUsesWith(other_global);1046 try global.replace(other_global, &object.builder);
682 deleteLlvmGlobal(llvm_global);
683 entry.value_ptr.* = other_global;
684 }1047 }
685 object.extern_collisions.clearRetainingCapacity();1048 object.extern_collisions.clearRetainingCapacity();
6861049
687 const export_keys = mod.decl_exports.keys();1050 for (mod.decl_exports.keys(), mod.decl_exports.values()) |decl_index, export_list| {
688 for (mod.decl_exports.values(), 0..) |export_list, i| {1051 const global = object.decl_map.get(decl_index) orelse continue;
689 const decl_index = export_keys[i];
690 const llvm_global = object.decl_map.get(decl_index) orelse continue;
691 for (export_list.items) |exp| {1052 for (export_list.items) |exp| {
692 // Detect if the LLVM global has already been created as an extern. In such1053 // Detect if the LLVM global has already been created as an extern. In such
693 // case, we need to replace all uses of it with this exported global.1054 // 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;1057 const other_global = object.builder.getGlobal(exp_name) orelse continue;
697 if (other_global == llvm_global) continue;1058 if (other_global.eql(global, &object.builder)) continue;
6981059
699 other_global.replaceAllUsesWith(llvm_global);1060 try global.takeName(other_global, &object.builder);
700 llvm_global.takeName(other_global);1061 try other_global.replace(global, &object.builder);
701 deleteLlvmGlobal(other_global);
702 // Problem: now we need to replace in the decl_map that1062 // Problem: now we need to replace in the decl_map that
703 // the extern decl index points to this new global. However we don't1063 // the extern decl index points to this new global. However we don't
704 // know the decl index.1064 // know the decl index.
...@@ -744,20 +1104,9 @@ pub const Object = struct {...@@ -744,20 +1104,9 @@ pub const Object = struct {
7441104
745 if (comp.verbose_llvm_ir) |path| {1105 if (comp.verbose_llvm_ir) |path| {
746 if (std.mem.eql(u8, path, "-")) {1106 if (std.mem.eql(u8, path, "-")) {
747 self.llvm_module.dump();1107 self.builder.dump();
748 } else {1108 } else {
749 const path_z = try comp.gpa.dupeZ(u8, path);1109 _ = try self.builder.printToFile(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 }
761 }1110 }
762 }1111 }
7631112
...@@ -884,7 +1233,9 @@ pub const Object = struct {...@@ -884,7 +1233,9 @@ pub const Object = struct {
884 .err_msg = null,1233 .err_msg = null,
885 };1234 };
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
889 if (func.analysis(ip).is_noinline) {1240 if (func.analysis(ip).is_noinline) {
890 o.addFnAttr(llvm_func, "noinline");1241 o.addFnAttr(llvm_func, "noinline");
...@@ -921,24 +1272,27 @@ pub const Object = struct {...@@ -921,24 +1272,27 @@ pub const Object = struct {
921 o.addFnAttrString(llvm_func, "no-stack-arg-probe", "");1272 o.addFnAttrString(llvm_func, "no-stack-arg-probe", "");
922 }1273 }
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);
925 llvm_func.setSection(section);1277 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();
931 }1278 }
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");1285 const builder = wip.llvm.builder;
936 builder.positionBuilderAtEnd(entry_block);1286 var llvm_arg_i: u32 = 0;
9371287
938 // This gets the LLVM values from the function and stores them in `dg.args`.1288 // This gets the LLVM values from the function and stores them in `dg.args`.
939 const fn_info = mod.typeToFunc(decl.ty).?;1289 const fn_info = mod.typeToFunc(decl.ty).?;
940 const sret = firstParamSRet(fn_info, mod);1290 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;
942 const gpa = o.gpa;1296 const gpa = o.gpa;
9431297
944 if (ccAbiPromoteInt(fn_info.cc, mod, fn_info.return_type.toType())) |s| switch (s) {1298 if (ccAbiPromoteInt(fn_info.cc, mod, fn_info.return_type.toType())) |s| switch (s) {
...@@ -949,207 +1303,183 @@ pub const Object = struct {...@@ -949,207 +1303,183 @@ pub const Object = struct {
949 const err_return_tracing = fn_info.return_type.toType().isError(mod) and1303 const err_return_tracing = fn_info.return_type.toType().isError(mod) and
950 mod.comp.bin_file.options.error_return_tracing;1304 mod.comp.bin_file.options.error_return_tracing;
9511305
952 const err_ret_trace = if (err_return_tracing)1306 const err_ret_trace: Builder.Value = if (err_return_tracing) param: {
953 llvm_func.getParam(@intFromBool(ret_ptr != null))1307 const param = wip.arg(llvm_arg_i);
954 else1308 llvm_arg_i += 1;
955 null;1309 break :param param;
1310 } else .none;
9561311
957 // This is the list of args we will use that correspond directly to the AIR arg1312 // This is the list of args we will use that correspond directly to the AIR arg
958 // instructions. Depending on the calling convention, this list is not necessarily1313 // instructions. Depending on the calling convention, this list is not necessarily
959 // a bijection with the actual LLVM parameters of the function.1314 // a bijection with the actual LLVM parameters of the function.
960 var args = std.ArrayList(*llvm.Value).init(gpa);1315 var args: std.ArrayListUnmanaged(Builder.Value) = .{};
961 defer args.deinit();1316 defer args.deinit(gpa);
9621317
963 {1318 {
964 var llvm_arg_i = @as(c_uint, @intFromBool(ret_ptr != null)) + @intFromBool(err_return_tracing);
965 var it = iterateParamTypes(o, fn_info);1319 var it = iterateParamTypes(o, fn_info);
966 while (it.next()) |lowering| switch (lowering) {1320 while (try it.next()) |lowering| {
967 .no_bits => continue,1321 try args.ensureUnusedCapacity(gpa, 1);
968 .byval => {1322
969 assert(!it.byval_attr);1323 switch (lowering) {
970 const param_index = it.zig_index - 1;1324 .no_bits => continue,
971 const param_ty = fn_info.param_types.get(ip)[param_index].toType();1325 .byval => {
972 const param = llvm_func.getParam(llvm_arg_i);1326 assert(!it.byval_attr);
973 try args.ensureUnusedCapacity(1);1327 const param_index = it.zig_index - 1;
9741328 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
975 if (isByRef(param_ty, mod)) {1329 const param = wip.arg(llvm_arg_i);
976 const alignment = param_ty.abiAlignment(mod);1330
977 const param_llvm_ty = param.typeOf();1331 if (isByRef(param_ty, mod)) {
978 const arg_ptr = buildAllocaInner(o.context, builder, llvm_func, false, param_llvm_ty, alignment, target);1332 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
979 const store_inst = builder.buildStore(param, arg_ptr);1333 const param_llvm_ty = param.typeOfWip(&wip);
980 store_inst.setAlignment(alignment);1334 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
981 args.appendAssumeCapacity(arg_ptr);1335 _ = try wip.store(.normal, param, arg_ptr, alignment);
982 } else {1336 args.appendAssumeCapacity(arg_ptr);
983 args.appendAssumeCapacity(param);1337 } else {
9841338 args.appendAssumeCapacity(param);
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);
10181339
1019 if (isByRef(param_ty, mod)) {1340 o.addByValParamAttrs(llvm_func, param_ty, param_index, fn_info, @intCast(llvm_arg_i));
1020 args.appendAssumeCapacity(param);1341 }
1021 } else {1342 llvm_arg_i += 1;
1022 const load_inst = builder.buildLoad(param_llvm_ty, param, "");1343 },
1023 load_inst.setAlignment(alignment);1344 .byref => {
1024 args.appendAssumeCapacity(load_inst);1345 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1025 }1346 const param_llvm_ty = try o.lowerType(param_ty);
1026 },1347 const param = wip.arg(llvm_arg_i);
1027 .abi_sized_int => {1348 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
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;
10321349
1033 const param_llvm_ty = try o.lowerType(param_ty);1350 o.addByRefParamAttrs(llvm_func, @intCast(llvm_arg_i), @intCast(alignment.toByteUnits() orelse 0), it.byval_attr, param_llvm_ty);
1034 const abi_size = @as(c_uint, @intCast(param_ty.abiSize(mod)));1351 llvm_arg_i += 1;
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);
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)) {1365 o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "noundef");
1047 args.appendAssumeCapacity(arg_ptr);1366 llvm_arg_i += 1;
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);
10581367
1059 if (math.cast(u5, it.zig_index - 1)) |i| {1368 if (isByRef(param_ty, mod)) {
1060 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {1369 args.appendAssumeCapacity(param);
1061 o.addArgAttr(llvm_func, llvm_arg_i, "noalias");1370 } else {
1371 args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, ""));
1062 }1372 }
1063 }1373 },
1064 if (param_ty.zigTypeTag(mod) != .Optional) {1374 .abi_sized_int => {
1065 o.addArgAttr(llvm_func, llvm_arg_i, "nonnull");1375 assert(!it.byval_attr);
1066 }1376 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1067 if (ptr_info.flags.is_const) {1377 const param = wip.arg(llvm_arg_i);
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);
1094 llvm_arg_i += 1;1378 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);1380 const param_llvm_ty = try o.lowerType(param_ty);
1101 const loaded = if (is_by_ref) arg_ptr else l: {1381 const int_llvm_ty = try o.builder.intType(@intCast(param_ty.abiSize(mod) * 8));
1102 const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");1382 const alignment = Builder.Alignment.fromByteUnits(@max(
1103 load_inst.setAlignment(param_alignment);1383 param_ty.abiAlignment(mod),
1104 break :l load_inst;1384 o.target_data.abiAlignmentOfType(int_llvm_ty.toLlvm(&o.builder)),
1105 };1385 ));
1106 try args.append(loaded);1386 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
1107 },1387 _ = try wip.store(.normal, param, arg_ptr, alignment);
1108 .as_u16 => {1388
1109 assert(!it.byval_attr);1389 args.appendAssumeCapacity(if (isByRef(param_ty, mod))
1110 const param = llvm_func.getParam(llvm_arg_i);1390 arg_ptr
1111 llvm_arg_i += 1;1391 else
1112 const casted = builder.buildBitCast(param, o.context.halfType(), "");1392 try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));
1113 try args.ensureUnusedCapacity(1);1393 },
1114 args.appendAssumeCapacity(casted);1394 .slice => {
1115 },1395 assert(!it.byval_attr);
1116 .float_array => {1396 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1117 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();1397 const ptr_info = param_ty.ptrInfo(mod);
1118 const param_llvm_ty = try o.lowerType(param_ty);1398
1119 const param = llvm_func.getParam(llvm_arg_i);1399 if (math.cast(u5, it.zig_index - 1)) |i| {
1120 llvm_arg_i += 1;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);1439 const is_by_ref = isByRef(param_ty, mod);
1123 const arg_ptr = buildAllocaInner(o.context, builder, llvm_func, false, param_llvm_ty, alignment, target);1440 args.appendAssumeCapacity(if (is_by_ref)
1124 _ = builder.buildStore(param, arg_ptr);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)) {1457 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1127 try args.append(arg_ptr);1458 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
1128 } else {1459 _ = try wip.store(.normal, param, arg_ptr, alignment);
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;
11391460
1140 const alignment = param_ty.abiAlignment(mod);1461 args.appendAssumeCapacity(if (isByRef(param_ty, mod))
1141 const arg_ptr = buildAllocaInner(o.context, builder, llvm_func, false, param_llvm_ty, alignment, target);1462 arg_ptr
1142 _ = builder.buildStore(param, 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)) {1472 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1145 try args.append(arg_ptr);1473 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
1146 } else {1474 _ = try wip.store(.normal, param, arg_ptr, alignment);
1147 const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");1475
1148 load_inst.setAlignment(alignment);1476 args.appendAssumeCapacity(if (isByRef(param_ty, mod))
1149 try args.append(load_inst);1477 arg_ptr
1150 }1478 else
1151 },1479 try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));
1152 };1480 },
1481 }
1482 }
1153 }1483 }
11541484
1155 var di_file: ?*llvm.DIFile = null;1485 var di_file: ?*llvm.DIFile = null;
...@@ -1191,16 +1521,15 @@ pub const Object = struct {...@@ -1191,16 +1521,15 @@ pub const Object = struct {
1191 .gpa = gpa,1521 .gpa = gpa,
1192 .air = air,1522 .air = air,
1193 .liveness = liveness,1523 .liveness = liveness,
1194 .context = o.context,
1195 .dg = &dg,1524 .dg = &dg,
1525 .wip = wip,
1196 .builder = builder,1526 .builder = builder,
1197 .ret_ptr = ret_ptr,1527 .ret_ptr = ret_ptr,
1198 .args = args.items,1528 .args = args.items,
1199 .arg_index = 0,1529 .arg_index = 0,
1200 .func_inst_table = .{},1530 .func_inst_table = .{},
1201 .llvm_func = llvm_func,
1202 .blocks = .{},1531 .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,
1204 .di_scope = di_scope,1533 .di_scope = di_scope,
1205 .di_file = di_file,1534 .di_file = di_file,
1206 .base_line = dg.decl.src_line,1535 .base_line = dg.decl.src_line,
...@@ -1209,6 +1538,7 @@ pub const Object = struct {...@@ -1209,6 +1538,7 @@ pub const Object = struct {
1209 .err_ret_trace = err_ret_trace,1538 .err_ret_trace = err_ret_trace,
1210 };1539 };
1211 defer fg.deinit();1540 defer fg.deinit();
1541 deinit_wip = false;
12121542
1213 fg.genBody(air.getMainBody()) catch |err| switch (err) {1543 fg.genBody(air.getMainBody()) catch |err| switch (err) {
1214 error.CodegenFail => {1544 error.CodegenFail => {
...@@ -1220,6 +1550,8 @@ pub const Object = struct {...@@ -1220,6 +1550,8 @@ pub const Object = struct {
1220 else => |e| return e,1550 else => |e| return e,
1221 };1551 };
12221552
1553 try fg.wip.finish();
1554
1223 try o.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index));1555 try o.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index));
1224 }1556 }
12251557
...@@ -1243,14 +1575,6 @@ pub const Object = struct {...@@ -1243,14 +1575,6 @@ pub const Object = struct {
1243 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));1575 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
1244 }1576 }
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
1254 pub fn updateDeclExports(1578 pub fn updateDeclExports(
1255 self: *Object,1579 self: *Object,
1256 mod: *Module,1580 mod: *Module,
...@@ -1260,93 +1584,133 @@ pub const Object = struct {...@@ -1260,93 +1584,133 @@ pub const Object = struct {
1260 const gpa = mod.gpa;1584 const gpa = mod.gpa;
1261 // If the module does not already have the function, we ignore this function call1585 // If the module does not already have the function, we ignore this function call
1262 // because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`.1586 // 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);
1264 const decl = mod.declPtr(decl_index);1589 const decl = mod.declPtr(decl_index);
1265 if (decl.isExtern(mod)) {1590 if (decl.isExtern(mod)) {
1266 var free_decl_name = false;
1267 const decl_name = decl_name: {1591 const decl_name = decl_name: {
1268 const decl_name = mod.intern_pool.stringToSlice(decl.name);1592 const decl_name = mod.intern_pool.stringToSlice(decl.name);
12691593
1270 if (mod.getTarget().isWasm() and try decl.isFunction(mod)) {1594 if (mod.getTarget().isWasm() and try decl.isFunction(mod)) {
1271 if (mod.intern_pool.stringToSliceUnwrap(decl.getOwnedExternFunc(mod).?.lib_name)) |lib_name| {1595 if (mod.intern_pool.stringToSliceUnwrap(decl.getOwnedExternFunc(mod).?.lib_name)) |lib_name| {
1272 if (!std.mem.eql(u8, lib_name, "c")) {1596 if (!std.mem.eql(u8, lib_name, "c")) {
1273 free_decl_name = true;1597 break :decl_name try self.builder.fmt("{s}|{s}", .{ decl_name, lib_name });
1274 break :decl_name try std.fmt.allocPrintZ(gpa, "{s}|{s}", .{
1275 decl_name, lib_name,
1276 });
1277 }1598 }
1278 }1599 }
1279 }1600 }
12801601
1281 break :decl_name decl_name;1602 break :decl_name try self.builder.string(decl_name);
1282 };1603 };
1283 defer if (free_decl_name) gpa.free(decl_name);
12841604
1285 llvm_global.setValueName(decl_name);1605 if (self.builder.getGlobal(decl_name)) |other_global| {
1286 if (self.getLlvmGlobal(decl_name)) |other_global| {1606 if (other_global.toLlvm(&self.builder) != llvm_global) {
1287 if (other_global != llvm_global) {
1288 try self.extern_collisions.put(gpa, decl_index, {});1607 try self.extern_collisions.put(gpa, decl_index, {});
1289 }1608 }
1290 }1609 }
1610
1611 try global.rename(decl_name, &self.builder);
1612 global.ptr(&self.builder).unnamed_addr = .default;
1291 llvm_global.setUnnamedAddr(.False);1613 llvm_global.setUnnamedAddr(.False);
1614 global.ptr(&self.builder).linkage = .external;
1292 llvm_global.setLinkage(.External);1615 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 }
1294 if (self.di_map.get(decl)) |di_node| {1620 if (self.di_map.get(decl)) |di_node| {
1621 const decl_name_slice = decl_name.toSlice(&self.builder).?;
1295 if (try decl.isFunction(mod)) {1622 if (try decl.isFunction(mod)) {
1296 const di_func = @as(*llvm.DISubprogram, @ptrCast(di_node));1623 const di_func: *llvm.DISubprogram = @ptrCast(di_node);
1297 const linkage_name = llvm.MDString.get(self.context, decl_name.ptr, decl_name.len);1624 const linkage_name = llvm.MDString.get(self.builder.llvm.context, decl_name_slice.ptr, decl_name_slice.len);
1298 di_func.replaceLinkageName(linkage_name);1625 di_func.replaceLinkageName(linkage_name);
1299 } else {1626 } else {
1300 const di_global = @as(*llvm.DIGlobalVariable, @ptrCast(di_node));1627 const di_global: *llvm.DIGlobalVariable = @ptrCast(di_node);
1301 const linkage_name = llvm.MDString.get(self.context, decl_name.ptr, decl_name.len);1628 const linkage_name = llvm.MDString.get(self.builder.llvm.context, decl_name_slice.ptr, decl_name_slice.len);
1302 di_global.replaceLinkageName(linkage_name);1629 di_global.replaceLinkageName(linkage_name);
1303 }1630 }
1304 }1631 }
1305 if (decl.val.getVariable(mod)) |variable| {1632 if (decl.val.getVariable(mod)) |decl_var| {
1306 if (variable.is_threadlocal) {1633 if (decl_var.is_threadlocal) {
1634 global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local =
1635 .generaldynamic;
1307 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);1636 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
1308 } else {1637 } else {
1638 global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local =
1639 .default;
1309 llvm_global.setThreadLocalMode(.NotThreadLocal);1640 llvm_global.setThreadLocalMode(.NotThreadLocal);
1310 }1641 }
1311 if (variable.is_weak_linkage) {1642 if (decl_var.is_weak_linkage) {
1643 global.ptr(&self.builder).linkage = .extern_weak;
1312 llvm_global.setLinkage(.ExternalWeak);1644 llvm_global.setLinkage(.ExternalWeak);
1313 }1645 }
1314 }1646 }
1647 global.ptr(&self.builder).updateAttributes();
1315 } else if (exports.len != 0) {1648 } else if (exports.len != 0) {
1316 const exp_name = mod.intern_pool.stringToSlice(exports[0].opts.name);1649 const exp_name = try self.builder.string(mod.intern_pool.stringToSlice(exports[0].opts.name));
1317 llvm_global.setValueName2(exp_name.ptr, exp_name.len);1650 try global.rename(exp_name, &self.builder);
1651 global.ptr(&self.builder).unnamed_addr = .default;
1318 llvm_global.setUnnamedAddr(.False);1652 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 }
1320 if (self.di_map.get(decl)) |di_node| {1657 if (self.di_map.get(decl)) |di_node| {
1658 const exp_name_slice = exp_name.toSlice(&self.builder).?;
1321 if (try decl.isFunction(mod)) {1659 if (try decl.isFunction(mod)) {
1322 const di_func = @as(*llvm.DISubprogram, @ptrCast(di_node));1660 const di_func: *llvm.DISubprogram = @ptrCast(di_node);
1323 const linkage_name = llvm.MDString.get(self.context, exp_name.ptr, exp_name.len);1661 const linkage_name = llvm.MDString.get(self.builder.llvm.context, exp_name_slice.ptr, exp_name_slice.len);
1324 di_func.replaceLinkageName(linkage_name);1662 di_func.replaceLinkageName(linkage_name);
1325 } else {1663 } else {
1326 const di_global = @as(*llvm.DIGlobalVariable, @ptrCast(di_node));1664 const di_global: *llvm.DIGlobalVariable = @ptrCast(di_node);
1327 const linkage_name = llvm.MDString.get(self.context, exp_name.ptr, exp_name.len);1665 const linkage_name = llvm.MDString.get(self.builder.llvm.context, exp_name_slice.ptr, exp_name_slice.len);
1328 di_global.replaceLinkageName(linkage_name);1666 di_global.replaceLinkageName(linkage_name);
1329 }1667 }
1330 }1668 }
1331 switch (exports[0].opts.linkage) {1669 switch (exports[0].opts.linkage) {
1332 .Internal => unreachable,1670 .Internal => unreachable,
1333 .Strong => llvm_global.setLinkage(.External),1671 .Strong => {
1334 .Weak => llvm_global.setLinkage(.WeakODR),1672 global.ptr(&self.builder).linkage = .external;
1335 .LinkOnce => llvm_global.setLinkage(.LinkOnceODR),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 },
1336 }1683 }
1337 switch (exports[0].opts.visibility) {1684 switch (exports[0].opts.visibility) {
1338 .default => llvm_global.setVisibility(.Default),1685 .default => {
1339 .hidden => llvm_global.setVisibility(.Hidden),1686 global.ptr(&self.builder).visibility = .default;
1340 .protected => llvm_global.setVisibility(.Protected),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 },
1341 }1697 }
1342 if (mod.intern_pool.stringToSliceUnwrap(exports[0].opts.section)) |section| {1698 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 }
1343 llvm_global.setSection(section);1704 llvm_global.setSection(section);
1344 }1705 }
1345 if (decl.val.getVariable(mod)) |variable| {1706 if (decl.val.getVariable(mod)) |decl_var| {
1346 if (variable.is_threadlocal) {1707 if (decl_var.is_threadlocal) {
1708 global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local =
1709 .generaldynamic;
1347 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);1710 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
1348 }1711 }
1349 }1712 }
1713 global.ptr(&self.builder).updateAttributes();
13501714
1351 // If a Decl is exported more than one time (which is rare),1715 // If a Decl is exported more than one time (which is rare),
1352 // we add aliases for all but the first export.1716 // we add aliases for all but the first export.
...@@ -1361,7 +1725,7 @@ pub const Object = struct {...@@ -1361,7 +1725,7 @@ pub const Object = struct {
1361 alias.setAliasee(llvm_global);1725 alias.setAliasee(llvm_global);
1362 } else {1726 } else {
1363 _ = self.llvm_module.addAlias(1727 _ = self.llvm_module.addAlias(
1364 llvm_global.globalGetValueType(),1728 global.ptrConst(&self.builder).type.toLlvm(&self.builder),
1365 0,1729 0,
1366 llvm_global,1730 llvm_global,
1367 exp_name_z,1731 exp_name_z,
...@@ -1369,32 +1733,42 @@ pub const Object = struct {...@@ -1369,32 +1733,42 @@ pub const Object = struct {
1369 }1733 }
1370 }1734 }
1371 } else {1735 } else {
1372 const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));1736 const fqn = try self.builder.string(mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)));
1373 llvm_global.setValueName2(fqn.ptr, fqn.len);1737 try global.rename(fqn, &self.builder);
1738 global.ptr(&self.builder).linkage = .internal;
1374 llvm_global.setLinkage(.Internal);1739 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;
1376 llvm_global.setUnnamedAddr(.True);1745 llvm_global.setUnnamedAddr(.True);
1377 if (decl.val.getVariable(mod)) |variable| {1746 if (decl.val.getVariable(mod)) |decl_var| {
1378 const single_threaded = mod.comp.bin_file.options.single_threaded;1747 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;
1380 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);1751 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
1381 } else {1752 } else {
1753 global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local =
1754 .default;
1382 llvm_global.setThreadLocalMode(.NotThreadLocal);1755 llvm_global.setThreadLocalMode(.NotThreadLocal);
1383 }1756 }
1384 }1757 }
1758 global.ptr(&self.builder).updateAttributes();
1385 }1759 }
1386 }1760 }
13871761
1388 pub fn freeDecl(self: *Object, decl_index: Module.Decl.Index) void {1762 pub fn freeDecl(self: *Object, decl_index: Module.Decl.Index) void {
1389 const llvm_value = self.decl_map.get(decl_index) orelse return;1763 const global = self.decl_map.get(decl_index) orelse return;
1390 llvm_value.deleteGlobal();1764 global.toLlvm(&self.builder).deleteGlobal();
1391 }1765 }
13921766
1393 fn getDIFile(o: *Object, gpa: Allocator, file: *const Module.File) !*llvm.DIFile {1767 fn getDIFile(o: *Object, gpa: Allocator, file: *const Module.File) !*llvm.DIFile {
1394 const gop = try o.di_map.getOrPut(gpa, file);1768 const gop = try o.di_map.getOrPut(gpa, file);
1395 errdefer assert(o.di_map.remove(file));1769 errdefer assert(o.di_map.remove(file));
1396 if (gop.found_existing) {1770 if (gop.found_existing) {
1397 return @as(*llvm.DIFile, @ptrCast(gop.value_ptr.*));1771 return @ptrCast(gop.value_ptr.*);
1398 }1772 }
1399 const dir_path_z = d: {1773 const dir_path_z = d: {
1400 var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;1774 var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
...@@ -1542,7 +1916,7 @@ pub const Object = struct {...@@ -1542,7 +1916,7 @@ pub const Object = struct {
1542 ty.abiSize(mod) * 8,1916 ty.abiSize(mod) * 8,
1543 ty.abiAlignment(mod) * 8,1917 ty.abiAlignment(mod) * 8,
1544 enumerators.ptr,1918 enumerators.ptr,
1545 @as(c_int, @intCast(enumerators.len)),1919 @intCast(enumerators.len),
1546 try o.lowerDebugType(int_ty, .full),1920 try o.lowerDebugType(int_ty, .full),
1547 "",1921 "",
1548 );1922 );
...@@ -1717,7 +2091,7 @@ pub const Object = struct {...@@ -1717,7 +2091,7 @@ pub const Object = struct {
1717 ty.abiSize(mod) * 8,2091 ty.abiSize(mod) * 8,
1718 ty.abiAlignment(mod) * 8,2092 ty.abiAlignment(mod) * 8,
1719 try o.lowerDebugType(ty.childType(mod), .full),2093 try o.lowerDebugType(ty.childType(mod), .full),
1720 @as(i64, @intCast(ty.arrayLen(mod))),2094 @intCast(ty.arrayLen(mod)),
1721 );2095 );
1722 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.2096 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
1723 try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(array_di_ty));2097 try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(array_di_ty));
...@@ -2022,7 +2396,7 @@ pub const Object = struct {...@@ -2022,7 +2396,7 @@ pub const Object = struct {
2022 0, // flags2396 0, // flags
2023 null, // derived from2397 null, // derived from
2024 di_fields.items.ptr,2398 di_fields.items.ptr,
2025 @as(c_int, @intCast(di_fields.items.len)),2399 @intCast(di_fields.items.len),
2026 0, // run time lang2400 0, // run time lang
2027 null, // vtable holder2401 null, // vtable holder
2028 "", // unique id2402 "", // unique id
...@@ -2109,7 +2483,7 @@ pub const Object = struct {...@@ -2109,7 +2483,7 @@ pub const Object = struct {
2109 0, // flags2483 0, // flags
2110 null, // derived from2484 null, // derived from
2111 di_fields.items.ptr,2485 di_fields.items.ptr,
2112 @as(c_int, @intCast(di_fields.items.len)),2486 @intCast(di_fields.items.len),
2113 0, // run time lang2487 0, // run time lang
2114 null, // vtable holder2488 null, // vtable holder
2115 "", // unique id2489 "", // unique id
...@@ -2221,7 +2595,7 @@ pub const Object = struct {...@@ -2221,7 +2595,7 @@ pub const Object = struct {
2221 ty.abiAlignment(mod) * 8, // align in bits2595 ty.abiAlignment(mod) * 8, // align in bits
2222 0, // flags2596 0, // flags
2223 di_fields.items.ptr,2597 di_fields.items.ptr,
2224 @as(c_int, @intCast(di_fields.items.len)),2598 @intCast(di_fields.items.len),
2225 0, // run time lang2599 0, // run time lang
2226 "", // unique id2600 "", // unique id
2227 );2601 );
...@@ -2334,7 +2708,7 @@ pub const Object = struct {...@@ -2334,7 +2708,7 @@ pub const Object = struct {
23342708
2335 const fn_di_ty = dib.createSubroutineType(2709 const fn_di_ty = dib.createSubroutineType(
2336 param_di_types.items.ptr,2710 param_di_types.items.ptr,
2337 @as(c_int, @intCast(param_di_types.items.len)),2711 @intCast(param_di_types.items.len),
2338 0,2712 0,
2339 );2713 );
2340 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.2714 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
...@@ -2420,52 +2794,16 @@ pub const Object = struct {...@@ -2420,52 +2794,16 @@ pub const Object = struct {
2420 return buffer.toOwnedSliceSentinel(0);2794 return buffer.toOwnedSliceSentinel(0);
2421 }2795 }
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
2459 /// If the llvm function does not exist, create it.2797 /// If the llvm function does not exist, create it.
2460 /// Note that this can be called before the function's semantic analysis has2798 /// Note that this can be called before the function's semantic analysis has
2461 /// completed, so if any attributes rely on that, they must be done in updateFunc, not here.2799 /// 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 {
2463 const mod = o.module;2801 const mod = o.module;
2464 const gpa = o.gpa;2802 const gpa = o.gpa;
2465 const decl = mod.declPtr(decl_index);2803 const decl = mod.declPtr(decl_index);
2466 const zig_fn_type = decl.ty;2804 const zig_fn_type = decl.ty;
2467 const gop = try o.decl_map.getOrPut(gpa, decl_index);2805 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
2470 assert(decl.has_tv);2808 assert(decl.has_tv);
2471 const fn_info = mod.typeToFunc(zig_fn_type).?;2809 const fn_info = mod.typeToFunc(zig_fn_type).?;
...@@ -2474,16 +2812,25 @@ pub const Object = struct {...@@ -2474,16 +2812,25 @@ pub const Object = struct {
24742812
2475 const fn_type = try o.lowerType(zig_fn_type);2813 const fn_type = try o.lowerType(zig_fn_type);
24762814
2477 const fqn = try decl.getFullyQualifiedName(mod);
2478 const ip = &mod.intern_pool;2815 const ip = &mod.intern_pool;
2816 const fqn = try o.builder.string(ip.stringToSlice(try decl.getFullyQualifiedName(mod)));
24792817
2480 const llvm_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);2818 const llvm_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);
2481 const llvm_fn = o.llvm_module.addFunctionInAddressSpace(ip.stringToSlice(fqn), fn_type, llvm_addrspace);2819 const llvm_fn = o.llvm_module.addFunctionInAddressSpace(fqn.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder), @intFromEnum(llvm_addrspace));
2482 gop.value_ptr.* = llvm_fn;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
2484 const is_extern = decl.isExtern(mod);2829 const is_extern = decl.isExtern(mod);
2485 if (!is_extern) {2830 if (!is_extern) {
2831 global.linkage = .internal;
2486 llvm_fn.setLinkage(.Internal);2832 llvm_fn.setLinkage(.Internal);
2833 global.unnamed_addr = .unnamed_addr;
2487 llvm_fn.setUnnamedAddr(.True);2834 llvm_fn.setUnnamedAddr(.True);
2488 } else {2835 } else {
2489 if (target.isWasm()) {2836 if (target.isWasm()) {
...@@ -2500,7 +2847,7 @@ pub const Object = struct {...@@ -2500,7 +2847,7 @@ pub const Object = struct {
2500 o.addArgAttr(llvm_fn, 0, "nonnull"); // Sret pointers must not be address 02847 o.addArgAttr(llvm_fn, 0, "nonnull"); // Sret pointers must not be address 0
2501 o.addArgAttr(llvm_fn, 0, "noalias");2848 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);
2504 llvm_fn.addSretAttr(raw_llvm_ret_ty);2851 llvm_fn.addSretAttr(raw_llvm_ret_ty);
2505 }2852 }
25062853
...@@ -2528,7 +2875,8 @@ pub const Object = struct {...@@ -2528,7 +2875,8 @@ pub const Object = struct {
2528 }2875 }
25292876
2530 if (fn_info.alignment.toByteUnitsOptional()) |a| {2877 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));
2532 }2880 }
25332881
2534 // Function attributes that are independent of analysis results of the function body.2882 // Function attributes that are independent of analysis results of the function body.
...@@ -2544,7 +2892,7 @@ pub const Object = struct {...@@ -2544,7 +2892,7 @@ pub const Object = struct {
2544 var it = iterateParamTypes(o, fn_info);2892 var it = iterateParamTypes(o, fn_info);
2545 it.llvm_index += @intFromBool(sret);2893 it.llvm_index += @intFromBool(sret);
2546 it.llvm_index += @intFromBool(err_return_tracing);2894 it.llvm_index += @intFromBool(err_return_tracing);
2547 while (it.next()) |lowering| switch (lowering) {2895 while (try it.next()) |lowering| switch (lowering) {
2548 .byval => {2896 .byval => {
2549 const param_index = it.zig_index - 1;2897 const param_index = it.zig_index - 1;
2550 const param_ty = fn_info.param_types.get(ip)[param_index].toType();2898 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
...@@ -2576,7 +2924,10 @@ pub const Object = struct {...@@ -2576,7 +2924,10 @@ pub const Object = struct {
2576 };2924 };
2577 }2925 }
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;
2580 }2931 }
25812932
2582 fn addCommonFnAttributes(o: *Object, llvm_fn: *llvm.Value) void {2933 fn addCommonFnAttributes(o: *Object, llvm_fn: *llvm.Value) void {
...@@ -2622,65 +2973,80 @@ pub const Object = struct {...@@ -2622,65 +2973,80 @@ pub const Object = struct {
2622 }2973 }
2623 }2974 }
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 {
2626 const gop = try o.decl_map.getOrPut(o.gpa, decl_index);2977 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;
2628 errdefer assert(o.decl_map.remove(decl_index));2979 errdefer assert(o.decl_map.remove(decl_index));
26292980
2630 const mod = o.module;2981 const mod = o.module;
2631 const decl = mod.declPtr(decl_index);2982 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
2634 const target = mod.getTarget();2987 const target = mod.getTarget();
26352988
2636 const llvm_type = try o.lowerType(decl.ty);2989 var global = Builder.Global{
2637 const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);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;
2639 const llvm_global = o.llvm_module.addGlobalInAddressSpace(3003 const llvm_global = o.llvm_module.addGlobalInAddressSpace(
2640 llvm_type,3004 global.type.toLlvm(&o.builder),
2641 mod.intern_pool.stringToSlice(fqn),3005 fqn.toSlice(&o.builder).?,
2642 llvm_actual_addrspace,3006 @intFromEnum(global.addr_space),
2643 );3007 );
2644 gop.value_ptr.* = llvm_global;
26453008
2646 // This is needed for declarations created by `@extern`.3009 // This is needed for declarations created by `@extern`.
2647 if (decl.isExtern(mod)) {3010 if (is_extern) {
2648 llvm_global.setValueName(mod.intern_pool.stringToSlice(decl.name));3011 global.unnamed_addr = .default;
2649 llvm_global.setUnnamedAddr(.False);3012 llvm_global.setUnnamedAddr(.False);
3013 global.linkage = .external;
2650 llvm_global.setLinkage(.External);3014 llvm_global.setLinkage(.External);
2651 if (decl.val.getVariable(mod)) |variable| {3015 if (decl.val.getVariable(mod)) |decl_var| {
2652 const single_threaded = mod.comp.bin_file.options.single_threaded;3016 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;
2654 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);3019 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
2655 } else {3020 } else {
3021 variable.thread_local = .default;
2656 llvm_global.setThreadLocalMode(.NotThreadLocal);3022 llvm_global.setThreadLocalMode(.NotThreadLocal);
2657 }3023 }
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 }
2659 }3028 }
2660 } else {3029 } else {
3030 global.linkage = .internal;
2661 llvm_global.setLinkage(.Internal);3031 llvm_global.setLinkage(.Internal);
3032 global.unnamed_addr = .unnamed_addr;
2662 llvm_global.setUnnamedAddr(.True);3033 llvm_global.setUnnamedAddr(.True);
2663 }3034 }
26643035
2665 return llvm_global;3036 try o.builder.llvm.globals.append(o.gpa, llvm_global);
2666 }3037 gop.value_ptr.* = try o.builder.addGlobal(name, global);
26673038 try o.builder.variables.append(o.gpa, variable);
2668 fn isUnnamedType(o: *Object, ty: Type, val: *llvm.Value) bool {3039 return global.kind.variable;
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;
2675 }3040 }
26763041
2677 fn lowerType(o: *Object, t: Type) Allocator.Error!*llvm.Type {3042 fn lowerType(o: *Object, t: Type) Allocator.Error!Builder.Type {
2678 const llvm_ty = try lowerTypeInner(o, t);3043 const ty = try o.lowerTypeInner(t);
2679 const mod = o.module;3044 const mod = o.module;
2680 if (std.debug.runtime_safety and false) check: {3045 if (std.debug.runtime_safety and false) check: {
3046 const llvm_ty = ty.toLlvm(&o.builder);
2681 if (t.zigTypeTag(mod) == .Opaque) break :check;3047 if (t.zigTypeTag(mod) == .Opaque) break :check;
2682 if (!t.hasRuntimeBits(mod)) break :check;3048 if (!t.hasRuntimeBits(mod)) break :check;
2683 if (!llvm_ty.isSized().toBool()) break :check;3049 if (!try ty.isSized(&o.builder)) break :check;
26843050
2685 const zig_size = t.abiSize(mod);3051 const zig_size = t.abiSize(mod);
2686 const llvm_size = o.target_data.abiSizeOfType(llvm_ty);3052 const llvm_size = o.target_data.abiSizeOfType(llvm_ty);
...@@ -2690,456 +3056,511 @@ pub const Object = struct {...@@ -2690,456 +3056,511 @@ pub const Object = struct {
2690 });3056 });
2691 }3057 }
2692 }3058 }
2693 return llvm_ty;3059 return ty;
2694 }3060 }
26953061
2696 fn lowerTypeInner(o: *Object, t: Type) Allocator.Error!*llvm.Type {3062 fn lowerTypeInner(o: *Object, t: Type) Allocator.Error!Builder.Type {
2697 const gpa = o.gpa;
2698 const mod = o.module;3063 const mod = o.module;
2699 const target = mod.getTarget();3064 const target = mod.getTarget();
2700 switch (t.zigTypeTag(mod)) {3065 return switch (t.toIntern()) {
2701 .Void, .NoReturn => return o.context.voidType(),3066 .u0_type, .i0_type => unreachable,
2702 .Int => {3067 inline .u1_type,
2703 const info = t.intInfo(mod);3068 .u8_type,
2704 assert(info.bits != 0);3069 .i8_type,
2705 return o.context.intType(info.bits);3070 .u16_type,
2706 },3071 .i16_type,
2707 .Enum => {3072 .u29_type,
2708 const int_ty = t.intTagType(mod);3073 .u32_type,
2709 const bit_count = int_ty.intInfo(mod).bits;3074 .i32_type,
2710 assert(bit_count != 0);3075 .u64_type,
2711 return o.context.intType(bit_count);3076 .i64_type,
2712 },3077 .u80_type,
2713 .Float => switch (t.floatBits(target)) {3078 .u128_type,
2714 16 => return if (backendSupportsF16(target)) o.context.halfType() else o.context.intType(16),3079 .i128_type,
2715 32 => return o.context.floatType(),3080 => |tag| @field(Builder.Type, "i" ++ @tagName(tag)[1 .. @tagName(tag).len - "_type".len]),
2716 64 => return o.context.doubleType(),3081 .usize_type, .isize_type => try o.builder.intType(target.ptrBitWidth()),
2717 80 => return if (backendSupportsF80(target)) o.context.x86FP80Type() else o.context.intType(80),3082 inline .c_char_type,
2718 128 => return o.context.fp128Type(),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,
2719 else => unreachable,3106 else => unreachable,
2720 },3107 },
2721 .Bool => return o.context.intType(1),3108 .anyopaque_type => unreachable,
2722 .Pointer => {3109 .bool_type => .i1,
2723 if (t.isSlice(mod)) {3110 .void_type => .void,
2724 const ptr_type = t.slicePtrFieldType(mod);3111 .type_type => unreachable,
27253112 .anyerror_type => Builder.Type.err_int,
2726 const fields: [2]*llvm.Type = .{3113 .comptime_int_type,
2727 try o.lowerType(ptr_type),3114 .comptime_float_type,
2728 try o.lowerType(Type.usize),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 }),
2729 };3182 };
2730 return o.context.structType(&fields, fields.len, .False);3183 },
2731 }3184 .array_type => |array_type| o.builder.arrayType(
2732 const ptr_info = t.ptrInfo(mod);3185 array_type.len + @intFromBool(array_type.sentinel != .none),
2733 const llvm_addrspace = toLlvmAddressSpace(ptr_info.flags.address_space, target);3186 try o.lowerType(array_type.child.toType()),
2734 return o.context.pointerType(llvm_addrspace);3187 ),
2735 },3188 .vector_type => |vector_type| o.builder.vectorType(
2736 .Opaque => {3189 .normal,
2737 if (t.toIntern() == .anyopaque_type) return o.context.intType(8);3190 vector_type.len,
27383191 try o.lowerType(vector_type.child.toType()),
2739 const gop = try o.type_map.getOrPut(gpa, t.toIntern());3192 ),
2740 if (gop.found_existing) return gop.value_ptr.*;3193 .opt_type => |child_ty| {
27413194 if (!child_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) return .i8;
2742 const opaque_type = mod.intern_pool.indexToKey(t.toIntern()).opaque_type;3195
2743 const name = mod.intern_pool.stringToSlice(try mod.opaqueFullyQualifiedName(opaque_type));3196 const payload_ty = try o.lowerType(child_ty.toType());
27443197 if (t.optionalReprIsPayload(mod)) return payload_ty;
2745 const llvm_struct_ty = o.context.structCreateNamed(name);3198
2746 gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls3199 comptime assert(optional_layout_version == 3);
2747 return llvm_struct_ty;3200 var fields: [3]Builder.Type = .{ payload_ty, .i8, undefined };
2748 },3201 var fields_len: usize = 2;
2749 .Array => {3202 const offset = child_ty.toType().abiSize(mod) + 1;
2750 const elem_ty = t.childType(mod);3203 const abi_size = t.abiSize(mod);
2751 if (std.debug.runtime_safety) assert((try elem_ty.onePossibleValue(mod)) == null);3204 const padding_len = abi_size - offset;
2752 const elem_llvm_ty = try o.lowerType(elem_ty);3205 if (padding_len > 0) {
2753 const total_len = t.arrayLen(mod) + @intFromBool(t.sentinel(mod) != null);3206 fields[2] = try o.builder.arrayType(padding_len, .i8);
2754 return elem_llvm_ty.arrayType(@as(c_uint, @intCast(total_len)));3207 fields_len = 3;
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);
2808 }3208 }
2809 fields_buf[2] = o.context.intType(8).arrayType(padding);3209 return o.builder.structType(.normal, fields[0..fields_len]);
2810 return o.context.structType(&fields_buf, 3, .False);3210 },
2811 } else {3211 .anyframe_type => @panic("TODO implement lowerType for AnyFrame types"),
2812 fields_buf[0] = llvm_payload_type;3212 .error_union_type => |error_union_type| {
2813 fields_buf[1] = llvm_error_type;3213 const error_type = Builder.Type.err_int;
2814 const error_end =3214 if (!error_union_type.payload_type.toType().hasRuntimeBitsIgnoreComptime(mod))
2815 std.mem.alignForward(u64, payload_size, error_align) +3215 return error_type;
2816 error_size;3216 const payload_type = try o.lowerType(error_union_type.payload_type.toType());
2817 const abi_size = std.mem.alignForward(u64, error_end, payload_align);3217
2818 const padding = @as(c_uint, @intCast(abi_size - error_end));3218 const payload_align = error_union_type.payload_type.toType().abiAlignment(mod);
2819 if (padding == 0) {3219 const error_align = Type.err_int.abiAlignment(mod);
2820 return o.context.structType(&fields_buf, 2, .False);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;
2821 }3246 }
2822 fields_buf[2] = o.context.intType(8).arrayType(padding);3247 return o.builder.structType(.normal, fields[0..fields_len]);
2823 return o.context.structType(&fields_buf, 3, .False);3248 },
2824 }3249 .simple_type => unreachable,
2825 },3250 .struct_type => |struct_type| {
2826 .ErrorSet => return o.context.intType(16),3251 const gop = try o.type_map.getOrPut(o.gpa, t.toIntern());
2827 .Struct => {3252 if (gop.found_existing) return gop.value_ptr.*;
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
28353253
2836 var llvm_field_types: std.ArrayListUnmanaged(*llvm.Type) = .{};3254 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
2837 defer llvm_field_types.deinit(gpa);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);3268 assert(struct_obj.haveFieldTypes());
2842 var offset: u64 = 0;
2843 var big_align: u32 = 0;
28443269
2845 for (tuple.types, tuple.values) |field_ty, field_val| {3270 var llvm_field_types = std.ArrayListUnmanaged(Builder.Type){};
2846 if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue;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);3274 comptime assert(struct_layout_version == 2);
2849 big_align = @max(big_align, field_align);3275 var offset: u64 = 0;
2850 const prev_offset = offset;3276 var big_align: u32 = 1;
2851 offset = std.mem.alignForward(u64, offset, field_align);3277 var struct_kind: Builder.Type.Structure.Kind = .normal;
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);
28603278
2861 offset += field_ty.toType().abiSize(mod);3279 var it = struct_obj.runtimeFieldIterator(mod);
2862 }3280 while (it.next()) |field_and_index| {
2863 {3281 const field = field_and_index.field;
2864 const prev_offset = offset;3282 const field_align = field.alignment(mod, struct_obj.layout);
2865 offset = std.mem.alignForward(u64, offset, big_align);3283 const field_ty_align = field.ty.abiAlignment(mod);
2866 const padding_len = offset - prev_offset;3284 if (field_align < field_ty_align) struct_kind = .@"packed";
2867 if (padding_len > 0) {3285 big_align = @max(big_align, field_align);
2868 const llvm_array_ty = o.context.intType(8).arrayType(@as(c_uint, @intCast(padding_len)));3286 const prev_offset = offset;
2869 try llvm_field_types.append(gpa, llvm_array_ty);3287 offset = std.mem.alignForward(u64, offset, field_align);
2870 }
2871 }
28723288
2873 llvm_struct_ty.structSetBody(3289 const padding_len = offset - prev_offset;
2874 llvm_field_types.items.ptr,3290 if (padding_len > 0) try llvm_field_types.append(
2875 @as(c_uint, @intCast(llvm_field_types.items.len)),3291 o.gpa,
2876 .False,3292 try o.builder.arrayType(padding_len, .i8),
2877 );3293 );
3294 try llvm_field_types.append(o.gpa, try o.lowerType(field.ty));
28783295
2879 return llvm_struct_ty;3296 offset += field.ty.abiSize(mod);
2880 },3297 }
2881 .struct_type => |struct_type| struct_type,3298 {
2882 else => unreachable,3299 const prev_offset = offset;
2883 };3300 offset = std.mem.alignForward(u64, offset, big_align);
28843301 const padding_len = offset - prev_offset;
2885 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;3302 if (padding_len > 0) try llvm_field_types.append(
28863303 o.gpa,
2887 if (struct_obj.layout == .Packed) {3304 try o.builder.arrayType(padding_len, .i8),
2888 assert(struct_obj.haveLayout());3305 );
2889 const int_llvm_ty = try o.lowerType(struct_obj.backing_int_ty);3306 }
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));
28953307
2896 const llvm_struct_ty = o.context.structCreateNamed(name);3308 try o.builder.namedTypeSetBody(
2897 gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls3309 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) = .{};3323 for (anon_struct_type.types, anon_struct_type.values) |field_ty, field_val| {
2902 defer llvm_field_types.deinit(gpa);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);3331 const padding_len = offset - prev_offset;
2907 var offset: u64 = 0;3332 if (padding_len > 0) try llvm_field_types.append(
2908 var big_align: u32 = 1;3333 o.gpa,
2909 var any_underaligned_fields = false;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);3338 offset += field_ty.toType().abiSize(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);
2926 }3339 }
2927 const field_llvm_ty = try o.lowerType(field.ty);3340 {
2928 try llvm_field_types.append(gpa, field_llvm_ty);3341 const prev_offset = offset;
29293342 offset = std.mem.alignForward(u64, offset, big_align);
2930 offset += field.ty.abiSize(mod);3343 const padding_len = offset - prev_offset;
2931 }3344 if (padding_len > 0) try llvm_field_types.append(
2932 {3345 o.gpa,
2933 const prev_offset = offset;3346 try o.builder.arrayType(padding_len, .i8),
2934 offset = std.mem.alignForward(u64, offset, big_align);3347 );
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);
2939 }3348 }
2940 }3349 return o.builder.structType(.normal, llvm_field_types.items);
29413350 },
2942 llvm_struct_ty.structSetBody(3351 .union_type => |union_type| {
2943 llvm_field_types.items.ptr,3352 const gop = try o.type_map.getOrPut(o.gpa, t.toIntern());
2944 @as(c_uint, @intCast(llvm_field_types.items.len)),3353 if (gop.found_existing) return gop.value_ptr.*;
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.*;
29533354
2954 const layout = t.unionGetLayout(mod);3355 const union_obj = mod.unionPtr(union_type.index);
2955 const union_obj = mod.typeToUnion(t).?;3356 const layout = union_obj.getLayout(mod, union_type.hasTag());
29563357
2957 if (union_obj.layout == .Packed) {3358 if (union_obj.layout == .Packed) {
2958 const bitsize = @as(c_uint, @intCast(t.bitSize(mod)));3359 const int_ty = try o.builder.intType(@intCast(t.bitSize(mod)));
2959 const int_llvm_ty = o.context.intType(bitsize);3360 gop.value_ptr.* = int_ty;
2960 gop.value_ptr.* = int_llvm_ty;3361 return int_ty;
2961 return int_llvm_ty;3362 }
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 }
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);3370 const name = try o.builder.string(mod.intern_pool.stringToSlice(
2973 gop.value_ptr.* = llvm_union_ty; // must be done before any recursive calls3371 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];3376 const aligned_field = union_obj.fields.values()[layout.most_aligned_field];
2976 const llvm_aligned_field_ty = try o.lowerType(aligned_field.ty);3377 const aligned_field_ty = try o.lowerType(aligned_field.ty);
29773378
2978 const llvm_payload_ty = t: {3379 const payload_ty = ty: {
2979 if (layout.most_aligned_field_size == layout.payload_size) {3380 if (layout.most_aligned_field_size == layout.payload_size) {
2980 break :t llvm_aligned_field_ty;3381 break :ty aligned_field_ty;
2981 }3382 }
2982 const padding_len = if (layout.tag_size == 0)3383 const padding_len = if (layout.tag_size == 0)
2983 @as(c_uint, @intCast(layout.abi_size - layout.most_aligned_field_size))3384 layout.abi_size - layout.most_aligned_field_size
2984 else3385 else
2985 @as(c_uint, @intCast(layout.payload_size - layout.most_aligned_field_size));3386 layout.payload_size - layout.most_aligned_field_size;
2986 const fields: [2]*llvm.Type = .{3387 break :ty try o.builder.structType(.@"packed", &.{
2987 llvm_aligned_field_ty,3388 aligned_field_ty,
2988 o.context.intType(8).arrayType(padding_len),3389 try o.builder.arrayType(padding_len, .i8),
3390 });
2989 };3391 };
2990 break :t o.context.structType(&fields, fields.len, .True);
2991 };
29923392
2993 if (layout.tag_size == 0) {3393 if (layout.tag_size == 0) {
2994 var llvm_fields: [1]*llvm.Type = .{llvm_payload_ty};3394 try o.builder.namedTypeSetBody(
2995 llvm_union_ty.structSetBody(&llvm_fields, llvm_fields.len, .False);3395 ty,
2996 return llvm_union_ty;3396 try o.builder.structType(.normal, &.{payload_ty}),
2997 }3397 );
2998 const enum_tag_llvm_ty = try o.lowerType(union_obj.tag_ty);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's3402 // Put the tag before or after the payload depending on which one's
3001 // alignment is greater.3403 // alignment is greater.
3002 var llvm_fields: [3]*llvm.Type = undefined;3404 var llvm_fields: [3]Builder.Type = undefined;
3003 var llvm_fields_len: c_uint = 2;3405 var llvm_fields_len: usize = 2;
30043406
3005 if (layout.tag_align >= layout.payload_align) {3407 if (layout.tag_align >= layout.payload_align) {
3006 llvm_fields = .{ enum_tag_llvm_ty, llvm_payload_ty, undefined };3408 llvm_fields = .{ enum_tag_ty, payload_ty, .none };
3007 } else {3409 } else {
3008 llvm_fields = .{ llvm_payload_ty, enum_tag_llvm_ty, undefined };3410 llvm_fields = .{ payload_ty, enum_tag_ty, .none };
3009 }3411 }
30103412
3011 // Insert padding to make the LLVM struct ABI size match the Zig union ABI size.3413 // Insert padding to make the LLVM struct ABI size match the Zig union ABI size.
3012 if (layout.padding != 0) {3414 if (layout.padding != 0) {
3013 llvm_fields[2] = o.context.intType(8).arrayType(layout.padding);3415 llvm_fields[llvm_fields_len] = try o.builder.arrayType(layout.padding, .i8);
3014 llvm_fields_len = 3;3416 llvm_fields_len += 1;
3015 }3417 }
30163418
3017 llvm_union_ty.structSetBody(&llvm_fields, llvm_fields_len, .False);3419 try o.builder.namedTypeSetBody(
3018 return llvm_union_ty;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,
3019 },3459 },
3020 .Fn => return lowerTypeFn(o, t),3460 };
3021 .ComptimeInt => unreachable,3461 }
3022 .ComptimeFloat => unreachable,
3023 .Type => unreachable,
3024 .Undefined => unreachable,
3025 .Null => unreachable,
3026 .EnumLiteral => unreachable,
30273462
3028 .Frame => @panic("TODO implement llvmType for Frame types"),3463 /// Use this instead of lowerType when you want to handle correctly the case of elem_ty
3029 .AnyFrame => @panic("TODO implement llvmType for AnyFrame types"),3464 /// being a zero bit type, but it should still be lowered as an i8 in such case.
3030 }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;
3031 }3475 }
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 {
3034 const mod = o.module;3478 const mod = o.module;
3035 const ip = &mod.intern_pool;3479 const ip = &mod.intern_pool;
3036 const fn_info = mod.typeToFunc(fn_ty).?;3480 const target = mod.getTarget();
3037 const llvm_ret_ty = try lowerFnRetTy(o, fn_info);3481 const ret_ty = try lowerFnRetTy(o, fn_info);
30383482
3039 var llvm_params = std.ArrayList(*llvm.Type).init(o.gpa);3483 var llvm_params = std.ArrayListUnmanaged(Builder.Type){};
3040 defer llvm_params.deinit();3484 defer llvm_params.deinit(o.gpa);
30413485
3042 if (firstParamSRet(fn_info, mod)) {3486 if (firstParamSRet(fn_info, mod)) {
3043 try llvm_params.append(o.context.pointerType(0));3487 try llvm_params.append(o.gpa, .ptr);
3044 }3488 }
30453489
3046 if (fn_info.return_type.toType().isError(mod) and3490 if (fn_info.return_type.toType().isError(mod) and
3047 mod.comp.bin_file.options.error_return_tracing)3491 mod.comp.bin_file.options.error_return_tracing)
3048 {3492 {
3049 const ptr_ty = try mod.singleMutPtrType(try o.getStackTraceType());3493 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));
3051 }3495 }
30523496
3053 var it = iterateParamTypes(o, fn_info);3497 var it = iterateParamTypes(o, fn_info);
3054 while (it.next()) |lowering| switch (lowering) {3498 while (try it.next()) |lowering| switch (lowering) {
3055 .no_bits => continue,3499 .no_bits => continue,
3056 .byval => {3500 .byval => {
3057 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();3501 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));
3059 },3503 },
3060 .byref, .byref_mut => {3504 .byref, .byref_mut => {
3061 try llvm_params.append(o.context.pointerType(0));3505 try llvm_params.append(o.gpa, .ptr);
3062 },3506 },
3063 .abi_sized_int => {3507 .abi_sized_int => {
3064 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();3508 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)));3509 try llvm_params.append(o.gpa, try o.builder.intType(
3066 try llvm_params.append(o.context.intType(abi_size * 8));3510 @intCast(param_ty.abiSize(mod) * 8),
3511 ));
3067 },3512 },
3068 .slice => {3513 .slice => {
3069 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();3514 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
3070 const ptr_ty = if (param_ty.zigTypeTag(mod) == .Optional)3515 try llvm_params.appendSlice(o.gpa, &.{
3071 param_ty.optionalChild(mod).slicePtrFieldType(mod)3516 try o.builder.ptrType(toLlvmAddressSpace(param_ty.ptrAddressSpace(mod), target)),
3072 else3517 try o.lowerType(Type.usize),
3073 param_ty.slicePtrFieldType(mod);3518 });
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);
3080 },3519 },
3081 .multiple_llvm_types => {3520 .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]);
3083 },3522 },
3084 .as_u16 => {3523 .as_u16 => {
3085 try llvm_params.append(o.context.intType(16));3524 try llvm_params.append(o.gpa, .i16);
3086 },3525 },
3087 .float_array => |count| {3526 .float_array => |count| {
3088 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();3527 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
3089 const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(param_ty, mod).?);3528 const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(param_ty, mod).?);
3090 const field_count = @as(c_uint, @intCast(count));3529 try llvm_params.append(o.gpa, try o.builder.arrayType(count, float_ty));
3091 const arr_ty = float_ty.arrayType(field_count);
3092 try llvm_params.append(arr_ty);
3093 },3530 },
3094 .i32_array, .i64_array => |arr_len| {3531 .i32_array, .i64_array => |arr_len| {
3095 const elem_size: u8 = if (lowering == .i32_array) 32 else 64;3532 try llvm_params.append(o.gpa, try o.builder.arrayType(arr_len, switch (lowering) {
3096 const arr_ty = o.context.intType(elem_size).arrayType(arr_len);3533 .i32_array => .i32,
3097 try llvm_params.append(arr_ty);3534 .i64_array => .i64,
3535 else => unreachable,
3536 }));
3098 },3537 },
3099 };3538 };
31003539
3101 return llvm.functionType(3540 return o.builder.fnType(
3102 llvm_ret_ty,3541 ret_ty,
3103 llvm_params.items.ptr,3542 llvm_params.items,
3104 @as(c_uint, @intCast(llvm_params.items.len)),3543 if (fn_info.is_var_args) .vararg else .normal,
3105 llvm.Bool.fromBool(fn_info.is_var_args),
3106 );3544 );
3107 }3545 }
31083546
3109 /// Use this instead of lowerType when you want to handle correctly the case of elem_ty3547 fn lowerValue(o: *Object, arg_val: InternPool.Index) Error!Builder.Constant {
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 {
3113 const mod = o.module;3548 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;
3131 const target = mod.getTarget();3549 const target = mod.getTarget();
3132 var tv = arg_tv;3550
3133 switch (mod.intern_pool.indexToKey(tv.val.toIntern())) {3551 var val = arg_val.toValue();
3134 .runtime_value => |rt| tv.val = rt.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(),
3135 else => {},3555 else => {},
3136 }3556 }
3137 if (tv.val.isUndefDeep(mod)) {3557 if (val.isUndefDeep(mod)) {
3138 const llvm_type = try o.lowerType(tv.ty);3558 return o.builder.undefConst(try o.lowerType(arg_val_key.typeOf().toType()));
3139 return llvm_type.getUndef();
3140 }3559 }
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) {
3143 .int_type,3564 .int_type,
3144 .ptr_type,3565 .ptr_type,
3145 .array_type,3566 .array_type,
...@@ -3167,10 +3588,8 @@ pub const Object = struct {...@@ -3167,10 +3588,8 @@ pub const Object = struct {
3167 .@"unreachable",3588 .@"unreachable",
3168 .generic_poison,3589 .generic_poison,
3169 => unreachable, // non-runtime values3590 => unreachable, // non-runtime values
3170 .false, .true => {3591 .false => .false,
3171 const llvm_type = try o.lowerType(tv.ty);3592 .true => .true,
3172 return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull();
3173 },
3174 },3593 },
3175 .variable,3594 .variable,
3176 .enum_literal,3595 .enum_literal,
...@@ -3180,309 +3599,276 @@ pub const Object = struct {...@@ -3180,309 +3599,276 @@ pub const Object = struct {
3180 const fn_decl_index = extern_func.decl;3599 const fn_decl_index = extern_func.decl;
3181 const fn_decl = mod.declPtr(fn_decl_index);3600 const fn_decl = mod.declPtr(fn_decl_index);
3182 try mod.markDeclAlive(fn_decl);3601 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();
3184 },3604 },
3185 .func => |func| {3605 .func => |func| {
3186 const fn_decl_index = func.owner_decl;3606 const fn_decl_index = func.owner_decl;
3187 const fn_decl = mod.declPtr(fn_decl_index);3607 const fn_decl = mod.declPtr(fn_decl_index);
3188 try mod.markDeclAlive(fn_decl);3608 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();
3190 },3611 },
3191 .int => {3612 .int => {
3192 var bigint_space: Value.BigIntSpace = undefined;3613 var bigint_space: Value.BigIntSpace = undefined;
3193 const bigint = tv.val.toBigInt(&bigint_space, mod);3614 const bigint = val.toBigInt(&bigint_space, mod);
3194 return lowerBigInt(o, tv.ty, bigint);3615 return lowerBigInt(o, ty, bigint);
3195 },3616 },
3196 .err => |err| {3617 .err => |err| {
3197 const llvm_ty = try o.lowerType(Type.anyerror);
3198 const int = try mod.getErrorValue(err.name);3618 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;
3200 },3621 },
3201 .error_union => |error_union| {3622 .error_union => |error_union| {
3202 const err_tv: TypedValue = switch (error_union.val) {3623 const err_val = switch (error_union.val) {
3203 .err_name => |err_name| .{3624 .err_name => |err_name| try mod.intern(.{ .err = .{
3204 .ty = tv.ty.errorUnionSet(mod),3625 .ty = ty.errorUnionSet(mod).toIntern(),
3205 .val = (try mod.intern(.{ .err = .{3626 .name = err_name,
3206 .ty = tv.ty.errorUnionSet(mod).toIntern(),3627 } }),
3207 .name = err_name,3628 .payload => (try mod.intValue(Type.err_int, 0)).toIntern(),
3208 } })).toValue(),
3209 },
3210 .payload => .{
3211 .ty = Type.err_int,
3212 .val = try mod.intValue(Type.err_int, 0),
3213 },
3214 };3629 };
3215 const payload_type = tv.ty.errorUnionPayload(mod);3630 const payload_type = ty.errorUnionPayload(mod);
3216 if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) {3631 if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) {
3217 // We use the error type directly as the type.3632 // We use the error type directly as the type.
3218 return o.lowerValue(err_tv);3633 return o.lowerValue(err_val);
3219 }3634 }
32203635
3221 const payload_align = payload_type.abiAlignment(mod);3636 const payload_align = payload_type.abiAlignment(mod);
3222 const error_align = err_tv.ty.abiAlignment(mod);3637 const error_align = Type.err_int.abiAlignment(mod);
3223 const llvm_error_value = try o.lowerValue(err_tv);3638 const llvm_error_value = try o.lowerValue(err_val);
3224 const llvm_payload_value = try o.lowerValue(.{3639 const llvm_payload_value = try o.lowerValue(switch (error_union.val) {
3225 .ty = payload_type,3640 .err_name => try mod.intern(.{ .undef = payload_type.toIntern() }),
3226 .val = switch (error_union.val) {3641 .payload => |payload| payload,
3227 .err_name => try mod.intern(.{ .undef = payload_type.toIntern() }),
3228 .payload => |payload| payload,
3229 }.toValue(),
3230 });3642 });
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;
3240 if (error_align > payload_align) {3646 if (error_align > payload_align) {
3241 fields_buf[0] = llvm_error_value;3647 vals[0] = llvm_error_value;
3242 fields_buf[1] = llvm_payload_value;3648 vals[1] = llvm_payload_value;
3243 return o.context.constStruct(&fields_buf, llvm_field_count, .False);
3244 } else {3649 } else {
3245 fields_buf[0] = llvm_payload_value;3650 vals[0] = llvm_payload_value;
3246 fields_buf[1] = llvm_error_value;3651 vals[1] = llvm_error_value;
3247 return o.context.constStruct(&fields_buf, llvm_field_count, .False);
3248 }3652 }
3249 },3653 fields[0] = vals[0].typeOf(&o.builder);
3250 .enum_tag => {3654 fields[1] = vals[1].typeOf(&o.builder);
3251 const int_val = try tv.intFromEnum(mod);3655
32523656 const llvm_ty = try o.lowerType(ty);
3253 var bigint_space: Value.BigIntSpace = undefined;3657 const llvm_ty_fields = llvm_ty.structFields(&o.builder);
3254 const bigint = int_val.toBigInt(&bigint_space, mod);3658 if (llvm_ty_fields.len > 2) {
32553659 assert(llvm_ty_fields.len == 3);
3256 const int_info = tv.ty.intInfo(mod);3660 fields[2] = llvm_ty_fields[2];
3257 const llvm_type = o.context.intType(int_info.bits);3661 vals[2] = try o.builder.undefConst(fields[2]);
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);
3273 }3662 }
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]);
3275 },3667 },
3276 .float => {3668 .enum_tag => |enum_tag| o.lowerValue(enum_tag.int),
3277 const llvm_ty = try o.lowerType(tv.ty);3669 .float => switch (ty.floatBits(target)) {
3278 switch (tv.ty.floatBits(target)) {3670 16 => if (backendSupportsF16(target))
3279 16 => {3671 try o.builder.halfConst(val.toFloat(f16, mod))
3280 const repr = @as(u16, @bitCast(tv.val.toFloat(f16, mod)));3672 else
3281 const llvm_i16 = o.context.intType(16);3673 try o.builder.intConst(.i16, @as(i16, @bitCast(val.toFloat(f16, mod)))),
3282 const int = llvm_i16.constInt(repr, .False);3674 32 => try o.builder.floatConst(val.toFloat(f32, mod)),
3283 return int.constBitCast(llvm_ty);3675 64 => try o.builder.doubleConst(val.toFloat(f64, mod)),
3284 },3676 80 => if (backendSupportsF80(target))
3285 32 => {3677 try o.builder.x86_fp80Const(val.toFloat(f80, mod))
3286 const repr = @as(u32, @bitCast(tv.val.toFloat(f32, mod)));3678 else
3287 const llvm_i32 = o.context.intType(32);3679 try o.builder.intConst(.i80, @as(i80, @bitCast(val.toFloat(f80, mod)))),
3288 const int = llvm_i32.constInt(repr, .False);3680 128 => try o.builder.fp128Const(val.toFloat(f128, mod)),
3289 return int.constBitCast(llvm_ty);3681 else => unreachable,
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 }
3322 },3682 },
3323 .ptr => |ptr| {3683 .ptr => |ptr| {
3324 const ptr_tv: TypedValue = switch (ptr.len) {3684 const ptr_ty = switch (ptr.len) {
3325 .none => tv,3685 .none => ty,
3326 else => .{ .ty = tv.ty.slicePtrFieldType(mod), .val = tv.val.slicePtr(mod) },3686 else => ty.slicePtrFieldType(mod),
3327 };3687 };
3328 const llvm_ptr_val = switch (ptr.addr) {3688 const ptr_val = switch (ptr.addr) {
3329 .decl => |decl| try o.lowerDeclRefValue(ptr_tv, decl),3689 .decl => |decl| try o.lowerDeclRefValue(ptr_ty, decl),
3330 .mut_decl => |mut_decl| try o.lowerDeclRefValue(ptr_tv, mut_decl.decl),3690 .mut_decl => |mut_decl| try o.lowerDeclRefValue(ptr_ty, mut_decl.decl),
3331 .int => |int| try o.lowerIntAsPtr(int.toValue()),3691 .int => |int| try o.lowerIntAsPtr(int),
3332 .eu_payload,3692 .eu_payload,
3333 .opt_payload,3693 .opt_payload,
3334 .elem,3694 .elem,
3335 .field,3695 .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),
3337 .comptime_field => unreachable,3697 .comptime_field => unreachable,
3338 };3698 };
3339 switch (ptr.len) {3699 switch (ptr.len) {
3340 .none => return llvm_ptr_val,3700 .none => return ptr_val,
3341 else => {3701 else => return o.builder.structConst(try o.lowerType(ty), &.{
3342 const fields: [2]*llvm.Value = .{3702 ptr_val, try o.lowerValue(ptr.len),
3343 llvm_ptr_val,3703 }),
3344 try o.lowerValue(.{ .ty = Type.usize, .val = ptr.len.toValue() }),
3345 };
3346 return o.context.constStruct(&fields, fields.len, .False);
3347 },
3348 }3704 }
3349 },3705 },
3350 .opt => |opt| {3706 .opt => |opt| {
3351 comptime assert(optional_layout_version == 3);3707 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);3710 const non_null_bit = try o.builder.intConst(.i8, @intFromBool(opt.val != .none));
3355 const non_null_bit = switch (opt.val) {
3356 .none => llvm_i8.constNull(),
3357 else => llvm_i8.constInt(1, .False),
3358 };
3359 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {3711 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
3360 return non_null_bit;3712 return non_null_bit;
3361 }3713 }
3362 const llvm_ty = try o.lowerType(tv.ty);3714 const llvm_ty = try o.lowerType(ty);
3363 if (tv.ty.optionalReprIsPayload(mod)) return switch (opt.val) {3715 if (ty.optionalReprIsPayload(mod)) return switch (opt.val) {
3364 .none => llvm_ty.constNull(),3716 .none => switch (llvm_ty.tag(&o.builder)) {
3365 else => |payload| o.lowerValue(.{ .ty = payload_ty, .val = payload.toValue() }),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),
3366 };3723 };
3367 assert(payload_ty.zigTypeTag(mod) != .Fn);3724 assert(payload_ty.zigTypeTag(mod) != .Fn);
33683725
3369 const llvm_field_count = llvm_ty.countStructElementTypes();3726 var fields: [3]Builder.Type = undefined;
3370 var fields_buf: [3]*llvm.Value = undefined;3727 var vals: [3]Builder.Constant = undefined;
3371 fields_buf[0] = try o.lowerValue(.{3728 vals[0] = try o.lowerValue(switch (opt.val) {
3372 .ty = payload_ty,3729 .none => try mod.intern(.{ .undef = payload_ty.toIntern() }),
3373 .val = switch (opt.val) {3730 else => |payload| payload,
3374 .none => try mod.intern(.{ .undef = payload_ty.toIntern() }),
3375 else => |payload| payload,
3376 }.toValue(),
3377 });3731 });
3378 fields_buf[1] = non_null_bit;3732 vals[1] = non_null_bit;
3379 if (llvm_field_count > 2) {3733 fields[0] = vals[0].typeOf(&o.builder);
3380 assert(llvm_field_count == 3);3734 fields[1] = vals[1].typeOf(&o.builder);
3381 fields_buf[2] = llvm_ty.structGetTypeAtIndex(2).getUndef();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]);
3382 }3741 }
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]);
3384 },3746 },
3385 .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(tv.ty.toIntern())) {3747 .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(ty.toIntern())) {
3386 .array_type => switch (aggregate.storage) {3748 .array_type => |array_type| switch (aggregate.storage) {
3387 .bytes => |bytes| return o.context.constString(3749 .bytes => |bytes| try o.builder.stringConst(try o.builder.string(bytes)),
3388 bytes.ptr,3750 .elems => |elems| {
3389 @as(c_uint, @intCast(tv.ty.arrayLenIncludingSentinel(mod))),3751 const array_ty = try o.lowerType(ty);
3390 .True, // Don't null terminate. Bytes has the sentinel, if any.3752 const elem_ty = array_ty.childType(&o.builder);
3391 ),3753 assert(elems.len == array_ty.aggregateLen(&o.builder));
3392 .elems => |elem_vals| {3754
3393 const elem_ty = tv.ty.childType(mod);3755 const ExpectedContents = extern struct {
3394 const llvm_elems = try gpa.alloc(*llvm.Value, elem_vals.len);3756 vals: [Builder.expected_fields_len]Builder.Constant,
3395 defer gpa.free(llvm_elems);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
3396 var need_unnamed = false;3769 var need_unnamed = false;
3397 for (elem_vals, 0..) |elem_val, i| {3770 for (vals, fields, elems) |*result_val, *result_field, elem| {
3398 llvm_elems[i] = try o.lowerValue(.{ .ty = elem_ty, .val = elem_val.toValue() });3771 result_val.* = try o.lowerValue(elem);
3399 need_unnamed = need_unnamed or o.isUnnamedType(elem_ty, llvm_elems[i]);3772 result_field.* = result_val.typeOf(&o.builder);
3400 }3773 if (result_field.* != elem_ty) need_unnamed = true;
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 );
3413 }3774 }
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);
3414 },3779 },
3415 .repeated_elem => |val| {3780 .repeated_elem => |elem| {
3416 const elem_ty = tv.ty.childType(mod);3781 const len: usize = @intCast(array_type.len);
3417 const sentinel = tv.ty.sentinel(mod);3782 const len_including_sentinel: usize =
3418 const len = @as(usize, @intCast(tv.ty.arrayLen(mod)));3783 @intCast(len + @intFromBool(array_type.sentinel != .none));
3419 const len_including_sent = len + @intFromBool(sentinel != null);3784 const array_ty = try o.lowerType(ty);
3420 const llvm_elems = try gpa.alloc(*llvm.Value, len_including_sent);3785 const elem_ty = array_ty.childType(&o.builder);
3421 defer gpa.free(llvm_elems);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
3423 var need_unnamed = false;3801 var need_unnamed = false;
3424 if (len != 0) {3802 @memset(vals[0..len], try o.lowerValue(elem));
3425 for (llvm_elems[0..len]) |*elem| {3803 @memset(fields[0..len], vals[0].typeOf(&o.builder));
3426 elem.* = try o.lowerValue(.{ .ty = elem_ty, .val = val.toValue() });3804 if (fields[0] != elem_ty) need_unnamed = true;
3427 }3805
3428 need_unnamed = need_unnamed or o.isUnnamedType(elem_ty, llvm_elems[0]);3806 if (array_type.sentinel != .none) {
3429 }3807 vals[len] = try o.lowerValue(array_type.sentinel);
34303808 fields[len] = vals[len].typeOf(&o.builder);
3431 if (sentinel) |sent| {3809 if (fields[len] != elem_ty) need_unnamed = true;
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]);
3434 }3810 }
34353811
3436 if (need_unnamed) {3812 return if (need_unnamed) try o.builder.structConst(
3437 return o.context.constStruct(3813 try o.builder.structType(.@"packed", fields),
3438 llvm_elems.ptr,3814 vals,
3439 @as(c_uint, @intCast(llvm_elems.len)),3815 ) else try o.builder.arrayConst(array_ty, vals);
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 }
3449 },3816 },
3450 },3817 },
3451 .vector_type => |vector_type| {3818 .vector_type => |vector_type| {
3452 const elem_ty = vector_type.child.toType();3819 const vector_ty = try o.lowerType(ty);
3453 const llvm_elems = try gpa.alloc(*llvm.Value, vector_type.len);3820 switch (aggregate.storage) {
3454 defer gpa.free(llvm_elems);3821 .bytes, .elems => {
3455 const llvm_i8 = o.context.intType(8);3822 const ExpectedContents = [Builder.expected_fields_len]Builder.Constant;
3456 for (llvm_elems, 0..) |*llvm_elem, i| {3823 var stack align(@max(
3457 llvm_elem.* = switch (aggregate.storage) {3824 @alignOf(std.heap.StackFallbackAllocator(0)),
3458 .bytes => |bytes| llvm_i8.constInt(bytes[i], .False),3825 @alignOf(ExpectedContents),
3459 .elems => |elems| try o.lowerValue(.{3826 )) = std.heap.stackFallback(@sizeOf(ExpectedContents), o.gpa);
3460 .ty = elem_ty,3827 const allocator = stack.get();
3461 .val = elems[i].toValue(),3828 const vals = try allocator.alloc(Builder.Constant, vector_type.len);
3462 }),3829 defer allocator.free(vals);
3463 .repeated_elem => |elem| try o.lowerValue(.{3830
3464 .ty = elem_ty,3831 switch (aggregate.storage) {
3465 .val = elem.toValue(),3832 .bytes => |bytes| for (vals, bytes) |*result_val, byte| {
3466 }),3833 result_val.* = try o.builder.intConst(.i8, byte);
3467 };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 ),
3468 }3846 }
3469 return llvm.constVector(
3470 llvm_elems.ptr,
3471 @as(c_uint, @intCast(llvm_elems.len)),
3472 );
3473 },3847 },
3474 .anon_struct_type => |tuple| {3848 .anon_struct_type => |tuple| {
3475 var llvm_fields: std.ArrayListUnmanaged(*llvm.Value) = .{};3849 const struct_ty = try o.lowerType(ty);
3476 defer llvm_fields.deinit(gpa);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
3480 comptime assert(struct_layout_version == 2);3866 comptime assert(struct_layout_version == 2);
3867 var llvm_index: usize = 0;
3481 var offset: u64 = 0;3868 var offset: u64 = 0;
3482 var big_align: u32 = 0;3869 var big_align: u32 = 0;
3483 var need_unnamed = false;3870 var need_unnamed = false;
34843871 for (tuple.types, tuple.values, 0..) |field_ty, field_val, field_index| {
3485 for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| {
3486 if (field_val != .none) continue;3872 if (field_val != .none) continue;
3487 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;3873 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
34883874
...@@ -3493,20 +3879,20 @@ pub const Object = struct {...@@ -3493,20 +3879,20 @@ pub const Object = struct {
34933879
3494 const padding_len = offset - prev_offset;3880 const padding_len = offset - prev_offset;
3495 if (padding_len > 0) {3881 if (padding_len > 0) {
3496 const llvm_array_ty = o.context.intType(8).arrayType(@as(c_uint, @intCast(padding_len)));
3497 // TODO make this and all other padding elsewhere in debug3882 // TODO make this and all other padding elsewhere in debug
3498 // builds be 0xaa not undef.3883 // 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;
3500 }3888 }
35013889
3502 const field_llvm_val = try o.lowerValue(.{3890 vals[llvm_index] =
3503 .ty = field_ty.toType(),3891 try o.lowerValue((try val.fieldValue(mod, field_index)).toIntern());
3504 .val = try tv.val.fieldValue(mod, i),3892 fields[llvm_index] = vals[llvm_index].typeOf(&o.builder);
3505 });3893 if (fields[llvm_index] != struct_ty.structFields(&o.builder)[llvm_index])
35063894 need_unnamed = true;
3507 need_unnamed = need_unnamed or o.isUnnamedType(field_ty.toType(), field_llvm_val);3895 llvm_index += 1;
3508
3509 llvm_fields.appendAssumeCapacity(field_llvm_val);
35103896
3511 offset += field_ty.toType().abiSize(mod);3897 offset += field_ty.toType().abiSize(mod);
3512 }3898 }
...@@ -3515,73 +3901,71 @@ pub const Object = struct {...@@ -3515,73 +3901,71 @@ pub const Object = struct {
3515 offset = std.mem.alignForward(u64, offset, big_align);3901 offset = std.mem.alignForward(u64, offset, big_align);
3516 const padding_len = offset - prev_offset;3902 const padding_len = offset - prev_offset;
3517 if (padding_len > 0) {3903 if (padding_len > 0) {
3518 const llvm_array_ty = o.context.intType(8).arrayType(@as(c_uint, @intCast(padding_len)));3904 fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);
3519 llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef());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;
3520 }3908 }
3521 }3909 }
3910 assert(llvm_index == llvm_len);
35223911
3523 if (need_unnamed) {3912 return o.builder.structConst(if (need_unnamed)
3524 return o.context.constStruct(3913 try o.builder.structType(struct_ty.structKind(&o.builder), fields)
3525 llvm_fields.items.ptr,3914 else
3526 @as(c_uint, @intCast(llvm_fields.items.len)),3915 struct_ty, vals);
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 }
3536 },3916 },
3537 .struct_type => |struct_type| {3917 .struct_type => |struct_type| {
3538 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;3918 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3539 const llvm_struct_ty = try o.lowerType(tv.ty);3919 assert(struct_obj.haveLayout());
35403920 const struct_ty = try o.lowerType(ty);
3541 if (struct_obj.layout == .Packed) {3921 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();
3546 comptime assert(Type.packed_struct_layout_version == 2);3922 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);
3548 var running_bits: u16 = 0;3924 var running_bits: u16 = 0;
3549 for (fields, 0..) |field, i| {3925 for (struct_obj.fields.values(), 0..) |field, field_index| {
3550 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;3926 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
35513927
3552 const non_int_val = try o.lowerValue(.{3928 const non_int_val =
3553 .ty = field.ty,3929 try o.lowerValue((try val.fieldValue(mod, field_index)).toIntern());
3554 .val = try tv.val.fieldValue(mod, i),3930 const ty_bit_size: u16 = @intCast(field.ty.bitSize(mod));
3555 });3931 const small_int_ty = try o.builder.intType(ty_bit_size);
3556 const ty_bit_size = @as(u16, @intCast(field.ty.bitSize(mod)));3932 const small_int_val = try o.builder.castConst(
3557 const small_int_ty = o.context.intType(ty_bit_size);3933 if (field.ty.isPtrAtRuntime(mod)) .ptrtoint else .bitcast,
3558 const small_int_val = if (field.ty.isPtrAtRuntime(mod))3934 non_int_val,
3559 non_int_val.constPtrToInt(small_int_ty)3935 small_int_ty,
3560 else3936 );
3561 non_int_val.constBitCast(small_int_ty);3937 const shift_rhs = try o.builder.intConst(struct_ty, running_bits);
3562 const shift_rhs = int_llvm_ty.constInt(running_bits, .False);3938 const extended_int_val =
3563 // If the field is as large as the entire packed struct, this3939 try o.builder.convConst(.unsigned, small_int_val, struct_ty);
3564 // zext would go from, e.g. i16 to i16. This is legal with3940 const shifted = try o.builder.binConst(.shl, extended_int_val, shift_rhs);
3565 // constZExtOrBitCast but not legal with constZExt.3941 running_int = try o.builder.binConst(.@"or", running_int, shifted);
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);
3569 running_bits += ty_bit_size;3942 running_bits += ty_bit_size;
3570 }3943 }
3571 return running_int;3944 return running_int;
3572 }3945 }
3946 const llvm_len = struct_ty.aggregateLen(&o.builder);
35733947
3574 const llvm_field_count = llvm_struct_ty.countStructElementTypes();3948 const ExpectedContents = extern struct {
3575 var llvm_fields = try std.ArrayListUnmanaged(*llvm.Value).initCapacity(gpa, llvm_field_count);3949 vals: [Builder.expected_fields_len]Builder.Constant,
3576 defer llvm_fields.deinit(gpa);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
3578 comptime assert(struct_layout_version == 2);3962 comptime assert(struct_layout_version == 2);
3963 var llvm_index: usize = 0;
3579 var offset: u64 = 0;3964 var offset: u64 = 0;
3580 var big_align: u32 = 0;3965 var big_align: u32 = 0;
3581 var need_unnamed = false;3966 var need_unnamed = false;
35823967 var field_it = struct_obj.runtimeFieldIterator(mod);
3583 var it = struct_obj.runtimeFieldIterator(mod);3968 while (field_it.next()) |field_and_index| {
3584 while (it.next()) |field_and_index| {
3585 const field = field_and_index.field;3969 const field = field_and_index.field;
3586 const field_align = field.alignment(mod, struct_obj.layout);3970 const field_align = field.alignment(mod, struct_obj.layout);
3587 big_align = @max(big_align, field_align);3971 big_align = @max(big_align, field_align);
...@@ -3590,20 +3974,22 @@ pub const Object = struct {...@@ -3590,20 +3974,22 @@ pub const Object = struct {
35903974
3591 const padding_len = offset - prev_offset;3975 const padding_len = offset - prev_offset;
3592 if (padding_len > 0) {3976 if (padding_len > 0) {
3593 const llvm_array_ty = o.context.intType(8).arrayType(@as(c_uint, @intCast(padding_len)));
3594 // TODO make this and all other padding elsewhere in debug3977 // TODO make this and all other padding elsewhere in debug
3595 // builds be 0xaa not undef.3978 // 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;
3597 }3984 }
35983985
3599 const field_llvm_val = try o.lowerValue(.{3986 vals[llvm_index] = try o.lowerValue(
3600 .ty = field.ty,3987 (try val.fieldValue(mod, field_and_index.index)).toIntern(),
3601 .val = try tv.val.fieldValue(mod, field_and_index.index),3988 );
3602 });3989 fields[llvm_index] = vals[llvm_index].typeOf(&o.builder);
36033990 if (fields[llvm_index] != struct_ty.structFields(&o.builder)[llvm_index])
3604 need_unnamed = need_unnamed or o.isUnnamedType(field.ty, field_llvm_val);3991 need_unnamed = true;
36053992 llvm_index += 1;
3606 llvm_fields.appendAssumeCapacity(field_llvm_val);
36073993
3608 offset += field.ty.abiSize(mod);3994 offset += field.ty.abiSize(mod);
3609 }3995 }
...@@ -3612,202 +3998,158 @@ pub const Object = struct {...@@ -3612,202 +3998,158 @@ pub const Object = struct {
3612 offset = std.mem.alignForward(u64, offset, big_align);3998 offset = std.mem.alignForward(u64, offset, big_align);
3613 const padding_len = offset - prev_offset;3999 const padding_len = offset - prev_offset;
3614 if (padding_len > 0) {4000 if (padding_len > 0) {
3615 const llvm_array_ty = o.context.intType(8).arrayType(@as(c_uint, @intCast(padding_len)));4001 fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);
3616 llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef());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;
3617 }4005 }
3618 }4006 }
4007 assert(llvm_index == llvm_len);
36194008
3620 if (need_unnamed) {4009 return o.builder.structConst(if (need_unnamed)
3621 return o.context.constStruct(4010 try o.builder.structType(struct_ty.structKind(&o.builder), fields)
3622 llvm_fields.items.ptr,4011 else
3623 @as(c_uint, @intCast(llvm_fields.items.len)),4012 struct_ty, vals);
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 }
3632 },4013 },
3633 else => unreachable,4014 else => unreachable,
3634 },4015 },
3635 .un => {4016 .un => |un| {
3636 const llvm_union_ty = try o.lowerType(tv.ty);4017 const union_ty = try o.lowerType(ty);
3637 const tag_and_val: Value.Payload.Union.Data = switch (tv.val.toIntern()) {4018 const layout = ty.unionGetLayout(mod);
3638 .none => tv.val.castTag(.@"union").?.data,4019 if (layout.payload_size == 0) return o.lowerValue(un.tag);
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);
36464020
3647 if (layout.payload_size == 0) {4021 const union_obj = mod.typeToUnion(ty).?;
3648 return lowerValue(o, .{4022 const field_index = ty.unionTagFieldIndex(un.tag.toValue(), o.module).?;
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).?;
3655 assert(union_obj.haveFieldTypes());4023 assert(union_obj.haveFieldTypes());
36564024
3657 const field_ty = union_obj.fields.values()[field_index].ty;4025 const field_ty = union_obj.fields.values()[field_index].ty;
3658 if (union_obj.layout == .Packed) {4026 if (union_obj.layout == .Packed) {
3659 if (!field_ty.hasRuntimeBits(mod))4027 if (!field_ty.hasRuntimeBits(mod)) return o.builder.intConst(union_ty, 0);
3660 return llvm_union_ty.constNull();4028 const small_int_val = try o.builder.castConst(
3661 const non_int_val = try lowerValue(o, .{ .ty = field_ty, .val = tag_and_val.val });4029 if (field_ty.isPtrAtRuntime(mod)) .ptrtoint else .bitcast,
3662 const ty_bit_size = @as(u16, @intCast(field_ty.bitSize(mod)));4030 try o.lowerValue(un.val),
3663 const small_int_ty = o.context.intType(ty_bit_size);4031 try o.builder.intType(@intCast(field_ty.bitSize(mod))),
3664 const small_int_val = if (field_ty.isPtrAtRuntime(mod))4032 );
3665 non_int_val.constPtrToInt(small_int_ty)4033 return o.builder.convConst(.unsigned, small_int_val, union_ty);
3666 else
3667 non_int_val.constBitCast(small_int_ty);
3668 return small_int_val.constZExtOrBitCast(llvm_union_ty);
3669 }4034 }
36704035
3671 // Sometimes we must make an unnamed struct because LLVM does4036 // Sometimes we must make an unnamed struct because LLVM does
3672 // not support bitcasting our payload struct to the true union payload type.4037 // not support bitcasting our payload struct to the true union payload type.
3673 // Instead we use an unnamed struct and every reference to the global4038 // Instead we use an unnamed struct and every reference to the global
3674 // must pointer cast to the expected type before accessing the union.4039 // 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;
3676 const payload = p: {4041 const payload = p: {
3677 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) {4042 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) {
3678 const padding_len = @as(c_uint, @intCast(layout.payload_size));4043 const padding_len = layout.payload_size;
3679 break :p o.context.intType(8).arrayType(padding_len).getUndef();4044 break :p try o.builder.undefConst(try o.builder.arrayType(padding_len, .i8));
3680 }4045 }
3681 const field = try lowerValue(o, .{ .ty = field_ty, .val = tag_and_val.val });4046 const payload = try o.lowerValue(un.val);
3682 need_unnamed = need_unnamed or o.isUnnamedType(field_ty, field);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;
3683 const field_size = field_ty.abiSize(mod);4051 const field_size = field_ty.abiSize(mod);
3684 if (field_size == layout.payload_size) {4052 if (field_size == layout.payload_size) break :p payload;
3685 break :p field;4053 const padding_len = layout.payload_size - field_size;
3686 }4054 const padding_ty = try o.builder.arrayType(padding_len, .i8);
3687 const padding_len = @as(c_uint, @intCast(layout.payload_size - field_size));4055 break :p try o.builder.structConst(
3688 const fields: [2]*llvm.Value = .{4056 try o.builder.structType(.@"packed", &.{ payload_ty, padding_ty }),
3689 field, o.context.intType(8).arrayType(padding_len).getUndef(),4057 &.{ payload, try o.builder.undefConst(padding_ty) },
3690 };4058 );
3691 break :p o.context.constStruct(&fields, fields.len, .True);
3692 };4059 };
4060 const payload_ty = payload.typeOf(&o.builder);
36934061
3694 if (layout.tag_size == 0) {4062 if (layout.tag_size == 0) return o.builder.structConst(if (need_unnamed)
3695 const fields: [1]*llvm.Value = .{payload};4063 try o.builder.structType(union_ty.structKind(&o.builder), &.{payload_ty})
3696 if (need_unnamed) {4064 else
3697 return o.context.constStruct(&fields, fields.len, .False);4065 union_ty, &.{payload});
3698 } else {4066 const tag = try o.lowerValue(un.tag);
3699 return llvm_union_ty.constNamedStruct(&fields, fields.len);4067 const tag_ty = tag.typeOf(&o.builder);
3700 }4068 var fields: [3]Builder.Type = undefined;
3701 }4069 var vals: [3]Builder.Constant = undefined;
3702 const llvm_tag_value = try lowerValue(o, .{4070 var len: usize = 2;
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;
3708 if (layout.tag_align >= layout.payload_align) {4071 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 };
3710 } else {4074 } else {
3711 fields = .{ payload, llvm_tag_value, undefined };4075 fields = .{ payload_ty, tag_ty, undefined };
4076 vals = .{ payload, tag, undefined };
3712 }4077 }
3713 if (layout.padding != 0) {4078 if (layout.padding != 0) {
3714 fields[2] = o.context.intType(8).arrayType(layout.padding).getUndef();4079 fields[2] = try o.builder.arrayType(layout.padding, .i8);
3715 fields_len = 3;4080 vals[2] = try o.builder.undefConst(fields[2]);
3716 }4081 len = 3;
3717 if (need_unnamed) {
3718 return o.context.constStruct(&fields, fields_len, .False);
3719 } else {
3720 return llvm_union_ty.constNamedStruct(&fields, fields_len);
3721 }4082 }
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]);
3722 },4087 },
3723 .memoized_call => unreachable,4088 .memoized_call => unreachable,
3724 }4089 };
3725 }4090 }
37264091
3727 fn lowerIntAsPtr(o: *Object, val: Value) Error!*llvm.Value {4092 fn lowerIntAsPtr(o: *Object, val: InternPool.Index) Allocator.Error!Builder.Constant {
3728 const mod = o.module;4093 const mod = o.module;
3729 switch (mod.intern_pool.indexToKey(val.toIntern())) {4094 switch (mod.intern_pool.indexToKey(val)) {
3730 .undef => return o.context.pointerType(0).getUndef(),4095 .undef => return o.builder.undefConst(.ptr),
3731 .int => {4096 .int => {
3732 var bigint_space: Value.BigIntSpace = undefined;4097 var bigint_space: Value.BigIntSpace = undefined;
3733 const bigint = val.toBigInt(&bigint_space, mod);4098 const bigint = val.toValue().toBigInt(&bigint_space, mod);
3734 const llvm_int = lowerBigInt(o, Type.usize, bigint);4099 const llvm_int = try lowerBigInt(o, Type.usize, bigint);
3735 return llvm_int.constIntToPtr(o.context.pointerType(0));4100 return o.builder.castConst(.inttoptr, llvm_int, .ptr);
3736 },4101 },
3737 else => unreachable,4102 else => unreachable,
3738 }4103 }
3739 }4104 }
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 {
3742 const mod = o.module;4111 const mod = o.module;
3743 const int_info = ty.intInfo(mod);4112 return o.builder.bigIntConst(try o.builder.intType(ty.intInfo(mod).bits), bigint);
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;
3763 }4113 }
37644114
3765 const ParentPtr = struct {4115 const ParentPtr = struct {
3766 ty: Type,4116 ty: Type,
3767 llvm_ptr: *llvm.Value,4117 llvm_ptr: Builder.Value,
3768 };4118 };
37694119
3770 fn lowerParentPtrDecl(4120 fn lowerParentPtrDecl(o: *Object, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant {
3771 o: *Object,
3772 ptr_val: Value,
3773 decl_index: Module.Decl.Index,
3774 ) Error!*llvm.Value {
3775 const mod = o.module;4121 const mod = o.module;
3776 const decl = mod.declPtr(decl_index);4122 const decl = mod.declPtr(decl_index);
3777 try mod.markDeclAlive(decl);4123 try mod.markDeclAlive(decl);
3778 const ptr_ty = try mod.singleMutPtrType(decl.ty);4124 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);
3780 }4126 }
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 {
3783 const mod = o.module;4129 const mod = o.module;
3784 const target = mod.getTarget();
3785 return switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) {4130 return switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) {
3786 .decl => |decl| o.lowerParentPtrDecl(ptr_val, decl),4131 .decl => |decl| o.lowerParentPtrDecl(decl),
3787 .mut_decl => |mut_decl| o.lowerParentPtrDecl(ptr_val, mut_decl.decl),4132 .mut_decl => |mut_decl| o.lowerParentPtrDecl(mut_decl.decl),
3788 .int => |int| o.lowerIntAsPtr(int.toValue()),4133 .int => |int| try o.lowerIntAsPtr(int),
3789 .eu_payload => |eu_ptr| {4134 .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
3792 const eu_ty = mod.intern_pool.typeOf(eu_ptr).toType().childType(mod);4137 const eu_ty = mod.intern_pool.typeOf(eu_ptr).toType().childType(mod);
3793 const payload_ty = eu_ty.errorUnionPayload(mod);4138 const payload_ty = eu_ty.errorUnionPayload(mod);
3794 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {4139 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
3795 // In this case, we represent pointer to error union the same as pointer4140 // In this case, we represent pointer to error union the same as pointer
3796 // to the payload.4141 // to the payload.
3797 return parent_llvm_ptr;4142 return parent_ptr;
3798 }4143 }
37994144
3800 const payload_offset: u8 = if (payload_ty.abiAlignment(mod) > Type.anyerror.abiSize(mod)) 2 else 1;4145 const index: u32 =
3801 const llvm_u32 = o.context.intType(32);4146 if (payload_ty.abiAlignment(mod) > Type.err_int.abiSize(mod)) 2 else 1;
3802 const indices: [2]*llvm.Value = .{4147 return o.builder.gepConst(.inbounds, try o.lowerType(eu_ty), parent_ptr, null, &.{
3803 llvm_u32.constInt(0, .False),4148 try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, index),
3804 llvm_u32.constInt(payload_offset, .False),4149 });
3805 };
3806 const eu_llvm_ty = try o.lowerType(eu_ty);
3807 return eu_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
3808 },4150 },
3809 .opt_payload => |opt_ptr| {4151 .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
3812 const opt_ty = mod.intern_pool.typeOf(opt_ptr).toType().childType(mod);4154 const opt_ty = mod.intern_pool.typeOf(opt_ptr).toType().childType(mod);
3813 const payload_ty = opt_ty.optionalChild(mod);4155 const payload_ty = opt_ty.optionalChild(mod);
...@@ -3816,99 +4158,89 @@ pub const Object = struct {...@@ -3816,99 +4158,89 @@ pub const Object = struct {
3816 {4158 {
3817 // In this case, we represent pointer to optional the same as pointer4159 // In this case, we represent pointer to optional the same as pointer
3818 // to the payload.4160 // to the payload.
3819 return parent_llvm_ptr;4161 return parent_ptr;
3820 }4162 }
38214163
3822 const llvm_u32 = o.context.intType(32);4164 return o.builder.gepConst(.inbounds, try o.lowerType(opt_ty), parent_ptr, null, &.{
3823 const indices: [2]*llvm.Value = .{4165 try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, 0),
3824 llvm_u32.constInt(0, .False),4166 });
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);
3829 },4167 },
3830 .comptime_field => unreachable,4168 .comptime_field => unreachable,
3831 .elem => |elem_ptr| {4169 .elem => |elem_ptr| {
3832 const parent_llvm_ptr = try o.lowerParentPtr(elem_ptr.base.toValue(), true);4170 const parent_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 };
3838 const elem_ty = mod.intern_pool.typeOf(elem_ptr.base).toType().elemType2(mod);4171 const elem_ty = mod.intern_pool.typeOf(elem_ptr.base).toType().elemType2(mod);
3839 const elem_llvm_ty = try o.lowerType(elem_ty);4172
3840 return elem_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);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 });
3841 },4176 },
3842 .field => |field_ptr| {4177 .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);
3844 const parent_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod);4179 const parent_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod);
38454180
3846 const field_index = @as(u32, @intCast(field_ptr.index));4181 const field_index: u32 = @intCast(field_ptr.index);
3847 const llvm_u32 = o.context.intType(32);
3848 switch (parent_ty.zigTypeTag(mod)) {4182 switch (parent_ty.zigTypeTag(mod)) {
3849 .Union => {4183 .Union => {
3850 if (parent_ty.containerLayout(mod) == .Packed) {4184 if (parent_ty.containerLayout(mod) == .Packed) {
3851 return parent_llvm_ptr;4185 return parent_ptr;
3852 }4186 }
38534187
3854 const layout = parent_ty.unionGetLayout(mod);4188 const layout = parent_ty.unionGetLayout(mod);
3855 if (layout.payload_size == 0) {4189 if (layout.payload_size == 0) {
3856 // In this case a pointer to the union and a pointer to any4190 // In this case a pointer to the union and a pointer to any
3857 // (void) payload is the same.4191 // (void) payload is the same.
3858 return parent_llvm_ptr;4192 return parent_ptr;
3859 }4193 }
3860 const llvm_pl_index = if (layout.tag_size == 0)4194
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 };
3868 const parent_llvm_ty = try o.lowerType(parent_ty);4195 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 });
3870 },4201 },
3871 .Struct => {4202 .Struct => {
3872 if (parent_ty.containerLayout(mod) == .Packed) {4203 if (parent_ty.containerLayout(mod) == .Packed) {
3873 if (!byte_aligned) return parent_llvm_ptr;4204 if (!byte_aligned) return parent_ptr;
3874 const llvm_usize = o.context.intType(target.ptrBitWidth());4205 const llvm_usize = try o.lowerType(Type.usize);
3875 const base_addr = parent_llvm_ptr.constPtrToInt(llvm_usize);4206 const base_addr =
4207 try o.builder.castConst(.ptrtoint, parent_ptr, llvm_usize);
3876 // count bits of fields before this one4208 // count bits of fields before this one
3877 const prev_bits = b: {4209 const prev_bits = b: {
3878 var b: usize = 0;4210 var b: usize = 0;
3879 for (parent_ty.structFields(mod).values()[0..field_index]) |field| {4211 for (parent_ty.structFields(mod).values()[0..field_index]) |field| {
3880 if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;4212 if (field.is_comptime) continue;
3881 b += @as(usize, @intCast(field.ty.bitSize(mod)));4213 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
4214 b += @intCast(field.ty.bitSize(mod));
3882 }4215 }
3883 break :b b;4216 break :b b;
3884 };4217 };
3885 const byte_offset = llvm_usize.constInt(prev_bits / 8, .False);4218 const byte_offset = try o.builder.intConst(llvm_usize, prev_bits / 8);
3886 const field_addr = base_addr.constAdd(byte_offset);4219 const field_addr = try o.builder.binConst(.add, base_addr, byte_offset);
3887 const final_llvm_ty = o.context.pointerType(0);4220 return o.builder.castConst(.inttoptr, field_addr, .ptr);
3888 return field_addr.constIntToPtr(final_llvm_ty);
3889 }4221 }
38904222
3891 const parent_llvm_ty = try o.lowerType(parent_ty);4223 return o.builder.gepConst(
3892 if (llvmField(parent_ty, field_index, mod)) |llvm_field| {4224 .inbounds,
3893 const indices: [2]*llvm.Value = .{4225 try o.lowerType(parent_ty),
3894 llvm_u32.constInt(0, .False),4226 parent_ptr,
3895 llvm_u32.constInt(llvm_field.index, .False),4227 null,
3896 };4228 if (llvmField(parent_ty, field_index, mod)) |llvm_field| &.{
3897 return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);4229 try o.builder.intConst(.i32, 0),
3898 } else {4230 try o.builder.intConst(.i32, llvm_field.index),
3899 const llvm_index = llvm_u32.constInt(@intFromBool(parent_ty.hasRuntimeBitsIgnoreComptime(mod)), .False);4231 } else &.{
3900 const indices: [1]*llvm.Value = .{llvm_index};4232 try o.builder.intConst(.i32, @intFromBool(
3901 return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);4233 parent_ty.hasRuntimeBitsIgnoreComptime(mod),
3902 }4234 )),
4235 },
4236 );
3903 },4237 },
3904 .Pointer => {4238 .Pointer => {
3905 assert(parent_ty.isSlice(mod));4239 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 };
3910 const parent_llvm_ty = try o.lowerType(parent_ty);4240 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 });
3912 },4244 },
3913 else => unreachable,4245 else => unreachable,
3914 }4246 }
...@@ -3916,11 +4248,7 @@ pub const Object = struct {...@@ -3916,11 +4248,7 @@ pub const Object = struct {
3916 };4248 };
3917 }4249 }
39184250
3919 fn lowerDeclRefValue(4251 fn lowerDeclRefValue(o: *Object, ty: Type, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant {
3920 o: *Object,
3921 tv: TypedValue,
3922 decl_index: Module.Decl.Index,
3923 ) Error!*llvm.Value {
3924 const mod = o.module;4252 const mod = o.module;
39254253
3926 // In the case of something like:4254 // In the case of something like:
...@@ -3931,69 +4259,59 @@ pub const Object = struct {...@@ -3931,69 +4259,59 @@ pub const Object = struct {
3931 const decl = mod.declPtr(decl_index);4259 const decl = mod.declPtr(decl_index);
3932 if (decl.val.getFunction(mod)) |func| {4260 if (decl.val.getFunction(mod)) |func| {
3933 if (func.owner_decl != decl_index) {4261 if (func.owner_decl != decl_index) {
3934 return o.lowerDeclRefValue(tv, func.owner_decl);4262 return o.lowerDeclRefValue(ty, func.owner_decl);
3935 }4263 }
3936 } else if (decl.val.getExternFunc(mod)) |func| {4264 } else if (decl.val.getExternFunc(mod)) |func| {
3937 if (func.decl != decl_index) {4265 if (func.decl != decl_index) {
3938 return o.lowerDeclRefValue(tv, func.decl);4266 return o.lowerDeclRefValue(ty, func.decl);
3939 }4267 }
3940 }4268 }
39414269
3942 const is_fn_body = decl.ty.zigTypeTag(mod) == .Fn;4270 const is_fn_body = decl.ty.zigTypeTag(mod) == .Fn;
3943 if ((!is_fn_body and !decl.ty.hasRuntimeBits(mod)) or4271 if ((!is_fn_body and !decl.ty.hasRuntimeBits(mod)) or
3944 (is_fn_body and mod.typeToFunc(decl.ty).?.is_generic))4272 (is_fn_body and mod.typeToFunc(decl.ty).?.is_generic)) return o.lowerPtrToVoid(ty);
3945 {
3946 return o.lowerPtrToVoid(tv.ty);
3947 }
39484273
3949 try mod.markDeclAlive(decl);4274 try mod.markDeclAlive(decl);
39504275
3951 const llvm_decl_val = if (is_fn_body)4276 const llvm_global = if (is_fn_body)
3952 try o.resolveLlvmFunction(decl_index)4277 (try o.resolveLlvmFunction(decl_index)).ptrConst(&o.builder).global
3953 else4278 else
3954 try o.resolveGlobalDecl(decl_index);4279 (try o.resolveGlobalDecl(decl_index)).ptrConst(&o.builder).global;
39554280
3956 const target = mod.getTarget();4281 const llvm_val = try o.builder.convConst(
3957 const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);4282 .unneeded,
3958 const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);4283 llvm_global.toConst(),
3959 const llvm_val = if (llvm_wanted_addrspace != llvm_actual_addrspace) blk: {4284 try o.builder.ptrType(toLlvmAddressSpace(decl.@"addrspace", mod.getTarget())),
3960 const llvm_decl_wanted_ptr_ty = o.context.pointerType(llvm_wanted_addrspace);4285 );
3961 break :blk llvm_decl_val.constAddrSpaceCast(llvm_decl_wanted_ptr_ty);4286
3962 } else llvm_decl_val;4287 return o.builder.convConst(if (ty.isAbiInt(mod)) switch (ty.intInfo(mod).signedness) {
39634288 .signed => .signed,
3964 const llvm_type = try o.lowerType(tv.ty);4289 .unsigned => .unsigned,
3965 if (tv.ty.zigTypeTag(mod) == .Int) {4290 } else .unneeded, llvm_val, try o.lowerType(ty));
3966 return llvm_val.constPtrToInt(llvm_type);
3967 } else {
3968 return llvm_val.constBitCast(llvm_type);
3969 }
3970 }4291 }
39714292
3972 fn lowerPtrToVoid(o: *Object, ptr_ty: Type) !*llvm.Value {4293 fn lowerPtrToVoid(o: *Object, ptr_ty: Type) Allocator.Error!Builder.Constant {
3973 const mod = o.module;4294 const mod = o.module;
3974 // Even though we are pointing at something which has zero bits (e.g. `void`),4295 // Even though we are pointing at something which has zero bits (e.g. `void`),
3975 // Pointers are defined to have bits. So we must return something here.4296 // Pointers are defined to have bits. So we must return something here.
3976 // The value cannot be undefined, because we use the `nonnull` annotation4297 // The value cannot be undefined, because we use the `nonnull` annotation
3977 // for non-optional pointers. We also need to respect the alignment, even though4298 // for non-optional pointers. We also need to respect the alignment, even though
3978 // the address will never be dereferenced.4299 // the address will never be dereferenced.
3979 const llvm_usize = try o.lowerType(Type.usize);4300 const int: u64 = ptr_ty.ptrInfo(mod).flags.alignment.toByteUnitsOptional() orelse
3980 const llvm_ptr_ty = try o.lowerType(ptr_ty);4301 // Note that these 0xaa values are appropriate even in release-optimized builds
3981 if (ptr_ty.ptrInfo(mod).flags.alignment.toByteUnitsOptional()) |alignment| {4302 // because we need a well-defined value that is not null, and LLVM does not
3982 return llvm_usize.constInt(alignment, .False).constIntToPtr(llvm_ptr_ty);4303 // have an "undef_but_not_null" attribute. As an example, if this `alloc` AIR
3983 }4304 // instruction is followed by a `wrap_optional`, it will return this value
3984 // Note that these 0xaa values are appropriate even in release-optimized builds4305 // verbatim, and the result should test as non-null.
3985 // because we need a well-defined value that is not null, and LLVM does not4306 switch (mod.getTarget().ptrBitWidth()) {
3986 // have an "undef_but_not_null" attribute. As an example, if this `alloc` AIR4307 16 => 0xaaaa,
3987 // instruction is followed by a `wrap_optional`, it will return this value4308 32 => 0xaaaaaaaa,
3988 // verbatim, and the result should test as non-null.4309 64 => 0xaaaaaaaa_aaaaaaaa,
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),
3994 else => unreachable,4310 else => unreachable,
3995 };4311 };
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);
3997 }4315 }
39984316
3999 fn addAttr(o: *Object, val: *llvm.Value, index: llvm.AttributeIndex, name: []const u8) void {4317 fn addAttr(o: *Object, val: *llvm.Value, index: llvm.AttributeIndex, name: []const u8) void {
...@@ -4023,7 +4341,7 @@ pub const Object = struct {...@@ -4023,7 +4341,7 @@ pub const Object = struct {
4023 ) void {4341 ) void {
4024 const kind_id = llvm.getEnumAttributeKindForName(name.ptr, name.len);4342 const kind_id = llvm.getEnumAttributeKindForName(name.ptr, name.len);
4025 assert(kind_id != 0);4343 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);
4027 val.addAttributeAtIndex(index, llvm_attr);4345 val.addAttributeAtIndex(index, llvm_attr);
4028 }4346 }
40294347
...@@ -4034,11 +4352,11 @@ pub const Object = struct {...@@ -4034,11 +4352,11 @@ pub const Object = struct {
4034 name: []const u8,4352 name: []const u8,
4035 value: []const u8,4353 value: []const u8,
4036 ) void {4354 ) void {
4037 const llvm_attr = o.context.createStringAttribute(4355 const llvm_attr = o.builder.llvm.context.createStringAttribute(
4038 name.ptr,4356 name.ptr,
4039 @as(c_uint, @intCast(name.len)),4357 @intCast(name.len),
4040 value.ptr,4358 value.ptr,
4041 @as(c_uint, @intCast(value.len)),4359 @intCast(value.len),
4042 );4360 );
4043 val.addAttributeAtIndex(index, llvm_attr);4361 val.addAttributeAtIndex(index, llvm_attr);
4044 }4362 }
...@@ -4063,23 +4381,23 @@ pub const Object = struct {...@@ -4063,23 +4381,23 @@ pub const Object = struct {
4063 /// widen it before using it and then truncate the result.4381 /// widen it before using it and then truncate the result.
4064 /// RMW exchange of floating-point values is bitcasted to same-sized integer4382 /// RMW exchange of floating-point values is bitcasted to same-sized integer
4065 /// types to work around a LLVM deficiency when targeting ARM/AArch64.4383 /// 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 {
4067 const mod = o.module;4385 const mod = o.module;
4068 const int_ty = switch (ty.zigTypeTag(mod)) {4386 const int_ty = switch (ty.zigTypeTag(mod)) {
4069 .Int => ty,4387 .Int => ty,
4070 .Enum => ty.intTagType(mod),4388 .Enum => ty.intTagType(mod),
4071 .Float => {4389 .Float => {
4072 if (!is_rmw_xchg) return null;4390 if (!is_rmw_xchg) return .none;
4073 return o.context.intType(@as(c_uint, @intCast(ty.abiSize(mod) * 8)));4391 return o.builder.intType(@intCast(ty.abiSize(mod) * 8));
4074 },4392 },
4075 .Bool => return o.context.intType(8),4393 .Bool => return .i8,
4076 else => return null,4394 else => return .none,
4077 };4395 };
4078 const bit_count = int_ty.intInfo(mod).bits;4396 const bit_count = int_ty.intInfo(mod).bits;
4079 if (!std.math.isPowerOfTwo(bit_count) or (bit_count % 8) != 0) {4397 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));
4081 } else {4399 } else {
4082 return null;4400 return .none;
4083 }4401 }
4084 }4402 }
40854403
...@@ -4120,13 +4438,13 @@ pub const Object = struct {...@@ -4120,13 +4438,13 @@ pub const Object = struct {
4120 llvm_arg_i: u32,4438 llvm_arg_i: u32,
4121 alignment: u32,4439 alignment: u32,
4122 byval_attr: bool,4440 byval_attr: bool,
4123 param_llvm_ty: *llvm.Type,4441 param_llvm_ty: Builder.Type,
4124 ) void {4442 ) void {
4125 o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");4443 o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");
4126 o.addArgAttr(llvm_fn, llvm_arg_i, "readonly");4444 o.addArgAttr(llvm_fn, llvm_arg_i, "readonly");
4127 o.addArgAttrInt(llvm_fn, llvm_arg_i, "align", alignment);4445 o.addArgAttrInt(llvm_fn, llvm_arg_i, "align", alignment);
4128 if (byval_attr) {4446 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));
4130 }4448 }
4131 }4449 }
4132};4450};
...@@ -4159,20 +4477,26 @@ pub const DeclGen = struct {...@@ -4159,20 +4477,26 @@ pub const DeclGen = struct {
4159 _ = try o.resolveLlvmFunction(extern_func.decl);4477 _ = try o.resolveLlvmFunction(extern_func.decl);
4160 } else {4478 } else {
4161 const target = mod.getTarget();4479 const target = mod.getTarget();
4162 var global = try o.resolveGlobalDecl(decl_index);4480 const variable = try o.resolveGlobalDecl(decl_index);
4163 global.setAlignment(decl.getAlignment(mod));4481 const global = variable.ptrConst(&o.builder).global;
4164 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| global.setSection(s);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 }
4165 assert(decl.has_tv);4489 assert(decl.has_tv);
4166 const init_val = if (decl.val.getVariable(mod)) |variable| init_val: {4490 const init_val = if (decl.val.getVariable(mod)) |decl_var| decl_var.init else init_val: {
4167 break :init_val variable.init;4491 variable.ptr(&o.builder).mutability = .constant;
4168 } else init_val: {4492 llvm_global.setGlobalConstant(.True);
4169 global.setGlobalConstant(.True);
4170 break :init_val decl.val.toIntern();4493 break :init_val decl.val.toIntern();
4171 };4494 };
4172 if (init_val != .none) {4495 if (init_val != .none) {
4173 const llvm_init = try o.lowerValue(.{ .ty = decl.ty, .val = init_val.toValue() });4496 const llvm_init = try o.lowerValue(init_val);
4174 if (global.globalGetValueType() == llvm_init.typeOf()) {4497 const llvm_init_ty = llvm_init.typeOf(&o.builder);
4175 global.setInitializer(llvm_init);4498 if (global.ptrConst(&o.builder).type == llvm_init_ty) {
4499 llvm_global.setInitializer(llvm_init.toLlvm(&o.builder));
4176 } else {4500 } else {
4177 // LLVM does not allow us to change the type of globals. So we must4501 // LLVM does not allow us to change the type of globals. So we must
4178 // create a new global with the correct type, copy all its attributes,4502 // create a new global with the correct type, copy all its attributes,
...@@ -4189,23 +4513,27 @@ pub const DeclGen = struct {...@@ -4189,23 +4513,27 @@ pub const DeclGen = struct {
4189 // Related: https://github.com/ziglang/zig/issues/132654513 // Related: https://github.com/ziglang/zig/issues/13265
4190 const llvm_global_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);4514 const llvm_global_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);
4191 const new_global = o.llvm_module.addGlobalInAddressSpace(4515 const new_global = o.llvm_module.addGlobalInAddressSpace(
4192 llvm_init.typeOf(),4516 llvm_init_ty.toLlvm(&o.builder),
4193 "",4517 "",
4194 llvm_global_addrspace,4518 @intFromEnum(llvm_global_addrspace),
4195 );4519 );
4196 new_global.setLinkage(global.getLinkage());4520 new_global.setLinkage(llvm_global.getLinkage());
4197 new_global.setUnnamedAddr(global.getUnnamedAddress());4521 new_global.setUnnamedAddr(llvm_global.getUnnamedAddress());
4198 new_global.setAlignment(global.getAlignment());4522 new_global.setAlignment(llvm_global.getAlignment());
4199 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s|4523 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |section|
4200 new_global.setSection(s);4524 new_global.setSection(section);
4201 new_global.setInitializer(llvm_init);4525 new_global.setInitializer(llvm_init.toLlvm(&o.builder));
4202 // TODO: How should this work then the address space of a global changed?4526 // TODO: How should this work then the address space of a global changed?
4203 global.replaceAllUsesWith(new_global);4527 llvm_global.replaceAllUsesWith(new_global);
4204 o.decl_map.putAssumeCapacity(decl_index, new_global);4528 new_global.takeName(llvm_global);
4205 new_global.takeName(global);4529 o.builder.llvm.globals.items[@intFromEnum(variable.ptrConst(&o.builder).global)] =
4206 global.deleteGlobal();4530 new_global;
4207 global = 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;
4208 }4535 }
4536 variable.ptr(&o.builder).init = llvm_init;
4209 }4537 }
42104538
4211 if (o.di_builder) |dib| {4539 if (o.di_builder) |dib| {
...@@ -4216,7 +4544,7 @@ pub const DeclGen = struct {...@@ -4216,7 +4544,7 @@ pub const DeclGen = struct {
4216 const di_global = dib.createGlobalVariableExpression(4544 const di_global = dib.createGlobalVariableExpression(
4217 di_file.toScope(),4545 di_file.toScope(),
4218 mod.intern_pool.stringToSlice(decl.name),4546 mod.intern_pool.stringToSlice(decl.name),
4219 global.getValueName(),4547 llvm_global.getValueName(),
4220 di_file,4548 di_file,
4221 line_number,4549 line_number,
4222 try o.lowerDebugType(decl.ty, .full),4550 try o.lowerDebugType(decl.ty, .full),
...@@ -4224,7 +4552,7 @@ pub const DeclGen = struct {...@@ -4224,7 +4552,7 @@ pub const DeclGen = struct {
4224 );4552 );
42254553
4226 try o.di_map.put(o.gpa, dg.decl, di_global.getVariable().toNode());4554 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);
4228 }4556 }
4229 }4557 }
4230 }4558 }
...@@ -4235,7 +4563,7 @@ pub const FuncGen = struct {...@@ -4235,7 +4563,7 @@ pub const FuncGen = struct {
4235 dg: *DeclGen,4563 dg: *DeclGen,
4236 air: Air,4564 air: Air,
4237 liveness: Liveness,4565 liveness: Liveness,
4238 context: *llvm.Context,4566 wip: Builder.WipFunction,
4239 builder: *llvm.Builder,4567 builder: *llvm.Builder,
4240 di_scope: ?*llvm.DIScope,4568 di_scope: ?*llvm.DIScope,
4241 di_file: ?*llvm.DIFile,4569 di_file: ?*llvm.DIFile,
...@@ -4252,43 +4580,44 @@ pub const FuncGen = struct {...@@ -4252,43 +4580,44 @@ pub const FuncGen = struct {
42524580
4253 /// This stores the LLVM values used in a function, such that they can be referred to4581 /// This stores the LLVM values used in a function, such that they can be referred to
4254 /// in other instructions. This table is cleared before every function is generated.4582 /// 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
4257 /// If the return type is sret, this is the result pointer. Otherwise null.4585 /// If the return type is sret, this is the result pointer. Otherwise null.
4258 /// Note that this can disagree with isByRef for the return type in the case4586 /// Note that this can disagree with isByRef for the return type in the case
4259 /// of C ABI functions.4587 /// of C ABI functions.
4260 ret_ptr: ?*llvm.Value,4588 ret_ptr: Builder.Value,
4261 /// Any function that needs to perform Valgrind client requests needs an array alloca4589 /// Any function that needs to perform Valgrind client requests needs an array alloca
4262 /// instruction, however a maximum of one per function is needed.4590 /// 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,
4264 /// These fields are used to refer to the LLVM value of the function parameters4592 /// These fields are used to refer to the LLVM value of the function parameters
4265 /// in an Arg instruction.4593 /// in an Arg instruction.
4266 /// This list may be shorter than the list according to the zig type system;4594 /// This list may be shorter than the list according to the zig type system;
4267 /// it omits 0-bit types. If the function uses sret as the first parameter,4595 /// it omits 0-bit types. If the function uses sret as the first parameter,
4268 /// this slice does not include it.4596 /// this slice does not include it.
4269 args: []const *llvm.Value,4597 args: []const Builder.Value,
4270 arg_index: c_uint,4598 arg_index: usize,
42714599
4272 llvm_func: *llvm.Value,4600 err_ret_trace: Builder.Value = .none,
4273
4274 err_ret_trace: ?*llvm.Value = null,
42754601
4276 /// This data structure is used to implement breaking to blocks.4602 /// This data structure is used to implement breaking to blocks.
4277 blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, struct {4603 blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, struct {
4278 parent_bb: *llvm.BasicBlock,4604 parent_bb: Builder.Function.Block.Index,
4279 breaks: *BreakList,4605 breaks: *BreakList,
4280 }),4606 }),
42814607
4282 single_threaded: bool,4608 sync_scope: Builder.SyncScope,
42834609
4284 const DbgState = struct { loc: *llvm.DILocation, scope: *llvm.DIScope, base_line: u32 };4610 const DbgState = struct { loc: *llvm.DILocation, scope: *llvm.DIScope, base_line: u32 };
4285 const BreakList = std.MultiArrayList(struct {4611 const BreakList = union {
4286 bb: *llvm.BasicBlock,4612 list: std.MultiArrayList(struct {
4287 val: *llvm.Value,4613 bb: Builder.Function.Block.Index,
4288 });4614 val: Builder.Value,
4615 }),
4616 len: usize,
4617 };
42894618
4290 fn deinit(self: *FuncGen) void {4619 fn deinit(self: *FuncGen) void {
4291 self.builder.dispose();4620 self.wip.deinit();
4292 self.dbg_inlined.deinit(self.gpa);4621 self.dbg_inlined.deinit(self.gpa);
4293 self.dbg_block_stack.deinit(self.gpa);4622 self.dbg_block_stack.deinit(self.gpa);
4294 self.func_inst_table.deinit(self.gpa);4623 self.func_inst_table.deinit(self.gpa);
...@@ -4300,7 +4629,7 @@ pub const FuncGen = struct {...@@ -4300,7 +4629,7 @@ pub const FuncGen = struct {
4300 return self.dg.todo(format, args);4629 return self.dg.todo(format, args);
4301 }4630 }
43024631
4303 fn resolveInst(self: *FuncGen, inst: Air.Inst.Ref) !*llvm.Value {4632 fn resolveInst(self: *FuncGen, inst: Air.Inst.Ref) !Builder.Value {
4304 const gpa = self.gpa;4633 const gpa = self.gpa;
4305 const gop = try self.func_inst_table.getOrPut(gpa, inst);4634 const gop = try self.func_inst_table.getOrPut(gpa, inst);
4306 if (gop.found_existing) return gop.value_ptr.*;4635 if (gop.found_existing) return gop.value_ptr.*;
...@@ -4311,14 +4640,14 @@ pub const FuncGen = struct {...@@ -4311,14 +4640,14 @@ pub const FuncGen = struct {
4311 .ty = self.typeOf(inst),4640 .ty = self.typeOf(inst),
4312 .val = (try self.air.value(inst, mod)).?,4641 .val = (try self.air.value(inst, mod)).?,
4313 });4642 });
4314 gop.value_ptr.* = llvm_val;4643 gop.value_ptr.* = llvm_val.toValue();
4315 return llvm_val;4644 return llvm_val.toValue();
4316 }4645 }
43174646
4318 fn resolveValue(self: *FuncGen, tv: TypedValue) !*llvm.Value {4647 fn resolveValue(self: *FuncGen, tv: TypedValue) Error!Builder.Constant {
4319 const o = self.dg.object;4648 const o = self.dg.object;
4320 const mod = o.module;4649 const mod = o.module;
4321 const llvm_val = try o.lowerValue(tv);4650 const llvm_val = try o.lowerValue(tv.val.toIntern());
4322 if (!isByRef(tv.ty, mod)) return llvm_val;4651 if (!isByRef(tv.ty, mod)) return llvm_val;
43234652
4324 // We have an LLVM value but we need to create a global constant and4653 // We have an LLVM value but we need to create a global constant and
...@@ -4326,17 +4655,50 @@ pub const FuncGen = struct {...@@ -4326,17 +4655,50 @@ pub const FuncGen = struct {
4326 const target = mod.getTarget();4655 const target = mod.getTarget();
4327 const llvm_wanted_addrspace = toLlvmAddressSpace(.generic, target);4656 const llvm_wanted_addrspace = toLlvmAddressSpace(.generic, target);
4328 const llvm_actual_addrspace = toLlvmGlobalAddressSpace(.generic, target);4657 const llvm_actual_addrspace = toLlvmGlobalAddressSpace(.generic, target);
4329 const global = o.llvm_module.addGlobalInAddressSpace(llvm_val.typeOf(), "", llvm_actual_addrspace);4658 const llvm_ty = llvm_val.typeOf(&o.builder);
4330 global.setInitializer(llvm_val);4659 const llvm_alignment = tv.ty.abiAlignment(mod);
4331 global.setLinkage(.Private);4660 const llvm_global = o.llvm_module.addGlobalInAddressSpace(llvm_ty.toLlvm(&o.builder), "", @intFromEnum(llvm_actual_addrspace));
4332 global.setGlobalConstant(.True);4661 llvm_global.setInitializer(llvm_val.toLlvm(&o.builder));
4333 global.setUnnamedAddr(.True);4662 llvm_global.setLinkage(.Private);
4334 global.setAlignment(tv.ty.abiAlignment(mod));4663 llvm_global.setGlobalConstant(.True);
4335 const addrspace_casted_ptr = if (llvm_actual_addrspace != llvm_wanted_addrspace)4664 llvm_global.setUnnamedAddr(.True);
4336 global.constAddrSpaceCast(self.context.pointerType(llvm_wanted_addrspace))4665 llvm_global.setAlignment(llvm_alignment);
4337 else4666
4338 global;4667 var global = Builder.Global{
4339 return addrspace_casted_ptr;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;
4340 }4702 }
43414703
4342 fn genBody(self: *FuncGen, body: []const Air.Inst.Index) Error!void {4704 fn genBody(self: *FuncGen, body: []const Air.Inst.Index) Error!void {
...@@ -4345,10 +4707,9 @@ pub const FuncGen = struct {...@@ -4345,10 +4707,9 @@ pub const FuncGen = struct {
4345 const ip = &mod.intern_pool;4707 const ip = &mod.intern_pool;
4346 const air_tags = self.air.instructions.items(.tag);4708 const air_tags = self.air.instructions.items(.tag);
4347 for (body, 0..) |inst, i| {4709 for (body, 0..) |inst, i| {
4348 if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip))4710 if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) continue;
4349 continue;
43504711
4351 const opt_value: ?*llvm.Value = switch (air_tags[inst]) {4712 const val: Builder.Value = switch (air_tags[inst]) {
4352 // zig fmt: off4713 // zig fmt: off
4353 .add => try self.airAdd(inst, false),4714 .add => try self.airAdd(inst, false),
4354 .add_optimized => try self.airAdd(inst, true),4715 .add_optimized => try self.airAdd(inst, true),
...@@ -4439,15 +4800,15 @@ pub const FuncGen = struct {...@@ -4439,15 +4800,15 @@ pub const FuncGen = struct {
4439 .cmp_vector_optimized => try self.airCmpVector(inst, true),4800 .cmp_vector_optimized => try self.airCmpVector(inst, true),
4440 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),4801 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),
44414802
4442 .is_non_null => try self.airIsNonNull(inst, false, .NE),4803 .is_non_null => try self.airIsNonNull(inst, false, .ne),
4443 .is_non_null_ptr => try self.airIsNonNull(inst, true , .NE),4804 .is_non_null_ptr => try self.airIsNonNull(inst, true , .ne),
4444 .is_null => try self.airIsNonNull(inst, false, .EQ),4805 .is_null => try self.airIsNonNull(inst, false, .eq),
4445 .is_null_ptr => try self.airIsNonNull(inst, true , .EQ),4806 .is_null_ptr => try self.airIsNonNull(inst, true , .eq),
44464807
4447 .is_non_err => try self.airIsErr(inst, .EQ, false),4808 .is_non_err => try self.airIsErr(inst, .eq, false),
4448 .is_non_err_ptr => try self.airIsErr(inst, .EQ, true),4809 .is_non_err_ptr => try self.airIsErr(inst, .eq, true),
4449 .is_err => try self.airIsErr(inst, .NE, false),4810 .is_err => try self.airIsErr(inst, .ne, false),
4450 .is_err_ptr => try self.airIsErr(inst, .NE, true),4811 .is_err_ptr => try self.airIsErr(inst, .ne, true),
44514812
4452 .alloc => try self.airAlloc(inst),4813 .alloc => try self.airAlloc(inst),
4453 .ret_ptr => try self.airRetPtr(inst),4814 .ret_ptr => try self.airRetPtr(inst),
...@@ -4524,10 +4885,10 @@ pub const FuncGen = struct {...@@ -4524,10 +4885,10 @@ pub const FuncGen = struct {
4524 .reduce => try self.airReduce(inst, false),4885 .reduce => try self.airReduce(inst, false),
4525 .reduce_optimized => try self.airReduce(inst, true),4886 .reduce_optimized => try self.airReduce(inst, true),
45264887
4527 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),4888 .atomic_store_unordered => try self.airAtomicStore(inst, .unordered),
4528 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),4889 .atomic_store_monotonic => try self.airAtomicStore(inst, .monotonic),
4529 .atomic_store_release => try self.airAtomicStore(inst, .Release),4890 .atomic_store_release => try self.airAtomicStore(inst, .release),
4530 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SequentiallyConsistent),4891 .atomic_store_seq_cst => try self.airAtomicStore(inst, .seq_cst),
45314892
4532 .struct_field_ptr => try self.airStructFieldPtr(inst),4893 .struct_field_ptr => try self.airStructFieldPtr(inst),
4533 .struct_field_val => try self.airStructFieldVal(body[i..]),4894 .struct_field_val => try self.airStructFieldVal(body[i..]),
...@@ -4569,8 +4930,8 @@ pub const FuncGen = struct {...@@ -4569,8 +4930,8 @@ pub const FuncGen = struct {
45694930
4570 .inferred_alloc, .inferred_alloc_comptime => unreachable,4931 .inferred_alloc, .inferred_alloc_comptime => unreachable,
45714932
4572 .unreach => self.airUnreach(inst),4933 .unreach => try self.airUnreach(inst),
4573 .dbg_stmt => self.airDbgStmt(inst),4934 .dbg_stmt => try self.airDbgStmt(inst),
4574 .dbg_inline_begin => try self.airDbgInlineBegin(inst),4935 .dbg_inline_begin => try self.airDbgInlineBegin(inst),
4575 .dbg_inline_end => try self.airDbgInlineEnd(inst),4936 .dbg_inline_end => try self.airDbgInlineEnd(inst),
4576 .dbg_block_begin => try self.airDbgBlockBegin(),4937 .dbg_block_begin => try self.airDbgBlockBegin(),
...@@ -4588,17 +4949,14 @@ pub const FuncGen = struct {...@@ -4588,17 +4949,14 @@ pub const FuncGen = struct {
4588 .work_group_id => try self.airWorkGroupId(inst),4949 .work_group_id => try self.airWorkGroupId(inst),
4589 // zig fmt: on4950 // zig fmt: on
4590 };4951 };
4591 if (opt_value) |val| {4952 if (val != .none) try self.func_inst_table.putNoClobber(self.gpa, Air.indexToRef(inst), val);
4592 const ref = Air.indexToRef(inst);
4593 try self.func_inst_table.putNoClobber(self.gpa, ref, val);
4594 }
4595 }4953 }
4596 }4954 }
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 {
4599 const pl_op = self.air.instructions.items(.data)[inst].pl_op;4957 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
4600 const extra = self.air.extraData(Air.Call, pl_op.payload);4958 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]);
4602 const o = self.dg.object;4960 const o = self.dg.object;
4603 const mod = o.module;4961 const mod = o.module;
4604 const ip = &mod.intern_pool;4962 const ip = &mod.intern_pool;
...@@ -4619,19 +4977,21 @@ pub const FuncGen = struct {...@@ -4619,19 +4977,21 @@ pub const FuncGen = struct {
46194977
4620 const ret_ptr = if (!sret) null else blk: {4978 const ret_ptr = if (!sret) null else blk: {
4621 const llvm_ret_ty = try o.lowerType(return_type);4979 const llvm_ret_ty = try o.lowerType(return_type);
4622 const ret_ptr = self.buildAlloca(llvm_ret_ty, return_type.abiAlignment(mod));4980 const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));
4623 try llvm_args.append(ret_ptr);4981 const ret_ptr = try self.buildAlloca(llvm_ret_ty, alignment);
4982 try llvm_args.append(ret_ptr.toLlvm(&self.wip));
4624 break :blk ret_ptr;4983 break :blk ret_ptr;
4625 };4984 };
46264985
4627 const err_return_tracing = return_type.isError(mod) and4986 const err_return_tracing = return_type.isError(mod) and
4628 o.module.comp.bin_file.options.error_return_tracing;4987 o.module.comp.bin_file.options.error_return_tracing;
4629 if (err_return_tracing) {4988 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));
4631 }4991 }
46324992
4633 var it = iterateParamTypes(o, fn_info);4993 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) {
4635 .no_bits => continue,4995 .no_bits => continue,
4636 .byval => {4996 .byval => {
4637 const arg = args[it.zig_index - 1];4997 const arg = args[it.zig_index - 1];
...@@ -4639,12 +4999,11 @@ pub const FuncGen = struct {...@@ -4639,12 +4999,11 @@ pub const FuncGen = struct {
4639 const llvm_arg = try self.resolveInst(arg);4999 const llvm_arg = try self.resolveInst(arg);
4640 const llvm_param_ty = try o.lowerType(param_ty);5000 const llvm_param_ty = try o.lowerType(param_ty);
4641 if (isByRef(param_ty, mod)) {5001 if (isByRef(param_ty, mod)) {
4642 const alignment = param_ty.abiAlignment(mod);5002 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
4643 const load_inst = self.builder.buildLoad(llvm_param_ty, llvm_arg, "");5003 const loaded = try self.wip.load(.normal, llvm_param_ty, llvm_arg, alignment, "");
4644 load_inst.setAlignment(alignment);5004 try llvm_args.append(loaded.toLlvm(&self.wip));
4645 try llvm_args.append(load_inst);
4646 } else {5005 } else {
4647 try llvm_args.append(llvm_arg);5006 try llvm_args.append(llvm_arg.toLlvm(&self.wip));
4648 }5007 }
4649 },5008 },
4650 .byref => {5009 .byref => {
...@@ -4652,14 +5011,13 @@ pub const FuncGen = struct {...@@ -4652,14 +5011,13 @@ pub const FuncGen = struct {
4652 const param_ty = self.typeOf(arg);5011 const param_ty = self.typeOf(arg);
4653 const llvm_arg = try self.resolveInst(arg);5012 const llvm_arg = try self.resolveInst(arg);
4654 if (isByRef(param_ty, mod)) {5013 if (isByRef(param_ty, mod)) {
4655 try llvm_args.append(llvm_arg);5014 try llvm_args.append(llvm_arg.toLlvm(&self.wip));
4656 } else {5015 } else {
4657 const alignment = param_ty.abiAlignment(mod);5016 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
4658 const param_llvm_ty = llvm_arg.typeOf();5017 const param_llvm_ty = llvm_arg.typeOfWip(&self.wip);
4659 const arg_ptr = self.buildAlloca(param_llvm_ty, alignment);5018 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);
4660 const store_inst = self.builder.buildStore(llvm_arg, arg_ptr);5019 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);
4661 store_inst.setAlignment(alignment);5020 try llvm_args.append(arg_ptr.toLlvm(&self.wip));
4662 try llvm_args.append(arg_ptr);
4663 }5021 }
4664 },5022 },
4665 .byref_mut => {5023 .byref_mut => {
...@@ -4667,134 +5025,124 @@ pub const FuncGen = struct {...@@ -4667,134 +5025,124 @@ pub const FuncGen = struct {
4667 const param_ty = self.typeOf(arg);5025 const param_ty = self.typeOf(arg);
4668 const llvm_arg = try self.resolveInst(arg);5026 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));
4671 const param_llvm_ty = try o.lowerType(param_ty);5029 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);
4673 if (isByRef(param_ty, mod)) {5031 if (isByRef(param_ty, mod)) {
4674 const load_inst = self.builder.buildLoad(param_llvm_ty, llvm_arg, "");5032 const loaded = try self.wip.load(.normal, param_llvm_ty, llvm_arg, alignment, "");
4675 load_inst.setAlignment(alignment);5033 _ = try self.wip.store(.normal, loaded, arg_ptr, 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);
4680 } else {5034 } else {
4681 const store_inst = self.builder.buildStore(llvm_arg, arg_ptr);5035 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);
4682 store_inst.setAlignment(alignment);
4683 try llvm_args.append(arg_ptr);
4684 }5036 }
5037 try llvm_args.append(arg_ptr.toLlvm(&self.wip));
4685 },5038 },
4686 .abi_sized_int => {5039 .abi_sized_int => {
4687 const arg = args[it.zig_index - 1];5040 const arg = args[it.zig_index - 1];
4688 const param_ty = self.typeOf(arg);5041 const param_ty = self.typeOf(arg);
4689 const llvm_arg = try self.resolveInst(arg);5042 const llvm_arg = try self.resolveInst(arg);
4690 const abi_size = @as(c_uint, @intCast(param_ty.abiSize(mod)));5043 const int_llvm_ty = try o.builder.intType(@intCast(param_ty.abiSize(mod) * 8));
4691 const int_llvm_ty = self.context.intType(abi_size * 8);
46925044
4693 if (isByRef(param_ty, mod)) {5045 if (isByRef(param_ty, mod)) {
4694 const alignment = param_ty.abiAlignment(mod);5046 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
4695 const load_inst = self.builder.buildLoad(int_llvm_ty, llvm_arg, "");5047 const loaded = try self.wip.load(.normal, int_llvm_ty, llvm_arg, alignment, "");
4696 load_inst.setAlignment(alignment);5048 try llvm_args.append(loaded.toLlvm(&self.wip));
4697 try llvm_args.append(load_inst);
4698 } else {5049 } else {
4699 // LLVM does not allow bitcasting structs so we must allocate5050 // LLVM does not allow bitcasting structs so we must allocate
4700 // a local, store as one type, and then load as another type.5051 // a local, store as one type, and then load as another type.
4701 const alignment = @max(5052 const alignment = Builder.Alignment.fromByteUnits(@max(
4702 param_ty.abiAlignment(mod),5053 param_ty.abiAlignment(mod),
4703 o.target_data.abiAlignmentOfType(int_llvm_ty),5054 o.target_data.abiAlignmentOfType(int_llvm_ty.toLlvm(&o.builder)),
4704 );5055 ));
4705 const int_ptr = self.buildAlloca(int_llvm_ty, alignment);5056 const int_ptr = try self.buildAlloca(int_llvm_ty, alignment);
4706 const store_inst = self.builder.buildStore(llvm_arg, int_ptr);5057 _ = try self.wip.store(.normal, llvm_arg, int_ptr, alignment);
4707 store_inst.setAlignment(alignment);5058 const loaded = try self.wip.load(.normal, int_llvm_ty, int_ptr, alignment, "");
4708 const load_inst = self.builder.buildLoad(int_llvm_ty, int_ptr, "");5059 try llvm_args.append(loaded.toLlvm(&self.wip));
4709 load_inst.setAlignment(alignment);
4710 try llvm_args.append(load_inst);
4711 }5060 }
4712 },5061 },
4713 .slice => {5062 .slice => {
4714 const arg = args[it.zig_index - 1];5063 const arg = args[it.zig_index - 1];
4715 const llvm_arg = try self.resolveInst(arg);5064 const llvm_arg = try self.resolveInst(arg);
4716 const ptr = self.builder.buildExtractValue(llvm_arg, 0, "");5065 const ptr = try self.wip.extractValue(llvm_arg, &.{0}, "");
4717 const len = self.builder.buildExtractValue(llvm_arg, 1, "");5066 const len = try self.wip.extractValue(llvm_arg, &.{1}, "");
4718 try llvm_args.ensureUnusedCapacity(2);5067 try llvm_args.appendSlice(&.{ ptr.toLlvm(&self.wip), len.toLlvm(&self.wip) });
4719 llvm_args.appendAssumeCapacity(ptr);
4720 llvm_args.appendAssumeCapacity(len);
4721 },5068 },
4722 .multiple_llvm_types => {5069 .multiple_llvm_types => {
4723 const arg = args[it.zig_index - 1];5070 const arg = args[it.zig_index - 1];
4724 const param_ty = self.typeOf(arg);5071 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];
4726 const llvm_arg = try self.resolveInst(arg);5073 const llvm_arg = try self.resolveInst(arg);
4727 const is_by_ref = isByRef(param_ty, mod);5074 const is_by_ref = isByRef(param_ty, mod);
4728 const arg_ptr = if (is_by_ref) llvm_arg else p: {5075 const arg_ptr = if (is_by_ref) llvm_arg else ptr: {
4729 const p = self.buildAlloca(llvm_arg.typeOf(), null);5076 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
4730 const store_inst = self.builder.buildStore(llvm_arg, p);5077 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);
4731 store_inst.setAlignment(param_ty.abiAlignment(mod));5078 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);
4732 break :p p;5079 break :ptr ptr;
4733 };5080 };
47345081
4735 const llvm_ty = self.context.structType(llvm_types.ptr, @as(c_uint, @intCast(llvm_types.len)), .False);5082 const llvm_ty = try o.builder.structType(.normal, llvm_types);
4736 try llvm_args.ensureUnusedCapacity(it.llvm_types_len);5083 try llvm_args.ensureUnusedCapacity(it.types_len);
4737 for (llvm_types, 0..) |field_ty, i_usize| {5084 for (llvm_types, 0..) |field_ty, i| {
4738 const i = @as(c_uint, @intCast(i_usize));5085 const alignment =
4739 const field_ptr = self.builder.buildStructGEP(llvm_ty, arg_ptr, i, "");5086 Builder.Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
4740 const load_inst = self.builder.buildLoad(field_ty, field_ptr, "");5087 const field_ptr = try self.wip.gepStruct(llvm_ty, arg_ptr, i, "");
4741 load_inst.setAlignment(target.ptrBitWidth() / 8);5088 const loaded = try self.wip.load(.normal, field_ty, field_ptr, alignment, "");
4742 llvm_args.appendAssumeCapacity(load_inst);5089 llvm_args.appendAssumeCapacity(loaded.toLlvm(&self.wip));
4743 }5090 }
4744 },5091 },
4745 .as_u16 => {5092 .as_u16 => {
4746 const arg = args[it.zig_index - 1];5093 const arg = args[it.zig_index - 1];
4747 const llvm_arg = try self.resolveInst(arg);5094 const llvm_arg = try self.resolveInst(arg);
4748 const casted = self.builder.buildBitCast(llvm_arg, self.context.intType(16), "");5095 const casted = try self.wip.cast(.bitcast, llvm_arg, .i16, "");
4749 try llvm_args.append(casted);5096 try llvm_args.append(casted.toLlvm(&self.wip));
4750 },5097 },
4751 .float_array => |count| {5098 .float_array => |count| {
4752 const arg = args[it.zig_index - 1];5099 const arg = args[it.zig_index - 1];
4753 const arg_ty = self.typeOf(arg);5100 const arg_ty = self.typeOf(arg);
4754 var llvm_arg = try self.resolveInst(arg);5101 var llvm_arg = try self.resolveInst(arg);
5102 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
4755 if (!isByRef(arg_ty, mod)) {5103 if (!isByRef(arg_ty, mod)) {
4756 const p = self.buildAlloca(llvm_arg.typeOf(), null);5104 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);
4757 const store_inst = self.builder.buildStore(llvm_arg, p);5105 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);
4758 store_inst.setAlignment(arg_ty.abiAlignment(mod));5106 llvm_arg = ptr;
4759 llvm_arg = store_inst;
4760 }5107 }
47615108
4762 const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(arg_ty, mod).?);5109 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);5112 const loaded = try self.wip.load(.normal, array_ty, llvm_arg, alignment, "");
4766 const load_inst = self.builder.buildLoad(array_llvm_ty, llvm_arg, "");5113 try llvm_args.append(loaded.toLlvm(&self.wip));
4767 load_inst.setAlignment(alignment);
4768 try llvm_args.append(load_inst);
4769 },5114 },
4770 .i32_array, .i64_array => |arr_len| {5115 .i32_array, .i64_array => |arr_len| {
4771 const elem_size: u8 = if (lowering == .i32_array) 32 else 64;5116 const elem_size: u8 = if (lowering == .i32_array) 32 else 64;
4772 const arg = args[it.zig_index - 1];5117 const arg = args[it.zig_index - 1];
4773 const arg_ty = self.typeOf(arg);5118 const arg_ty = self.typeOf(arg);
4774 var llvm_arg = try self.resolveInst(arg);5119 var llvm_arg = try self.resolveInst(arg);
5120 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
4775 if (!isByRef(arg_ty, mod)) {5121 if (!isByRef(arg_ty, mod)) {
4776 const p = self.buildAlloca(llvm_arg.typeOf(), null);5122 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);
4777 const store_inst = self.builder.buildStore(llvm_arg, p);5123 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);
4778 store_inst.setAlignment(arg_ty.abiAlignment(mod));5124 llvm_arg = ptr;
4779 llvm_arg = store_inst;
4780 }5125 }
47815126
4782 const array_llvm_ty = self.context.intType(elem_size).arrayType(arr_len);5127 const array_ty =
4783 const alignment = arg_ty.abiAlignment(mod);5128 try o.builder.arrayType(arr_len, try o.builder.intType(@intCast(elem_size)));
4784 const load_inst = self.builder.buildLoad(array_llvm_ty, llvm_arg, "");5129 const loaded = try self.wip.load(.normal, array_ty, llvm_arg, alignment, "");
4785 load_inst.setAlignment(alignment);5130 try llvm_args.append(loaded.toLlvm(&self.wip));
4786 try llvm_args.append(load_inst);
4787 },5131 },
4788 };5132 };
47895133
4790 const call = self.builder.buildCall(5134 const llvm_fn_ty = try o.lowerType(zig_fn_ty);
4791 try o.lowerType(zig_fn_ty),5135 const call = (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(
4792 llvm_fn,5136 self.builder.buildCall(
4793 llvm_args.items.ptr,5137 llvm_fn_ty.toLlvm(&o.builder),
4794 @as(c_uint, @intCast(llvm_args.items.len)),5138 llvm_fn.toLlvm(&self.wip),
4795 toLlvmCallConv(fn_info.cc, target),5139 llvm_args.items.ptr,
4796 attr,5140 @intCast(llvm_args.items.len),
4797 "",5141 toLlvmCallConv(fn_info.cc, target),
5142 attr,
5143 "",
5144 ),
5145 &self.wip,
4798 );5146 );
47995147
4800 if (callee_ty.zigTypeTag(mod) == .Pointer) {5148 if (callee_ty.zigTypeTag(mod) == .Pointer) {
...@@ -4802,12 +5150,12 @@ pub const FuncGen = struct {...@@ -4802,12 +5150,12 @@ pub const FuncGen = struct {
4802 it = iterateParamTypes(o, fn_info);5150 it = iterateParamTypes(o, fn_info);
4803 it.llvm_index += @intFromBool(sret);5151 it.llvm_index += @intFromBool(sret);
4804 it.llvm_index += @intFromBool(err_return_tracing);5152 it.llvm_index += @intFromBool(err_return_tracing);
4805 while (it.next()) |lowering| switch (lowering) {5153 while (try it.next()) |lowering| switch (lowering) {
4806 .byval => {5154 .byval => {
4807 const param_index = it.zig_index - 1;5155 const param_index = it.zig_index - 1;
4808 const param_ty = fn_info.param_types.get(ip)[param_index].toType();5156 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
4809 if (!isByRef(param_ty, mod)) {5157 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);
4811 }5159 }
4812 },5160 },
4813 .byref => {5161 .byref => {
...@@ -4815,10 +5163,10 @@ pub const FuncGen = struct {...@@ -4815,10 +5163,10 @@ pub const FuncGen = struct {
4815 const param_ty = fn_info.param_types.get(ip)[param_index].toType();5163 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
4816 const param_llvm_ty = try o.lowerType(param_ty);5164 const param_llvm_ty = try o.lowerType(param_ty);
4817 const alignment = param_ty.abiAlignment(mod);5165 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);
4819 },5167 },
4820 .byref_mut => {5168 .byref_mut => {
4821 o.addArgAttr(call, it.llvm_index - 1, "noundef");5169 o.addArgAttr(call.toLlvm(&self.wip), it.llvm_index - 1, "noundef");
4822 },5170 },
4823 // No attributes needed for these.5171 // No attributes needed for these.
4824 .no_bits,5172 .no_bits,
...@@ -4838,41 +5186,40 @@ pub const FuncGen = struct {...@@ -4838,41 +5186,40 @@ pub const FuncGen = struct {
48385186
4839 if (math.cast(u5, it.zig_index - 1)) |i| {5187 if (math.cast(u5, it.zig_index - 1)) |i| {
4840 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {5188 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");
4842 }5190 }
4843 }5191 }
4844 if (param_ty.zigTypeTag(mod) != .Optional) {5192 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");
4846 }5194 }
4847 if (ptr_info.flags.is_const) {5195 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");
4849 }5197 }
4850 const elem_align = ptr_info.flags.alignment.toByteUnitsOptional() orelse5198 const elem_align = ptr_info.flags.alignment.toByteUnitsOptional() orelse
4851 @max(ptr_info.child.toType().abiAlignment(mod), 1);5199 @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);
4853 },5201 },
4854 };5202 };
4855 }5203 }
48565204
4857 if (fn_info.return_type == .noreturn_type and attr != .AlwaysTail) {5205 if (fn_info.return_type == .noreturn_type and attr != .AlwaysTail) {
4858 return null;5206 return .none;
4859 }5207 }
48605208
4861 if (self.liveness.isUnused(inst) or !return_type.hasRuntimeBitsIgnoreComptime(mod)) {5209 if (self.liveness.isUnused(inst) or !return_type.hasRuntimeBitsIgnoreComptime(mod)) {
4862 return null;5210 return .none;
4863 }5211 }
48645212
4865 const llvm_ret_ty = try o.lowerType(return_type);5213 const llvm_ret_ty = try o.lowerType(return_type);
48665214
4867 if (ret_ptr) |rp| {5215 if (ret_ptr) |rp| {
4868 call.setCallSret(llvm_ret_ty);5216 call.toLlvm(&self.wip).setCallSret(llvm_ret_ty.toLlvm(&o.builder));
4869 if (isByRef(return_type, mod)) {5217 if (isByRef(return_type, mod)) {
4870 return rp;5218 return rp;
4871 } else {5219 } else {
4872 // our by-ref status disagrees with sret so we must load.5220 // our by-ref status disagrees with sret so we must load.
4873 const loaded = self.builder.buildLoad(llvm_ret_ty, rp, "");5221 const return_alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));
4874 loaded.setAlignment(return_type.abiAlignment(mod));5222 return self.wip.load(.normal, llvm_ret_ty, rp, return_alignment, "");
4875 return loaded;
4876 }5223 }
4877 }5224 }
48785225
...@@ -4882,26 +5229,23 @@ pub const FuncGen = struct {...@@ -4882,26 +5229,23 @@ pub const FuncGen = struct {
4882 // In this case the function return type is honoring the calling convention by having5229 // In this case the function return type is honoring the calling convention by having
4883 // a different LLVM type than the usual one. We solve this here at the callsite5230 // a different LLVM type than the usual one. We solve this here at the callsite
4884 // by using our canonical type, then loading it if necessary.5231 // by using our canonical type, then loading it if necessary.
4885 const alignment = o.target_data.abiAlignmentOfType(abi_ret_ty);5232 const alignment = Builder.Alignment.fromByteUnits(
4886 const rp = self.buildAlloca(llvm_ret_ty, alignment);5233 o.target_data.abiAlignmentOfType(abi_ret_ty.toLlvm(&o.builder)),
4887 const store_inst = self.builder.buildStore(call, rp);5234 );
4888 store_inst.setAlignment(alignment);5235 const rp = try self.buildAlloca(llvm_ret_ty, alignment);
4889 if (isByRef(return_type, mod)) {5236 _ = try self.wip.store(.normal, call, rp, alignment);
4890 return rp;5237 return if (isByRef(return_type, mod))
4891 } else {5238 rp
4892 const load_inst = self.builder.buildLoad(llvm_ret_ty, rp, "");5239 else
4893 load_inst.setAlignment(alignment);5240 try self.wip.load(.normal, llvm_ret_ty, rp, alignment, "");
4894 return load_inst;
4895 }
4896 }5241 }
48975242
4898 if (isByRef(return_type, mod)) {5243 if (isByRef(return_type, mod)) {
4899 // our by-ref status disagrees with sret so we must allocate, store,5244 // our by-ref status disagrees with sret so we must allocate, store,
4900 // and return the allocation pointer.5245 // and return the allocation pointer.
4901 const alignment = return_type.abiAlignment(mod);5246 const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));
4902 const rp = self.buildAlloca(llvm_ret_ty, alignment);5247 const rp = try self.buildAlloca(llvm_ret_ty, alignment);
4903 const store_inst = self.builder.buildStore(call, rp);5248 _ = try self.wip.store(.normal, call, rp, alignment);
4904 store_inst.setAlignment(alignment);
4905 return rp;5249 return rp;
4906 } else {5250 } else {
4907 return call;5251 return call;
...@@ -4914,13 +5258,10 @@ pub const FuncGen = struct {...@@ -4914,13 +5258,10 @@ pub const FuncGen = struct {
4914 const msg_decl_index = mod.panic_messages[@intFromEnum(panic_id)].unwrap().?;5258 const msg_decl_index = mod.panic_messages[@intFromEnum(panic_id)].unwrap().?;
4915 const msg_decl = mod.declPtr(msg_decl_index);5259 const msg_decl = mod.declPtr(msg_decl_index);
4916 const msg_len = msg_decl.ty.childType(mod).arrayLen(mod);5260 const msg_len = msg_decl.ty.childType(mod).arrayLen(mod);
4917 const msg_ptr = try o.lowerValue(.{5261 const msg_ptr = try o.lowerValue(try msg_decl.internValue(mod));
4918 .ty = msg_decl.ty,5262 const null_opt_addr_global = try fg.resolveNullOptUsize();
4919 .val = msg_decl.val,
4920 });
4921 const null_opt_addr_global = try o.getNullOptAddr();
4922 const target = mod.getTarget();5263 const target = mod.getTarget();
4923 const llvm_usize = fg.context.intType(target.ptrBitWidth());5264 const llvm_usize = try o.lowerType(Type.usize);
4924 // example:5265 // example:
4925 // call fastcc void @test2.panic(5266 // call fastcc void @test2.panic(
4926 // ptr @builtin.panic_messages.integer_overflow__anon_987, ; msg.ptr5267 // ptr @builtin.panic_messages.integer_overflow__anon_987, ; msg.ptr
...@@ -4929,38 +5270,38 @@ pub const FuncGen = struct {...@@ -4929,38 +5270,38 @@ pub const FuncGen = struct {
4929 // ptr @2, ; addr (null ?usize)5270 // ptr @2, ; addr (null ?usize)
4930 // )5271 // )
4931 const args = [4]*llvm.Value{5272 const args = [4]*llvm.Value{
4932 msg_ptr,5273 msg_ptr.toLlvm(&o.builder),
4933 llvm_usize.constInt(msg_len, .False),5274 (try o.builder.intConst(llvm_usize, msg_len)).toLlvm(&o.builder),
4934 fg.context.pointerType(0).constNull(),5275 (try o.builder.nullConst(.ptr)).toLlvm(&o.builder),
4935 null_opt_addr_global,5276 null_opt_addr_global.toLlvm(&o.builder),
4936 };5277 };
4937 const panic_func = mod.funcInfo(mod.panic_func_index);5278 const panic_func = mod.funcInfo(mod.panic_func_index);
4938 const panic_decl = mod.declPtr(panic_func.owner_decl);5279 const panic_decl = mod.declPtr(panic_func.owner_decl);
4939 const fn_info = mod.typeToFunc(panic_decl.ty).?;5280 const fn_info = mod.typeToFunc(panic_decl.ty).?;
4940 const panic_global = try o.resolveLlvmFunction(panic_func.owner_decl);5281 const panic_global = try o.resolveLlvmFunction(panic_func.owner_decl);
4941 _ = fg.builder.buildCall(5282 _ = (try fg.wip.unimplemented(.void, "")).finish(fg.builder.buildCall(
4942 try o.lowerType(panic_decl.ty),5283 (try o.lowerType(panic_decl.ty)).toLlvm(&o.builder),
4943 panic_global,5284 panic_global.toLlvm(&o.builder),
4944 &args,5285 &args,
4945 args.len,5286 args.len,
4946 toLlvmCallConv(fn_info.cc, target),5287 toLlvmCallConv(fn_info.cc, target),
4947 .Auto,5288 .Auto,
4948 "",5289 "",
4949 );5290 ), &fg.wip);
4950 _ = fg.builder.buildUnreachable();5291 _ = try fg.wip.@"unreachable"();
4951 }5292 }
49525293
4953 fn airRet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5294 fn airRet(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
4954 const o = self.dg.object;5295 const o = self.dg.object;
4955 const mod = o.module;5296 const mod = o.module;
4956 const un_op = self.air.instructions.items(.data)[inst].un_op;5297 const un_op = self.air.instructions.items(.data)[inst].un_op;
4957 const ret_ty = self.typeOf(un_op);5298 const ret_ty = self.typeOf(un_op);
4958 if (self.ret_ptr) |ret_ptr| {5299 if (self.ret_ptr != .none) {
4959 const operand = try self.resolveInst(un_op);5300 const operand = try self.resolveInst(un_op);
4960 const ptr_ty = try mod.singleMutPtrType(ret_ty);5301 const ptr_ty = try mod.singleMutPtrType(ret_ty);
4961 try self.store(ret_ptr, ptr_ty, operand, .NotAtomic);5302 try self.store(self.ret_ptr, ptr_ty, operand, .none);
4962 _ = self.builder.buildRetVoid();5303 _ = try self.wip.retVoid();
4963 return null;5304 return .none;
4964 }5305 }
4965 const fn_info = mod.typeToFunc(self.dg.decl.ty).?;5306 const fn_info = mod.typeToFunc(self.dg.decl.ty).?;
4966 if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) {5307 if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) {
...@@ -4968,43 +5309,37 @@ pub const FuncGen = struct {...@@ -4968,43 +5309,37 @@ pub const FuncGen = struct {
4968 // Functions with an empty error set are emitted with an error code5309 // Functions with an empty error set are emitted with an error code
4969 // return type and return zero so they can be function pointers coerced5310 // return type and return zero so they can be function pointers coerced
4970 // to functions that return anyerror.5311 // to functions that return anyerror.
4971 const err_int = try o.lowerType(Type.anyerror);5312 _ = try self.wip.ret(try o.builder.intValue(Builder.Type.err_int, 0));
4972 _ = self.builder.buildRet(err_int.constInt(0, .False));
4973 } else {5313 } else {
4974 _ = self.builder.buildRetVoid();5314 _ = try self.wip.retVoid();
4975 }5315 }
4976 return null;5316 return .none;
4977 }5317 }
49785318
4979 const abi_ret_ty = try lowerFnRetTy(o, fn_info);5319 const abi_ret_ty = try lowerFnRetTy(o, fn_info);
4980 const operand = try self.resolveInst(un_op);5320 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
4983 if (isByRef(ret_ty, mod)) {5323 if (isByRef(ret_ty, mod)) {
4984 // operand is a pointer however self.ret_ptr is null so that means5324 // operand is a pointer however self.ret_ptr is null so that means
4985 // we need to return a value.5325 // we need to return a value.
4986 const load_inst = self.builder.buildLoad(abi_ret_ty, operand, "");5326 _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, operand, alignment, ""));
4987 load_inst.setAlignment(alignment);5327 return .none;
4988 _ = self.builder.buildRet(load_inst);
4989 return null;
4990 }5328 }
49915329
4992 const llvm_ret_ty = operand.typeOf();5330 const llvm_ret_ty = operand.typeOfWip(&self.wip);
4993 if (abi_ret_ty == llvm_ret_ty) {5331 if (abi_ret_ty == llvm_ret_ty) {
4994 _ = self.builder.buildRet(operand);5332 _ = try self.wip.ret(operand);
4995 return null;5333 return .none;
4996 }5334 }
49975335
4998 const rp = self.buildAlloca(llvm_ret_ty, alignment);5336 const rp = try self.buildAlloca(llvm_ret_ty, alignment);
4999 const store_inst = self.builder.buildStore(operand, rp);5337 _ = try self.wip.store(.normal, operand, rp, alignment);
5000 store_inst.setAlignment(alignment);5338 _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, rp, alignment, ""));
5001 const load_inst = self.builder.buildLoad(abi_ret_ty, rp, "");5339 return .none;
5002 load_inst.setAlignment(alignment);
5003 _ = self.builder.buildRet(load_inst);
5004 return null;
5005 }5340 }
50065341
5007 fn airRetLoad(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5342 fn airRetLoad(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5008 const o = self.dg.object;5343 const o = self.dg.object;
5009 const mod = o.module;5344 const mod = o.module;
5010 const un_op = self.air.instructions.items(.data)[inst].un_op;5345 const un_op = self.air.instructions.items(.data)[inst].un_op;
...@@ -5016,36 +5351,34 @@ pub const FuncGen = struct {...@@ -5016,36 +5351,34 @@ pub const FuncGen = struct {
5016 // Functions with an empty error set are emitted with an error code5351 // Functions with an empty error set are emitted with an error code
5017 // return type and return zero so they can be function pointers coerced5352 // return type and return zero so they can be function pointers coerced
5018 // to functions that return anyerror.5353 // to functions that return anyerror.
5019 const err_int = try o.lowerType(Type.anyerror);5354 _ = try self.wip.ret(try o.builder.intValue(Builder.Type.err_int, 0));
5020 _ = self.builder.buildRet(err_int.constInt(0, .False));
5021 } else {5355 } else {
5022 _ = self.builder.buildRetVoid();5356 _ = try self.wip.retVoid();
5023 }5357 }
5024 return null;5358 return .none;
5025 }5359 }
5026 if (self.ret_ptr != null) {5360 if (self.ret_ptr != .none) {
5027 _ = self.builder.buildRetVoid();5361 _ = try self.wip.retVoid();
5028 return null;5362 return .none;
5029 }5363 }
5030 const ptr = try self.resolveInst(un_op);5364 const ptr = try self.resolveInst(un_op);
5031 const abi_ret_ty = try lowerFnRetTy(o, fn_info);5365 const abi_ret_ty = try lowerFnRetTy(o, fn_info);
5032 const loaded = self.builder.buildLoad(abi_ret_ty, ptr, "");5366 const alignment = Builder.Alignment.fromByteUnits(ret_ty.abiAlignment(mod));
5033 loaded.setAlignment(ret_ty.abiAlignment(mod));5367 _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, ptr, alignment, ""));
5034 _ = self.builder.buildRet(loaded);5368 return .none;
5035 return null;
5036 }5369 }
50375370
5038 fn airCVaArg(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5371 fn airCVaArg(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5039 const o = self.dg.object;5372 const o = self.dg.object;
5040 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5373 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5041 const list = try self.resolveInst(ty_op.operand);5374 const list = try self.resolveInst(ty_op.operand);
5042 const arg_ty = self.air.getRefType(ty_op.ty);5375 const arg_ty = self.air.getRefType(ty_op.ty);
5043 const llvm_arg_ty = try o.lowerType(arg_ty);5376 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, "");
5046 }5379 }
50475380
5048 fn airCVaCopy(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5381 fn airCVaCopy(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5049 const o = self.dg.object;5382 const o = self.dg.object;
5050 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5383 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5051 const src_list = try self.resolveInst(ty_op.operand);5384 const src_list = try self.resolveInst(ty_op.operand);
...@@ -5053,75 +5386,86 @@ pub const FuncGen = struct {...@@ -5053,75 +5386,86 @@ pub const FuncGen = struct {
5053 const llvm_va_list_ty = try o.lowerType(va_list_ty);5386 const llvm_va_list_ty = try o.lowerType(va_list_ty);
5054 const mod = o.module;5387 const mod = o.module;
50555388
5056 const result_alignment = va_list_ty.abiAlignment(mod);5389 const result_alignment = Builder.Alignment.fromByteUnits(va_list_ty.abiAlignment(mod));
5057 const dest_list = self.buildAlloca(llvm_va_list_ty, result_alignment);5390 const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment);
50585391
5059 const llvm_fn_name = "llvm.va_copy";5392 const llvm_fn_name = "llvm.va_copy";
5060 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {5393 const llvm_fn_ty = try o.builder.fnType(.void, &.{ .ptr, .ptr }, .normal);
5061 const param_types = [_]*llvm.Type{5394 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse
5062 self.context.pointerType(0),5395 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
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 };
50685396
5069 const args: [2]*llvm.Value = .{ dest_list, src_list };5397 const args: [2]*llvm.Value = .{ dest_list.toLlvm(&self.wip), src_list.toLlvm(&self.wip) };
5070 _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");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)) {5408 return if (isByRef(va_list_ty, mod))
5073 return dest_list;5409 dest_list
5074 } else {5410 else
5075 const loaded = self.builder.buildLoad(llvm_va_list_ty, dest_list, "");5411 try self.wip.load(.normal, llvm_va_list_ty, dest_list, result_alignment, "");
5076 loaded.setAlignment(result_alignment);
5077 return loaded;
5078 }
5079 }5412 }
50805413
5081 fn airCVaEnd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5414 fn airCVaEnd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5082 const o = self.dg.object;5415 const o = self.dg.object;
5083 const un_op = self.air.instructions.items(.data)[inst].un_op;5416 const un_op = self.air.instructions.items(.data)[inst].un_op;
5084 const list = try self.resolveInst(un_op);5417 const list = try self.resolveInst(un_op);
50855418
5086 const llvm_fn_name = "llvm.va_end";5419 const llvm_fn_name = "llvm.va_end";
5087 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {5420 const llvm_fn_ty = try o.builder.fnType(.void, &.{.ptr}, .normal);
5088 const param_types = [_]*llvm.Type{self.context.pointerType(0)};5421 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse
5089 const fn_type = llvm.functionType(self.context.voidType(), &param_types, param_types.len, .False);5422 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
5090 break :blk o.llvm_module.addFunction(llvm_fn_name, fn_type);5423
5091 };5424 const args: [1]*llvm.Value = .{list.toLlvm(&self.wip)};
5092 const args: [1]*llvm.Value = .{list};5425 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
5093 _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");5426 llvm_fn_ty.toLlvm(&o.builder),
5094 return null;5427 llvm_fn,
5428 &args,
5429 args.len,
5430 .Fast,
5431 .Auto,
5432 "",
5433 ), &self.wip);
5434 return .none;
5095 }5435 }
50965436
5097 fn airCVaStart(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5437 fn airCVaStart(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5098 const o = self.dg.object;5438 const o = self.dg.object;
5099 const mod = o.module;5439 const mod = o.module;
5100 const va_list_ty = self.typeOfIndex(inst);5440 const va_list_ty = self.typeOfIndex(inst);
5101 const llvm_va_list_ty = try o.lowerType(va_list_ty);5441 const llvm_va_list_ty = try o.lowerType(va_list_ty);
51025442
5103 const result_alignment = va_list_ty.abiAlignment(mod);5443 const result_alignment = Builder.Alignment.fromByteUnits(va_list_ty.abiAlignment(mod));
5104 const list = self.buildAlloca(llvm_va_list_ty, result_alignment);5444 const list = try self.buildAlloca(llvm_va_list_ty, result_alignment);
51055445
5106 const llvm_fn_name = "llvm.va_start";5446 const llvm_fn_name = "llvm.va_start";
5107 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {5447 const llvm_fn_ty = try o.builder.fnType(.void, &.{.ptr}, .normal);
5108 const param_types = [_]*llvm.Type{self.context.pointerType(0)};5448 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse
5109 const fn_type = llvm.functionType(self.context.voidType(), &param_types, param_types.len, .False);5449 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
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, "");
51145450
5115 if (isByRef(va_list_ty, mod)) {5451 const args: [1]*llvm.Value = .{list.toLlvm(&self.wip)};
5116 return list;5452 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
5117 } else {5453 llvm_fn_ty.toLlvm(&o.builder),
5118 const loaded = self.builder.buildLoad(llvm_va_list_ty, list, "");5454 llvm_fn,
5119 loaded.setAlignment(result_alignment);5455 &args,
5120 return loaded;5456 args.len,
5121 }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, "");
5122 }5466 }
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 {
5125 self.builder.setFastMath(want_fast_math);5469 self.builder.setFastMath(want_fast_math);
51265470
5127 const bin_op = self.air.instructions.items(.data)[inst].bin_op;5471 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -5132,7 +5476,7 @@ pub const FuncGen = struct {...@@ -5132,7 +5476,7 @@ pub const FuncGen = struct {
5132 return self.cmp(lhs, rhs, operand_ty, op);5476 return self.cmp(lhs, rhs, operand_ty, op);
5133 }5477 }
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 {
5136 self.builder.setFastMath(want_fast_math);5480 self.builder.setFastMath(want_fast_math);
51375481
5138 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;5482 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -5146,21 +5490,30 @@ pub const FuncGen = struct {...@@ -5146,21 +5490,30 @@ pub const FuncGen = struct {
5146 return self.cmp(lhs, rhs, vec_ty, cmp_op);5490 return self.cmp(lhs, rhs, vec_ty, cmp_op);
5147 }5491 }
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;
5150 const un_op = self.air.instructions.items(.data)[inst].un_op;5495 const un_op = self.air.instructions.items(.data)[inst].un_op;
5151 const operand = try self.resolveInst(un_op);5496 const operand = try self.resolveInst(un_op);
5152 const llvm_fn = try self.getCmpLtErrorsLenFunction();5497 const llvm_fn = try self.getCmpLtErrorsLenFunction();
5153 const args: [1]*llvm.Value = .{operand};5498 const args: [1]*llvm.Value = .{operand.toLlvm(&self.wip)};
5154 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");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);
5155 }5508 }
51565509
5157 fn cmp(5510 fn cmp(
5158 self: *FuncGen,5511 self: *FuncGen,
5159 lhs: *llvm.Value,5512 lhs: Builder.Value,
5160 rhs: *llvm.Value,5513 rhs: Builder.Value,
5161 operand_ty: Type,5514 operand_ty: Type,
5162 op: math.CompareOperator,5515 op: math.CompareOperator,
5163 ) Allocator.Error!*llvm.Value {5516 ) Allocator.Error!Builder.Value {
5164 const o = self.dg.object;5517 const o = self.dg.object;
5165 const mod = o.module;5518 const mod = o.module;
5166 const scalar_ty = operand_ty.scalarType(mod);5519 const scalar_ty = operand_ty.scalarType(mod);
...@@ -5178,46 +5531,47 @@ pub const FuncGen = struct {...@@ -5178,46 +5531,47 @@ pub const FuncGen = struct {
5178 // of optionals that are not pointers.5531 // of optionals that are not pointers.
5179 const is_by_ref = isByRef(scalar_ty, mod);5532 const is_by_ref = isByRef(scalar_ty, mod);
5180 const opt_llvm_ty = try o.lowerType(scalar_ty);5533 const opt_llvm_ty = try o.lowerType(scalar_ty);
5181 const lhs_non_null = self.optIsNonNull(opt_llvm_ty, lhs, is_by_ref);5534 const lhs_non_null = try self.optCmpNull(.ne, opt_llvm_ty, lhs, is_by_ref);
5182 const rhs_non_null = self.optIsNonNull(opt_llvm_ty, rhs, is_by_ref);5535 const rhs_non_null = try self.optCmpNull(.ne, opt_llvm_ty, rhs, is_by_ref);
5183 const llvm_i2 = self.context.intType(2);5536 const llvm_i2 = try o.builder.intType(2);
5184 const lhs_non_null_i2 = self.builder.buildZExt(lhs_non_null, llvm_i2, "");5537 const lhs_non_null_i2 = try self.wip.cast(.zext, lhs_non_null, llvm_i2, "");
5185 const rhs_non_null_i2 = self.builder.buildZExt(rhs_non_null, llvm_i2, "");5538 const rhs_non_null_i2 = try self.wip.cast(.zext, rhs_non_null, llvm_i2, "");
5186 const lhs_shifted = self.builder.buildShl(lhs_non_null_i2, llvm_i2.constInt(1, .False), "");5539 const lhs_shifted = try self.wip.bin(.shl, lhs_non_null_i2, try o.builder.intValue(llvm_i2, 1), "");
5187 const lhs_rhs_ored = self.builder.buildOr(lhs_shifted, rhs_non_null_i2, "");5540 const lhs_rhs_ored = try self.wip.bin(.@"or", lhs_shifted, rhs_non_null_i2, "");
5188 const both_null_block = self.context.appendBasicBlock(self.llvm_func, "BothNull");5541 const both_null_block = try self.wip.block(1, "BothNull");
5189 const mixed_block = self.context.appendBasicBlock(self.llvm_func, "Mixed");5542 const mixed_block = try self.wip.block(1, "Mixed");
5190 const both_pl_block = self.context.appendBasicBlock(self.llvm_func, "BothNonNull");5543 const both_pl_block = try self.wip.block(1, "BothNonNull");
5191 const end_block = self.context.appendBasicBlock(self.llvm_func, "End");5544 const end_block = try self.wip.block(3, "End");
5192 const llvm_switch = self.builder.buildSwitch(lhs_rhs_ored, mixed_block, 2);5545 var wip_switch = try self.wip.@"switch"(lhs_rhs_ored, mixed_block, 2);
5193 const llvm_i2_00 = llvm_i2.constInt(0b00, .False);5546 defer wip_switch.finish(&self.wip);
5194 const llvm_i2_11 = llvm_i2.constInt(0b11, .False);5547 try wip_switch.addCase(
5195 llvm_switch.addCase(llvm_i2_00, both_null_block);5548 try o.builder.intConst(llvm_i2, 0b00),
5196 llvm_switch.addCase(llvm_i2_11, both_pl_block);5549 both_null_block,
51975550 &self.wip,
5198 self.builder.positionBuilderAtEnd(both_null_block);5551 );
5199 _ = self.builder.buildBr(end_block);5552 try wip_switch.addCase(
52005553 try o.builder.intConst(llvm_i2, 0b11),
5201 self.builder.positionBuilderAtEnd(mixed_block);5554 both_pl_block,
5202 _ = self.builder.buildBr(end_block);5555 &self.wip,
52035556 );
5204 self.builder.positionBuilderAtEnd(both_pl_block);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 };
5205 const lhs_payload = try self.optPayloadHandle(opt_llvm_ty, lhs, scalar_ty, true);5565 const lhs_payload = try self.optPayloadHandle(opt_llvm_ty, lhs, scalar_ty, true);
5206 const rhs_payload = try self.optPayloadHandle(opt_llvm_ty, rhs, scalar_ty, true);5566 const rhs_payload = try self.optPayloadHandle(opt_llvm_ty, rhs, scalar_ty, true);
5207 const payload_cmp = try self.cmp(lhs_payload, rhs_payload, payload_ty, op);5567 const payload_cmp = try self.cmp(lhs_payload, rhs_payload, payload_ty, op);
5208 _ = self.builder.buildBr(end_block);5568 _ = try self.wip.br(end_block);
5209 const both_pl_block_end = self.builder.getInsertBlock();5569 const both_pl_block_end = self.wip.cursor.block;
52105570
5211 self.builder.positionBuilderAtEnd(end_block);5571 self.wip.cursor = .{ .block = end_block };
5212 const incoming_blocks: [3]*llvm.BasicBlock = .{5572 const llvm_i1_0 = try o.builder.intValue(.i1, 0);
5213 both_null_block,5573 const llvm_i1_1 = try o.builder.intValue(.i1, 1);
5214 mixed_block,5574 const incoming_values: [3]Builder.Value = .{
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 = .{
5221 switch (op) {5575 switch (op) {
5222 .eq => llvm_i1_1,5576 .eq => llvm_i1_1,
5223 .neq => llvm_i1_0,5577 .neq => llvm_i1_0,
...@@ -5231,47 +5585,48 @@ pub const FuncGen = struct {...@@ -5231,47 +5585,48 @@ pub const FuncGen = struct {
5231 payload_cmp,5585 payload_cmp,
5232 };5586 };
52335587
5234 const phi_node = self.builder.buildPhi(llvm_i1, "");5588 const phi = try self.wip.phi(.i1, "");
5235 comptime assert(incoming_values.len == incoming_blocks.len);5589 try phi.finish(
5236 phi_node.addIncoming(
5237 &incoming_values,5590 &incoming_values,
5238 &incoming_blocks,5591 &.{ both_null_block, mixed_block, both_pl_block_end },
5239 incoming_values.len,5592 &self.wip,
5240 );5593 );
5241 return phi_node;5594 return phi.toValue();
5242 },5595 },
5243 .Float => return self.buildFloatCmp(op, operand_ty, .{ lhs, rhs }),5596 .Float => return self.buildFloatCmp(op, operand_ty, .{ lhs, rhs }),
5244 else => unreachable,5597 else => unreachable,
5245 };5598 };
5246 const is_signed = int_ty.isSignedInt(mod);5599 const is_signed = int_ty.isSignedInt(mod);
5247 const operation: llvm.IntPredicate = switch (op) {5600 const cond: Builder.IntegerCondition = switch (op) {
5248 .eq => .EQ,5601 .eq => .eq,
5249 .neq => .NE,5602 .neq => .ne,
5250 .lt => if (is_signed) llvm.IntPredicate.SLT else .ULT,5603 .lt => if (is_signed) .slt else .ult,
5251 .lte => if (is_signed) llvm.IntPredicate.SLE else .ULE,5604 .lte => if (is_signed) .sle else .ule,
5252 .gt => if (is_signed) llvm.IntPredicate.SGT else .UGT,5605 .gt => if (is_signed) .sgt else .ugt,
5253 .gte => if (is_signed) llvm.IntPredicate.SGE else .UGE,5606 .gte => if (is_signed) .sge else .uge,
5254 };5607 };
5255 return self.builder.buildICmp(operation, lhs, rhs, "");5608 return self.wip.icmp(cond, lhs, rhs, "");
5256 }5609 }
52575610
5258 fn airBlock(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5611 fn airBlock(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5259 const o = self.dg.object;5612 const o = self.dg.object;
5260 const mod = o.module;5613 const mod = o.module;
5261 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;5614 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
5262 const extra = self.air.extraData(Air.Block, ty_pl.payload);5615 const extra = self.air.extraData(Air.Block, ty_pl.payload);
5263 const body = self.air.extra[extra.end..][0..extra.data.body_len];5616 const body = self.air.extra[extra.end..][0..extra.data.body_len];
5264 const inst_ty = self.typeOfIndex(inst);5617 const inst_ty = self.typeOfIndex(inst);
5265 const parent_bb = self.context.createBasicBlock("Block");
52665618
5267 if (inst_ty.isNoReturn(mod)) {5619 if (inst_ty.isNoReturn(mod)) {
5268 try self.genBody(body);5620 try self.genBody(body);
5269 return null;5621 return .none;
5270 }5622 }
52715623
5272 var breaks: BreakList = .{};5624 const have_block_result = inst_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod);
5273 defer breaks.deinit(self.gpa);
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");
5275 try self.blocks.putNoClobber(self.gpa, inst, .{5630 try self.blocks.putNoClobber(self.gpa, inst, .{
5276 .parent_bb = parent_bb,5631 .parent_bb = parent_bb,
5277 .breaks = &breaks,5632 .breaks = &breaks,
...@@ -5280,36 +5635,33 @@ pub const FuncGen = struct {...@@ -5280,36 +5635,33 @@ pub const FuncGen = struct {
52805635
5281 try self.genBody(body);5636 try self.genBody(body);
52825637
5283 self.llvm_func.appendExistingBasicBlock(parent_bb);5638 self.wip.cursor = .{ .block = parent_bb };
5284 self.builder.positionBuilderAtEnd(parent_bb);
52855639
5286 // Create a phi node only if the block returns a value.5640 // Create a phi node only if the block returns a value.
5287 const is_body = inst_ty.zigTypeTag(mod) == .Fn;5641 if (have_block_result) {
5288 if (!is_body and !inst_ty.hasRuntimeBitsIgnoreComptime(mod)) return null;5642 const raw_llvm_ty = try o.lowerType(inst_ty);
52895643 const llvm_ty: Builder.Type = ty: {
5290 const raw_llvm_ty = try o.lowerType(inst_ty);5644 // If the zig tag type is a function, this represents an actual function body; not
52915645 // a pointer to it. LLVM IR allows the call instruction to use function bodies instead
5292 const llvm_ty = ty: {5646 // of function pointers, however the phi makes it a runtime value and therefore
5293 // If the zig tag type is a function, this represents an actual function body; not5647 // the LLVM type has to be wrapped in a pointer.
5294 // a pointer to it. LLVM IR allows the call instruction to use function bodies instead5648 if (inst_ty.zigTypeTag(mod) == .Fn or isByRef(inst_ty, mod)) {
5295 // of function pointers, however the phi makes it a runtime value and therefore5649 break :ty .ptr;
5296 // the LLVM type has to be wrapped in a pointer.5650 }
5297 if (is_body or isByRef(inst_ty, mod)) {5651 break :ty raw_llvm_ty;
5298 break :ty self.context.pointerType(0);5652 };
5299 }
5300 break :ty raw_llvm_ty;
5301 };
53025653
5303 const phi_node = self.builder.buildPhi(llvm_ty, "");5654 parent_bb.ptr(&self.wip).incoming = @intCast(breaks.list.len);
5304 phi_node.addIncoming(5655 const phi = try self.wip.phi(llvm_ty, "");
5305 breaks.items(.val).ptr,5656 try phi.finish(breaks.list.items(.val), breaks.list.items(.bb), &self.wip);
5306 breaks.items(.bb).ptr,5657 return phi.toValue();
5307 @as(c_uint, @intCast(breaks.len)),5658 } else {
5308 );5659 parent_bb.ptr(&self.wip).incoming = @intCast(breaks.len);
5309 return phi_node;5660 return .none;
5661 }
5310 }5662 }
53115663
5312 fn airBr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5664 fn airBr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5313 const o = self.dg.object;5665 const o = self.dg.object;
5314 const branch = self.air.instructions.items(.data)[inst].br;5666 const branch = self.air.instructions.items(.data)[inst].br;
5315 const block = self.blocks.get(branch.block_inst).?;5667 const block = self.blocks.get(branch.block_inst).?;
...@@ -5317,42 +5669,39 @@ pub const FuncGen = struct {...@@ -5317,42 +5669,39 @@ pub const FuncGen = struct {
5317 // Add the values to the lists only if the break provides a value.5669 // Add the values to the lists only if the break provides a value.
5318 const operand_ty = self.typeOf(branch.operand);5670 const operand_ty = self.typeOf(branch.operand);
5319 const mod = o.module;5671 const mod = o.module;
5320 if (operand_ty.hasRuntimeBitsIgnoreComptime(mod) or operand_ty.zigTypeTag(mod) == .Fn) {5672 if (operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) {
5321 const val = try self.resolveInst(branch.operand);5673 const val = try self.resolveInst(branch.operand);
53225674
5323 // For the phi node, we need the basic blocks and the values of the5675 // For the phi node, we need the basic blocks and the values of the
5324 // break instructions.5676 // break instructions.
5325 try block.breaks.append(self.gpa, .{5677 try block.breaks.list.append(self.gpa, .{ .bb = self.wip.cursor.block, .val = val });
5326 .bb = self.builder.getInsertBlock(),5678 } else block.breaks.len += 1;
5327 .val = val,5679 _ = try self.wip.br(block.parent_bb);
5328 });5680 return .none;
5329 }
5330 _ = self.builder.buildBr(block.parent_bb);
5331 return null;
5332 }5681 }
53335682
5334 fn airCondBr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5683 fn airCondBr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5335 const pl_op = self.air.instructions.items(.data)[inst].pl_op;5684 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
5336 const cond = try self.resolveInst(pl_op.operand);5685 const cond = try self.resolveInst(pl_op.operand);
5337 const extra = self.air.extraData(Air.CondBr, pl_op.payload);5686 const extra = self.air.extraData(Air.CondBr, pl_op.payload);
5338 const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len];5687 const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len];
5339 const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];5688 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");5690 const then_block = try self.wip.block(1, "Then");
5342 const else_block = self.context.appendBasicBlock(self.llvm_func, "Else");5691 const else_block = try self.wip.block(1, "Else");
5343 _ = self.builder.buildCondBr(cond, then_block, else_block);5692 _ = try self.wip.brCond(cond, then_block, else_block);
53445693
5345 self.builder.positionBuilderAtEnd(then_block);5694 self.wip.cursor = .{ .block = then_block };
5346 try self.genBody(then_body);5695 try self.genBody(then_body);
53475696
5348 self.builder.positionBuilderAtEnd(else_block);5697 self.wip.cursor = .{ .block = else_block };
5349 try self.genBody(else_body);5698 try self.genBody(else_body);
53505699
5351 // No need to reset the insert cursor since this instruction is noreturn.5700 // No need to reset the insert cursor since this instruction is noreturn.
5352 return null;5701 return .none;
5353 }5702 }
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 {
5356 const o = self.dg.object;5705 const o = self.dg.object;
5357 const mod = o.module;5706 const mod = o.module;
5358 const inst = body_tail[0];5707 const inst = body_tail[0];
...@@ -5367,7 +5716,7 @@ pub const FuncGen = struct {...@@ -5367,7 +5716,7 @@ pub const FuncGen = struct {
5367 return lowerTry(self, err_union, body, err_union_ty, false, can_elide_load, is_unused);5716 return lowerTry(self, err_union, body, err_union_ty, false, can_elide_load, is_unused);
5368 }5717 }
53695718
5370 fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5719 fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5371 const o = self.dg.object;5720 const o = self.dg.object;
5372 const mod = o.module;5721 const mod = o.module;
5373 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;5722 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -5381,13 +5730,13 @@ pub const FuncGen = struct {...@@ -5381,13 +5730,13 @@ pub const FuncGen = struct {
53815730
5382 fn lowerTry(5731 fn lowerTry(
5383 fg: *FuncGen,5732 fg: *FuncGen,
5384 err_union: *llvm.Value,5733 err_union: Builder.Value,
5385 body: []const Air.Inst.Index,5734 body: []const Air.Inst.Index,
5386 err_union_ty: Type,5735 err_union_ty: Type,
5387 operand_is_ptr: bool,5736 operand_is_ptr: bool,
5388 can_elide_load: bool,5737 can_elide_load: bool,
5389 is_unused: bool,5738 is_unused: bool,
5390 ) !?*llvm.Value {5739 ) !Builder.Value {
5391 const o = fg.dg.object;5740 const o = fg.dg.object;
5392 const mod = o.module;5741 const mod = o.module;
5393 const payload_ty = err_union_ty.errorUnionPayload(mod);5742 const payload_ty = err_union_ty.errorUnionPayload(mod);
...@@ -5395,122 +5744,135 @@ pub const FuncGen = struct {...@@ -5395,122 +5744,135 @@ pub const FuncGen = struct {
5395 const err_union_llvm_ty = try o.lowerType(err_union_ty);5744 const err_union_llvm_ty = try o.lowerType(err_union_ty);
53965745
5397 if (!err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) {5746 if (!err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) {
5398 const is_err = err: {5747 const loaded = loaded: {
5399 const err_set_ty = try o.lowerType(Type.anyerror);
5400 const zero = err_set_ty.constNull();
5401 if (!payload_has_bits) {5748 if (!payload_has_bits) {
5402 // TODO add alignment to this load5749 // TODO add alignment to this load
5403 const loaded = if (operand_is_ptr)5750 break :loaded if (operand_is_ptr)
5404 fg.builder.buildLoad(err_set_ty, err_union, "")5751 try fg.wip.load(.normal, Builder.Type.err_int, err_union, .default, "")
5405 else5752 else
5406 err_union;5753 err_union;
5407 break :err fg.builder.buildICmp(.NE, loaded, zero, "");
5408 }5754 }
5409 const err_field_index = errUnionErrorOffset(payload_ty, mod);5755 const err_field_index = errUnionErrorOffset(payload_ty, mod);
5410 if (operand_is_ptr or isByRef(err_union_ty, mod)) {5756 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, "");
5412 // TODO add alignment to this load5759 // TODO add alignment to this load
5413 const loaded = fg.builder.buildLoad(err_set_ty, err_field_ptr, "");5760 break :loaded try fg.wip.load(
5414 break :err fg.builder.buildICmp(.NE, loaded, zero, "");5761 .normal,
5762 Builder.Type.err_int,
5763 err_field_ptr,
5764 .default,
5765 "",
5766 );
5415 }5767 }
5416 const loaded = fg.builder.buildExtractValue(err_union, err_field_index, "");5768 break :loaded try fg.wip.extractValue(err_union, &.{err_field_index}, "");
5417 break :err fg.builder.buildICmp(.NE, loaded, zero, "");
5418 };5769 };
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");5773 const return_block = try fg.wip.block(1, "TryRet");
5421 const continue_block = fg.context.appendBasicBlock(fg.llvm_func, "TryCont");5774 const continue_block = try fg.wip.block(1, "TryCont");
5422 _ = fg.builder.buildCondBr(is_err, return_block, continue_block);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 };
5425 try fg.genBody(body);5778 try fg.genBody(body);
54265779
5427 fg.builder.positionBuilderAtEnd(continue_block);5780 fg.wip.cursor = .{ .block = 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;
5434 }5781 }
5782 if (is_unused) return .none;
5783 if (!payload_has_bits) return if (operand_is_ptr) err_union else .none;
5435 const offset = errUnionPayloadOffset(payload_ty, mod);5784 const offset = errUnionPayloadOffset(payload_ty, mod);
5436 if (operand_is_ptr) {5785 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, "");
5438 } else if (isByRef(err_union_ty, mod)) {5787 } 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));
5440 if (isByRef(payload_ty, mod)) {5790 if (isByRef(payload_ty, mod)) {
5441 if (can_elide_load)5791 if (can_elide_load)
5442 return payload_ptr;5792 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);
5445 }5795 }
5446 const load_inst = fg.builder.buildLoad(err_union_llvm_ty.structGetTypeAtIndex(offset), payload_ptr, "");5796 const load_ty = err_union_llvm_ty.structFields(&o.builder)[offset];
5447 load_inst.setAlignment(payload_ty.abiAlignment(mod));5797 return fg.wip.load(.normal, load_ty, payload_ptr, payload_alignment, "");
5448 return load_inst;
5449 }5798 }
5450 return fg.builder.buildExtractValue(err_union, offset, "");5799 return fg.wip.extractValue(err_union, &.{offset}, "");
5451 }5800 }
54525801
5453 fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5802 fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5454 const o = self.dg.object;5803 const o = self.dg.object;
5455 const mod = o.module;
5456 const pl_op = self.air.instructions.items(.data)[inst].pl_op;5804 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
5457 const cond = try self.resolveInst(pl_op.operand);5805 const cond = try self.resolveInst(pl_op.operand);
5458 const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload);5806 const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload);
5459 const else_block = self.context.appendBasicBlock(self.llvm_func, "Else");5807 const else_block = try self.wip.block(1, "Default");
5460 const target = mod.getTarget();5808 const llvm_usize = try o.lowerType(Type.usize);
5461 const llvm_usize = self.context.intType(target.ptrBitWidth());5809 const cond_int = if (cond.typeOfWip(&self.wip).isPointer(&o.builder))
5462 const cond_int = if (cond.typeOf().getTypeKind() == .Pointer)5810 try self.wip.cast(.ptrtoint, cond, llvm_usize, "")
5463 self.builder.buildPtrToInt(cond, llvm_usize, "")
5464 else5811 else
5465 cond;5812 cond;
5466 const llvm_switch = self.builder.buildSwitch(cond_int, else_block, switch_br.data.cases_len);
54675813
5468 var extra_index: usize = switch_br.end;5814 var extra_index: usize = switch_br.end;
5469 var case_i: u32 = 0;5815 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;
5471 while (case_i < switch_br.data.cases_len) : (case_i += 1) {5832 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
5472 const case = self.air.extraData(Air.SwitchBr.Case, extra_index);5833 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]);
5474 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];5836 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
5475 extra_index = case.end + case.data.items_len + case_body.len;5837 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
5479 for (items) |item| {5841 for (items) |item| {
5480 const llvm_item = try self.resolveInst(item);5842 const llvm_item = (try self.resolveInst(item)).toConst().?;
5481 const llvm_int_item = if (llvm_item.typeOf().getTypeKind() == .Pointer)5843 const llvm_int_item = if (llvm_item.typeOf(&o.builder).isPointer(&o.builder))
5482 llvm_item.constPtrToInt(llvm_usize)5844 try o.builder.castConst(.ptrtoint, llvm_item, llvm_usize)
5483 else5845 else
5484 llvm_item;5846 llvm_item;
5485 llvm_switch.addCase(llvm_int_item, case_block);5847 try wip_switch.addCase(llvm_int_item, case_block, &self.wip);
5486 }5848 }
54875849
5488 self.builder.positionBuilderAtEnd(case_block);5850 self.wip.cursor = .{ .block = case_block };
5489 try self.genBody(case_body);5851 try self.genBody(case_body);
5490 }5852 }
54915853
5492 self.builder.positionBuilderAtEnd(else_block);5854 self.wip.cursor = .{ .block = else_block };
5493 const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];5855 const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];
5494 if (else_body.len != 0) {5856 if (else_body.len != 0) {
5495 try self.genBody(else_body);5857 try self.genBody(else_body);
5496 } else {5858 } else {
5497 _ = self.builder.buildUnreachable();5859 _ = try self.wip.@"unreachable"();
5498 }5860 }
54995861
5500 // No need to reset the insert cursor since this instruction is noreturn.5862 // No need to reset the insert cursor since this instruction is noreturn.
5501 return null;5863 return .none;
5502 }5864 }
55035865
5504 fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5866 fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5505 const o = self.dg.object;5867 const o = self.dg.object;
5506 const mod = o.module;5868 const mod = o.module;
5507 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;5869 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
5508 const loop = self.air.extraData(Air.Block, ty_pl.payload);5870 const loop = self.air.extraData(Air.Block, ty_pl.payload);
5509 const body = self.air.extra[loop.end..][0..loop.data.body_len];5871 const body = self.air.extra[loop.end..][0..loop.data.body_len];
5510 const loop_block = self.context.appendBasicBlock(self.llvm_func, "Loop");5872 const loop_block = try self.wip.block(2, "Loop");
5511 _ = self.builder.buildBr(loop_block);5873 _ = try self.wip.br(loop_block);
55125874
5513 self.builder.positionBuilderAtEnd(loop_block);5875 self.wip.cursor = .{ .block = loop_block };
5514 try self.genBody(body);5876 try self.genBody(body);
55155877
5516 // TODO instead of this logic, change AIR to have the property that5878 // TODO instead of this logic, change AIR to have the property that
...@@ -5520,35 +5882,30 @@ pub const FuncGen = struct {...@@ -5520,35 +5882,30 @@ pub const FuncGen = struct {
5520 // be while(true) instead of for(body), which will eliminate 1 branch on5882 // be while(true) instead of for(body), which will eliminate 1 branch on
5521 // a hot path.5883 // a hot path.
5522 if (body.len == 0 or !self.typeOfIndex(body[body.len - 1]).isNoReturn(mod)) {5884 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);
5524 }5886 }
5525 return null;5887 return .none;
5526 }5888 }
55275889
5528 fn airArrayToSlice(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5890 fn airArrayToSlice(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5529 const o = self.dg.object;5891 const o = self.dg.object;
5530 const mod = o.module;5892 const mod = o.module;
5531 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5893 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5532 const operand_ty = self.typeOf(ty_op.operand);5894 const operand_ty = self.typeOf(ty_op.operand);
5533 const array_ty = operand_ty.childType(mod);5895 const array_ty = operand_ty.childType(mod);
5534 const llvm_usize = try o.lowerType(Type.usize);5896 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));
5536 const slice_llvm_ty = try o.lowerType(self.typeOfIndex(inst));5898 const slice_llvm_ty = try o.lowerType(self.typeOfIndex(inst));
5537 const operand = try self.resolveInst(ty_op.operand);5899 const operand = try self.resolveInst(ty_op.operand);
5538 if (!array_ty.hasRuntimeBitsIgnoreComptime(mod)) {5900 if (!array_ty.hasRuntimeBitsIgnoreComptime(mod))
5539 const partial = self.builder.buildInsertValue(slice_llvm_ty.getUndef(), operand, 0, "");5901 return self.wip.buildAggregate(slice_llvm_ty, &.{ operand, len }, "");
5540 return self.builder.buildInsertValue(partial, len, 1, "");5902 const ptr = try self.wip.gep(.inbounds, try o.lowerType(array_ty), operand, &.{
5541 }5903 try o.builder.intValue(llvm_usize, 0), try o.builder.intValue(llvm_usize, 0),
5542 const indices: [2]*llvm.Value = .{5904 }, "");
5543 llvm_usize.constNull(), llvm_usize.constNull(),5905 return self.wip.buildAggregate(slice_llvm_ty, &.{ ptr, len }, "");
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, "");
5549 }5906 }
55505907
5551 fn airFloatFromInt(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5908 fn airFloatFromInt(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5552 const o = self.dg.object;5909 const o = self.dg.object;
5553 const mod = o.module;5910 const mod = o.module;
5554 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5911 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -5562,51 +5919,53 @@ pub const FuncGen = struct {...@@ -5562,51 +5919,53 @@ pub const FuncGen = struct {
5562 const dest_llvm_ty = try o.lowerType(dest_ty);5919 const dest_llvm_ty = try o.lowerType(dest_ty);
5563 const target = mod.getTarget();5920 const target = mod.getTarget();
55645921
5565 if (intrinsicsAllowed(dest_scalar_ty, target)) {5922 if (intrinsicsAllowed(dest_scalar_ty, target)) return self.wip.conv(
5566 if (operand_scalar_ty.isSignedInt(mod)) {5923 if (operand_scalar_ty.isSignedInt(mod)) .signed else .unsigned,
5567 return self.builder.buildSIToFP(operand, dest_llvm_ty, "");5924 operand,
5568 } else {5925 dest_llvm_ty,
5569 return self.builder.buildUIToFP(operand, dest_llvm_ty, "");5926 "",
5570 }5927 );
5571 }
55725928
5573 const operand_bits = @as(u16, @intCast(operand_scalar_ty.bitSize(mod)));5929 const rt_int_bits = compilerRtIntBits(@intCast(operand_scalar_ty.bitSize(mod)));
5574 const rt_int_bits = compilerRtIntBits(operand_bits);5930 const rt_int_ty = try o.builder.intType(rt_int_bits);
5575 const rt_int_ty = self.context.intType(rt_int_bits);5931 var extended = try self.wip.conv(
5576 var extended = e: {5932 if (operand_scalar_ty.isSignedInt(mod)) .signed else .unsigned,
5577 if (operand_scalar_ty.isSignedInt(mod)) {5933 operand,
5578 break :e self.builder.buildSExtOrBitCast(operand, rt_int_ty, "");5934 rt_int_ty,
5579 } else {5935 "",
5580 break :e self.builder.buildZExtOrBitCast(operand, rt_int_ty, "");5936 );
5581 }
5582 };
5583 const dest_bits = dest_scalar_ty.floatBits(target);5937 const dest_bits = dest_scalar_ty.floatBits(target);
5584 const compiler_rt_operand_abbrev = compilerRtIntAbbrev(rt_int_bits);5938 const compiler_rt_operand_abbrev = compilerRtIntAbbrev(rt_int_bits);
5585 const compiler_rt_dest_abbrev = compilerRtFloatAbbrev(dest_bits);5939 const compiler_rt_dest_abbrev = compilerRtFloatAbbrev(dest_bits);
5586 const sign_prefix = if (operand_scalar_ty.isSignedInt(mod)) "" else "un";5940 const sign_prefix = if (operand_scalar_ty.isSignedInt(mod)) "" else "un";
5587 var fn_name_buf: [64]u8 = undefined;5941 const fn_name = try o.builder.fmt("__float{s}{s}i{s}f", .{
5588 const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__float{s}{s}i{s}f", .{
5589 sign_prefix,5942 sign_prefix,
5590 compiler_rt_operand_abbrev,5943 compiler_rt_operand_abbrev,
5591 compiler_rt_dest_abbrev,5944 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;
5595 if (rt_int_bits == 128 and (target.os.tag == .windows and target.cpu.arch == .x86_64)) {5948 if (rt_int_bits == 128 and (target.os.tag == .windows and target.cpu.arch == .x86_64)) {
5596 // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard5949 // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard
5597 // i128 calling convention to adhere to the ABI that LLVM expects compiler-rt to have.5950 // i128 calling convention to adhere to the ABI that LLVM expects compiler-rt to have.
5598 const v2i64 = self.context.intType(64).vectorType(2);5951 param_type = try o.builder.vectorType(.normal, 2, .i64);
5599 extended = self.builder.buildBitCast(extended, v2i64, "");5952 extended = try self.wip.cast(.bitcast, extended, param_type, "");
5600 param_types = [1]*llvm.Type{v2i64};
5601 }5953 }
56025954
5603 const libc_fn = self.getLibcFunction(fn_name, &param_types, dest_llvm_ty);5955 const libc_fn = try self.getLibcFunction(fn_name, &.{param_type}, dest_llvm_ty);
5604 const params = [1]*llvm.Value{extended};5956 const params = [1]*llvm.Value{extended.toLlvm(&self.wip)};
56055957 return (try self.wip.unimplemented(dest_llvm_ty, "")).finish(self.builder.buildCall(
5606 return self.builder.buildCall(libc_fn.globalGetValueType(), libc_fn, &params, params.len, .C, .Auto, "");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);
5607 }5966 }
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 {
5610 self.builder.setFastMath(want_fast_math);5969 self.builder.setFastMath(want_fast_math);
56115970
5612 const o = self.dg.object;5971 const o = self.dg.object;
...@@ -5624,19 +5983,20 @@ pub const FuncGen = struct {...@@ -5624,19 +5983,20 @@ pub const FuncGen = struct {
56245983
5625 if (intrinsicsAllowed(operand_scalar_ty, target)) {5984 if (intrinsicsAllowed(operand_scalar_ty, target)) {
5626 // TODO set fast math flag5985 // TODO set fast math flag
5627 if (dest_scalar_ty.isSignedInt(mod)) {5986 return self.wip.conv(
5628 return self.builder.buildFPToSI(operand, dest_llvm_ty, "");5987 if (dest_scalar_ty.isSignedInt(mod)) .signed else .unsigned,
5629 } else {5988 operand,
5630 return self.builder.buildFPToUI(operand, dest_llvm_ty, "");5989 dest_llvm_ty,
5631 }5990 "",
5991 );
5632 }5992 }
56335993
5634 const rt_int_bits = compilerRtIntBits(@as(u16, @intCast(dest_scalar_ty.bitSize(mod))));5994 const rt_int_bits = compilerRtIntBits(@intCast(dest_scalar_ty.bitSize(mod)));
5635 const ret_ty = self.context.intType(rt_int_bits);5995 const ret_ty = try o.builder.intType(rt_int_bits);
5636 const libc_ret_ty = if (rt_int_bits == 128 and (target.os.tag == .windows and target.cpu.arch == .x86_64)) b: {5996 const libc_ret_ty = if (rt_int_bits == 128 and (target.os.tag == .windows and target.cpu.arch == .x86_64)) b: {
5637 // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard5997 // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard
5638 // i128 calling convention to adhere to the ABI that LLVM expects compiler-rt to have.5998 // 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);
5640 } else ret_ty;6000 } else ret_ty;
56416001
5642 const operand_bits = operand_scalar_ty.floatBits(target);6002 const operand_bits = operand_scalar_ty.floatBits(target);
...@@ -5645,66 +6005,66 @@ pub const FuncGen = struct {...@@ -5645,66 +6005,66 @@ pub const FuncGen = struct {
5645 const compiler_rt_dest_abbrev = compilerRtIntAbbrev(rt_int_bits);6005 const compiler_rt_dest_abbrev = compilerRtIntAbbrev(rt_int_bits);
5646 const sign_prefix = if (dest_scalar_ty.isSignedInt(mod)) "" else "uns";6006 const sign_prefix = if (dest_scalar_ty.isSignedInt(mod)) "" else "uns";
56476007
5648 var fn_name_buf: [64]u8 = undefined;6008 const fn_name = try o.builder.fmt("__fix{s}{s}f{s}i", .{
5649 const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__fix{s}{s}f{s}i", .{
5650 sign_prefix,6009 sign_prefix,
5651 compiler_rt_operand_abbrev,6010 compiler_rt_operand_abbrev,
5652 compiler_rt_dest_abbrev,6011 compiler_rt_dest_abbrev,
5653 }) catch unreachable;6012 });
56546013
5655 const operand_llvm_ty = try o.lowerType(operand_ty);6014 const operand_llvm_ty = try o.lowerType(operand_ty);
5656 const param_types = [1]*llvm.Type{operand_llvm_ty};6015 const libc_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, libc_ret_ty);
5657 const libc_fn = self.getLibcFunction(fn_name, &param_types, libc_ret_ty);6016 const params = [1]*llvm.Value{operand.toLlvm(&self.wip)};
5658 const params = [1]*llvm.Value{operand};6017 var result = (try self.wip.unimplemented(libc_ret_ty, "")).finish(self.builder.buildCall(
56596018 libc_fn.typeOf(&o.builder).toLlvm(&o.builder),
5660 var result = self.builder.buildCall(libc_fn.globalGetValueType(), libc_fn, &params, params.len, .C, .Auto, "");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, "");6027 if (libc_ret_ty != ret_ty) result = try self.wip.cast(.bitcast, result, ret_ty, "");
5663 if (ret_ty != dest_llvm_ty) result = self.builder.buildTrunc(result, dest_llvm_ty, "");6028 if (ret_ty != dest_llvm_ty) result = try self.wip.cast(.trunc, result, dest_llvm_ty, "");
5664 return result;6029 return result;
5665 }6030 }
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 {
5668 const o = fg.dg.object;6033 const o = fg.dg.object;
5669 const mod = o.module;6034 const mod = o.module;
5670 if (ty.isSlice(mod)) {6035 return if (ty.isSlice(mod)) fg.wip.extractValue(ptr, &.{0}, "") else ptr;
5671 return fg.builder.buildExtractValue(ptr, 0, "");
5672 } else {
5673 return ptr;
5674 }
5675 }6036 }
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 {
5678 const o = fg.dg.object;6039 const o = fg.dg.object;
5679 const mod = o.module;6040 const mod = o.module;
5680 const target = mod.getTarget();6041 const llvm_usize = try o.lowerType(Type.usize);
5681 const llvm_usize_ty = fg.context.intType(target.ptrBitWidth());
5682 switch (ty.ptrSize(mod)) {6042 switch (ty.ptrSize(mod)) {
5683 .Slice => {6043 .Slice => {
5684 const len = fg.builder.buildExtractValue(ptr, 1, "");6044 const len = try fg.wip.extractValue(ptr, &.{1}, "");
5685 const elem_ty = ty.childType(mod);6045 const elem_ty = ty.childType(mod);
5686 const abi_size = elem_ty.abiSize(mod);6046 const abi_size = elem_ty.abiSize(mod);
5687 if (abi_size == 1) return len;6047 if (abi_size == 1) return len;
5688 const abi_size_llvm_val = llvm_usize_ty.constInt(abi_size, .False);6048 const abi_size_llvm_val = try o.builder.intValue(llvm_usize, abi_size);
5689 return fg.builder.buildMul(len, abi_size_llvm_val, "");6049 return fg.wip.bin(.@"mul nuw", len, abi_size_llvm_val, "");
5690 },6050 },
5691 .One => {6051 .One => {
5692 const array_ty = ty.childType(mod);6052 const array_ty = ty.childType(mod);
5693 const elem_ty = array_ty.childType(mod);6053 const elem_ty = array_ty.childType(mod);
5694 const abi_size = elem_ty.abiSize(mod);6054 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);
5696 },6056 },
5697 .Many, .C => unreachable,6057 .Many, .C => unreachable,
5698 }6058 }
5699 }6059 }
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 {
5702 const ty_op = self.air.instructions.items(.data)[inst].ty_op;6062 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5703 const operand = try self.resolveInst(ty_op.operand);6063 const operand = try self.resolveInst(ty_op.operand);
5704 return self.builder.buildExtractValue(operand, index, "");6064 return self.wip.extractValue(operand, &.{index}, "");
5705 }6065 }
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 {
5708 const o = self.dg.object;6068 const o = self.dg.object;
5709 const mod = o.module;6069 const mod = o.module;
5710 const ty_op = self.air.instructions.items(.data)[inst].ty_op;6070 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -5712,10 +6072,10 @@ pub const FuncGen = struct {...@@ -5712,10 +6072,10 @@ pub const FuncGen = struct {
5712 const slice_ptr_ty = self.typeOf(ty_op.operand);6072 const slice_ptr_ty = self.typeOf(ty_op.operand);
5713 const slice_llvm_ty = try o.lowerPtrElemTy(slice_ptr_ty.childType(mod));6073 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, "");
5716 }6076 }
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 {
5719 const o = self.dg.object;6079 const o = self.dg.object;
5720 const mod = o.module;6080 const mod = o.module;
5721 const inst = body_tail[0];6081 const inst = body_tail[0];
...@@ -5725,20 +6085,20 @@ pub const FuncGen = struct {...@@ -5725,20 +6085,20 @@ pub const FuncGen = struct {
5725 const index = try self.resolveInst(bin_op.rhs);6085 const index = try self.resolveInst(bin_op.rhs);
5726 const elem_ty = slice_ty.childType(mod);6086 const elem_ty = slice_ty.childType(mod);
5727 const llvm_elem_ty = try o.lowerPtrElemTy(elem_ty);6087 const llvm_elem_ty = try o.lowerPtrElemTy(elem_ty);
5728 const base_ptr = self.builder.buildExtractValue(slice, 0, "");6088 const base_ptr = try self.wip.extractValue(slice, &.{0}, "");
5729 const indices: [1]*llvm.Value = .{index};6089 const ptr = try self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{index}, "");
5730 const ptr = self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
5731 if (isByRef(elem_ty, mod)) {6090 if (isByRef(elem_ty, mod)) {
5732 if (self.canElideLoad(body_tail))6091 if (self.canElideLoad(body_tail))
5733 return ptr;6092 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);
5736 }6096 }
57376097
5738 return self.load(ptr, slice_ty);6098 return self.load(ptr, slice_ty);
5739 }6099 }
57406100
5741 fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6101 fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5742 const o = self.dg.object;6102 const o = self.dg.object;
5743 const mod = o.module;6103 const mod = o.module;
5744 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;6104 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -5748,12 +6108,11 @@ pub const FuncGen = struct {...@@ -5748,12 +6108,11 @@ pub const FuncGen = struct {
5748 const slice = try self.resolveInst(bin_op.lhs);6108 const slice = try self.resolveInst(bin_op.lhs);
5749 const index = try self.resolveInst(bin_op.rhs);6109 const index = try self.resolveInst(bin_op.rhs);
5750 const llvm_elem_ty = try o.lowerPtrElemTy(slice_ty.childType(mod));6110 const llvm_elem_ty = try o.lowerPtrElemTy(slice_ty.childType(mod));
5751 const base_ptr = self.builder.buildExtractValue(slice, 0, "");6111 const base_ptr = try self.wip.extractValue(slice, &.{0}, "");
5752 const indices: [1]*llvm.Value = .{index};6112 return self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{index}, "");
5753 return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
5754 }6113 }
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 {
5757 const o = self.dg.object;6116 const o = self.dg.object;
5758 const mod = o.module;6117 const mod = o.module;
5759 const inst = body_tail[0];6118 const inst = body_tail[0];
...@@ -5765,13 +6124,15 @@ pub const FuncGen = struct {...@@ -5765,13 +6124,15 @@ pub const FuncGen = struct {
5765 const array_llvm_ty = try o.lowerType(array_ty);6124 const array_llvm_ty = try o.lowerType(array_ty);
5766 const elem_ty = array_ty.childType(mod);6125 const elem_ty = array_ty.childType(mod);
5767 if (isByRef(array_ty, mod)) {6126 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 };
5769 if (isByRef(elem_ty, mod)) {6130 if (isByRef(elem_ty, mod)) {
5770 const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, array_llvm_val, &indices, indices.len, "");6131 const elem_ptr =
5771 if (canElideLoad(self, body_tail))6132 try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &indices, "");
5772 return elem_ptr;6133 if (canElideLoad(self, body_tail)) return elem_ptr;
57736134 const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
5774 return self.loadByRef(elem_ptr, elem_ty, elem_ty.abiAlignment(mod), false);6135 return self.loadByRef(elem_ptr, elem_ty, elem_alignment, false);
5775 } else {6136 } else {
5776 const elem_llvm_ty = try o.lowerType(elem_ty);6137 const elem_llvm_ty = try o.lowerType(elem_ty);
5777 if (Air.refToIndex(bin_op.lhs)) |lhs_index| {6138 if (Air.refToIndex(bin_op.lhs)) |lhs_index| {
...@@ -5781,26 +6142,38 @@ pub const FuncGen = struct {...@@ -5781,26 +6142,38 @@ pub const FuncGen = struct {
5781 if (Air.refToIndex(load_ptr)) |load_ptr_index| {6142 if (Air.refToIndex(load_ptr)) |load_ptr_index| {
5782 const load_ptr_tag = self.air.instructions.items(.tag)[load_ptr_index];6143 const load_ptr_tag = self.air.instructions.items(.tag)[load_ptr_index];
5783 switch (load_ptr_tag) {6144 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 => {
5785 const load_ptr_inst = try self.resolveInst(load_ptr);6151 const load_ptr_inst = try self.resolveInst(load_ptr);
5786 const gep = self.builder.buildInBoundsGEP(array_llvm_ty, load_ptr_inst, &indices, indices.len, "");6152 const gep = try self.wip.gep(
5787 return self.builder.buildLoad(elem_llvm_ty, 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, "");
5788 },6160 },
5789 else => {},6161 else => {},
5790 }6162 }
5791 }6163 }
5792 }6164 }
5793 }6165 }
5794 const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, array_llvm_val, &indices, indices.len, "");6166 const elem_ptr =
5795 return self.builder.buildLoad(elem_llvm_ty, 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, "");
5796 }6169 }
5797 }6170 }
57986171
5799 // This branch can be reached for vectors, which are always by-value.6172 // 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, "");
5801 }6174 }
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 {
5804 const o = self.dg.object;6177 const o = self.dg.object;
5805 const mod = o.module;6178 const mod = o.module;
5806 const inst = body_tail[0];6179 const inst = body_tail[0];
...@@ -5811,32 +6184,28 @@ pub const FuncGen = struct {...@@ -5811,32 +6184,28 @@ pub const FuncGen = struct {
5811 const base_ptr = try self.resolveInst(bin_op.lhs);6184 const base_ptr = try self.resolveInst(bin_op.lhs);
5812 const rhs = try self.resolveInst(bin_op.rhs);6185 const rhs = try self.resolveInst(bin_op.rhs);
5813 // TODO: when we go fully opaque pointers in LLVM 16 we can remove this branch6186 // 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))
5815 // If this is a single-item pointer to an array, we need another index in the GEP.6188 // 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 };6189 &.{ try o.builder.intValue(try o.lowerType(Type.usize), 0), rhs }
5817 break :ptr self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");6190 else
5818 } else ptr: {6191 &.{rhs}, "");
5819 const indices: [1]*llvm.Value = .{rhs};
5820 break :ptr self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
5821 };
5822 if (isByRef(elem_ty, mod)) {6192 if (isByRef(elem_ty, mod)) {
5823 if (self.canElideLoad(body_tail))6193 if (self.canElideLoad(body_tail)) return ptr;
5824 return ptr;6194 const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
58256195 return self.loadByRef(ptr, elem_ty, elem_alignment, false);
5826 return self.loadByRef(ptr, elem_ty, elem_ty.abiAlignment(mod), false);
5827 }6196 }
58286197
5829 return self.load(ptr, ptr_ty);6198 return self.load(ptr, ptr_ty);
5830 }6199 }
58316200
5832 fn airPtrElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6201 fn airPtrElemPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5833 const o = self.dg.object;6202 const o = self.dg.object;
5834 const mod = o.module;6203 const mod = o.module;
5835 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;6204 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
5836 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;6205 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
5837 const ptr_ty = self.typeOf(bin_op.lhs);6206 const ptr_ty = self.typeOf(bin_op.lhs);
5838 const elem_ty = ptr_ty.childType(mod);6207 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
5841 const base_ptr = try self.resolveInst(bin_op.lhs);6210 const base_ptr = try self.resolveInst(bin_op.lhs);
5842 const rhs = try self.resolveInst(bin_op.rhs);6211 const rhs = try self.resolveInst(bin_op.rhs);
...@@ -5845,17 +6214,14 @@ pub const FuncGen = struct {...@@ -5845,17 +6214,14 @@ pub const FuncGen = struct {
5845 if (elem_ptr.ptrInfo(mod).flags.vector_index != .none) return base_ptr;6214 if (elem_ptr.ptrInfo(mod).flags.vector_index != .none) return base_ptr;
58466215
5847 const llvm_elem_ty = try o.lowerPtrElemTy(elem_ty);6216 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))
5849 // If this is a single-item pointer to an array, we need another index in the GEP.6218 // 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 };6219 &.{ try o.builder.intValue(try o.lowerType(Type.usize), 0), rhs }
5851 return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");6220 else
5852 } else {6221 &.{rhs}, "");
5853 const indices: [1]*llvm.Value = .{rhs};
5854 return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
5855 }
5856 }6222 }
58576223
5858 fn airStructFieldPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6224 fn airStructFieldPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5859 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;6225 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
5860 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;6226 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
5861 const struct_ptr = try self.resolveInst(struct_field.struct_operand);6227 const struct_ptr = try self.resolveInst(struct_field.struct_operand);
...@@ -5867,14 +6233,14 @@ pub const FuncGen = struct {...@@ -5867,14 +6233,14 @@ pub const FuncGen = struct {
5867 self: *FuncGen,6233 self: *FuncGen,
5868 inst: Air.Inst.Index,6234 inst: Air.Inst.Index,
5869 field_index: u32,6235 field_index: u32,
5870 ) !?*llvm.Value {6236 ) !Builder.Value {
5871 const ty_op = self.air.instructions.items(.data)[inst].ty_op;6237 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5872 const struct_ptr = try self.resolveInst(ty_op.operand);6238 const struct_ptr = try self.resolveInst(ty_op.operand);
5873 const struct_ptr_ty = self.typeOf(ty_op.operand);6239 const struct_ptr_ty = self.typeOf(ty_op.operand);
5874 return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, field_index);6240 return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, field_index);
5875 }6241 }
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 {
5878 const o = self.dg.object;6244 const o = self.dg.object;
5879 const mod = o.module;6245 const mod = o.module;
5880 const inst = body_tail[0];6246 const inst = body_tail[0];
...@@ -5884,9 +6250,7 @@ pub const FuncGen = struct {...@@ -5884,9 +6250,7 @@ pub const FuncGen = struct {
5884 const struct_llvm_val = try self.resolveInst(struct_field.struct_operand);6250 const struct_llvm_val = try self.resolveInst(struct_field.struct_operand);
5885 const field_index = struct_field.field_index;6251 const field_index = struct_field.field_index;
5886 const field_ty = struct_ty.structFieldType(field_index, mod);6252 const field_ty = struct_ty.structFieldType(field_index, mod);
5887 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) {6253 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none;
5888 return null;
5889 }
58906254
5891 if (!isByRef(struct_ty, mod)) {6255 if (!isByRef(struct_ty, mod)) {
5892 assert(!isByRef(field_ty, mod));6256 assert(!isByRef(field_ty, mod));
...@@ -5896,25 +6260,26 @@ pub const FuncGen = struct {...@@ -5896,25 +6260,26 @@ pub const FuncGen = struct {
5896 const struct_obj = mod.typeToStruct(struct_ty).?;6260 const struct_obj = mod.typeToStruct(struct_ty).?;
5897 const bit_offset = struct_obj.packedFieldBitOffset(mod, field_index);6261 const bit_offset = struct_obj.packedFieldBitOffset(mod, field_index);
5898 const containing_int = struct_llvm_val;6262 const containing_int = struct_llvm_val;
5899 const shift_amt = containing_int.typeOf().constInt(bit_offset, .False);6263 const shift_amt =
5900 const shifted_value = self.builder.buildLShr(containing_int, 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, "");
5901 const elem_llvm_ty = try o.lowerType(field_ty);6266 const elem_llvm_ty = try o.lowerType(field_ty);
5902 if (field_ty.zigTypeTag(mod) == .Float or field_ty.zigTypeTag(mod) == .Vector) {6267 if (field_ty.zigTypeTag(mod) == .Float or field_ty.zigTypeTag(mod) == .Vector) {
5903 const elem_bits = @as(c_uint, @intCast(field_ty.bitSize(mod)));6268 const same_size_int = try o.builder.intType(@intCast(field_ty.bitSize(mod)));
5904 const same_size_int = self.context.intType(elem_bits);6269 const truncated_int =
5905 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");6270 try self.wip.cast(.trunc, shifted_value, same_size_int, "");
5906 return self.builder.buildBitCast(truncated_int, elem_llvm_ty, "");6271 return self.wip.cast(.bitcast, truncated_int, elem_llvm_ty, "");
5907 } else if (field_ty.isPtrAtRuntime(mod)) {6272 } else if (field_ty.isPtrAtRuntime(mod)) {
5908 const elem_bits = @as(c_uint, @intCast(field_ty.bitSize(mod)));6273 const same_size_int = try o.builder.intType(@intCast(field_ty.bitSize(mod)));
5909 const same_size_int = self.context.intType(elem_bits);6274 const truncated_int =
5910 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");6275 try self.wip.cast(.trunc, shifted_value, same_size_int, "");
5911 return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, "");6276 return self.wip.cast(.inttoptr, truncated_int, elem_llvm_ty, "");
5912 }6277 }
5913 return self.builder.buildTrunc(shifted_value, elem_llvm_ty, "");6278 return self.wip.cast(.trunc, shifted_value, elem_llvm_ty, "");
5914 },6279 },
5915 else => {6280 else => {
5916 const llvm_field_index = llvmField(struct_ty, field_index, mod).?.index;6281 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}, "");
5918 },6283 },
5919 },6284 },
5920 .Union => {6285 .Union => {
...@@ -5922,17 +6287,17 @@ pub const FuncGen = struct {...@@ -5922,17 +6287,17 @@ pub const FuncGen = struct {
5922 const containing_int = struct_llvm_val;6287 const containing_int = struct_llvm_val;
5923 const elem_llvm_ty = try o.lowerType(field_ty);6288 const elem_llvm_ty = try o.lowerType(field_ty);
5924 if (field_ty.zigTypeTag(mod) == .Float or field_ty.zigTypeTag(mod) == .Vector) {6289 if (field_ty.zigTypeTag(mod) == .Float or field_ty.zigTypeTag(mod) == .Vector) {
5925 const elem_bits = @as(c_uint, @intCast(field_ty.bitSize(mod)));6290 const same_size_int = try o.builder.intType(@intCast(field_ty.bitSize(mod)));
5926 const same_size_int = self.context.intType(elem_bits);6291 const truncated_int =
5927 const truncated_int = self.builder.buildTrunc(containing_int, same_size_int, "");6292 try self.wip.cast(.trunc, containing_int, same_size_int, "");
5928 return self.builder.buildBitCast(truncated_int, elem_llvm_ty, "");6293 return self.wip.cast(.bitcast, truncated_int, elem_llvm_ty, "");
5929 } else if (field_ty.isPtrAtRuntime(mod)) {6294 } else if (field_ty.isPtrAtRuntime(mod)) {
5930 const elem_bits = @as(c_uint, @intCast(field_ty.bitSize(mod)));6295 const same_size_int = try o.builder.intType(@intCast(field_ty.bitSize(mod)));
5931 const same_size_int = self.context.intType(elem_bits);6296 const truncated_int =
5932 const truncated_int = self.builder.buildTrunc(containing_int, same_size_int, "");6297 try self.wip.cast(.trunc, containing_int, same_size_int, "");
5933 return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, "");6298 return self.wip.cast(.inttoptr, truncated_int, elem_llvm_ty, "");
5934 }6299 }
5935 return self.builder.buildTrunc(containing_int, elem_llvm_ty, "");6300 return self.wip.cast(.trunc, containing_int, elem_llvm_ty, "");
5936 },6301 },
5937 else => unreachable,6302 else => unreachable,
5938 }6303 }
...@@ -5943,7 +6308,8 @@ pub const FuncGen = struct {...@@ -5943,7 +6308,8 @@ pub const FuncGen = struct {
5943 assert(struct_ty.containerLayout(mod) != .Packed);6308 assert(struct_ty.containerLayout(mod) != .Packed);
5944 const llvm_field = llvmField(struct_ty, field_index, mod).?;6309 const llvm_field = llvmField(struct_ty, field_index, mod).?;
5945 const struct_llvm_ty = try o.lowerType(struct_ty);6310 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, "");
5947 const field_ptr_ty = try mod.ptrType(.{6313 const field_ptr_ty = try mod.ptrType(.{
5948 .child = llvm_field.ty.toIntern(),6314 .child = llvm_field.ty.toIntern(),
5949 .flags = .{6315 .flags = .{
...@@ -5955,7 +6321,8 @@ pub const FuncGen = struct {...@@ -5955,7 +6321,8 @@ pub const FuncGen = struct {
5955 return field_ptr;6321 return field_ptr;
59566322
5957 assert(llvm_field.alignment != 0);6323 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);
5959 } else {6326 } else {
5960 return self.load(field_ptr, field_ptr_ty);6327 return self.load(field_ptr, field_ptr_ty);
5961 }6328 }
...@@ -5964,22 +6331,22 @@ pub const FuncGen = struct {...@@ -5964,22 +6331,22 @@ pub const FuncGen = struct {
5964 const union_llvm_ty = try o.lowerType(struct_ty);6331 const union_llvm_ty = try o.lowerType(struct_ty);
5965 const layout = struct_ty.unionGetLayout(mod);6332 const layout = struct_ty.unionGetLayout(mod);
5966 const payload_index = @intFromBool(layout.tag_align >= layout.payload_align);6333 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, "");
5968 const llvm_field_ty = try o.lowerType(field_ty);6336 const llvm_field_ty = try o.lowerType(field_ty);
6337 const payload_alignment = Builder.Alignment.fromByteUnits(layout.payload_align);
5969 if (isByRef(field_ty, mod)) {6338 if (isByRef(field_ty, mod)) {
5970 if (canElideLoad(self, body_tail))6339 if (canElideLoad(self, body_tail)) return field_ptr;
5971 return field_ptr;6340 return self.loadByRef(field_ptr, field_ty, payload_alignment, false);
5972
5973 return self.loadByRef(field_ptr, field_ty, layout.payload_align, false);
5974 } else {6341 } else {
5975 return self.builder.buildLoad(llvm_field_ty, field_ptr, "");6342 return self.wip.load(.normal, llvm_field_ty, field_ptr, payload_alignment, "");
5976 }6343 }
5977 },6344 },
5978 else => unreachable,6345 else => unreachable,
5979 }6346 }
5980 }6347 }
59816348
5982 fn airFieldParentPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6349 fn airFieldParentPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5983 const o = self.dg.object;6350 const o = self.dg.object;
5984 const mod = o.module;6351 const mod = o.module;
5985 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;6352 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -5987,50 +6354,52 @@ pub const FuncGen = struct {...@@ -5987,50 +6354,52 @@ pub const FuncGen = struct {
59876354
5988 const field_ptr = try self.resolveInst(extra.field_ptr);6355 const field_ptr = try self.resolveInst(extra.field_ptr);
59896356
5990 const target = o.module.getTarget();
5991 const parent_ty = self.air.getRefType(ty_pl.ty).childType(mod);6357 const parent_ty = self.air.getRefType(ty_pl.ty).childType(mod);
5992 const field_offset = parent_ty.structFieldOffset(extra.field_index, mod);6358 const field_offset = parent_ty.structFieldOffset(extra.field_index, mod);
6359 if (field_offset == 0) return field_ptr;
59936360
5994 const res_ty = try o.lowerType(self.air.getRefType(ty_pl.ty));6361 const res_ty = try o.lowerType(self.air.getRefType(ty_pl.ty));
5995 if (field_offset == 0) {6362 const llvm_usize = try o.lowerType(Type.usize);
5996 return field_ptr;
5997 }
5998 const llvm_usize_ty = self.context.intType(target.ptrBitWidth());
59996363
6000 const field_ptr_int = self.builder.buildPtrToInt(field_ptr, llvm_usize_ty, "");6364 const field_ptr_int = try self.wip.cast(.ptrtoint, field_ptr, llvm_usize, "");
6001 const base_ptr_int = self.builder.buildNUWSub(field_ptr_int, llvm_usize_ty.constInt(field_offset, .False), "");6365 const base_ptr_int = try self.wip.bin(
6002 return self.builder.buildIntToPtr(base_ptr_int, res_ty, "");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, "");
6003 }6372 }
60046373
6005 fn airNot(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6374 fn airNot(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6006 const ty_op = self.air.instructions.items(.data)[inst].ty_op;6375 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
6007 const operand = try self.resolveInst(ty_op.operand);6376 const operand = try self.resolveInst(ty_op.operand);
60086377
6009 return self.builder.buildNot(operand, "");6378 return self.wip.not(operand, "");
6010 }6379 }
60116380
6012 fn airUnreach(self: *FuncGen, inst: Air.Inst.Index) ?*llvm.Value {6381 fn airUnreach(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6013 _ = inst;6382 _ = inst;
6014 _ = self.builder.buildUnreachable();6383 _ = try self.wip.@"unreachable"();
6015 return null;6384 return .none;
6016 }6385 }
60176386
6018 fn airDbgStmt(self: *FuncGen, inst: Air.Inst.Index) ?*llvm.Value {6387 fn airDbgStmt(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6019 const di_scope = self.di_scope orelse return null;6388 const di_scope = self.di_scope orelse return .none;
6020 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;6389 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));6390 self.prev_dbg_line = @intCast(self.base_line + dbg_stmt.line + 1);
6022 self.prev_dbg_column = @as(c_uint, @intCast(dbg_stmt.column + 1));6391 self.prev_dbg_column = @intCast(dbg_stmt.column + 1);
6023 const inlined_at = if (self.dbg_inlined.items.len > 0)6392 const inlined_at = if (self.dbg_inlined.items.len > 0)
6024 self.dbg_inlined.items[self.dbg_inlined.items.len - 1].loc6393 self.dbg_inlined.items[self.dbg_inlined.items.len - 1].loc
6025 else6394 else
6026 null;6395 null;
6027 self.builder.setCurrentDebugLocation(self.prev_dbg_line, self.prev_dbg_column, di_scope, inlined_at);6396 self.builder.setCurrentDebugLocation(self.prev_dbg_line, self.prev_dbg_column, di_scope, inlined_at);
6028 return null;6397 return .none;
6029 }6398 }
60306399
6031 fn airDbgInlineBegin(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6400 fn airDbgInlineBegin(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6032 const o = self.dg.object;6401 const o = self.dg.object;
6033 const dib = o.di_builder orelse return null;6402 const dib = o.di_builder orelse return .none;
6034 const ty_fn = self.air.instructions.items(.data)[inst].ty_fn;6403 const ty_fn = self.air.instructions.items(.data)[inst].ty_fn;
60356404
6036 const mod = o.module;6405 const mod = o.module;
...@@ -6083,12 +6452,12 @@ pub const FuncGen = struct {...@@ -6083,12 +6452,12 @@ pub const FuncGen = struct {
6083 const lexical_block = dib.createLexicalBlock(subprogram.toScope(), di_file, line_number, 1);6452 const lexical_block = dib.createLexicalBlock(subprogram.toScope(), di_file, line_number, 1);
6084 self.di_scope = lexical_block.toScope();6453 self.di_scope = lexical_block.toScope();
6085 self.base_line = decl.src_line;6454 self.base_line = decl.src_line;
6086 return null;6455 return .none;
6087 }6456 }
60886457
6089 fn airDbgInlineEnd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6458 fn airDbgInlineEnd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6090 const o = self.dg.object;6459 const o = self.dg.object;
6091 if (o.di_builder == null) return null;6460 if (o.di_builder == null) return .none;
6092 const ty_fn = self.air.instructions.items(.data)[inst].ty_fn;6461 const ty_fn = self.air.instructions.items(.data)[inst].ty_fn;
60936462
6094 const mod = o.module;6463 const mod = o.module;
...@@ -6098,30 +6467,30 @@ pub const FuncGen = struct {...@@ -6098,30 +6467,30 @@ pub const FuncGen = struct {
6098 const old = self.dbg_inlined.pop();6467 const old = self.dbg_inlined.pop();
6099 self.di_scope = old.scope;6468 self.di_scope = old.scope;
6100 self.base_line = old.base_line;6469 self.base_line = old.base_line;
6101 return null;6470 return .none;
6102 }6471 }
61036472
6104 fn airDbgBlockBegin(self: *FuncGen) !?*llvm.Value {6473 fn airDbgBlockBegin(self: *FuncGen) !Builder.Value {
6105 const o = self.dg.object;6474 const o = self.dg.object;
6106 const dib = o.di_builder orelse return null;6475 const dib = o.di_builder orelse return .none;
6107 const old_scope = self.di_scope.?;6476 const old_scope = self.di_scope.?;
6108 try self.dbg_block_stack.append(self.gpa, old_scope);6477 try self.dbg_block_stack.append(self.gpa, old_scope);
6109 const lexical_block = dib.createLexicalBlock(old_scope, self.di_file.?, self.prev_dbg_line, self.prev_dbg_column);6478 const lexical_block = dib.createLexicalBlock(old_scope, self.di_file.?, self.prev_dbg_line, self.prev_dbg_column);
6110 self.di_scope = lexical_block.toScope();6479 self.di_scope = lexical_block.toScope();
6111 return null;6480 return .none;
6112 }6481 }
61136482
6114 fn airDbgBlockEnd(self: *FuncGen) !?*llvm.Value {6483 fn airDbgBlockEnd(self: *FuncGen) !Builder.Value {
6115 const o = self.dg.object;6484 const o = self.dg.object;
6116 if (o.di_builder == null) return null;6485 if (o.di_builder == null) return .none;
6117 self.di_scope = self.dbg_block_stack.pop();6486 self.di_scope = self.dbg_block_stack.pop();
6118 return null;6487 return .none;
6119 }6488 }
61206489
6121 fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6490 fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6122 const o = self.dg.object;6491 const o = self.dg.object;
6123 const mod = o.module;6492 const mod = o.module;
6124 const dib = o.di_builder orelse return null;6493 const dib = o.di_builder orelse return .none;
6125 const pl_op = self.air.instructions.items(.data)[inst].pl_op;6494 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
6126 const operand = try self.resolveInst(pl_op.operand);6495 const operand = try self.resolveInst(pl_op.operand);
6127 const name = self.air.nullTerminatedString(pl_op.payload);6496 const name = self.air.nullTerminatedString(pl_op.payload);
...@@ -6141,22 +6510,20 @@ pub const FuncGen = struct {...@@ -6141,22 +6510,20 @@ pub const FuncGen = struct {
6141 else6510 else
6142 null;6511 null;
6143 const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?, inlined_at);6512 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();6513 const insert_block = self.wip.cursor.block.toLlvm(&self.wip);
6145 _ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block);6514 _ = dib.insertDeclareAtEnd(operand.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
6146 return null;6515 return .none;
6147 }6516 }
61486517
6149 fn airDbgVarVal(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6518 fn airDbgVarVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6150 const o = self.dg.object;6519 const o = self.dg.object;
6151 const dib = o.di_builder orelse return null;6520 const dib = o.di_builder orelse return .none;
6152 const pl_op = self.air.instructions.items(.data)[inst].pl_op;6521 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
6153 const operand = try self.resolveInst(pl_op.operand);6522 const operand = try self.resolveInst(pl_op.operand);
6154 const operand_ty = self.typeOf(pl_op.operand);6523 const operand_ty = self.typeOf(pl_op.operand);
6155 const name = self.air.nullTerminatedString(pl_op.payload);6524 const name = self.air.nullTerminatedString(pl_op.payload);
61566525
6157 if (needDbgVarWorkaround(o)) {6526 if (needDbgVarWorkaround(o)) return .none;
6158 return null;
6159 }
61606527
6161 const di_local_var = dib.createAutoVariable(6528 const di_local_var = dib.createAutoVariable(
6162 self.di_scope.?,6529 self.di_scope.?,
...@@ -6172,23 +6539,22 @@ pub const FuncGen = struct {...@@ -6172,23 +6539,22 @@ pub const FuncGen = struct {
6172 else6539 else
6173 null;6540 null;
6174 const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?, inlined_at);6541 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);
6176 const mod = o.module;6543 const mod = o.module;
6177 if (isByRef(operand_ty, mod)) {6544 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);
6179 } else if (o.module.comp.bin_file.options.optimize_mode == .Debug) {6546 } else if (o.module.comp.bin_file.options.optimize_mode == .Debug) {
6180 const alignment = operand_ty.abiAlignment(mod);6547 const alignment = Builder.Alignment.fromByteUnits(operand_ty.abiAlignment(mod));
6181 const alloca = self.buildAlloca(operand.typeOf(), alignment);6548 const alloca = try self.buildAlloca(operand.typeOfWip(&self.wip), alignment);
6182 const store_inst = self.builder.buildStore(operand, alloca);6549 _ = try self.wip.store(.normal, operand, alloca, alignment);
6183 store_inst.setAlignment(alignment);6550 _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
6184 _ = dib.insertDeclareAtEnd(alloca, di_local_var, debug_loc, insert_block);
6185 } else {6551 } 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);
6187 }6553 }
6188 return null;6554 return .none;
6189 }6555 }
61906556
6191 fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6557 fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6192 // Eventually, the Zig compiler needs to be reworked to have inline6558 // Eventually, the Zig compiler needs to be reworked to have inline
6193 // assembly go through the same parsing code regardless of backend, and6559 // assembly go through the same parsing code regardless of backend, and
6194 // have LLVM-flavored inline assembly be *output* from that assembler.6560 // have LLVM-flavored inline assembly be *output* from that assembler.
...@@ -6199,12 +6565,12 @@ pub const FuncGen = struct {...@@ -6199,12 +6565,12 @@ pub const FuncGen = struct {
6199 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;6565 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
6200 const extra = self.air.extraData(Air.Asm, ty_pl.payload);6566 const extra = self.air.extraData(Air.Asm, ty_pl.payload);
6201 const is_volatile = @as(u1, @truncate(extra.data.flags >> 31)) != 0;6567 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);
6203 var extra_i: usize = extra.end;6569 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]);
6206 extra_i += outputs.len;6572 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]);
6208 extra_i += inputs.len;6574 extra_i += inputs.len;
62096575
6210 var llvm_constraints: std.ArrayListUnmanaged(u8) = .{};6576 var llvm_constraints: std.ArrayListUnmanaged(u8) = .{};
...@@ -6217,15 +6583,15 @@ pub const FuncGen = struct {...@@ -6217,15 +6583,15 @@ pub const FuncGen = struct {
6217 // The exact number of return / parameter values depends on which output values6583 // The exact number of return / parameter values depends on which output values
6218 // are passed by reference as indirect outputs (determined below).6584 // are passed by reference as indirect outputs (determined below).
6219 const max_return_count = outputs.len;6585 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);
6221 const llvm_ret_indirect = try arena.alloc(bool, max_return_count);6587 const llvm_ret_indirect = try arena.alloc(bool, max_return_count);
62226588
6223 const max_param_count = inputs.len + outputs.len;6589 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);
6225 const llvm_param_values = try arena.alloc(*llvm.Value, max_param_count);6591 const llvm_param_values = try arena.alloc(*llvm.Value, max_param_count);
6226 // This stores whether we need to add an elementtype attribute and6592 // This stores whether we need to add an elementtype attribute and
6227 // if so, the element type itself.6593 // 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);
6229 const mod = o.module;6595 const mod = o.module;
6230 const target = mod.getTarget();6596 const target = mod.getTarget();
62316597
...@@ -6262,8 +6628,8 @@ pub const FuncGen = struct {...@@ -6262,8 +6628,8 @@ pub const FuncGen = struct {
6262 // Pass the result by reference as an indirect output (e.g. "=*m")6628 // Pass the result by reference as an indirect output (e.g. "=*m")
6263 llvm_constraints.appendAssumeCapacity('*');6629 llvm_constraints.appendAssumeCapacity('*');
62646630
6265 llvm_param_values[llvm_param_i] = output_inst;6631 llvm_param_values[llvm_param_i] = output_inst.toLlvm(&self.wip);
6266 llvm_param_types[llvm_param_i] = output_inst.typeOf();6632 llvm_param_types[llvm_param_i] = output_inst.typeOfWip(&self.wip);
6267 llvm_param_attrs[llvm_param_i] = elem_llvm_ty;6633 llvm_param_attrs[llvm_param_i] = elem_llvm_ty;
6268 llvm_param_i += 1;6634 llvm_param_i += 1;
6269 } else {6635 } else {
...@@ -6308,31 +6674,30 @@ pub const FuncGen = struct {...@@ -6308,31 +6674,30 @@ pub const FuncGen = struct {
63086674
6309 const arg_llvm_value = try self.resolveInst(input);6675 const arg_llvm_value = try self.resolveInst(input);
6310 const arg_ty = self.typeOf(input);6676 const arg_ty = self.typeOf(input);
6311 var llvm_elem_ty: ?*llvm.Type = null;6677 var llvm_elem_ty: Builder.Type = .none;
6312 if (isByRef(arg_ty, mod)) {6678 if (isByRef(arg_ty, mod)) {
6313 llvm_elem_ty = try o.lowerPtrElemTy(arg_ty);6679 llvm_elem_ty = try o.lowerPtrElemTy(arg_ty);
6314 if (constraintAllowsMemory(constraint)) {6680 if (constraintAllowsMemory(constraint)) {
6315 llvm_param_values[llvm_param_i] = arg_llvm_value;6681 llvm_param_values[llvm_param_i] = arg_llvm_value.toLlvm(&self.wip);
6316 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOf();6682 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
6317 } else {6683 } else {
6318 const alignment = arg_ty.abiAlignment(mod);6684 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
6319 const arg_llvm_ty = try o.lowerType(arg_ty);6685 const arg_llvm_ty = try o.lowerType(arg_ty);
6320 const load_inst = self.builder.buildLoad(arg_llvm_ty, arg_llvm_value, "");6686 const load_inst =
6321 load_inst.setAlignment(alignment);6687 try self.wip.load(.normal, arg_llvm_ty, arg_llvm_value, alignment, "");
6322 llvm_param_values[llvm_param_i] = load_inst;6688 llvm_param_values[llvm_param_i] = load_inst.toLlvm(&self.wip);
6323 llvm_param_types[llvm_param_i] = arg_llvm_ty;6689 llvm_param_types[llvm_param_i] = arg_llvm_ty;
6324 }6690 }
6325 } else {6691 } else {
6326 if (constraintAllowsRegister(constraint)) {6692 if (constraintAllowsRegister(constraint)) {
6327 llvm_param_values[llvm_param_i] = arg_llvm_value;6693 llvm_param_values[llvm_param_i] = arg_llvm_value.toLlvm(&self.wip);
6328 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOf();6694 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
6329 } else {6695 } else {
6330 const alignment = arg_ty.abiAlignment(mod);6696 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
6331 const arg_ptr = self.buildAlloca(arg_llvm_value.typeOf(), alignment);6697 const arg_ptr = try self.buildAlloca(arg_llvm_value.typeOfWip(&self.wip), alignment);
6332 const store_inst = self.builder.buildStore(arg_llvm_value, arg_ptr);6698 _ = try self.wip.store(.normal, arg_llvm_value, arg_ptr, alignment);
6333 store_inst.setAlignment(alignment);6699 llvm_param_values[llvm_param_i] = arg_ptr.toLlvm(&self.wip);
6334 llvm_param_values[llvm_param_i] = arg_ptr;6700 llvm_param_types[llvm_param_i] = arg_ptr.typeOfWip(&self.wip);
6335 llvm_param_types[llvm_param_i] = arg_ptr.typeOf();
6336 }6701 }
6337 }6702 }
63386703
...@@ -6356,10 +6721,12 @@ pub const FuncGen = struct {...@@ -6356,10 +6721,12 @@ pub const FuncGen = struct {
6356 // In the case of indirect inputs, LLVM requires the callsite to have6721 // In the case of indirect inputs, LLVM requires the callsite to have
6357 // an elementtype(<ty>) attribute.6722 // an elementtype(<ty>) attribute.
6358 if (constraint[0] == '*') {6723 if (constraint[0] == '*') {
6359 llvm_param_attrs[llvm_param_i] = llvm_elem_ty orelse6724 llvm_param_attrs[llvm_param_i] = if (llvm_elem_ty != .none)
6725 llvm_elem_ty
6726 else
6360 try o.lowerPtrElemTy(arg_ty.childType(mod));6727 try o.lowerPtrElemTy(arg_ty.childType(mod));
6361 } else {6728 } else {
6362 llvm_param_attrs[llvm_param_i] = null;6729 llvm_param_attrs[llvm_param_i] = .none;
6363 }6730 }
63646731
6365 llvm_param_i += 1;6732 llvm_param_i += 1;
...@@ -6477,23 +6844,14 @@ pub const FuncGen = struct {...@@ -6477,23 +6844,14 @@ pub const FuncGen = struct {
6477 }6844 }
64786845
6479 const ret_llvm_ty = switch (return_count) {6846 const ret_llvm_ty = switch (return_count) {
6480 0 => self.context.voidType(),6847 0 => .void,
6481 1 => llvm_ret_types[0],6848 1 => llvm_ret_types[0],
6482 else => self.context.structType(6849 else => try o.builder.structType(.normal, llvm_ret_types),
6483 llvm_ret_types.ptr,
6484 @as(c_uint, @intCast(return_count)),
6485 .False,
6486 ),
6487 };6850 };
64886851
6489 const llvm_fn_ty = llvm.functionType(6852 const llvm_fn_ty = try o.builder.fnType(ret_llvm_ty, llvm_param_types[0..param_count], .normal);
6490 ret_llvm_ty,
6491 llvm_param_types.ptr,
6492 @as(c_uint, @intCast(param_count)),
6493 .False,
6494 );
6495 const asm_fn = llvm.getInlineAsm(6853 const asm_fn = llvm.getInlineAsm(
6496 llvm_fn_ty,6854 llvm_fn_ty.toLlvm(&o.builder),
6497 rendered_template.items.ptr,6855 rendered_template.items.ptr,
6498 rendered_template.items.len,6856 rendered_template.items.len,
6499 llvm_constraints.items.ptr,6857 llvm_constraints.items.ptr,
...@@ -6503,18 +6861,18 @@ pub const FuncGen = struct {...@@ -6503,18 +6861,18 @@ pub const FuncGen = struct {
6503 .ATT,6861 .ATT,
6504 .False,6862 .False,
6505 );6863 );
6506 const call = self.builder.buildCall(6864 const call = (try self.wip.unimplemented(ret_llvm_ty, "")).finish(self.builder.buildCall(
6507 llvm_fn_ty,6865 llvm_fn_ty.toLlvm(&o.builder),
6508 asm_fn,6866 asm_fn,
6509 llvm_param_values.ptr,6867 llvm_param_values.ptr,
6510 @as(c_uint, @intCast(param_count)),6868 @intCast(param_count),
6511 .C,6869 .C,
6512 .Auto,6870 .Auto,
6513 "",6871 "",
6514 );6872 ), &self.wip);
6515 for (llvm_param_attrs[0..param_count], 0..) |llvm_elem_ty, i| {6873 for (llvm_param_attrs[0..param_count], 0..) |llvm_elem_ty, i| {
6516 if (llvm_elem_ty) |llvm_ty| {6874 if (llvm_elem_ty != .none) {
6517 llvm.setCallElemTypeAttr(call, i, llvm_ty);6875 llvm.setCallElemTypeAttr(call.toLlvm(&self.wip), i, llvm_elem_ty.toLlvm(&o.builder));
6518 }6876 }
6519 }6877 }
65206878
...@@ -6523,16 +6881,17 @@ pub const FuncGen = struct {...@@ -6523,16 +6881,17 @@ pub const FuncGen = struct {
6523 for (outputs, 0..) |output, i| {6881 for (outputs, 0..) |output, i| {
6524 if (llvm_ret_indirect[i]) continue;6882 if (llvm_ret_indirect[i]) continue;
65256883
6526 const output_value = if (return_count > 1) b: {6884 const output_value = if (return_count > 1)
6527 break :b self.builder.buildExtractValue(call, @as(c_uint, @intCast(llvm_ret_i)), "");6885 try self.wip.extractValue(call, &[_]u32{@intCast(llvm_ret_i)}, "")
6528 } else call;6886 else
6887 call;
65296888
6530 if (output != .none) {6889 if (output != .none) {
6531 const output_ptr = try self.resolveInst(output);6890 const output_ptr = try self.resolveInst(output);
6532 const output_ptr_ty = self.typeOf(output);6891 const output_ptr_ty = self.typeOf(output);
65336892
6534 const store_inst = self.builder.buildStore(output_value, output_ptr);6893 const alignment = Builder.Alignment.fromByteUnits(output_ptr_ty.ptrAlignment(mod));
6535 store_inst.setAlignment(output_ptr_ty.ptrAlignment(mod));6894 _ = try self.wip.store(.normal, output_value, output_ptr, alignment);
6536 } else {6895 } else {
6537 ret_val = output_value;6896 ret_val = output_value;
6538 }6897 }
...@@ -6546,8 +6905,8 @@ pub const FuncGen = struct {...@@ -6546,8 +6905,8 @@ pub const FuncGen = struct {
6546 self: *FuncGen,6905 self: *FuncGen,
6547 inst: Air.Inst.Index,6906 inst: Air.Inst.Index,
6548 operand_is_ptr: bool,6907 operand_is_ptr: bool,
6549 pred: llvm.IntPredicate,6908 cond: Builder.IntegerCondition,
6550 ) !?*llvm.Value {6909 ) !Builder.Value {
6551 const o = self.dg.object;6910 const o = self.dg.object;
6552 const mod = o.module;6911 const mod = o.module;
6553 const un_op = self.air.instructions.items(.data)[inst].un_op;6912 const un_op = self.air.instructions.items(.data)[inst].un_op;
...@@ -6558,43 +6917,40 @@ pub const FuncGen = struct {...@@ -6558,43 +6917,40 @@ pub const FuncGen = struct {
6558 const payload_ty = optional_ty.optionalChild(mod);6917 const payload_ty = optional_ty.optionalChild(mod);
6559 if (optional_ty.optionalReprIsPayload(mod)) {6918 if (optional_ty.optionalReprIsPayload(mod)) {
6560 const loaded = if (operand_is_ptr)6919 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, "")
6562 else6921 else
6563 operand;6922 operand;
6564 if (payload_ty.isSlice(mod)) {6923 if (payload_ty.isSlice(mod)) {
6565 const slice_ptr = self.builder.buildExtractValue(loaded, 0, "");6924 const slice_ptr = try self.wip.extractValue(loaded, &.{0}, "");
6566 const ptr_ty = try o.lowerType(payload_ty.slicePtrFieldType(mod));6925 const ptr_ty = try o.builder.ptrType(toLlvmAddressSpace(
6567 return self.builder.buildICmp(pred, slice_ptr, ptr_ty.constNull(), "");6926 payload_ty.ptrAddressSpace(mod),
6927 mod.getTarget(),
6928 ));
6929 return self.wip.icmp(cond, slice_ptr, try o.builder.nullValue(ptr_ty), "");
6568 }6930 }
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), "");
6570 }6932 }
65716933
6572 comptime assert(optional_layout_version == 3);6934 comptime assert(optional_layout_version == 3);
65736935
6574 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {6936 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
6575 const loaded = if (operand_is_ptr)6937 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, "")
6577 else6939 else
6578 operand;6940 operand;
6579 const llvm_i8 = self.context.intType(8);6941 return self.wip.icmp(cond, loaded, try o.builder.intValue(.i8, 0), "");
6580 return self.builder.buildICmp(pred, loaded, llvm_i8.constNull(), "");
6581 }6942 }
65826943
6583 const is_by_ref = operand_is_ptr or isByRef(optional_ty, mod);6944 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);6945 return self.optCmpNull(cond, 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 }
6590 }6946 }
65916947
6592 fn airIsErr(6948 fn airIsErr(
6593 self: *FuncGen,6949 self: *FuncGen,
6594 inst: Air.Inst.Index,6950 inst: Air.Inst.Index,
6595 op: llvm.IntPredicate,6951 cond: Builder.IntegerCondition,
6596 operand_is_ptr: bool,6952 operand_is_ptr: bool,
6597 ) !?*llvm.Value {6953 ) !Builder.Value {
6598 const o = self.dg.object;6954 const o = self.dg.object;
6599 const mod = o.module;6955 const mod = o.module;
6600 const un_op = self.air.instructions.items(.data)[inst].un_op;6956 const un_op = self.air.instructions.items(.data)[inst].un_op;
...@@ -6602,40 +6958,37 @@ pub const FuncGen = struct {...@@ -6602,40 +6958,37 @@ pub const FuncGen = struct {
6602 const operand_ty = self.typeOf(un_op);6958 const operand_ty = self.typeOf(un_op);
6603 const err_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty;6959 const err_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty;
6604 const payload_ty = err_union_ty.errorUnionPayload(mod);6960 const payload_ty = err_union_ty.errorUnionPayload(mod);
6605 const err_set_ty = try o.lowerType(Type.anyerror);6961 const zero = try o.builder.intValue(Builder.Type.err_int, 0);
6606 const zero = err_set_ty.constNull();
66076962
6608 if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) {6963 if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) {
6609 const llvm_i1 = self.context.intType(1);6964 const val: Builder.Constant = switch (cond) {
6610 switch (op) {6965 .eq => .true, // 0 == 0
6611 .EQ => return llvm_i1.constInt(1, .False), // 0 == 06966 .ne => .false, // 0 != 0
6612 .NE => return llvm_i1.constInt(0, .False), // 0 != 0
6613 else => unreachable,6967 else => unreachable,
6614 }6968 };
6969 return val.toValue();
6615 }6970 }
66166971
6617 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {6972 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
6618 const loaded = if (operand_is_ptr)6973 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, "")
6620 else6975 else
6621 operand;6976 operand;
6622 return self.builder.buildICmp(op, loaded, zero, "");6977 return self.wip.icmp(cond, loaded, zero, "");
6623 }6978 }
66246979
6625 const err_field_index = errUnionErrorOffset(payload_ty, mod);6980 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: {
6628 const err_union_llvm_ty = try o.lowerType(err_union_ty);6983 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, "");6984 const err_field_ptr =
6630 const loaded = self.builder.buildLoad(err_set_ty, err_field_ptr, "");6985 try self.wip.gepStruct(err_union_llvm_ty, operand, err_field_index, "");
6631 return self.builder.buildICmp(op, loaded, zero, "");6986 break :loaded try self.wip.load(.normal, Builder.Type.err_int, err_field_ptr, .default, "");
6632 }6987 } else try self.wip.extractValue(operand, &.{err_field_index}, "");
66336988 return self.wip.icmp(cond, loaded, zero, "");
6634 const loaded = self.builder.buildExtractValue(operand, err_field_index, "");
6635 return self.builder.buildICmp(op, loaded, zero, "");
6636 }6989 }
66376990
6638 fn airOptionalPayloadPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6991 fn airOptionalPayloadPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6639 const o = self.dg.object;6992 const o = self.dg.object;
6640 const mod = o.module;6993 const mod = o.module;
6641 const ty_op = self.air.instructions.items(.data)[inst].ty_op;6994 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -6651,11 +7004,10 @@ pub const FuncGen = struct {...@@ -6651,11 +7004,10 @@ pub const FuncGen = struct {
6651 // The payload and the optional are the same value.7004 // The payload and the optional are the same value.
6652 return operand;7005 return operand;
6653 }7006 }
6654 const optional_llvm_ty = try o.lowerType(optional_ty);7007 return self.wip.gepStruct(try o.lowerType(optional_ty), operand, 0, "");
6655 return self.builder.buildStructGEP(optional_llvm_ty, operand, 0, "");
6656 }7008 }
66577009
6658 fn airOptionalPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7010 fn airOptionalPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6659 comptime assert(optional_layout_version == 3);7011 comptime assert(optional_layout_version == 3);
66607012
6661 const o = self.dg.object;7013 const o = self.dg.object;
...@@ -6664,10 +7016,10 @@ pub const FuncGen = struct {...@@ -6664,10 +7016,10 @@ pub const FuncGen = struct {
6664 const operand = try self.resolveInst(ty_op.operand);7016 const operand = try self.resolveInst(ty_op.operand);
6665 const optional_ty = self.typeOf(ty_op.operand).childType(mod);7017 const optional_ty = self.typeOf(ty_op.operand).childType(mod);
6666 const payload_ty = optional_ty.optionalChild(mod);7018 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);
6668 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {7020 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
6669 // We have a pointer to a i8. We need to set it to 1 and then return the same pointer.7021 // 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);
6671 return operand;7023 return operand;
6672 }7024 }
6673 if (optional_ty.optionalReprIsPayload(mod)) {7025 if (optional_ty.optionalReprIsPayload(mod)) {
...@@ -6678,18 +7030,17 @@ pub const FuncGen = struct {...@@ -6678,18 +7030,17 @@ pub const FuncGen = struct {
66787030
6679 // First set the non-null bit.7031 // First set the non-null bit.
6680 const optional_llvm_ty = try o.lowerType(optional_ty);7032 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, "");
6682 // TODO set alignment on this store7034 // 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
6685 // Then return the payload pointer (only if it's used).7037 // Then return the payload pointer (only if it's used).
6686 if (self.liveness.isUnused(inst))7038 if (self.liveness.isUnused(inst)) return .none;
6687 return null;
66887039
6689 return self.builder.buildStructGEP(optional_llvm_ty, operand, 0, "");7040 return self.wip.gepStruct(optional_llvm_ty, operand, 0, "");
6690 }7041 }
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 {
6693 const o = self.dg.object;7044 const o = self.dg.object;
6694 const mod = o.module;7045 const mod = o.module;
6695 const inst = body_tail[0];7046 const inst = body_tail[0];
...@@ -6697,7 +7048,7 @@ pub const FuncGen = struct {...@@ -6697,7 +7048,7 @@ pub const FuncGen = struct {
6697 const operand = try self.resolveInst(ty_op.operand);7048 const operand = try self.resolveInst(ty_op.operand);
6698 const optional_ty = self.typeOf(ty_op.operand);7049 const optional_ty = self.typeOf(ty_op.operand);
6699 const payload_ty = self.typeOfIndex(inst);7050 const payload_ty = self.typeOfIndex(inst);
6700 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return null;7051 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none;
67017052
6702 if (optional_ty.optionalReprIsPayload(mod)) {7053 if (optional_ty.optionalReprIsPayload(mod)) {
6703 // Payload value is the same as the optional value.7054 // Payload value is the same as the optional value.
...@@ -6713,7 +7064,7 @@ pub const FuncGen = struct {...@@ -6713,7 +7064,7 @@ pub const FuncGen = struct {
6713 self: *FuncGen,7064 self: *FuncGen,
6714 body_tail: []const Air.Inst.Index,7065 body_tail: []const Air.Inst.Index,
6715 operand_is_ptr: bool,7066 operand_is_ptr: bool,
6716 ) !?*llvm.Value {7067 ) !Builder.Value {
6717 const o = self.dg.object;7068 const o = self.dg.object;
6718 const mod = o.module;7069 const mod = o.module;
6719 const inst = body_tail[0];7070 const inst = body_tail[0];
...@@ -6725,32 +7076,30 @@ pub const FuncGen = struct {...@@ -6725,32 +7076,30 @@ pub const FuncGen = struct {
6725 const payload_ty = if (operand_is_ptr) result_ty.childType(mod) else result_ty;7076 const payload_ty = if (operand_is_ptr) result_ty.childType(mod) else result_ty;
67267077
6727 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {7078 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
6728 return if (operand_is_ptr) operand else null;7079 return if (operand_is_ptr) operand else .none;
6729 }7080 }
6730 const offset = errUnionPayloadOffset(payload_ty, mod);7081 const offset = errUnionPayloadOffset(payload_ty, mod);
6731 const err_union_llvm_ty = try o.lowerType(err_union_ty);7082 const err_union_llvm_ty = try o.lowerType(err_union_ty);
6732 if (operand_is_ptr) {7083 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, "");
6734 } else if (isByRef(err_union_ty, mod)) {7085 } 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, "");
6736 if (isByRef(payload_ty, mod)) {7088 if (isByRef(payload_ty, mod)) {
6737 if (self.canElideLoad(body_tail))7089 if (self.canElideLoad(body_tail)) return payload_ptr;
6738 return payload_ptr;7090 return self.loadByRef(payload_ptr, payload_ty, payload_alignment, false);
6739
6740 return self.loadByRef(payload_ptr, payload_ty, payload_ty.abiAlignment(mod), false);
6741 }7091 }
6742 const load_inst = self.builder.buildLoad(err_union_llvm_ty.structGetTypeAtIndex(offset), payload_ptr, "");7092 const payload_llvm_ty = err_union_llvm_ty.structFields(&o.builder)[offset];
6743 load_inst.setAlignment(payload_ty.abiAlignment(mod));7093 return self.wip.load(.normal, payload_llvm_ty, payload_ptr, payload_alignment, "");
6744 return load_inst;
6745 }7094 }
6746 return self.builder.buildExtractValue(operand, offset, "");7095 return self.wip.extractValue(operand, &.{offset}, "");
6747 }7096 }
67487097
6749 fn airErrUnionErr(7098 fn airErrUnionErr(
6750 self: *FuncGen,7099 self: *FuncGen,
6751 inst: Air.Inst.Index,7100 inst: Air.Inst.Index,
6752 operand_is_ptr: bool,7101 operand_is_ptr: bool,
6753 ) !?*llvm.Value {7102 ) !Builder.Value {
6754 const o = self.dg.object;7103 const o = self.dg.object;
6755 const mod = o.module;7104 const mod = o.module;
6756 const ty_op = self.air.instructions.items(.data)[inst].ty_op;7105 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -6758,34 +7107,31 @@ pub const FuncGen = struct {...@@ -6758,34 +7107,31 @@ pub const FuncGen = struct {
6758 const operand_ty = self.typeOf(ty_op.operand);7107 const operand_ty = self.typeOf(ty_op.operand);
6759 const err_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty;7108 const err_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty;
6760 if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) {7109 if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) {
6761 const err_llvm_ty = try o.lowerType(Type.anyerror);
6762 if (operand_is_ptr) {7110 if (operand_is_ptr) {
6763 return operand;7111 return operand;
6764 } else {7112 } else {
6765 return err_llvm_ty.constInt(0, .False);7113 return o.builder.intValue(Builder.Type.err_int, 0);
6766 }7114 }
6767 }7115 }
67687116
6769 const err_set_llvm_ty = try o.lowerType(Type.anyerror);
6770
6771 const payload_ty = err_union_ty.errorUnionPayload(mod);7117 const payload_ty = err_union_ty.errorUnionPayload(mod);
6772 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {7118 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
6773 if (!operand_is_ptr) return operand;7119 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, "");
6775 }7121 }
67767122
6777 const offset = errUnionErrorOffset(payload_ty, mod);7123 const offset = errUnionErrorOffset(payload_ty, mod);
67787124
6779 if (operand_is_ptr or isByRef(err_union_ty, mod)) {7125 if (operand_is_ptr or isByRef(err_union_ty, mod)) {
6780 const err_union_llvm_ty = try o.lowerType(err_union_ty);7126 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, "");7127 const err_field_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, "");
6782 return self.builder.buildLoad(err_set_llvm_ty, err_field_ptr, "");7128 return self.wip.load(.normal, Builder.Type.err_int, err_field_ptr, .default, "");
6783 }7129 }
67847130
6785 return self.builder.buildExtractValue(operand, offset, "");7131 return self.wip.extractValue(operand, &.{offset}, "");
6786 }7132 }
67877133
6788 fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7134 fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6789 const o = self.dg.object;7135 const o = self.dg.object;
6790 const mod = o.module;7136 const mod = o.module;
6791 const ty_op = self.air.instructions.items(.data)[inst].ty_op;7137 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -6793,49 +7139,49 @@ pub const FuncGen = struct {...@@ -6793,49 +7139,49 @@ pub const FuncGen = struct {
6793 const err_union_ty = self.typeOf(ty_op.operand).childType(mod);7139 const err_union_ty = self.typeOf(ty_op.operand).childType(mod);
67947140
6795 const payload_ty = err_union_ty.errorUnionPayload(mod);7141 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);
6797 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {7143 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
6798 _ = self.builder.buildStore(non_error_val, operand);7144 _ = try self.wip.store(.normal, non_error_val, operand, .default);
6799 return operand;7145 return operand;
6800 }7146 }
6801 const err_union_llvm_ty = try o.lowerType(err_union_ty);7147 const err_union_llvm_ty = try o.lowerType(err_union_ty);
6802 {7148 {
7149 const error_alignment = Builder.Alignment.fromByteUnits(Type.err_int.abiAlignment(mod));
6803 const error_offset = errUnionErrorOffset(payload_ty, mod);7150 const error_offset = errUnionErrorOffset(payload_ty, mod);
6804 // First set the non-error value.7151 // First set the non-error value.
6805 const non_null_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, error_offset, "");7152 const non_null_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, error_offset, "");
6806 const store_inst = self.builder.buildStore(non_error_val, non_null_ptr);7153 _ = try self.wip.store(.normal, non_error_val, non_null_ptr, error_alignment);
6807 store_inst.setAlignment(Type.anyerror.abiAlignment(mod));
6808 }7154 }
6809 // Then return the payload pointer (only if it is used).7155 // Then return the payload pointer (only if it is used).
6810 if (self.liveness.isUnused(inst))7156 if (self.liveness.isUnused(inst)) return .none;
6811 return null;
68127157
6813 const payload_offset = errUnionPayloadOffset(payload_ty, mod);7158 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, "");
6815 }7160 }
68167161
6817 fn airErrReturnTrace(self: *FuncGen, _: Air.Inst.Index) !?*llvm.Value {7162 fn airErrReturnTrace(self: *FuncGen, _: Air.Inst.Index) !Builder.Value {
6818 return self.err_ret_trace.?;7163 assert(self.err_ret_trace != .none);
7164 return self.err_ret_trace;
6819 }7165 }
68207166
6821 fn airSetErrReturnTrace(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7167 fn airSetErrReturnTrace(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6822 const un_op = self.air.instructions.items(.data)[inst].un_op;7168 const un_op = self.air.instructions.items(.data)[inst].un_op;
6823 const operand = try self.resolveInst(un_op);7169 self.err_ret_trace = try self.resolveInst(un_op);
6824 self.err_ret_trace = operand;7170 return .none;
6825 return null;
6826 }7171 }
68277172
6828 fn airSaveErrReturnTraceIndex(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7173 fn airSaveErrReturnTraceIndex(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6829 const o = self.dg.object;7174 const o = self.dg.object;
6830 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;7175 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
6831 //const struct_ty = try self.resolveInst(ty_pl.ty);
6832 const struct_ty = self.air.getRefType(ty_pl.ty);7176 const struct_ty = self.air.getRefType(ty_pl.ty);
6833 const field_index = ty_pl.payload;7177 const field_index = ty_pl.payload;
68347178
6835 const mod = o.module;7179 const mod = o.module;
6836 const llvm_field = llvmField(struct_ty, field_index, mod).?;7180 const llvm_field = llvmField(struct_ty, field_index, mod).?;
6837 const struct_llvm_ty = try o.lowerType(struct_ty);7181 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, "");
6839 const field_ptr_ty = try mod.ptrType(.{7185 const field_ptr_ty = try mod.ptrType(.{
6840 .child = llvm_field.ty.toIntern(),7186 .child = llvm_field.ty.toIntern(),
6841 .flags = .{7187 .flags = .{
...@@ -6845,34 +7191,32 @@ pub const FuncGen = struct {...@@ -6845,34 +7191,32 @@ pub const FuncGen = struct {
6845 return self.load(field_ptr, field_ptr_ty);7191 return self.load(field_ptr, field_ptr_ty);
6846 }7192 }
68477193
6848 fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7194 fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6849 const o = self.dg.object;7195 const o = self.dg.object;
6850 const mod = o.module;7196 const mod = o.module;
6851 const ty_op = self.air.instructions.items(.data)[inst].ty_op;7197 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
6852 const payload_ty = self.typeOf(ty_op.operand);7198 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);
6854 comptime assert(optional_layout_version == 3);7200 comptime assert(optional_layout_version == 3);
6855 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return non_null_bit;7201 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return non_null_bit;
6856 const operand = try self.resolveInst(ty_op.operand);7202 const operand = try self.resolveInst(ty_op.operand);
6857 const optional_ty = self.typeOfIndex(inst);7203 const optional_ty = self.typeOfIndex(inst);
6858 if (optional_ty.optionalReprIsPayload(mod)) {7204 if (optional_ty.optionalReprIsPayload(mod)) return operand;
6859 return operand;
6860 }
6861 const llvm_optional_ty = try o.lowerType(optional_ty);7205 const llvm_optional_ty = try o.lowerType(optional_ty);
6862 if (isByRef(optional_ty, mod)) {7206 if (isByRef(optional_ty, mod)) {
6863 const optional_ptr = self.buildAlloca(llvm_optional_ty, optional_ty.abiAlignment(mod));7207 const alignment = Builder.Alignment.fromByteUnits(optional_ty.abiAlignment(mod));
6864 const payload_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 0, "");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, "");
6865 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);7210 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);
6866 try self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic);7211 try self.store(payload_ptr, payload_ptr_ty, operand, .none);
6867 const non_null_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 1, "");7212 const non_null_ptr = try self.wip.gepStruct(llvm_optional_ty, optional_ptr, 1, "");
6868 _ = self.builder.buildStore(non_null_bit, non_null_ptr);7213 _ = try self.wip.store(.normal, non_null_bit, non_null_ptr, .default);
6869 return optional_ptr;7214 return optional_ptr;
6870 }7215 }
6871 const partial = self.builder.buildInsertValue(llvm_optional_ty.getUndef(), operand, 0, "");7216 return self.wip.buildAggregate(llvm_optional_ty, &.{ operand, non_null_bit }, "");
6872 return self.builder.buildInsertValue(partial, non_null_bit, 1, "");
6873 }7217 }
68747218
6875 fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7219 fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6876 const o = self.dg.object;7220 const o = self.dg.object;
6877 const mod = o.module;7221 const mod = o.module;
6878 const ty_op = self.air.instructions.items(.data)[inst].ty_op;7222 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -6882,46 +7226,47 @@ pub const FuncGen = struct {...@@ -6882,46 +7226,47 @@ pub const FuncGen = struct {
6882 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {7226 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
6883 return operand;7227 return operand;
6884 }7228 }
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);
6886 const err_un_llvm_ty = try o.lowerType(err_un_ty);7230 const err_un_llvm_ty = try o.lowerType(err_un_ty);
68877231
6888 const payload_offset = errUnionPayloadOffset(payload_ty, mod);7232 const payload_offset = errUnionPayloadOffset(payload_ty, mod);
6889 const error_offset = errUnionErrorOffset(payload_ty, mod);7233 const error_offset = errUnionErrorOffset(payload_ty, mod);
6890 if (isByRef(err_un_ty, mod)) {7234 if (isByRef(err_un_ty, mod)) {
6891 const result_ptr = self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(mod));7235 const alignment = Builder.Alignment.fromByteUnits(err_un_ty.abiAlignment(mod));
6892 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");7236 const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment);
6893 const store_inst = self.builder.buildStore(ok_err_code, err_ptr);7237 const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, "");
6894 store_inst.setAlignment(Type.anyerror.abiAlignment(mod));7238 const error_alignment = Builder.Alignment.fromByteUnits(Type.err_int.abiAlignment(mod));
6895 const payload_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, payload_offset, "");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, "");
6896 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);7241 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);
6898 return result_ptr;7243 return result_ptr;
6899 }7244 }
69007245 var fields: [2]Builder.Value = undefined;
6901 const partial = self.builder.buildInsertValue(err_un_llvm_ty.getUndef(), ok_err_code, error_offset, "");7246 fields[payload_offset] = operand;
6902 return self.builder.buildInsertValue(partial, operand, payload_offset, "");7247 fields[error_offset] = ok_err_code;
7248 return self.wip.buildAggregate(err_un_llvm_ty, &fields, "");
6903 }7249 }
69047250
6905 fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7251 fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6906 const o = self.dg.object;7252 const o = self.dg.object;
6907 const mod = o.module;7253 const mod = o.module;
6908 const ty_op = self.air.instructions.items(.data)[inst].ty_op;7254 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
6909 const err_un_ty = self.typeOfIndex(inst);7255 const err_un_ty = self.typeOfIndex(inst);
6910 const payload_ty = err_un_ty.errorUnionPayload(mod);7256 const payload_ty = err_un_ty.errorUnionPayload(mod);
6911 const operand = try self.resolveInst(ty_op.operand);7257 const operand = try self.resolveInst(ty_op.operand);
6912 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {7258 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return operand;
6913 return operand;
6914 }
6915 const err_un_llvm_ty = try o.lowerType(err_un_ty);7259 const err_un_llvm_ty = try o.lowerType(err_un_ty);
69167260
6917 const payload_offset = errUnionPayloadOffset(payload_ty, mod);7261 const payload_offset = errUnionPayloadOffset(payload_ty, mod);
6918 const error_offset = errUnionErrorOffset(payload_ty, mod);7262 const error_offset = errUnionErrorOffset(payload_ty, mod);
6919 if (isByRef(err_un_ty, mod)) {7263 if (isByRef(err_un_ty, mod)) {
6920 const result_ptr = self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(mod));7264 const alignment = Builder.Alignment.fromByteUnits(err_un_ty.abiAlignment(mod));
6921 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");7265 const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment);
6922 const store_inst = self.builder.buildStore(operand, err_ptr);7266 const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, "");
6923 store_inst.setAlignment(Type.anyerror.abiAlignment(mod));7267 const error_alignment = Builder.Alignment.fromByteUnits(Type.err_int.abiAlignment(mod));
6924 const payload_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, payload_offset, "");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, "");
6925 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);7270 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);
6926 // TODO store undef to payload_ptr7271 // TODO store undef to payload_ptr
6927 _ = payload_ptr;7272 _ = payload_ptr;
...@@ -6929,34 +7274,52 @@ pub const FuncGen = struct {...@@ -6929,34 +7274,52 @@ pub const FuncGen = struct {
6929 return result_ptr;7274 return result_ptr;
6930 }7275 }
69317276
6932 const partial = self.builder.buildInsertValue(err_un_llvm_ty.getUndef(), operand, error_offset, "");
6933 // TODO set payload bytes to undef7277 // 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}, "");
6935 }7280 }
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;
6938 const pl_op = self.air.instructions.items(.data)[inst].pl_op;7284 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
6939 const index = pl_op.payload;7285 const index = pl_op.payload;
6940 const llvm_u32 = self.context.intType(32);7286 const llvm_fn = try self.getIntrinsic("llvm.wasm.memory.size", &.{.i32});
6941 const llvm_fn = self.getIntrinsic("llvm.wasm.memory.size", &.{llvm_u32});7287 const args: [1]*llvm.Value = .{
6942 const args: [1]*llvm.Value = .{llvm_u32.constInt(index, .False)};7288 (try o.builder.intConst(.i32, index)).toLlvm(&o.builder),
6943 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");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);
6944 }7299 }
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;
6947 const pl_op = self.air.instructions.items(.data)[inst].pl_op;7303 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
6948 const index = pl_op.payload;7304 const index = pl_op.payload;
6949 const operand = try self.resolveInst(pl_op.operand);7305 const operand = try self.resolveInst(pl_op.operand);
6950 const llvm_u32 = self.context.intType(32);7306 const llvm_fn = try self.getIntrinsic("llvm.wasm.memory.grow", &.{.i32});
6951 const llvm_fn = self.getIntrinsic("llvm.wasm.memory.grow", &.{llvm_u32});
6952 const args: [2]*llvm.Value = .{7307 const args: [2]*llvm.Value = .{
6953 llvm_u32.constInt(index, .False),7308 (try o.builder.intConst(.i32, index)).toLlvm(&o.builder),
6954 operand,7309 operand.toLlvm(&self.wip),
6955 };7310 };
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);
6957 }7320 }
69587321
6959 fn airVectorStoreElem(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7322 fn airVectorStoreElem(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6960 const o = self.dg.object;7323 const o = self.dg.object;
6961 const mod = o.module;7324 const mod = o.module;
6962 const data = self.air.instructions.items(.data)[inst].vector_store_elem;7325 const data = self.air.instructions.items(.data)[inst].vector_store_elem;
...@@ -6967,19 +7330,20 @@ pub const FuncGen = struct {...@@ -6967,19 +7330,20 @@ pub const FuncGen = struct {
6967 const index = try self.resolveInst(extra.lhs);7330 const index = try self.resolveInst(extra.lhs);
6968 const operand = try self.resolveInst(extra.rhs);7331 const operand = try self.resolveInst(extra.rhs);
69697332
6970 const loaded_vector = blk: {7333 const kind: Builder.MemoryAccessKind = switch (vector_ptr_ty.isVolatilePtr(mod)) {
6971 const elem_llvm_ty = try o.lowerType(vector_ptr_ty.childType(mod));7334 false => .normal,
6972 const load_inst = self.builder.buildLoad(elem_llvm_ty, vector_ptr, "");7335 true => .@"volatile",
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;
6976 };7336 };
6977 const modified_vector = self.builder.buildInsertElement(loaded_vector, operand, index, "");7337 const elem_llvm_ty = try o.lowerType(vector_ptr_ty.childType(mod));
6978 try self.store(vector_ptr, vector_ptr_ty, modified_vector, .NotAtomic);7338 const alignment = Builder.Alignment.fromByteUnits(vector_ptr_ty.ptrAlignment(mod));
6979 return null;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;
6980 }7344 }
69817345
6982 fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7346 fn airMin(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6983 const o = self.dg.object;7347 const o = self.dg.object;
6984 const mod = o.module;7348 const mod = o.module;
6985 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7349 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -6988,11 +7352,13 @@ pub const FuncGen = struct {...@@ -6988,11 +7352,13 @@ pub const FuncGen = struct {
6988 const scalar_ty = self.typeOfIndex(inst).scalarType(mod);7352 const scalar_ty = self.typeOfIndex(inst).scalarType(mod);
69897353
6990 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.fmin, scalar_ty, 2, .{ lhs, rhs });7354 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, "");7355 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
6992 return self.builder.buildUMin(lhs, rhs, "");7356 .@"llvm.smin."
7357 else
7358 .@"llvm.umin.", lhs, rhs, "");
6993 }7359 }
69947360
6995 fn airMax(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7361 fn airMax(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6996 const o = self.dg.object;7362 const o = self.dg.object;
6997 const mod = o.module;7363 const mod = o.module;
6998 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7364 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -7001,26 +7367,23 @@ pub const FuncGen = struct {...@@ -7001,26 +7367,23 @@ pub const FuncGen = struct {
7001 const scalar_ty = self.typeOfIndex(inst).scalarType(mod);7367 const scalar_ty = self.typeOfIndex(inst).scalarType(mod);
70027368
7003 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.fmax, scalar_ty, 2, .{ lhs, rhs });7369 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, "");7370 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7005 return self.builder.buildUMax(lhs, rhs, "");7371 .@"llvm.smax."
7372 else
7373 .@"llvm.umax.", lhs, rhs, "");
7006 }7374 }
70077375
7008 fn airSlice(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7376 fn airSlice(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7009 const o = self.dg.object;7377 const o = self.dg.object;
7010 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;7378 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
7011 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;7379 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
7012 const ptr = try self.resolveInst(bin_op.lhs);7380 const ptr = try self.resolveInst(bin_op.lhs);
7013 const len = try self.resolveInst(bin_op.rhs);7381 const len = try self.resolveInst(bin_op.rhs);
7014 const inst_ty = self.typeOfIndex(inst);7382 const inst_ty = self.typeOfIndex(inst);
7015 const llvm_slice_ty = try o.lowerType(inst_ty);7383 return self.wip.buildAggregate(try o.lowerType(inst_ty), &.{ ptr, len }, "");
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, "");
7021 }7384 }
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 {
7024 self.builder.setFastMath(want_fast_math);7387 self.builder.setFastMath(want_fast_math);
70257388
7026 const o = self.dg.object;7389 const o = self.dg.object;
...@@ -7032,8 +7395,7 @@ pub const FuncGen = struct {...@@ -7032,8 +7395,7 @@ pub const FuncGen = struct {
7032 const scalar_ty = inst_ty.scalarType(mod);7395 const scalar_ty = inst_ty.scalarType(mod);
70337396
7034 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.add, inst_ty, 2, .{ lhs, rhs });7397 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, "");7398 return self.wip.bin(if (scalar_ty.isSignedInt(mod)) .@"add nsw" else .@"add nuw", lhs, rhs, "");
7036 return self.builder.buildNUWAdd(lhs, rhs, "");
7037 }7399 }
70387400
7039 fn airSafeArithmetic(7401 fn airSafeArithmetic(
...@@ -7041,7 +7403,7 @@ pub const FuncGen = struct {...@@ -7041,7 +7403,7 @@ pub const FuncGen = struct {
7041 inst: Air.Inst.Index,7403 inst: Air.Inst.Index,
7042 signed_intrinsic: []const u8,7404 signed_intrinsic: []const u8,
7043 unsigned_intrinsic: []const u8,7405 unsigned_intrinsic: []const u8,
7044 ) !?*llvm.Value {7406 ) !Builder.Value {
7045 const o = fg.dg.object;7407 const o = fg.dg.object;
7046 const mod = o.module;7408 const mod = o.module;
70477409
...@@ -7057,42 +7419,50 @@ pub const FuncGen = struct {...@@ -7057,42 +7419,50 @@ pub const FuncGen = struct {
7057 false => unsigned_intrinsic,7419 false => unsigned_intrinsic,
7058 };7420 };
7059 const llvm_inst_ty = try o.lowerType(inst_ty);7421 const llvm_inst_ty = try o.lowerType(inst_ty);
7060 const llvm_fn = fg.getIntrinsic(intrinsic_name, &.{llvm_inst_ty});7422 const llvm_ret_ty = try o.builder.structType(.normal, &.{
7061 const result_struct = fg.builder.buildCall(7423 llvm_inst_ty,
7062 llvm_fn.globalGetValueType(),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),
7063 llvm_fn,7430 llvm_fn,
7064 &[_]*llvm.Value{ lhs, rhs },7431 &[_]*llvm.Value{ lhs.toLlvm(&fg.wip), rhs.toLlvm(&fg.wip) },
7065 2,7432 2,
7066 .Fast,7433 .Fast,
7067 .Auto,7434 .Auto,
7068 "",7435 "",
7069 );7436 ), &fg.wip);
7070 const overflow_bit = fg.builder.buildExtractValue(result_struct, 1, "");7437 const overflow_bit = try fg.wip.extractValue(result_struct, &.{1}, "");
7071 const scalar_overflow_bit = switch (is_scalar) {7438 const scalar_overflow_bit = switch (is_scalar) {
7072 true => overflow_bit,7439 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 ),
7074 };7444 };
70757445
7076 const fail_block = fg.context.appendBasicBlock(fg.llvm_func, "OverflowFail");7446 const fail_block = try fg.wip.block(1, "OverflowFail");
7077 const ok_block = fg.context.appendBasicBlock(fg.llvm_func, "OverflowOk");7447 const ok_block = try fg.wip.block(1, "OverflowOk");
7078 _ = fg.builder.buildCondBr(scalar_overflow_bit, fail_block, ok_block);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 };
7081 try fg.buildSimplePanic(.integer_overflow);7451 try fg.buildSimplePanic(.integer_overflow);
70827452
7083 fg.builder.positionBuilderAtEnd(ok_block);7453 fg.wip.cursor = .{ .block = ok_block };
7084 return fg.builder.buildExtractValue(result_struct, 0, "");7454 return fg.wip.extractValue(result_struct, &.{0}, "");
7085 }7455 }
70867456
7087 fn airAddWrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7457 fn airAddWrap(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7088 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7458 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
7089 const lhs = try self.resolveInst(bin_op.lhs);7459 const lhs = try self.resolveInst(bin_op.lhs);
7090 const rhs = try self.resolveInst(bin_op.rhs);7460 const rhs = try self.resolveInst(bin_op.rhs);
70917461
7092 return self.builder.buildAdd(lhs, rhs, "");7462 return self.wip.bin(.add, lhs, rhs, "");
7093 }7463 }
70947464
7095 fn airAddSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7465 fn airAddSat(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7096 const o = self.dg.object;7466 const o = self.dg.object;
7097 const mod = o.module;7467 const mod = o.module;
7098 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7468 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -7102,12 +7472,13 @@ pub const FuncGen = struct {...@@ -7102,12 +7472,13 @@ pub const FuncGen = struct {
7102 const scalar_ty = inst_ty.scalarType(mod);7472 const scalar_ty = inst_ty.scalarType(mod);
71037473
7104 if (scalar_ty.isAnyFloat()) return self.todo("saturating float add", .{});7474 if (scalar_ty.isAnyFloat()) return self.todo("saturating float add", .{});
7105 if (scalar_ty.isSignedInt(mod)) return self.builder.buildSAddSat(lhs, rhs, "");7475 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
71067476 .@"llvm.sadd.sat."
7107 return self.builder.buildUAddSat(lhs, rhs, "");7477 else
7478 .@"llvm.uadd.sat.", lhs, rhs, "");
7108 }7479 }
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 {
7111 self.builder.setFastMath(want_fast_math);7482 self.builder.setFastMath(want_fast_math);
71127483
7113 const o = self.dg.object;7484 const o = self.dg.object;
...@@ -7119,19 +7490,18 @@ pub const FuncGen = struct {...@@ -7119,19 +7490,18 @@ pub const FuncGen = struct {
7119 const scalar_ty = inst_ty.scalarType(mod);7490 const scalar_ty = inst_ty.scalarType(mod);
71207491
7121 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.sub, inst_ty, 2, .{ lhs, rhs });7492 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, "");7493 return self.wip.bin(if (scalar_ty.isSignedInt(mod)) .@"sub nsw" else .@"sub nuw", lhs, rhs, "");
7123 return self.builder.buildNUWSub(lhs, rhs, "");
7124 }7494 }
71257495
7126 fn airSubWrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7496 fn airSubWrap(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7127 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7497 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
7128 const lhs = try self.resolveInst(bin_op.lhs);7498 const lhs = try self.resolveInst(bin_op.lhs);
7129 const rhs = try self.resolveInst(bin_op.rhs);7499 const rhs = try self.resolveInst(bin_op.rhs);
71307500
7131 return self.builder.buildSub(lhs, rhs, "");7501 return self.wip.bin(.sub, lhs, rhs, "");
7132 }7502 }
71337503
7134 fn airSubSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7504 fn airSubSat(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7135 const o = self.dg.object;7505 const o = self.dg.object;
7136 const mod = o.module;7506 const mod = o.module;
7137 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7507 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -7141,11 +7511,13 @@ pub const FuncGen = struct {...@@ -7141,11 +7511,13 @@ pub const FuncGen = struct {
7141 const scalar_ty = inst_ty.scalarType(mod);7511 const scalar_ty = inst_ty.scalarType(mod);
71427512
7143 if (scalar_ty.isAnyFloat()) return self.todo("saturating float sub", .{});7513 if (scalar_ty.isAnyFloat()) return self.todo("saturating float sub", .{});
7144 if (scalar_ty.isSignedInt(mod)) return self.builder.buildSSubSat(lhs, rhs, "");7514 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7145 return self.builder.buildUSubSat(lhs, rhs, "");7515 .@"llvm.ssub.sat."
7516 else
7517 .@"llvm.usub.sat.", lhs, rhs, "");
7146 }7518 }
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 {
7149 self.builder.setFastMath(want_fast_math);7521 self.builder.setFastMath(want_fast_math);
71507522
7151 const o = self.dg.object;7523 const o = self.dg.object;
...@@ -7157,19 +7529,18 @@ pub const FuncGen = struct {...@@ -7157,19 +7529,18 @@ pub const FuncGen = struct {
7157 const scalar_ty = inst_ty.scalarType(mod);7529 const scalar_ty = inst_ty.scalarType(mod);
71587530
7159 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.mul, inst_ty, 2, .{ lhs, rhs });7531 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, "");7532 return self.wip.bin(if (scalar_ty.isSignedInt(mod)) .@"mul nsw" else .@"mul nuw", lhs, rhs, "");
7161 return self.builder.buildNUWMul(lhs, rhs, "");
7162 }7533 }
71637534
7164 fn airMulWrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7535 fn airMulWrap(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7165 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7536 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
7166 const lhs = try self.resolveInst(bin_op.lhs);7537 const lhs = try self.resolveInst(bin_op.lhs);
7167 const rhs = try self.resolveInst(bin_op.rhs);7538 const rhs = try self.resolveInst(bin_op.rhs);
71687539
7169 return self.builder.buildMul(lhs, rhs, "");7540 return self.wip.bin(.mul, lhs, rhs, "");
7170 }7541 }
71717542
7172 fn airMulSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7543 fn airMulSat(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7173 const o = self.dg.object;7544 const o = self.dg.object;
7174 const mod = o.module;7545 const mod = o.module;
7175 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7546 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -7179,11 +7550,13 @@ pub const FuncGen = struct {...@@ -7179,11 +7550,13 @@ pub const FuncGen = struct {
7179 const scalar_ty = inst_ty.scalarType(mod);7550 const scalar_ty = inst_ty.scalarType(mod);
71807551
7181 if (scalar_ty.isAnyFloat()) return self.todo("saturating float mul", .{});7552 if (scalar_ty.isAnyFloat()) return self.todo("saturating float mul", .{});
7182 if (scalar_ty.isSignedInt(mod)) return self.builder.buildSMulFixSat(lhs, rhs, "");7553 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7183 return self.builder.buildUMulFixSat(lhs, rhs, "");7554 .@"llvm.smul.fix.sat."
7555 else
7556 .@"llvm.umul.fix.sat.", lhs, rhs, "");
7184 }7557 }
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 {
7187 self.builder.setFastMath(want_fast_math);7560 self.builder.setFastMath(want_fast_math);
71887561
7189 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7562 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -7194,7 +7567,7 @@ pub const FuncGen = struct {...@@ -7194,7 +7567,7 @@ pub const FuncGen = struct {
7194 return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });7567 return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });
7195 }7568 }
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 {
7198 self.builder.setFastMath(want_fast_math);7571 self.builder.setFastMath(want_fast_math);
71997572
7200 const o = self.dg.object;7573 const o = self.dg.object;
...@@ -7209,11 +7582,10 @@ pub const FuncGen = struct {...@@ -7209,11 +7582,10 @@ pub const FuncGen = struct {
7209 const result = try self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });7582 const result = try self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });
7210 return self.buildFloatOp(.trunc, inst_ty, 1, .{result});7583 return self.buildFloatOp(.trunc, inst_ty, 1, .{result});
7211 }7584 }
7212 if (scalar_ty.isSignedInt(mod)) return self.builder.buildSDiv(lhs, rhs, "");7585 return self.wip.bin(if (scalar_ty.isSignedInt(mod)) .sdiv else .udiv, lhs, rhs, "");
7213 return self.builder.buildUDiv(lhs, rhs, "");
7214 }7586 }
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 {
7217 self.builder.setFastMath(want_fast_math);7589 self.builder.setFastMath(want_fast_math);
72187590
7219 const o = self.dg.object;7591 const o = self.dg.object;
...@@ -7230,31 +7602,24 @@ pub const FuncGen = struct {...@@ -7230,31 +7602,24 @@ pub const FuncGen = struct {
7230 }7602 }
7231 if (scalar_ty.isSignedInt(mod)) {7603 if (scalar_ty.isSignedInt(mod)) {
7232 const inst_llvm_ty = try o.lowerType(inst_ty);7604 const inst_llvm_ty = try o.lowerType(inst_ty);
7233 const scalar_bit_size_minus_one = scalar_ty.bitSize(mod) - 1;7605 const bit_size_minus_one = try o.builder.splatValue(inst_llvm_ty, try o.builder.intConst(
7234 const bit_size_minus_one = if (inst_ty.zigTypeTag(mod) == .Vector) const_vector: {7606 inst_llvm_ty.scalarType(&o.builder),
7235 const vec_len = inst_ty.vectorLen(mod);7607 inst_llvm_ty.scalarBits(&o.builder) - 1,
7236 const scalar_llvm_ty = try o.lowerType(scalar_ty);7608 ));
7237
7238 const shifts = try self.gpa.alloc(*llvm.Value, vec_len);
7239 defer self.gpa.free(shifts);
72407609
7241 @memset(shifts, scalar_llvm_ty.constInt(scalar_bit_size_minus_one, .False));7610 const div = try self.wip.bin(.sdiv, lhs, rhs, "");
7242 break :const_vector llvm.constVector(shifts.ptr, vec_len);7611 const rem = try self.wip.bin(.srem, lhs, rhs, "");
7243 } else inst_llvm_ty.constInt(scalar_bit_size_minus_one, .False);7612 const div_sign = try self.wip.bin(.xor, lhs, rhs, "");
72447613 const div_sign_mask = try self.wip.bin(.ashr, div_sign, bit_size_minus_one, "");
7245 const div = self.builder.buildSDiv(lhs, rhs, "");7614 const zero = try o.builder.zeroInitValue(inst_llvm_ty);
7246 const rem = self.builder.buildSRem(lhs, rhs, "");7615 const rem_nonzero = try self.wip.icmp(.ne, rem, zero, "");
7247 const div_sign = self.builder.buildXor(lhs, rhs, "");7616 const correction = try self.wip.select(rem_nonzero, div_sign_mask, zero, "");
7248 const div_sign_mask = self.builder.buildAShr(div_sign, bit_size_minus_one, "");7617 return self.wip.bin(.@"add nsw", div, correction, "");
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, "");
7253 }7618 }
7254 return self.builder.buildUDiv(lhs, rhs, "");7619 return self.wip.bin(.udiv, lhs, rhs, "");
7255 }7620 }
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 {
7258 self.builder.setFastMath(want_fast_math);7623 self.builder.setFastMath(want_fast_math);
72597624
7260 const o = self.dg.object;7625 const o = self.dg.object;
...@@ -7266,11 +7631,13 @@ pub const FuncGen = struct {...@@ -7266,11 +7631,13 @@ pub const FuncGen = struct {
7266 const scalar_ty = inst_ty.scalarType(mod);7631 const scalar_ty = inst_ty.scalarType(mod);
72677632
7268 if (scalar_ty.isRuntimeFloat()) return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });7633 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, "");7634 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7270 return self.builder.buildExactUDiv(lhs, rhs, "");7635 .@"sdiv exact"
7636 else
7637 .@"udiv exact", lhs, rhs, "");
7271 }7638 }
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 {
7274 self.builder.setFastMath(want_fast_math);7641 self.builder.setFastMath(want_fast_math);
72757642
7276 const o = self.dg.object;7643 const o = self.dg.object;
...@@ -7282,11 +7649,13 @@ pub const FuncGen = struct {...@@ -7282,11 +7649,13 @@ pub const FuncGen = struct {
7282 const scalar_ty = inst_ty.scalarType(mod);7649 const scalar_ty = inst_ty.scalarType(mod);
72837650
7284 if (scalar_ty.isRuntimeFloat()) return self.buildFloatOp(.fmod, inst_ty, 2, .{ lhs, rhs });7651 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, "");7652 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7286 return self.builder.buildURem(lhs, rhs, "");7653 .srem
7654 else
7655 .urem, lhs, rhs, "");
7287 }7656 }
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 {
7290 self.builder.setFastMath(want_fast_math);7659 self.builder.setFastMath(want_fast_math);
72917660
7292 const o = self.dg.object;7661 const o = self.dg.object;
...@@ -7302,36 +7671,29 @@ pub const FuncGen = struct {...@@ -7302,36 +7671,29 @@ pub const FuncGen = struct {
7302 const a = try self.buildFloatOp(.fmod, inst_ty, 2, .{ lhs, rhs });7671 const a = try self.buildFloatOp(.fmod, inst_ty, 2, .{ lhs, rhs });
7303 const b = try self.buildFloatOp(.add, inst_ty, 2, .{ a, rhs });7672 const b = try self.buildFloatOp(.add, inst_ty, 2, .{ a, rhs });
7304 const c = try self.buildFloatOp(.fmod, inst_ty, 2, .{ b, rhs });7673 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);
7306 const ltz = try self.buildFloatCmp(.lt, inst_ty, .{ lhs, zero });7675 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, "");
7308 }7677 }
7309 if (scalar_ty.isSignedInt(mod)) {7678 if (scalar_ty.isSignedInt(mod)) {
7310 const scalar_bit_size_minus_one = scalar_ty.bitSize(mod) - 1;7679 const bit_size_minus_one = try o.builder.splatValue(inst_llvm_ty, try o.builder.intConst(
7311 const bit_size_minus_one = if (inst_ty.zigTypeTag(mod) == .Vector) const_vector: {7680 inst_llvm_ty.scalarType(&o.builder),
7312 const vec_len = inst_ty.vectorLen(mod);7681 inst_llvm_ty.scalarBits(&o.builder) - 1,
7313 const scalar_llvm_ty = try o.lowerType(scalar_ty);7682 ));
7314
7315 const shifts = try self.gpa.alloc(*llvm.Value, vec_len);
7316 defer self.gpa.free(shifts);
73177683
7318 @memset(shifts, scalar_llvm_ty.constInt(scalar_bit_size_minus_one, .False));7684 const rem = try self.wip.bin(.srem, lhs, rhs, "");
7319 break :const_vector llvm.constVector(shifts.ptr, vec_len);7685 const div_sign = try self.wip.bin(.xor, lhs, rhs, "");
7320 } else inst_llvm_ty.constInt(scalar_bit_size_minus_one, .False);7686 const div_sign_mask = try self.wip.bin(.ashr, div_sign, bit_size_minus_one, "");
73217687 const rhs_masked = try self.wip.bin(.@"and", rhs, div_sign_mask, "");
7322 const rem = self.builder.buildSRem(lhs, rhs, "");7688 const zero = try o.builder.zeroInitValue(inst_llvm_ty);
7323 const div_sign = self.builder.buildXor(lhs, rhs, "");7689 const rem_nonzero = try self.wip.icmp(.ne, rem, zero, "");
7324 const div_sign_mask = self.builder.buildAShr(div_sign, bit_size_minus_one, "");7690 const correction = try self.wip.select(rem_nonzero, rhs_masked, zero, "");
7325 const rhs_masked = self.builder.buildAnd(rhs, div_sign_mask, "");7691 return self.wip.bin(.@"add nsw", rem, correction, "");
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, "");
7330 }7692 }
7331 return self.builder.buildURem(lhs, rhs, "");7693 return self.wip.bin(.urem, lhs, rhs, "");
7332 }7694 }
73337695
7334 fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7696 fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7335 const o = self.dg.object;7697 const o = self.dg.object;
7336 const mod = o.module;7698 const mod = o.module;
7337 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;7699 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -7341,49 +7703,37 @@ pub const FuncGen = struct {...@@ -7341,49 +7703,37 @@ pub const FuncGen = struct {
7341 const ptr_ty = self.typeOf(bin_op.lhs);7703 const ptr_ty = self.typeOf(bin_op.lhs);
7342 const llvm_elem_ty = try o.lowerPtrElemTy(ptr_ty.childType(mod));7704 const llvm_elem_ty = try o.lowerPtrElemTy(ptr_ty.childType(mod));
7343 switch (ptr_ty.ptrSize(mod)) {7705 switch (ptr_ty.ptrSize(mod)) {
7344 .One => {7706 // It's a pointer to an array, so according to LLVM we need an extra GEP index.
7345 // 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, &.{
7346 const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), offset };7708 try o.builder.intValue(try o.lowerType(Type.usize), 0), offset,
7347 return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, "");7709 }, ""),
7348 },7710 .C, .Many => return self.wip.gep(.inbounds, llvm_elem_ty, ptr, &.{offset}, ""),
7349 .C, .Many => {
7350 const indices: [1]*llvm.Value = .{offset};
7351 return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, "");
7352 },
7353 .Slice => {7711 .Slice => {
7354 const base = self.builder.buildExtractValue(ptr, 0, "");7712 const base = try self.wip.extractValue(ptr, &.{0}, "");
7355 const indices: [1]*llvm.Value = .{offset};7713 return self.wip.gep(.inbounds, llvm_elem_ty, base, &.{offset}, "");
7356 return self.builder.buildInBoundsGEP(llvm_elem_ty, base, &indices, indices.len, "");
7357 },7714 },
7358 }7715 }
7359 }7716 }
73607717
7361 fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7718 fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7362 const o = self.dg.object;7719 const o = self.dg.object;
7363 const mod = o.module;7720 const mod = o.module;
7364 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;7721 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
7365 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;7722 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
7366 const ptr = try self.resolveInst(bin_op.lhs);7723 const ptr = try self.resolveInst(bin_op.lhs);
7367 const offset = try self.resolveInst(bin_op.rhs);7724 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, "");
7369 const ptr_ty = self.typeOf(bin_op.lhs);7726 const ptr_ty = self.typeOf(bin_op.lhs);
7370 const llvm_elem_ty = try o.lowerPtrElemTy(ptr_ty.childType(mod));7727 const llvm_elem_ty = try o.lowerPtrElemTy(ptr_ty.childType(mod));
7371 switch (ptr_ty.ptrSize(mod)) {7728 switch (ptr_ty.ptrSize(mod)) {
7372 .One => {7729 // It's a pointer to an array, so according to LLVM we need an extra GEP index.
7373 // 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, &.{
7374 const indices: [2]*llvm.Value = .{7731 try o.builder.intValue(try o.lowerType(Type.usize), 0), negative_offset,
7375 self.context.intType(32).constNull(), negative_offset,7732 }, ""),
7376 };7733 .C, .Many => return self.wip.gep(.inbounds, llvm_elem_ty, ptr, &.{negative_offset}, ""),
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 },
7383 .Slice => {7734 .Slice => {
7384 const base = self.builder.buildExtractValue(ptr, 0, "");7735 const base = try self.wip.extractValue(ptr, &.{0}, "");
7385 const indices: [1]*llvm.Value = .{negative_offset};7736 return self.wip.gep(.inbounds, llvm_elem_ty, base, &.{negative_offset}, "");
7386 return self.builder.buildInBoundsGEP(llvm_elem_ty, base, &indices, indices.len, "");
7387 },7737 },
7388 }7738 }
7389 }7739 }
...@@ -7393,7 +7743,7 @@ pub const FuncGen = struct {...@@ -7393,7 +7743,7 @@ pub const FuncGen = struct {
7393 inst: Air.Inst.Index,7743 inst: Air.Inst.Index,
7394 signed_intrinsic: []const u8,7744 signed_intrinsic: []const u8,
7395 unsigned_intrinsic: []const u8,7745 unsigned_intrinsic: []const u8,
7396 ) !?*llvm.Value {7746 ) !Builder.Value {
7397 const o = self.dg.object;7747 const o = self.dg.object;
7398 const mod = o.module;7748 const mod = o.module;
7399 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;7749 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -7408,81 +7758,123 @@ pub const FuncGen = struct {...@@ -7408,81 +7758,123 @@ pub const FuncGen = struct {
74087758
7409 const intrinsic_name = if (scalar_ty.isSignedInt(mod)) signed_intrinsic else unsigned_intrinsic;7759 const intrinsic_name = if (scalar_ty.isSignedInt(mod)) signed_intrinsic else unsigned_intrinsic;
74107760
7411 const llvm_lhs_ty = try o.lowerType(lhs_ty);
7412 const llvm_dest_ty = try o.lowerType(dest_ty);7761 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});7764 const llvm_fn = try 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, "");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, "");7783 const result = try self.wip.extractValue(result_struct, &.{0}, "");
7418 const overflow_bit = self.builder.buildExtractValue(result_struct, 1, "");7784 const overflow_bit = try self.wip.extractValue(result_struct, &.{1}, "");
74197785
7420 const result_index = llvmField(dest_ty, 0, mod).?.index;7786 const result_index = llvmField(dest_ty, 0, mod).?.index;
7421 const overflow_index = llvmField(dest_ty, 1, mod).?.index;7787 const overflow_index = llvmField(dest_ty, 1, mod).?.index;
74227788
7423 if (isByRef(dest_ty, mod)) {7789 if (isByRef(dest_ty, mod)) {
7424 const result_alignment = dest_ty.abiAlignment(mod);7790 const result_alignment = Builder.Alignment.fromByteUnits(dest_ty.abiAlignment(mod));
7425 const alloca_inst = self.buildAlloca(llvm_dest_ty, result_alignment);7791 const alloca_inst = try self.buildAlloca(llvm_dest_ty, result_alignment);
7426 {7792 {
7427 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, "");7793 const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, result_index, "");
7428 const store_inst = self.builder.buildStore(result, field_ptr);7794 _ = try self.wip.store(.normal, result, field_ptr, result_alignment);
7429 store_inst.setAlignment(result_alignment);
7430 }7795 }
7431 {7796 {
7432 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, overflow_index, "");7797 const overflow_alignment = comptime Builder.Alignment.fromByteUnits(1);
7433 const store_inst = self.builder.buildStore(overflow_bit, field_ptr);7798 const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, overflow_index, "");
7434 store_inst.setAlignment(1);7799 _ = try self.wip.store(.normal, overflow_bit, field_ptr, overflow_alignment);
7435 }7800 }
74367801
7437 return alloca_inst;7802 return alloca_inst;
7438 }7803 }
74397804
7440 const partial = self.builder.buildInsertValue(llvm_dest_ty.getUndef(), result, result_index, "");7805 var fields: [2]Builder.Value = undefined;
7441 return self.builder.buildInsertValue(partial, overflow_bit, overflow_index, "");7806 fields[result_index] = result;
7807 fields[overflow_index] = overflow_bit;
7808 return self.wip.buildAggregate(llvm_dest_ty, &fields, "");
7442 }7809 }
74437810
7444 fn buildElementwiseCall(7811 fn buildElementwiseCall(
7445 self: *FuncGen,7812 self: *FuncGen,
7446 llvm_fn: *llvm.Value,7813 llvm_fn: Builder.Function.Index,
7447 args_vectors: []const *llvm.Value,7814 args_vectors: []const Builder.Value,
7448 result_vector: *llvm.Value,7815 result_vector: Builder.Value,
7449 vector_len: usize,7816 vector_len: usize,
7450 ) !*llvm.Value {7817 ) !Builder.Value {
7451 const args_len = @as(c_uint, @intCast(args_vectors.len));7818 const o = self.dg.object;
7452 const llvm_i32 = self.context.intType(32);7819 assert(args_vectors.len <= 3);
7453 assert(args_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
7455 var i: usize = 0;7824 var i: usize = 0;
7456 var result = result_vector;7825 var result = result_vector;
7457 while (i < vector_len) : (i += 1) {7826 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
7460 var args: [3]*llvm.Value = undefined;7829 var args: [3]*llvm.Value = undefined;
7461 for (args_vectors, 0..) |arg_vector, k| {7830 for (args[0..args_vectors.len], args_vectors) |*arg_elem, arg_vector| {
7462 args[k] = self.builder.buildExtractElement(arg_vector, index_i32, "");7831 arg_elem.* = (try self.wip.extractElement(arg_vector, index_i32, "")).toLlvm(&self.wip);
7463 }7832 }
7464 const result_elem = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args_len, .C, .Auto, "");7833 const result_elem = (try self.wip.unimplemented(llvm_scalar_ty, "")).finish(
7465 result = self.builder.buildInsertElement(result, result_elem, index_i32, "");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, "");
7466 }7846 }
7467 return result;7847 return result;
7468 }7848 }
74697849
7470 fn getLibcFunction(7850 fn getLibcFunction(
7471 self: *FuncGen,7851 self: *FuncGen,
7472 fn_name: [:0]const u8,7852 fn_name: Builder.String,
7473 param_types: []const *llvm.Type,7853 param_types: []const Builder.Type,
7474 return_type: *llvm.Type,7854 return_type: Builder.Type,
7475 ) *llvm.Value {7855 ) Allocator.Error!Builder.Function.Index {
7476 const o = self.dg.object;7856 const o = self.dg.object;
7477 return o.llvm_module.getNamedFunction(fn_name.ptr) orelse b: {7857 if (o.builder.getGlobal(fn_name)) |global| return switch (global.ptrConst(&o.builder).kind) {
7478 const alias = o.llvm_module.getNamedGlobalAlias(fn_name.ptr, fn_name.len);7858 .alias => |alias| alias.getAliasee(&o.builder).ptrConst(&o.builder).kind.function,
7479 break :b if (alias) |a| a.getAliasee() else null;7859 .function => |function| function,
7480 } orelse b: {7860 else => unreachable,
7481 const params_len = @as(c_uint, @intCast(param_types.len));7861 };
7482 const fn_type = llvm.functionType(return_type, param_types.ptr, params_len, .False);7862
7483 const f = o.llvm_module.addFunction(fn_name, fn_type);7863 const fn_type = try o.builder.fnType(return_type, param_types, .normal);
7484 break :b f;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()),
7485 };7872 };
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;
7486 }7878 }
74877879
7488 /// Creates a floating point comparison by lowering to the appropriate7880 /// Creates a floating point comparison by lowering to the appropriate
...@@ -7491,8 +7883,8 @@ pub const FuncGen = struct {...@@ -7491,8 +7883,8 @@ pub const FuncGen = struct {
7491 self: *FuncGen,7883 self: *FuncGen,
7492 pred: math.CompareOperator,7884 pred: math.CompareOperator,
7493 ty: Type,7885 ty: Type,
7494 params: [2]*llvm.Value,7886 params: [2]Builder.Value,
7495 ) !*llvm.Value {7887 ) !Builder.Value {
7496 const o = self.dg.object;7888 const o = self.dg.object;
7497 const mod = o.module;7889 const mod = o.module;
7498 const target = o.module.getTarget();7890 const target = o.module.getTarget();
...@@ -7500,20 +7892,19 @@ pub const FuncGen = struct {...@@ -7500,20 +7892,19 @@ pub const FuncGen = struct {
7500 const scalar_llvm_ty = try o.lowerType(scalar_ty);7892 const scalar_llvm_ty = try o.lowerType(scalar_ty);
75017893
7502 if (intrinsicsAllowed(scalar_ty, target)) {7894 if (intrinsicsAllowed(scalar_ty, target)) {
7503 const llvm_predicate: llvm.RealPredicate = switch (pred) {7895 const cond: Builder.FloatCondition = switch (pred) {
7504 .eq => .OEQ,7896 .eq => .oeq,
7505 .neq => .UNE,7897 .neq => .une,
7506 .lt => .OLT,7898 .lt => .olt,
7507 .lte => .OLE,7899 .lte => .ole,
7508 .gt => .OGT,7900 .gt => .ogt,
7509 .gte => .OGE,7901 .gte => .oge,
7510 };7902 };
7511 return self.builder.buildFCmp(llvm_predicate, params[0], params[1], "");7903 return self.wip.fcmp(cond, params[0], params[1], "");
7512 }7904 }
75137905
7514 const float_bits = scalar_ty.floatBits(target);7906 const float_bits = scalar_ty.floatBits(target);
7515 const compiler_rt_float_abbrev = compilerRtFloatAbbrev(float_bits);7907 const compiler_rt_float_abbrev = compilerRtFloatAbbrev(float_bits);
7516 var fn_name_buf: [64]u8 = undefined;
7517 const fn_base_name = switch (pred) {7908 const fn_base_name = switch (pred) {
7518 .neq => "ne",7909 .neq => "ne",
7519 .eq => "eq",7910 .eq => "eq",
...@@ -7522,37 +7913,50 @@ pub const FuncGen = struct {...@@ -7522,37 +7913,50 @@ pub const FuncGen = struct {
7522 .gt => "gt",7913 .gt => "gt",
7523 .gte => "ge",7914 .gte => "ge",
7524 };7915 };
7525 const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__{s}{s}f2", .{7916 const fn_name = try o.builder.fmt("__{s}{s}f2", .{ fn_base_name, compiler_rt_float_abbrev });
7526 fn_base_name, compiler_rt_float_abbrev,7917
7527 }) catch unreachable;7918 const libc_fn = try self.getLibcFunction(
75287919 fn_name,
7529 const param_types = [2]*llvm.Type{ scalar_llvm_ty, scalar_llvm_ty };7920 ([1]Builder.Type{scalar_llvm_ty} ** 2)[0..],
7530 const llvm_i32 = self.context.intType(32);7921 .i32,
7531 const libc_fn = self.getLibcFunction(fn_name, param_types[0..], llvm_i32);7922 );
75327923
7533 const zero = llvm_i32.constInt(0, .False);7924 const zero = try o.builder.intConst(.i32, 0);
7534 const int_pred: llvm.IntPredicate = switch (pred) {7925 const int_cond: Builder.IntegerCondition = switch (pred) {
7535 .eq => .EQ,7926 .eq => .eq,
7536 .neq => .NE,7927 .neq => .ne,
7537 .lt => .SLT,7928 .lt => .slt,
7538 .lte => .SLE,7929 .lte => .sle,
7539 .gt => .SGT,7930 .gt => .sgt,
7540 .gte => .SGE,7931 .gte => .sge,
7541 };7932 };
75427933
7543 if (ty.zigTypeTag(mod) == .Vector) {7934 if (ty.zigTypeTag(mod) == .Vector) {
7544 const vec_len = ty.vectorLen(mod);7935 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();7938 const init = try o.builder.poisonValue(vector_result_ty);
7548 result = try self.buildElementwiseCall(libc_fn, &params, result, vec_len);7939 const result = try self.buildElementwiseCall(libc_fn, &params, init, vec_len);
75497940
7550 const zero_vector = self.builder.buildVectorSplat(vec_len, zero, "");7941 const zero_vector = try o.builder.splatValue(vector_result_ty, zero);
7551 return self.builder.buildICmp(int_pred, result, zero_vector, "");7942 return self.wip.icmp(int_cond, result, zero_vector, "");
7552 }7943 }
75537944
7554 const result = self.builder.buildCall(libc_fn.globalGetValueType(), libc_fn, &params, params.len, .C, .Auto, "");7945 const llvm_fn_ty = libc_fn.typeOf(&o.builder);
7555 return self.builder.buildICmp(int_pred, result, zero, "");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(), "");
7556 }7960 }
75577961
7558 const FloatOp = enum {7962 const FloatOp = enum {
...@@ -7583,7 +7987,7 @@ pub const FuncGen = struct {...@@ -7583,7 +7987,7 @@ pub const FuncGen = struct {
75837987
7584 const FloatOpStrat = union(enum) {7988 const FloatOpStrat = union(enum) {
7585 intrinsic: []const u8,7989 intrinsic: []const u8,
7586 libc: [:0]const u8,7990 libc: Builder.String,
7587 };7991 };
75887992
7589 /// Creates a floating point operation (add, sub, fma, sqrt, exp, etc.)7993 /// Creates a floating point operation (add, sub, fma, sqrt, exp, etc.)
...@@ -7594,27 +7998,25 @@ pub const FuncGen = struct {...@@ -7594,27 +7998,25 @@ pub const FuncGen = struct {
7594 comptime op: FloatOp,7998 comptime op: FloatOp,
7595 ty: Type,7999 ty: Type,
7596 comptime params_len: usize,8000 comptime params_len: usize,
7597 params: [params_len]*llvm.Value,8001 params: [params_len]Builder.Value,
7598 ) !*llvm.Value {8002 ) !Builder.Value {
7599 const o = self.dg.object;8003 const o = self.dg.object;
7600 const mod = o.module;8004 const mod = o.module;
7601 const target = mod.getTarget();8005 const target = mod.getTarget();
7602 const scalar_ty = ty.scalarType(mod);8006 const scalar_ty = ty.scalarType(mod);
7603 const llvm_ty = try o.lowerType(ty);8007 const llvm_ty = try o.lowerType(ty);
7604 const scalar_llvm_ty = try o.lowerType(scalar_ty);
76058008
7606 const intrinsics_allowed = op != .tan and intrinsicsAllowed(scalar_ty, target);8009 const intrinsics_allowed = op != .tan and intrinsicsAllowed(scalar_ty, target);
7607 var fn_name_buf: [64]u8 = undefined;
7608 const strat: FloatOpStrat = if (intrinsics_allowed) switch (op) {8010 const strat: FloatOpStrat = if (intrinsics_allowed) switch (op) {
7609 // Some operations are dedicated LLVM instructions, not available as intrinsics8011 // Some operations are dedicated LLVM instructions, not available as intrinsics
7610 .neg => return self.builder.buildFNeg(params[0], ""),8012 .neg => return self.wip.un(.fneg, params[0], ""),
7611 .add => return self.builder.buildFAdd(params[0], params[1], ""),8013 .add => return self.wip.bin(.fadd, params[0], params[1], ""),
7612 .sub => return self.builder.buildFSub(params[0], params[1], ""),8014 .sub => return self.wip.bin(.fsub, params[0], params[1], ""),
7613 .mul => return self.builder.buildFMul(params[0], params[1], ""),8015 .mul => return self.wip.bin(.fmul, params[0], params[1], ""),
7614 .div => return self.builder.buildFDiv(params[0], params[1], ""),8016 .div => return self.wip.bin(.fdiv, params[0], params[1], ""),
7615 .fmod => return self.builder.buildFRem(params[0], params[1], ""),8017 .fmod => return self.wip.bin(.frem, params[0], params[1], ""),
7616 .fmax => return self.builder.buildMaxNum(params[0], params[1], ""),8018 .fmax => return self.wip.bin(.@"llvm.maxnum.", params[0], params[1], ""),
7617 .fmin => return self.builder.buildMinNum(params[0], params[1], ""),8019 .fmin => return self.wip.bin(.@"llvm.minnum.", params[0], params[1], ""),
7618 else => .{ .intrinsic = "llvm." ++ @tagName(op) },8020 else => .{ .intrinsic = "llvm." ++ @tagName(op) },
7619 } else b: {8021 } else b: {
7620 const float_bits = scalar_ty.floatBits(target);8022 const float_bits = scalar_ty.floatBits(target);
...@@ -7622,26 +8024,19 @@ pub const FuncGen = struct {...@@ -7622,26 +8024,19 @@ pub const FuncGen = struct {
7622 .neg => {8024 .neg => {
7623 // In this case we can generate a softfloat negation by XORing the8025 // In this case we can generate a softfloat negation by XORing the
7624 // bits with a constant.8026 // bits with a constant.
7625 const int_llvm_ty = self.context.intType(float_bits);8027 const int_ty = try o.builder.intType(@intCast(float_bits));
7626 const one = int_llvm_ty.constInt(1, .False);8028 const cast_ty = try llvm_ty.changeScalar(int_ty, &o.builder);
7627 const shift_amt = int_llvm_ty.constInt(float_bits - 1, .False);8029 const sign_mask = try o.builder.splatValue(
7628 const sign_mask = one.constShl(shift_amt);8030 cast_ty,
7629 const result = if (ty.zigTypeTag(mod) == .Vector) blk: {8031 try o.builder.intConst(int_ty, @as(u128, 1) << @intCast(float_bits - 1)),
7630 const splat_sign_mask = self.builder.buildVectorSplat(ty.vectorLen(mod), sign_mask, "");8032 );
7631 const cast_ty = int_llvm_ty.vectorType(ty.vectorLen(mod));8033 const bitcasted_operand = try self.wip.cast(.bitcast, params[0], cast_ty, "");
7632 const bitcasted_operand = self.builder.buildBitCast(params[0], cast_ty, "");8034 const result = try self.wip.bin(.xor, bitcasted_operand, sign_mask, "");
7633 break :blk self.builder.buildXor(bitcasted_operand, splat_sign_mask, "");8035 return self.wip.cast(.bitcast, result, llvm_ty, "");
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,
7644 },8036 },
8037 .add, .sub, .div, .mul => .{ .libc = try o.builder.fmt("__{s}{s}f3", .{
8038 @tagName(op), compilerRtFloatAbbrev(float_bits),
8039 }) },
7645 .ceil,8040 .ceil,
7646 .cos,8041 .cos,
7647 .exp,8042 .exp,
...@@ -7660,31 +8055,48 @@ pub const FuncGen = struct {...@@ -7660,31 +8055,48 @@ pub const FuncGen = struct {
7660 .sqrt,8055 .sqrt,
7661 .tan,8056 .tan,
7662 .trunc,8057 .trunc,
7663 => FloatOpStrat{8058 => .{ .libc = try o.builder.fmt("{s}{s}{s}", .{
7664 .libc = std.fmt.bufPrintZ(&fn_name_buf, "{s}{s}{s}", .{8059 libcFloatPrefix(float_bits), @tagName(op), libcFloatSuffix(float_bits),
7665 libcFloatPrefix(float_bits), @tagName(op), libcFloatSuffix(float_bits),8060 }) },
7666 }) catch unreachable,
7667 },
7668 };8061 };
7669 };8062 };
76708063
7671 const llvm_fn: *llvm.Value = switch (strat) {8064 const llvm_fn = switch (strat) {
7672 .intrinsic => |fn_name| self.getIntrinsic(fn_name, &.{llvm_ty}),8065 .intrinsic => |fn_name| try self.getIntrinsic(fn_name, &.{llvm_ty}),
7673 .libc => |fn_name| b: {8066 .libc => |fn_name| b: {
7674 const param_types = [3]*llvm.Type{ scalar_llvm_ty, scalar_llvm_ty, scalar_llvm_ty };8067 const scalar_llvm_ty = llvm_ty.scalarType(&o.builder);
7675 const libc_fn = self.getLibcFunction(fn_name, param_types[0..params.len], scalar_llvm_ty);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 );
7676 if (ty.zigTypeTag(mod) == .Vector) {8073 if (ty.zigTypeTag(mod) == .Vector) {
7677 const result = llvm_ty.getUndef();8074 const result = try o.builder.poisonValue(llvm_ty);
7678 return self.buildElementwiseCall(libc_fn, &params, result, ty.vectorLen(mod));8075 return self.buildElementwiseCall(libc_fn, &params, result, ty.vectorLen(mod));
7679 }8076 }
76808077
7681 break :b libc_fn;8078 break :b libc_fn.toLlvm(&o.builder);
7682 },8079 },
7683 };8080 };
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);
7685 }8097 }
76868098
7687 fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8099 fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7688 const pl_op = self.air.instructions.items(.data)[inst].pl_op;8100 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
7689 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;8101 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
76908102
...@@ -7696,7 +8108,7 @@ pub const FuncGen = struct {...@@ -7696,7 +8108,7 @@ pub const FuncGen = struct {
7696 return self.buildFloatOp(.fma, ty, 3, .{ mulend1, mulend2, addend });8108 return self.buildFloatOp(.fma, ty, 3, .{ mulend1, mulend2, addend });
7697 }8109 }
76988110
7699 fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8111 fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7700 const o = self.dg.object;8112 const o = self.dg.object;
7701 const mod = o.module;8113 const mod = o.module;
7702 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;8114 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -7706,72 +8118,67 @@ pub const FuncGen = struct {...@@ -7706,72 +8118,67 @@ pub const FuncGen = struct {
7706 const rhs = try self.resolveInst(extra.rhs);8118 const rhs = try self.resolveInst(extra.rhs);
77078119
7708 const lhs_ty = self.typeOf(extra.lhs);8120 const lhs_ty = self.typeOf(extra.lhs);
7709 const rhs_ty = self.typeOf(extra.rhs);
7710 const lhs_scalar_ty = lhs_ty.scalarType(mod);8121 const lhs_scalar_ty = lhs_ty.scalarType(mod);
7711 const rhs_scalar_ty = rhs_ty.scalarType(mod);
77128122
7713 const dest_ty = self.typeOfIndex(inst);8123 const dest_ty = self.typeOfIndex(inst);
7714 const llvm_dest_ty = try o.lowerType(dest_ty);8124 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))8126 const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty), "");
7717 self.builder.buildZExt(rhs, try o.lowerType(lhs_ty), "")
7718 else
7719 rhs;
77208127
7721 const result = self.builder.buildShl(lhs, casted_rhs, "");8128 const result = try self.wip.bin(.shl, lhs, casted_rhs, "");
7722 const reconstructed = if (lhs_scalar_ty.isSignedInt(mod))8129 const reconstructed = try self.wip.bin(if (lhs_scalar_ty.isSignedInt(mod))
7723 self.builder.buildAShr(result, casted_rhs, "")8130 .ashr
7724 else8131 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
7729 const result_index = llvmField(dest_ty, 0, mod).?.index;8136 const result_index = llvmField(dest_ty, 0, mod).?.index;
7730 const overflow_index = llvmField(dest_ty, 1, mod).?.index;8137 const overflow_index = llvmField(dest_ty, 1, mod).?.index;
77318138
7732 if (isByRef(dest_ty, mod)) {8139 if (isByRef(dest_ty, mod)) {
7733 const result_alignment = dest_ty.abiAlignment(mod);8140 const result_alignment = Builder.Alignment.fromByteUnits(dest_ty.abiAlignment(mod));
7734 const alloca_inst = self.buildAlloca(llvm_dest_ty, result_alignment);8141 const alloca_inst = try self.buildAlloca(llvm_dest_ty, result_alignment);
7735 {8142 {
7736 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, "");8143 const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, result_index, "");
7737 const store_inst = self.builder.buildStore(result, field_ptr);8144 _ = try self.wip.store(.normal, result, field_ptr, result_alignment);
7738 store_inst.setAlignment(result_alignment);
7739 }8145 }
7740 {8146 {
7741 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, overflow_index, "");8147 const field_alignment = comptime Builder.Alignment.fromByteUnits(1);
7742 const store_inst = self.builder.buildStore(overflow_bit, field_ptr);8148 const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, overflow_index, "");
7743 store_inst.setAlignment(1);8149 _ = try self.wip.store(.normal, overflow_bit, field_ptr, field_alignment);
7744 }8150 }
7745
7746 return alloca_inst;8151 return alloca_inst;
7747 }8152 }
77488153
7749 const partial = self.builder.buildInsertValue(llvm_dest_ty.getUndef(), result, result_index, "");8154 var fields: [2]Builder.Value = undefined;
7750 return self.builder.buildInsertValue(partial, overflow_bit, overflow_index, "");8155 fields[result_index] = result;
8156 fields[overflow_index] = overflow_bit;
8157 return self.wip.buildAggregate(llvm_dest_ty, &fields, "");
7751 }8158 }
77528159
7753 fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8160 fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7754 const bin_op = self.air.instructions.items(.data)[inst].bin_op;8161 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
7755 const lhs = try self.resolveInst(bin_op.lhs);8162 const lhs = try self.resolveInst(bin_op.lhs);
7756 const rhs = try self.resolveInst(bin_op.rhs);8163 const rhs = try self.resolveInst(bin_op.rhs);
7757 return self.builder.buildAnd(lhs, rhs, "");8164 return self.wip.bin(.@"and", lhs, rhs, "");
7758 }8165 }
77598166
7760 fn airOr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8167 fn airOr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7761 const bin_op = self.air.instructions.items(.data)[inst].bin_op;8168 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
7762 const lhs = try self.resolveInst(bin_op.lhs);8169 const lhs = try self.resolveInst(bin_op.lhs);
7763 const rhs = try self.resolveInst(bin_op.rhs);8170 const rhs = try self.resolveInst(bin_op.rhs);
7764 return self.builder.buildOr(lhs, rhs, "");8171 return self.wip.bin(.@"or", lhs, rhs, "");
7765 }8172 }
77668173
7767 fn airXor(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8174 fn airXor(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7768 const bin_op = self.air.instructions.items(.data)[inst].bin_op;8175 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
7769 const lhs = try self.resolveInst(bin_op.lhs);8176 const lhs = try self.resolveInst(bin_op.lhs);
7770 const rhs = try self.resolveInst(bin_op.rhs);8177 const rhs = try self.resolveInst(bin_op.rhs);
7771 return self.builder.buildXor(lhs, rhs, "");8178 return self.wip.bin(.xor, lhs, rhs, "");
7772 }8179 }
77738180
7774 fn airShlExact(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8181 fn airShlExact(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7775 const o = self.dg.object;8182 const o = self.dg.object;
7776 const mod = o.module;8183 const mod = o.module;
7777 const bin_op = self.air.instructions.items(.data)[inst].bin_op;8184 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -7780,39 +8187,29 @@ pub const FuncGen = struct {...@@ -7780,39 +8187,29 @@ pub const FuncGen = struct {
7780 const rhs = try self.resolveInst(bin_op.rhs);8187 const rhs = try self.resolveInst(bin_op.rhs);
77818188
7782 const lhs_ty = self.typeOf(bin_op.lhs);8189 const lhs_ty = self.typeOf(bin_op.lhs);
7783 const rhs_ty = self.typeOf(bin_op.rhs);
7784 const lhs_scalar_ty = lhs_ty.scalarType(mod);8190 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))8192 const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty), "");
7788 self.builder.buildZExt(rhs, try o.lowerType(lhs_ty), "")8193 return self.wip.bin(if (lhs_scalar_ty.isSignedInt(mod))
8194 .@"shl nsw"
7789 else8195 else
7790 rhs;8196 .@"shl nuw", lhs, casted_rhs, "");
7791 if (lhs_scalar_ty.isSignedInt(mod)) return self.builder.buildNSWShl(lhs, casted_rhs, "");
7792 return self.builder.buildNUWShl(lhs, casted_rhs, "");
7793 }8197 }
77948198
7795 fn airShl(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8199 fn airShl(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7796 const o = self.dg.object;8200 const o = self.dg.object;
7797 const mod = o.module;
7798 const bin_op = self.air.instructions.items(.data)[inst].bin_op;8201 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
77998202
7800 const lhs = try self.resolveInst(bin_op.lhs);8203 const lhs = try self.resolveInst(bin_op.lhs);
7801 const rhs = try self.resolveInst(bin_op.rhs);8204 const rhs = try self.resolveInst(bin_op.rhs);
78028205
7803 const lhs_type = self.typeOf(bin_op.lhs);8206 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))8208 const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_type), "");
7809 self.builder.buildZExt(rhs, try o.lowerType(lhs_type), "")8209 return self.wip.bin(.shl, lhs, casted_rhs, "");
7810 else
7811 rhs;
7812 return self.builder.buildShl(lhs, casted_rhs, "");
7813 }8210 }
78148211
7815 fn airShlSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8212 fn airShlSat(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7816 const o = self.dg.object;8213 const o = self.dg.object;
7817 const mod = o.module;8214 const mod = o.module;
7818 const bin_op = self.air.instructions.items(.data)[inst].bin_op;8215 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -7821,42 +8218,36 @@ pub const FuncGen = struct {...@@ -7821,42 +8218,36 @@ pub const FuncGen = struct {
7821 const rhs = try self.resolveInst(bin_op.rhs);8218 const rhs = try self.resolveInst(bin_op.rhs);
78228219
7823 const lhs_ty = self.typeOf(bin_op.lhs);8220 const lhs_ty = self.typeOf(bin_op.lhs);
7824 const rhs_ty = self.typeOf(bin_op.rhs);
7825 const lhs_scalar_ty = lhs_ty.scalarType(mod);8221 const lhs_scalar_ty = lhs_ty.scalarType(mod);
7826 const rhs_scalar_ty = rhs_ty.scalarType(mod);
7827 const lhs_bits = lhs_scalar_ty.bitSize(mod);8222 const lhs_bits = lhs_scalar_ty.bitSize(mod);
78288223
7829 const casted_rhs = if (rhs_scalar_ty.bitSize(mod) < lhs_bits)8224 const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty), "");
7830 self.builder.buildZExt(rhs, lhs.typeOf(), "")
7831 else
7832 rhs;
78338225
7834 const result = if (lhs_scalar_ty.isSignedInt(mod))8226 const result = try self.wip.bin(if (lhs_scalar_ty.isSignedInt(mod))
7835 self.builder.buildSShlSat(lhs, casted_rhs, "")8227 .@"llvm.sshl.sat."
7836 else8228 else
7837 self.builder.buildUShlSat(lhs, casted_rhs, "");8229 .@"llvm.ushl.sat.", lhs, casted_rhs, "");
78388230
7839 // LLVM langref says "If b is (statically or dynamically) equal to or8231 // LLVM langref says "If b is (statically or dynamically) equal to or
7840 // larger than the integer bit width of the arguments, the result is a8232 // larger than the integer bit width of the arguments, the result is a
7841 // poison value."8233 // poison value."
7842 // However Zig semantics says that saturating shift left can never produce8234 // However Zig semantics says that saturating shift left can never produce
7843 // undefined; instead it saturates.8235 // undefined; instead it saturates.
7844 const lhs_scalar_llvm_ty = try o.lowerType(lhs_scalar_ty);8236 const lhs_llvm_ty = try o.lowerType(lhs_ty);
7845 const bits = lhs_scalar_llvm_ty.constInt(lhs_bits, .False);8237 const lhs_scalar_llvm_ty = lhs_llvm_ty.scalarType(&o.builder);
7846 const lhs_max = lhs_scalar_llvm_ty.constAllOnes();8238 const bits = try o.builder.splatValue(
7847 if (rhs_ty.zigTypeTag(mod) == .Vector) {8239 lhs_llvm_ty,
7848 const vec_len = rhs_ty.vectorLen(mod);8240 try o.builder.intConst(lhs_scalar_llvm_ty, lhs_bits),
7849 const bits_vec = self.builder.buildVectorSplat(vec_len, bits, "");8241 );
7850 const lhs_max_vec = self.builder.buildVectorSplat(vec_len, lhs_max, "");8242 const lhs_max = try o.builder.splatValue(
7851 const in_range = self.builder.buildICmp(.ULT, rhs, bits_vec, "");8243 lhs_llvm_ty,
7852 return self.builder.buildSelect(in_range, result, lhs_max_vec, "");8244 try o.builder.intConst(lhs_scalar_llvm_ty, -1),
7853 } else {8245 );
7854 const in_range = self.builder.buildICmp(.ULT, rhs, bits, "");8246 const in_range = try self.wip.icmp(.ult, rhs, bits, "");
7855 return self.builder.buildSelect(in_range, result, lhs_max, "");8247 return self.wip.select(in_range, result, lhs_max, "");
7856 }
7857 }8248 }
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 {
7860 const o = self.dg.object;8251 const o = self.dg.object;
7861 const mod = o.module;8252 const mod = o.module;
7862 const bin_op = self.air.instructions.items(.data)[inst].bin_op;8253 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -7865,63 +8256,41 @@ pub const FuncGen = struct {...@@ -7865,63 +8256,41 @@ pub const FuncGen = struct {
7865 const rhs = try self.resolveInst(bin_op.rhs);8256 const rhs = try self.resolveInst(bin_op.rhs);
78668257
7867 const lhs_ty = self.typeOf(bin_op.lhs);8258 const lhs_ty = self.typeOf(bin_op.lhs);
7868 const rhs_ty = self.typeOf(bin_op.rhs);
7869 const lhs_scalar_ty = lhs_ty.scalarType(mod);8259 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))8261 const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty), "");
7873 self.builder.buildZExt(rhs, try o.lowerType(lhs_ty), "")
7874 else
7875 rhs;
7876 const is_signed_int = lhs_scalar_ty.isSignedInt(mod);8262 const is_signed_int = lhs_scalar_ty.isSignedInt(mod);
78778263
7878 if (is_exact) {8264 return self.wip.bin(if (is_exact)
7879 if (is_signed_int) {8265 if (is_signed_int) .@"ashr exact" else .@"lshr exact"
7880 return self.builder.buildAShrExact(lhs, casted_rhs, "");8266 else if (is_signed_int) .ashr else .lshr, 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 }
7891 }8267 }
78928268
7893 fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8269 fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7894 const o = self.dg.object;8270 const o = self.dg.object;
7895 const mod = o.module;8271 const mod = o.module;
7896 const ty_op = self.air.instructions.items(.data)[inst].ty_op;8272 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
7897 const dest_ty = self.typeOfIndex(inst);8273 const dest_ty = self.typeOfIndex(inst);
7898 const dest_info = dest_ty.intInfo(mod);
7899 const dest_llvm_ty = try o.lowerType(dest_ty);8274 const dest_llvm_ty = try o.lowerType(dest_ty);
7900 const operand = try self.resolveInst(ty_op.operand);8275 const operand = try self.resolveInst(ty_op.operand);
7901 const operand_ty = self.typeOf(ty_op.operand);8276 const operand_ty = self.typeOf(ty_op.operand);
7902 const operand_info = operand_ty.intInfo(mod);8277 const operand_info = operand_ty.intInfo(mod);
79038278
7904 if (operand_info.bits < dest_info.bits) {8279 return self.wip.conv(switch (operand_info.signedness) {
7905 switch (operand_info.signedness) {8280 .signed => .signed,
7906 .signed => return self.builder.buildSExt(operand, dest_llvm_ty, ""),8281 .unsigned => .unsigned,
7907 .unsigned => return self.builder.buildZExt(operand, dest_llvm_ty, ""),8282 }, 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 }
7914 }8283 }
79158284
7916 fn airTrunc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8285 fn airTrunc(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7917 const o = self.dg.object;8286 const o = self.dg.object;
7918 const ty_op = self.air.instructions.items(.data)[inst].ty_op;8287 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
7919 const operand = try self.resolveInst(ty_op.operand);8288 const operand = try self.resolveInst(ty_op.operand);
7920 const dest_llvm_ty = try o.lowerType(self.typeOfIndex(inst));8289 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, "");
7922 }8291 }
79238292
7924 fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8293 fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7925 const o = self.dg.object;8294 const o = self.dg.object;
7926 const mod = o.module;8295 const mod = o.module;
7927 const ty_op = self.air.instructions.items(.data)[inst].ty_op;8296 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -7933,26 +8302,30 @@ pub const FuncGen = struct {...@@ -7933,26 +8302,30 @@ pub const FuncGen = struct {
7933 const src_bits = operand_ty.floatBits(target);8302 const src_bits = operand_ty.floatBits(target);
79348303
7935 if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) {8304 if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) {
7936 const dest_llvm_ty = try o.lowerType(dest_ty);8305 return self.wip.cast(.fptrunc, operand, try o.lowerType(dest_ty), "");
7937 return self.builder.buildFPTrunc(operand, dest_llvm_ty, "");
7938 } else {8306 } else {
7939 const operand_llvm_ty = try o.lowerType(operand_ty);8307 const operand_llvm_ty = try o.lowerType(operand_ty);
7940 const dest_llvm_ty = try o.lowerType(dest_ty);8308 const dest_llvm_ty = try o.lowerType(dest_ty);
79418309
7942 var fn_name_buf: [64]u8 = undefined;8310 const fn_name = try o.builder.fmt("__trunc{s}f{s}f2", .{
7943 const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__trunc{s}f{s}f2", .{
7944 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),8311 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
7945 }) catch unreachable;8312 });
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);
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);
7952 }8325 }
7953 }8326 }
79548327
7955 fn airFpext(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8328 fn airFpext(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7956 const o = self.dg.object;8329 const o = self.dg.object;
7957 const mod = o.module;8330 const mod = o.module;
7958 const ty_op = self.air.instructions.items(.data)[inst].ty_op;8331 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -7964,36 +8337,40 @@ pub const FuncGen = struct {...@@ -7964,36 +8337,40 @@ pub const FuncGen = struct {
7964 const src_bits = operand_ty.floatBits(target);8337 const src_bits = operand_ty.floatBits(target);
79658338
7966 if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) {8339 if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) {
7967 const dest_llvm_ty = try o.lowerType(dest_ty);8340 return self.wip.cast(.fpext, operand, try o.lowerType(dest_ty), "");
7968 return self.builder.buildFPExt(operand, dest_llvm_ty, "");
7969 } else {8341 } else {
7970 const operand_llvm_ty = try o.lowerType(operand_ty);8342 const operand_llvm_ty = try o.lowerType(operand_ty);
7971 const dest_llvm_ty = try o.lowerType(dest_ty);8343 const dest_llvm_ty = try o.lowerType(dest_ty);
79728344
7973 var fn_name_buf: [64]u8 = undefined;8345 const fn_name = try o.builder.fmt("__extend{s}f{s}f2", .{
7974 const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__extend{s}f{s}f2", .{
7975 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),8346 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
7976 }) catch unreachable;8347 });
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);
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);
7983 }8360 }
7984 }8361 }
79858362
7986 fn airIntFromPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8363 fn airIntFromPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7987 const o = self.dg.object;8364 const o = self.dg.object;
7988 const un_op = self.air.instructions.items(.data)[inst].un_op;8365 const un_op = self.air.instructions.items(.data)[inst].un_op;
7989 const operand = try self.resolveInst(un_op);8366 const operand = try self.resolveInst(un_op);
7990 const ptr_ty = self.typeOf(un_op);8367 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);
7992 const dest_llvm_ty = try o.lowerType(self.typeOfIndex(inst));8369 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, "");
7994 }8371 }
79958372
7996 fn airBitCast(self: *FuncGen, inst: Air.Inst.Index) !*llvm.Value {8373 fn airBitCast(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7997 const ty_op = self.air.instructions.items(.data)[inst].ty_op;8374 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
7998 const operand_ty = self.typeOf(ty_op.operand);8375 const operand_ty = self.typeOf(ty_op.operand);
7999 const inst_ty = self.typeOfIndex(inst);8376 const inst_ty = self.typeOfIndex(inst);
...@@ -8001,7 +8378,7 @@ pub const FuncGen = struct {...@@ -8001,7 +8378,7 @@ pub const FuncGen = struct {
8001 return self.bitCast(operand, operand_ty, inst_ty);8378 return self.bitCast(operand, operand_ty, inst_ty);
8002 }8379 }
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 {
8005 const o = self.dg.object;8382 const o = self.dg.object;
8006 const mod = o.module;8383 const mod = o.module;
8007 const operand_is_ref = isByRef(operand_ty, mod);8384 const operand_is_ref = isByRef(operand_ty, mod);
...@@ -8013,14 +8390,14 @@ pub const FuncGen = struct {...@@ -8013,14 +8390,14 @@ pub const FuncGen = struct {
8013 return operand;8390 return operand;
8014 }8391 }
80158392
8016 if (llvm_dest_ty.getTypeKind() == .Integer and8393 if (llvm_dest_ty.isInteger(&o.builder) and
8017 operand.typeOf().getTypeKind() == .Integer)8394 operand.typeOfWip(&self.wip).isInteger(&o.builder))
8018 {8395 {
8019 return self.builder.buildZExtOrBitCast(operand, llvm_dest_ty, "");8396 return self.wip.conv(.unsigned, operand, llvm_dest_ty, "");
8020 }8397 }
80218398
8022 if (operand_ty.zigTypeTag(mod) == .Int and inst_ty.isPtrAtRuntime(mod)) {8399 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, "");
8024 }8401 }
80258402
8026 if (operand_ty.zigTypeTag(mod) == .Vector and inst_ty.zigTypeTag(mod) == .Array) {8403 if (operand_ty.zigTypeTag(mod) == .Vector and inst_ty.zigTypeTag(mod) == .Array) {
...@@ -8028,104 +8405,97 @@ pub const FuncGen = struct {...@@ -8028,104 +8405,97 @@ pub const FuncGen = struct {
8028 if (!result_is_ref) {8405 if (!result_is_ref) {
8029 return self.dg.todo("implement bitcast vector to non-ref array", .{});8406 return self.dg.todo("implement bitcast vector to non-ref array", .{});
8030 }8407 }
8031 const array_ptr = self.buildAlloca(llvm_dest_ty, null);8408 const array_ptr = try self.buildAlloca(llvm_dest_ty, .default);
8032 const bitcast_ok = elem_ty.bitSize(mod) == elem_ty.abiSize(mod) * 8;8409 const bitcast_ok = elem_ty.bitSize(mod) == elem_ty.abiSize(mod) * 8;
8033 if (bitcast_ok) {8410 if (bitcast_ok) {
8034 const llvm_store = self.builder.buildStore(operand, array_ptr);8411 const alignment = Builder.Alignment.fromByteUnits(inst_ty.abiAlignment(mod));
8035 llvm_store.setAlignment(inst_ty.abiAlignment(mod));8412 _ = try self.wip.store(.normal, operand, array_ptr, alignment);
8036 } else {8413 } else {
8037 // If the ABI size of the element type is not evenly divisible by size in bits;8414 // If the ABI size of the element type is not evenly divisible by size in bits;
8038 // a simple bitcast will not work, and we fall back to extractelement.8415 // a simple bitcast will not work, and we fall back to extractelement.
8039 const llvm_usize = try o.lowerType(Type.usize);8416 const llvm_usize = try o.lowerType(Type.usize);
8040 const llvm_u32 = self.context.intType(32);8417 const usize_zero = try o.builder.intValue(llvm_usize, 0);
8041 const zero = llvm_usize.constNull();
8042 const vector_len = operand_ty.arrayLen(mod);8418 const vector_len = operand_ty.arrayLen(mod);
8043 var i: u64 = 0;8419 var i: u64 = 0;
8044 while (i < vector_len) : (i += 1) {8420 while (i < vector_len) : (i += 1) {
8045 const index_usize = llvm_usize.constInt(i, .False);8421 const elem_ptr = try self.wip.gep(.inbounds, llvm_dest_ty, array_ptr, &.{
8046 const index_u32 = llvm_u32.constInt(i, .False);8422 usize_zero, try o.builder.intValue(llvm_usize, i),
8047 const indexes: [2]*llvm.Value = .{ zero, index_usize };8423 }, "");
8048 const elem_ptr = self.builder.buildInBoundsGEP(llvm_dest_ty, array_ptr, &indexes, indexes.len, "");8424 const elem =
8049 const elem = self.builder.buildExtractElement(operand, index_u32, "");8425 try self.wip.extractElement(operand, try o.builder.intValue(.i32, i), "");
8050 _ = self.builder.buildStore(elem, elem_ptr);8426 _ = try self.wip.store(.normal, elem, elem_ptr, .default);
8051 }8427 }
8052 }8428 }
8053 return array_ptr;8429 return array_ptr;
8054 } else if (operand_ty.zigTypeTag(mod) == .Array and inst_ty.zigTypeTag(mod) == .Vector) {8430 } else if (operand_ty.zigTypeTag(mod) == .Array and inst_ty.zigTypeTag(mod) == .Vector) {
8055 const elem_ty = operand_ty.childType(mod);8431 const elem_ty = operand_ty.childType(mod);
8056 const llvm_vector_ty = try o.lowerType(inst_ty);8432 const llvm_vector_ty = try o.lowerType(inst_ty);
8057 if (!operand_is_ref) {8433 if (!operand_is_ref) return self.dg.todo("implement bitcast non-ref array to vector", .{});
8058 return self.dg.todo("implement bitcast non-ref array to vector", .{});
8059 }
80608434
8061 const bitcast_ok = elem_ty.bitSize(mod) == elem_ty.abiSize(mod) * 8;8435 const bitcast_ok = elem_ty.bitSize(mod) == elem_ty.abiSize(mod) * 8;
8062 if (bitcast_ok) {8436 if (bitcast_ok) {
8063 const vector = self.builder.buildLoad(llvm_vector_ty, operand, "");
8064 // The array is aligned to the element's alignment, while the vector might have a completely8437 // The array is aligned to the element's alignment, while the vector might have a completely
8065 // different alignment. This means we need to enforce the alignment of this load.8438 // different alignment. This means we need to enforce the alignment of this load.
8066 vector.setAlignment(elem_ty.abiAlignment(mod));8439 const alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
8067 return vector;8440 return self.wip.load(.normal, llvm_vector_ty, operand, alignment, "");
8068 } else {8441 } else {
8069 // If the ABI size of the element type is not evenly divisible by size in bits;8442 // If the ABI size of the element type is not evenly divisible by size in bits;
8070 // a simple bitcast will not work, and we fall back to extractelement.8443 // a simple bitcast will not work, and we fall back to extractelement.
8071 const array_llvm_ty = try o.lowerType(operand_ty);8444 const array_llvm_ty = try o.lowerType(operand_ty);
8072 const elem_llvm_ty = try o.lowerType(elem_ty);8445 const elem_llvm_ty = try o.lowerType(elem_ty);
8073 const llvm_usize = try o.lowerType(Type.usize);8446 const llvm_usize = try o.lowerType(Type.usize);
8074 const llvm_u32 = self.context.intType(32);8447 const usize_zero = try o.builder.intValue(llvm_usize, 0);
8075 const zero = llvm_usize.constNull();
8076 const vector_len = operand_ty.arrayLen(mod);8448 const vector_len = operand_ty.arrayLen(mod);
8077 var vector = llvm_vector_ty.getUndef();8449 var vector = try o.builder.poisonValue(llvm_vector_ty);
8078 var i: u64 = 0;8450 var i: u64 = 0;
8079 while (i < vector_len) : (i += 1) {8451 while (i < vector_len) : (i += 1) {
8080 const index_usize = llvm_usize.constInt(i, .False);8452 const elem_ptr = try self.wip.gep(.inbounds, array_llvm_ty, operand, &.{
8081 const index_u32 = llvm_u32.constInt(i, .False);8453 usize_zero, try o.builder.intValue(llvm_usize, i),
8082 const indexes: [2]*llvm.Value = .{ zero, index_usize };8454 }, "");
8083 const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, operand, &indexes, indexes.len, "");8455 const elem = try self.wip.load(.normal, elem_llvm_ty, elem_ptr, .default, "");
8084 const elem = self.builder.buildLoad(elem_llvm_ty, elem_ptr, "");8456 vector =
8085 vector = self.builder.buildInsertElement(vector, elem, index_u32, "");8457 try self.wip.insertElement(vector, elem, try o.builder.intValue(.i32, i), "");
8086 }8458 }
8087
8088 return vector;8459 return vector;
8089 }8460 }
8090 }8461 }
80918462
8092 if (operand_is_ref) {8463 if (operand_is_ref) {
8093 const load_inst = self.builder.buildLoad(llvm_dest_ty, operand, "");8464 const alignment = Builder.Alignment.fromByteUnits(operand_ty.abiAlignment(mod));
8094 load_inst.setAlignment(operand_ty.abiAlignment(mod));8465 return self.wip.load(.normal, llvm_dest_ty, operand, alignment, "");
8095 return load_inst;
8096 }8466 }
80978467
8098 if (result_is_ref) {8468 if (result_is_ref) {
8099 const alignment = @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod));8469 const alignment = Builder.Alignment.fromByteUnits(
8100 const result_ptr = self.buildAlloca(llvm_dest_ty, alignment);8470 @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod)),
8101 const store_inst = self.builder.buildStore(operand, result_ptr);8471 );
8102 store_inst.setAlignment(alignment);8472 const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment);
8473 _ = try self.wip.store(.normal, operand, result_ptr, alignment);
8103 return result_ptr;8474 return result_ptr;
8104 }8475 }
81058476
8106 if (llvm_dest_ty.getTypeKind() == .Struct) {8477 if (llvm_dest_ty.isStruct(&o.builder)) {
8107 // Both our operand and our result are values, not pointers,8478 // Both our operand and our result are values, not pointers,
8108 // but LLVM won't let us bitcast struct values.8479 // but LLVM won't let us bitcast struct values.
8109 // Therefore, we store operand to alloca, then load for result.8480 // Therefore, we store operand to alloca, then load for result.
8110 const alignment = @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod));8481 const alignment = Builder.Alignment.fromByteUnits(
8111 const result_ptr = self.buildAlloca(llvm_dest_ty, alignment);8482 @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod)),
8112 const store_inst = self.builder.buildStore(operand, result_ptr);8483 );
8113 store_inst.setAlignment(alignment);8484 const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment);
8114 const load_inst = self.builder.buildLoad(llvm_dest_ty, result_ptr, "");8485 _ = try self.wip.store(.normal, operand, result_ptr, alignment);
8115 load_inst.setAlignment(alignment);8486 return self.wip.load(.normal, llvm_dest_ty, result_ptr, alignment, "");
8116 return load_inst;
8117 }8487 }
81188488
8119 return self.builder.buildBitCast(operand, llvm_dest_ty, "");8489 return self.wip.cast(.bitcast, operand, llvm_dest_ty, "");
8120 }8490 }
81218491
8122 fn airIntFromBool(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8492 fn airIntFromBool(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8123 const un_op = self.air.instructions.items(.data)[inst].un_op;8493 const un_op = self.air.instructions.items(.data)[inst].un_op;
8124 const operand = try self.resolveInst(un_op);8494 const operand = try self.resolveInst(un_op);
8125 return operand;8495 return operand;
8126 }8496 }
81278497
8128 fn airArg(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8498 fn airArg(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8129 const o = self.dg.object;8499 const o = self.dg.object;
8130 const mod = o.module;8500 const mod = o.module;
8131 const arg_val = self.args[self.arg_index];8501 const arg_val = self.args[self.arg_index];
...@@ -8133,9 +8503,7 @@ pub const FuncGen = struct {...@@ -8133,9 +8503,7 @@ pub const FuncGen = struct {
81338503
8134 const inst_ty = self.typeOfIndex(inst);8504 const inst_ty = self.typeOfIndex(inst);
8135 if (o.di_builder) |dib| {8505 if (o.di_builder) |dib| {
8136 if (needDbgVarWorkaround(o)) {8506 if (needDbgVarWorkaround(o)) return arg_val;
8137 return arg_val;
8138 }
81398507
8140 const src_index = self.air.instructions.items(.data)[inst].arg.src_index;8508 const src_index = self.air.instructions.items(.data)[inst].arg.src_index;
8141 const func_index = self.dg.decl.getOwnedFunctionIndex();8509 const func_index = self.dg.decl.getOwnedFunctionIndex();
...@@ -8150,61 +8518,64 @@ pub const FuncGen = struct {...@@ -8150,61 +8518,64 @@ pub const FuncGen = struct {
8150 try o.lowerDebugType(inst_ty, .full),8518 try o.lowerDebugType(inst_ty, .full),
8151 true, // always preserve8519 true, // always preserve
8152 0, // flags8520 0, // flags
8153 self.arg_index, // includes +1 because 0 is return type8521 @intCast(self.arg_index), // includes +1 because 0 is return type
8154 );8522 );
81558523
8156 const debug_loc = llvm.getDebugLoc(lbrace_line, lbrace_col, self.di_scope.?, null);8524 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);
8158 if (isByRef(inst_ty, mod)) {8526 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);
8160 } else if (o.module.comp.bin_file.options.optimize_mode == .Debug) {8528 } else if (o.module.comp.bin_file.options.optimize_mode == .Debug) {
8161 const alignment = inst_ty.abiAlignment(mod);8529 const alignment = Builder.Alignment.fromByteUnits(inst_ty.abiAlignment(mod));
8162 const alloca = self.buildAlloca(arg_val.typeOf(), alignment);8530 const alloca = try self.buildAlloca(arg_val.typeOfWip(&self.wip), alignment);
8163 const store_inst = self.builder.buildStore(arg_val, alloca);8531 _ = try self.wip.store(.normal, arg_val, alloca, alignment);
8164 store_inst.setAlignment(alignment);8532 _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
8165 _ = dib.insertDeclareAtEnd(alloca, di_local_var, debug_loc, insert_block);
8166 } else {8533 } 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);
8168 }8535 }
8169 }8536 }
81708537
8171 return arg_val;8538 return arg_val;
8172 }8539 }
81738540
8174 fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8541 fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8175 const o = self.dg.object;8542 const o = self.dg.object;
8176 const mod = o.module;8543 const mod = o.module;
8177 const ptr_ty = self.typeOfIndex(inst);8544 const ptr_ty = self.typeOfIndex(inst);
8178 const pointee_type = ptr_ty.childType(mod);8545 const pointee_type = ptr_ty.childType(mod);
8179 if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime(mod))8546 if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime(mod))
8180 return o.lowerPtrToVoid(ptr_ty);8547 return (try o.lowerPtrToVoid(ptr_ty)).toValue();
81818548
8182 const pointee_llvm_ty = try o.lowerType(pointee_type);8549 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));
8184 return self.buildAlloca(pointee_llvm_ty, alignment);8551 return self.buildAlloca(pointee_llvm_ty, alignment);
8185 }8552 }
81868553
8187 fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8554 fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8188 const o = self.dg.object;8555 const o = self.dg.object;
8189 const mod = o.module;8556 const mod = o.module;
8190 const ptr_ty = self.typeOfIndex(inst);8557 const ptr_ty = self.typeOfIndex(inst);
8191 const ret_ty = ptr_ty.childType(mod);8558 const ret_ty = ptr_ty.childType(mod);
8192 if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return o.lowerPtrToVoid(ptr_ty);8559 if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod))
8193 if (self.ret_ptr) |ret_ptr| return ret_ptr;8560 return (try o.lowerPtrToVoid(ptr_ty)).toValue();
8561 if (self.ret_ptr != .none) return self.ret_ptr;
8194 const ret_llvm_ty = try o.lowerType(ret_ty);8562 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);
8196 }8565 }
81978566
8198 /// Use this instead of builder.buildAlloca, because this function makes sure to8567 /// Use this instead of builder.buildAlloca, because this function makes sure to
8199 /// put the alloca instruction at the top of the function!8568 /// put the alloca instruction at the top of the function!
8200 fn buildAlloca(self: *FuncGen, llvm_ty: *llvm.Type, alignment: ?c_uint) *llvm.Value {8569 fn buildAlloca(
8201 const o = self.dg.object;8570 self: *FuncGen,
8202 const mod = o.module;8571 llvm_ty: Builder.Type,
8203 const target = mod.getTarget();8572 alignment: Builder.Alignment,
8204 return buildAllocaInner(self.context, self.builder, self.llvm_func, self.di_scope != null, llvm_ty, alignment, target);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);
8205 }8576 }
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 {
8208 const o = self.dg.object;8579 const o = self.dg.object;
8209 const mod = o.module;8580 const mod = o.module;
8210 const bin_op = self.air.instructions.items(.data)[inst].bin_op;8581 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -8217,25 +8588,30 @@ pub const FuncGen = struct {...@@ -8217,25 +8588,30 @@ pub const FuncGen = struct {
8217 // Even if safety is disabled, we still emit a memset to undefined since it conveys8588 // Even if safety is disabled, we still emit a memset to undefined since it conveys
8218 // extra information to LLVM. However, safety makes the difference between using8589 // extra information to LLVM. However, safety makes the difference between using
8219 // 0xaa or actual undefined for the fill byte.8590 // 0xaa or actual undefined for the fill byte.
8220 const u8_llvm_ty = self.context.intType(8);
8221 const fill_byte = if (safety)8591 const fill_byte = if (safety)
8222 u8_llvm_ty.constInt(0xaa, .False)8592 try o.builder.intConst(.i8, 0xaa)
8223 else8593 else
8224 u8_llvm_ty.getUndef();8594 try o.builder.undefConst(.i8);
8225 const operand_size = operand_ty.abiSize(mod);8595 const operand_size = operand_ty.abiSize(mod);
8226 const usize_llvm_ty = try o.lowerType(Type.usize);8596 const usize_ty = try o.lowerType(Type.usize);
8227 const len = usize_llvm_ty.constInt(operand_size, .False);8597 const len = try o.builder.intValue(usize_ty, operand_size);
8228 const dest_ptr_align = ptr_ty.ptrAlignment(mod);8598 const dest_ptr_align = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
8229 _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, ptr_ty.isVolatilePtr(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);
8230 if (safety and mod.comp.bin_file.options.valgrind) {8606 if (safety and mod.comp.bin_file.options.valgrind) {
8231 self.valgrindMarkUndef(dest_ptr, len);8607 try self.valgrindMarkUndef(dest_ptr, len);
8232 }8608 }
8233 return null;8609 return .none;
8234 }8610 }
82358611
8236 const src_operand = try self.resolveInst(bin_op.rhs);8612 const src_operand = try self.resolveInst(bin_op.rhs);
8237 try self.store(dest_ptr, ptr_ty, src_operand, .NotAtomic);8613 try self.store(dest_ptr, ptr_ty, src_operand, .none);
8238 return null;8614 return .none;
8239 }8615 }
82408616
8241 /// As an optimization, we want to avoid unnecessary copies of isByRef=true8617 /// As an optimization, we want to avoid unnecessary copies of isByRef=true
...@@ -8260,7 +8636,7 @@ pub const FuncGen = struct {...@@ -8260,7 +8636,7 @@ pub const FuncGen = struct {
8260 return false;8636 return false;
8261 }8637 }
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 {
8264 const o = fg.dg.object;8640 const o = fg.dg.object;
8265 const mod = o.module;8641 const mod = o.module;
8266 const inst = body_tail[0];8642 const inst = body_tail[0];
...@@ -8277,22 +8653,40 @@ pub const FuncGen = struct {...@@ -8277,22 +8653,40 @@ pub const FuncGen = struct {
8277 return fg.load(ptr, ptr_ty);8653 return fg.load(ptr, ptr_ty);
8278 }8654 }
82798655
8280 fn airTrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8656 fn airTrap(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8281 _ = inst;8657 _ = inst;
8282 const llvm_fn = self.getIntrinsic("llvm.trap", &.{});8658 const o = self.dg.object;
8283 _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, undefined, 0, .Cold, .Auto, "");8659 const llvm_fn = try self.getIntrinsic("llvm.trap", &.{});
8284 _ = self.builder.buildUnreachable();8660 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
8285 return null;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;
8286 }8671 }
82878672
8288 fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8673 fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8289 _ = inst;8674 _ = inst;
8290 const llvm_fn = self.getIntrinsic("llvm.debugtrap", &.{});8675 const o = self.dg.object;
8291 _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, undefined, 0, .C, .Auto, "");8676 const llvm_fn = try self.getIntrinsic("llvm.debugtrap", &.{});
8292 return null;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;
8293 }8687 }
82948688
8295 fn airRetAddr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8689 fn airRetAddr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8296 _ = inst;8690 _ = inst;
8297 const o = self.dg.object;8691 const o = self.dg.object;
8298 const mod = o.module;8692 const mod = o.module;
...@@ -8300,43 +8694,61 @@ pub const FuncGen = struct {...@@ -8300,43 +8694,61 @@ pub const FuncGen = struct {
8300 const target = mod.getTarget();8694 const target = mod.getTarget();
8301 if (!target_util.supportsReturnAddress(target)) {8695 if (!target_util.supportsReturnAddress(target)) {
8302 // https://github.com/ziglang/zig/issues/119468696 // https://github.com/ziglang/zig/issues/11946
8303 return llvm_usize.constNull();8697 return o.builder.intValue(llvm_usize, 0);
8304 }8698 }
83058699
8306 const llvm_i32 = self.context.intType(32);8700 const llvm_fn = try self.getIntrinsic("llvm.returnaddress", &.{});
8307 const llvm_fn = self.getIntrinsic("llvm.returnaddress", &.{});8701 const params = [_]*llvm.Value{
8308 const params = [_]*llvm.Value{llvm_i32.constNull()};8702 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
8309 const ptr_val = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, "");8703 };
8310 return self.builder.buildPtrToInt(ptr_val, llvm_usize, "");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, "");
8311 }8714 }
83128715
8313 fn airFrameAddress(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8716 fn airFrameAddress(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8314 _ = inst;8717 _ = inst;
8315 const o = self.dg.object;8718 const o = self.dg.object;
8316 const llvm_i32 = self.context.intType(32);
8317 const llvm_fn_name = "llvm.frameaddress.p0";8719 const llvm_fn_name = "llvm.frameaddress.p0";
8318 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {8720 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {
8319 const llvm_p0i8 = self.context.pointerType(0);8721 const fn_type = try o.builder.fnType(.ptr, &.{.i32}, .normal);
8320 const param_types = [_]*llvm.Type{llvm_i32};8722 break :blk o.llvm_module.addFunction(llvm_fn_name, fn_type.toLlvm(&o.builder));
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);
8323 };8723 };
8724 const llvm_fn_ty = try o.builder.fnType(.ptr, &.{.i32}, .normal);
83248725
8325 const params = [_]*llvm.Value{llvm_i32.constNull()};8726 const params = [_]*llvm.Value{
8326 const ptr_val = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, "");8727 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
8327 const llvm_usize = try o.lowerType(Type.usize);8728 };
8328 return self.builder.buildPtrToInt(ptr_val, llvm_usize, "");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), "");
8329 }8742 }
83308743
8331 fn airFence(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8744 fn airFence(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8332 const atomic_order = self.air.instructions.items(.data)[inst].fence;8745 const atomic_order = self.air.instructions.items(.data)[inst].fence;
8333 const llvm_memory_order = toLlvmAtomicOrdering(atomic_order);8746 const ordering = toLlvmAtomicOrdering(atomic_order);
8334 const single_threaded = llvm.Bool.fromBool(self.single_threaded);8747 _ = try self.wip.fence(self.sync_scope, ordering);
8335 _ = self.builder.buildFence(llvm_memory_order, single_threaded, "");8748 return .none;
8336 return null;
8337 }8749 }
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 {
8340 const o = self.dg.object;8752 const o = self.dg.object;
8341 const mod = o.module;8753 const mod = o.module;
8342 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;8754 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -8345,46 +8757,51 @@ pub const FuncGen = struct {...@@ -8345,46 +8757,51 @@ pub const FuncGen = struct {
8345 var expected_value = try self.resolveInst(extra.expected_value);8757 var expected_value = try self.resolveInst(extra.expected_value);
8346 var new_value = try self.resolveInst(extra.new_value);8758 var new_value = try self.resolveInst(extra.new_value);
8347 const operand_ty = self.typeOf(extra.ptr).childType(mod);8759 const operand_ty = self.typeOf(extra.ptr).childType(mod);
8348 const opt_abi_ty = o.getAtomicAbiType(operand_ty, false);8760 const llvm_operand_ty = try o.lowerType(operand_ty);
8349 if (opt_abi_ty) |abi_ty| {8761 const llvm_abi_ty = try o.getAtomicAbiType(operand_ty, false);
8762 if (llvm_abi_ty != .none) {
8350 // operand needs widening and truncating8763 // operand needs widening and truncating
8351 if (operand_ty.isSignedInt(mod)) {8764 const signedness: Builder.Function.Instruction.Cast.Signedness =
8352 expected_value = self.builder.buildSExt(expected_value, abi_ty, "");8765 if (operand_ty.isSignedInt(mod)) .signed else .unsigned;
8353 new_value = self.builder.buildSExt(new_value, abi_ty, "");8766 expected_value = try self.wip.conv(signedness, expected_value, llvm_abi_ty, "");
8354 } else {8767 new_value = try self.wip.conv(signedness, new_value, llvm_abi_ty, "");
8355 expected_value = self.builder.buildZExt(expected_value, abi_ty, "");
8356 new_value = self.builder.buildZExt(new_value, abi_ty, "");
8357 }
8358 }8768 }
8359 const result = self.builder.buildAtomicCmpXchg(8769
8360 ptr,8770 const llvm_result_ty = try o.builder.structType(.normal, &.{
8361 expected_value,8771 if (llvm_abi_ty != .none) llvm_abi_ty else llvm_operand_ty,
8362 new_value,8772 .i1,
8363 toLlvmAtomicOrdering(extra.successOrder()),8773 });
8364 toLlvmAtomicOrdering(extra.failureOrder()),8774 const result = (try self.wip.unimplemented(llvm_result_ty, "")).finish(
8365 llvm.Bool.fromBool(self.single_threaded),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,
8366 );8784 );
8367 result.setWeak(llvm.Bool.fromBool(is_weak));8785 result.toLlvm(&self.wip).setWeak(llvm.Bool.fromBool(is_weak));
83688786
8369 const optional_ty = self.typeOfIndex(inst);8787 const optional_ty = self.typeOfIndex(inst);
83708788
8371 var payload = self.builder.buildExtractValue(result, 0, "");8789 var payload = try self.wip.extractValue(result, &.{0}, "");
8372 if (opt_abi_ty != null) {8790 if (llvm_abi_ty != .none) payload = try self.wip.cast(.trunc, payload, llvm_operand_ty, "");
8373 payload = self.builder.buildTrunc(payload, try o.lowerType(operand_ty), "");8791 const success_bit = try self.wip.extractValue(result, &.{1}, "");
8374 }
8375 const success_bit = self.builder.buildExtractValue(result, 1, "");
83768792
8377 if (optional_ty.optionalReprIsPayload(mod)) {8793 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, "");
8379 }8796 }
83808797
8381 comptime assert(optional_layout_version == 3);8798 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, "");
8384 return buildOptional(self, optional_ty, payload, non_null_bit);8801 return buildOptional(self, optional_ty, payload, non_null_bit);
8385 }8802 }
83868803
8387 fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8804 fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8388 const o = self.dg.object;8805 const o = self.dg.object;
8389 const mod = o.module;8806 const mod = o.module;
8390 const pl_op = self.air.instructions.items(.data)[inst].pl_op;8807 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
...@@ -8397,120 +8814,146 @@ pub const FuncGen = struct {...@@ -8397,120 +8814,146 @@ pub const FuncGen = struct {
8397 const is_float = operand_ty.isRuntimeFloat();8814 const is_float = operand_ty.isRuntimeFloat();
8398 const op = toLlvmAtomicRmwBinOp(extra.op(), is_signed_int, is_float);8815 const op = toLlvmAtomicRmwBinOp(extra.op(), is_signed_int, is_float);
8399 const ordering = toLlvmAtomicOrdering(extra.ordering());8816 const ordering = toLlvmAtomicOrdering(extra.ordering());
8400 const single_threaded = llvm.Bool.fromBool(self.single_threaded);8817 const single_threaded = llvm.Bool.fromBool(self.sync_scope == .singlethread);
8401 const opt_abi_ty = o.getAtomicAbiType(operand_ty, op == .Xchg);8818 const llvm_abi_ty = try o.getAtomicAbiType(operand_ty, op == .Xchg);
8402 if (opt_abi_ty) |abi_ty| {8819 const llvm_operand_ty = try o.lowerType(operand_ty);
8820 if (llvm_abi_ty != .none) {
8403 // operand needs widening and truncating or bitcasting.8821 // operand needs widening and truncating or bitcasting.
8404 const casted_operand = if (is_float)8822 const casted_operand = try self.wip.cast(
8405 self.builder.buildBitCast(operand, abi_ty, "")8823 if (is_float) .bitcast else if (is_signed_int) .sext else .zext,
8406 else if (is_signed_int)8824 @enumFromInt(@intFromEnum(operand)),
8407 self.builder.buildSExt(operand, abi_ty, "")8825 llvm_abi_ty,
8408 else8826 "",
8409 self.builder.buildZExt(operand, abi_ty, "");8827 );
84108828
8411 const uncasted_result = self.builder.buildAtomicRmw(8829 const uncasted_result = (try self.wip.unimplemented(llvm_abi_ty, "")).finish(
8412 op,8830 self.builder.buildAtomicRmw(
8413 ptr,8831 op,
8414 casted_operand,8832 ptr.toLlvm(&self.wip),
8415 ordering,8833 casted_operand.toLlvm(&self.wip),
8416 single_threaded,8834 @enumFromInt(@intFromEnum(ordering)),
8835 single_threaded,
8836 ),
8837 &self.wip,
8417 );8838 );
8418 const operand_llvm_ty = try o.lowerType(operand_ty);8839
8419 if (is_float) {8840 if (is_float) {
8420 return self.builder.buildBitCast(uncasted_result, operand_llvm_ty, "");8841 return self.wip.cast(.bitcast, uncasted_result, llvm_operand_ty, "");
8421 } else {8842 } else {
8422 return self.builder.buildTrunc(uncasted_result, operand_llvm_ty, "");8843 return self.wip.cast(.trunc, uncasted_result, llvm_operand_ty, "");
8423 }8844 }
8424 }8845 }
84258846
8426 if (operand.typeOf().getTypeKind() != .Pointer) {8847 if (!llvm_operand_ty.isPointer(&o.builder)) {
8427 return self.builder.buildAtomicRmw(op, ptr, operand, ordering, single_threaded);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 );
8428 }8858 }
84298859
8430 // It's a pointer but we need to treat it as an int.8860 // It's a pointer but we need to treat it as an int.
8431 const usize_llvm_ty = try o.lowerType(Type.usize);8861 const llvm_usize = try o.lowerType(Type.usize);
8432 const casted_operand = self.builder.buildPtrToInt(operand, usize_llvm_ty, "");8862 const casted_operand = try self.wip.cast(.ptrtoint, operand, llvm_usize, "");
8433 const uncasted_result = self.builder.buildAtomicRmw(8863 const uncasted_result = (try self.wip.unimplemented(llvm_usize, "")).finish(
8434 op,8864 self.builder.buildAtomicRmw(
8435 ptr,8865 op,
8436 casted_operand,8866 ptr.toLlvm(&self.wip),
8437 ordering,8867 casted_operand.toLlvm(&self.wip),
8438 single_threaded,8868 @enumFromInt(@intFromEnum(ordering)),
8869 single_threaded,
8870 ),
8871 &self.wip,
8439 );8872 );
8440 const operand_llvm_ty = try o.lowerType(operand_ty);8873 return self.wip.cast(.inttoptr, uncasted_result, llvm_operand_ty, "");
8441 return self.builder.buildIntToPtr(uncasted_result, operand_llvm_ty, "");
8442 }8874 }
84438875
8444 fn airAtomicLoad(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8876 fn airAtomicLoad(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8445 const o = self.dg.object;8877 const o = self.dg.object;
8446 const mod = o.module;8878 const mod = o.module;
8447 const atomic_load = self.air.instructions.items(.data)[inst].atomic_load;8879 const atomic_load = self.air.instructions.items(.data)[inst].atomic_load;
8448 const ptr = try self.resolveInst(atomic_load.ptr);8880 const ptr = try self.resolveInst(atomic_load.ptr);
8449 const ptr_ty = self.typeOf(atomic_load.ptr);8881 const ptr_ty = self.typeOf(atomic_load.ptr);
8450 const ptr_info = ptr_ty.ptrInfo(mod);8882 const info = ptr_ty.ptrInfo(mod);
8451 const elem_ty = ptr_info.child.toType();8883 const elem_ty = info.child.toType();
8452 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod))8884 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none;
8453 return null;
8454 const ordering = toLlvmAtomicOrdering(atomic_load.order);8885 const ordering = toLlvmAtomicOrdering(atomic_load.order);
8455 const opt_abi_llvm_ty = o.getAtomicAbiType(elem_ty, false);8886 const llvm_abi_ty = try o.getAtomicAbiType(elem_ty, false);
8456 const ptr_alignment = @as(u32, @intCast(ptr_info.flags.alignment.toByteUnitsOptional() orelse8887 const ptr_alignment = Builder.Alignment.fromByteUnits(
8457 ptr_info.child.toType().abiAlignment(mod)));8888 info.flags.alignment.toByteUnitsOptional() orelse info.child.toType().abiAlignment(mod),
8458 const ptr_volatile = llvm.Bool.fromBool(ptr_info.flags.is_volatile);8889 );
8890 const ptr_kind: Builder.MemoryAccessKind = switch (info.flags.is_volatile) {
8891 false => .normal,
8892 true => .@"volatile",
8893 };
8459 const elem_llvm_ty = try o.lowerType(elem_ty);8894 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) {
8462 // operand needs widening and truncating8897 // operand needs widening and truncating
8463 const load_inst = self.builder.buildLoad(abi_llvm_ty, ptr, "");8898 const loaded = try self.wip.loadAtomic(
8464 load_inst.setAlignment(ptr_alignment);8899 ptr_kind,
8465 load_inst.setVolatile(ptr_volatile);8900 llvm_abi_ty,
8466 load_inst.setOrdering(ordering);8901 ptr,
8467 return self.builder.buildTrunc(load_inst, elem_llvm_ty, "");8902 self.sync_scope,
8903 ordering,
8904 ptr_alignment,
8905 "",
8906 );
8907 return self.wip.cast(.trunc, loaded, elem_llvm_ty, "");
8468 }8908 }
8469 const load_inst = self.builder.buildLoad(elem_llvm_ty, ptr, "");8909 return self.wip.loadAtomic(
8470 load_inst.setAlignment(ptr_alignment);8910 ptr_kind,
8471 load_inst.setVolatile(ptr_volatile);8911 elem_llvm_ty,
8472 load_inst.setOrdering(ordering);8912 ptr,
8473 return load_inst;8913 self.sync_scope,
8914 ordering,
8915 ptr_alignment,
8916 "",
8917 );
8474 }8918 }
84758919
8476 fn airAtomicStore(8920 fn airAtomicStore(
8477 self: *FuncGen,8921 self: *FuncGen,
8478 inst: Air.Inst.Index,8922 inst: Air.Inst.Index,
8479 ordering: llvm.AtomicOrdering,8923 ordering: Builder.AtomicOrdering,
8480 ) !?*llvm.Value {8924 ) !Builder.Value {
8481 const o = self.dg.object;8925 const o = self.dg.object;
8482 const mod = o.module;8926 const mod = o.module;
8483 const bin_op = self.air.instructions.items(.data)[inst].bin_op;8927 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
8484 const ptr_ty = self.typeOf(bin_op.lhs);8928 const ptr_ty = self.typeOf(bin_op.lhs);
8485 const operand_ty = ptr_ty.childType(mod);8929 const operand_ty = ptr_ty.childType(mod);
8486 if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return null;8930 if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return .none;
8487 const ptr = try self.resolveInst(bin_op.lhs);8931 const ptr = try self.resolveInst(bin_op.lhs);
8488 var element = try self.resolveInst(bin_op.rhs);8932 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) {
8492 // operand needs widening8936 // operand needs widening
8493 if (operand_ty.isSignedInt(mod)) {8937 element = try self.wip.conv(
8494 element = self.builder.buildSExt(element, abi_ty, "");8938 if (operand_ty.isSignedInt(mod)) .signed else .unsigned,
8495 } else {8939 element,
8496 element = self.builder.buildZExt(element, abi_ty, "");8940 llvm_abi_ty,
8497 }8941 "",
8942 );
8498 }8943 }
8499 try self.store(ptr, ptr_ty, element, ordering);8944 try self.store(ptr, ptr_ty, element, ordering);
8500 return null;8945 return .none;
8501 }8946 }
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 {
8504 const o = self.dg.object;8949 const o = self.dg.object;
8505 const mod = o.module;8950 const mod = o.module;
8506 const bin_op = self.air.instructions.items(.data)[inst].bin_op;8951 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
8507 const dest_slice = try self.resolveInst(bin_op.lhs);8952 const dest_slice = try self.resolveInst(bin_op.lhs);
8508 const ptr_ty = self.typeOf(bin_op.lhs);8953 const ptr_ty = self.typeOf(bin_op.lhs);
8509 const elem_ty = self.typeOf(bin_op.rhs);8954 const elem_ty = self.typeOf(bin_op.rhs);
8510 const target = mod.getTarget();8955 const dest_ptr_align = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
8511 const dest_ptr_align = ptr_ty.ptrAlignment(mod);8956 const dest_ptr = try self.sliceOrArrayPtr(dest_slice, ptr_ty);
8512 const u8_llvm_ty = self.context.intType(8);
8513 const dest_ptr = self.sliceOrArrayPtr(dest_slice, ptr_ty);
8514 const is_volatile = ptr_ty.isVolatilePtr(mod);8957 const is_volatile = ptr_ty.isVolatilePtr(mod);
85158958
8516 // Any WebAssembly runtime will trap when the destination pointer is out-of-bounds, regardless8959 // Any WebAssembly runtime will trap when the destination pointer is out-of-bounds, regardless
...@@ -8527,20 +8970,26 @@ pub const FuncGen = struct {...@@ -8527,20 +8970,26 @@ pub const FuncGen = struct {
8527 // extra information to LLVM. However, safety makes the difference between using8970 // extra information to LLVM. However, safety makes the difference between using
8528 // 0xaa or actual undefined for the fill byte.8971 // 0xaa or actual undefined for the fill byte.
8529 const fill_byte = if (safety)8972 const fill_byte = if (safety)
8530 u8_llvm_ty.constInt(0xaa, .False)8973 try o.builder.intValue(.i8, 0xaa)
8531 else8974 else
8532 u8_llvm_ty.getUndef();8975 try o.builder.undefValue(.i8);
8533 const len = self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);8976 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
8534 if (intrinsic_len0_traps) {8977 if (intrinsic_len0_traps) {
8535 try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);8978 try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);
8536 } else {8979 } 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);
8538 }8987 }
85398988
8540 if (safety and mod.comp.bin_file.options.valgrind) {8989 if (safety and mod.comp.bin_file.options.valgrind) {
8541 self.valgrindMarkUndef(dest_ptr, len);8990 try self.valgrindMarkUndef(dest_ptr, len);
8542 }8991 }
8543 return null;8992 return .none;
8544 }8993 }
85458994
8546 // Test if the element value is compile-time known to be a8995 // Test if the element value is compile-time known to be a
...@@ -8548,18 +8997,21 @@ pub const FuncGen = struct {...@@ -8548,18 +8997,21 @@ pub const FuncGen = struct {
8548 // repeating byte pattern of 0 bytes. In such case, the memset8997 // repeating byte pattern of 0 bytes. In such case, the memset
8549 // intrinsic can be used.8998 // intrinsic can be used.
8550 if (try elem_val.hasRepeatedByteRepr(elem_ty, mod)) |byte_val| {8999 if (try elem_val.hasRepeatedByteRepr(elem_ty, mod)) |byte_val| {
8551 const fill_byte = try self.resolveValue(.{9000 const fill_byte = try self.resolveValue(.{ .ty = Type.u8, .val = byte_val });
8552 .ty = Type.u8,9001 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
8553 .val = byte_val,
8554 });
8555 const len = self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
85569002
8557 if (intrinsic_len0_traps) {9003 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);
8559 } else {9005 } 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);
8561 }9013 }
8562 return null;9014 return .none;
8563 }9015 }
8564 }9016 }
85659017
...@@ -8569,14 +9021,20 @@ pub const FuncGen = struct {...@@ -8569,14 +9021,20 @@ pub const FuncGen = struct {
8569 if (elem_abi_size == 1) {9021 if (elem_abi_size == 1) {
8570 // In this case we can take advantage of LLVM's intrinsic.9022 // In this case we can take advantage of LLVM's intrinsic.
8571 const fill_byte = try self.bitCast(value, elem_ty, Type.u8);9023 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
8574 if (intrinsic_len0_traps) {9026 if (intrinsic_len0_traps) {
8575 try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);9027 try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);
8576 } else {9028 } 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);
8578 }9036 }
8579 return null;9037 return .none;
8580 }9038 }
85819039
8582 // non-byte-sized element. lower with a loop. something like this:9040 // non-byte-sized element. lower with a loop. something like this:
...@@ -8584,88 +9042,92 @@ pub const FuncGen = struct {...@@ -8584,88 +9042,92 @@ pub const FuncGen = struct {
8584 // entry:9042 // entry:
8585 // ...9043 // ...
8586 // %end_ptr = getelementptr %ptr, %len9044 // %end_ptr = getelementptr %ptr, %len
8587 // br loop9045 // br %loop
8588 // loop:9046 // loop:
8589 // %it_ptr = phi body %next_ptr, entry %ptr9047 // %it_ptr = phi body %next_ptr, entry %ptr
8590 // %end = cmp eq %it_ptr, %end_ptr9048 // %end = cmp eq %it_ptr, %end_ptr
8591 // cond_br %end body, end9049 // br %end, %body, %end
8592 // body:9050 // body:
8593 // store %it_ptr, %value9051 // store %it_ptr, %value
8594 // %next_ptr = getelementptr %it_ptr, 19052 // %next_ptr = getelementptr %it_ptr, 1
8595 // br loop9053 // br %loop
8596 // end:9054 // end:
8597 // ...9055 // ...
8598 const entry_block = self.builder.getInsertBlock();9056 const entry_block = self.wip.cursor.block;
8599 const loop_block = self.context.appendBasicBlock(self.llvm_func, "InlineMemsetLoop");9057 const loop_block = try self.wip.block(2, "InlineMemsetLoop");
8600 const body_block = self.context.appendBasicBlock(self.llvm_func, "InlineMemsetBody");9058 const body_block = try self.wip.block(1, "InlineMemsetBody");
8601 const end_block = self.context.appendBasicBlock(self.llvm_func, "InlineMemsetEnd");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);
8604 const len = switch (ptr_ty.ptrSize(mod)) {9062 const len = switch (ptr_ty.ptrSize(mod)) {
8605 .Slice => self.builder.buildExtractValue(dest_slice, 1, ""),9063 .Slice => try self.wip.extractValue(dest_slice, &.{1}, ""),
8606 .One => llvm_usize_ty.constInt(ptr_ty.childType(mod).arrayLen(mod), .False),9064 .One => try o.builder.intValue(usize_ty, ptr_ty.childType(mod).arrayLen(mod)),
8607 .Many, .C => unreachable,9065 .Many, .C => unreachable,
8608 };9066 };
8609 const elem_llvm_ty = try o.lowerType(elem_ty);9067 const elem_llvm_ty = try o.lowerType(elem_ty);
8610 const len_gep = [_]*llvm.Value{len};9068 const end_ptr = try self.wip.gep(.inbounds, elem_llvm_ty, dest_ptr, &.{len}, "");
8611 const end_ptr = self.builder.buildInBoundsGEP(elem_llvm_ty, dest_ptr, &len_gep, len_gep.len, "");9069 _ = try self.wip.br(loop_block);
8612 _ = self.builder.buildBr(loop_block);
86139070
8614 self.builder.positionBuilderAtEnd(loop_block);9071 self.wip.cursor = .{ .block = loop_block };
8615 const it_ptr = self.builder.buildPhi(self.context.pointerType(0), "");9072 const it_ptr = try self.wip.phi(.ptr, "");
8616 const end = self.builder.buildICmp(.NE, it_ptr, end_ptr, "");9073 const end = try self.wip.icmp(.ne, it_ptr.toValue(), end_ptr, "");
8617 _ = self.builder.buildCondBr(end, body_block, end_block);9074 _ = try self.wip.brCond(end, body_block, end_block);
86189075
8619 self.builder.positionBuilderAtEnd(body_block);9076 self.wip.cursor = .{ .block = body_block };
8620 const elem_abi_alignment = elem_ty.abiAlignment(mod);9077 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 );
8622 if (isByRef(elem_ty, mod)) {9081 if (isByRef(elem_ty, mod)) {
8623 _ = self.builder.buildMemCpy(9082 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy(
8624 it_ptr,9083 it_ptr.toValue().toLlvm(&self.wip),
8625 it_ptr_alignment,9084 @intCast(it_ptr_alignment.toByteUnits() orelse 0),
8626 value,9085 value.toLlvm(&self.wip),
8627 elem_abi_alignment,9086 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),
8629 is_volatile,9088 is_volatile,
8630 );9089 ), &self.wip);
8631 } else {9090 } else _ = try self.wip.store(switch (is_volatile) {
8632 const store_inst = self.builder.buildStore(value, it_ptr);9091 false => .normal,
8633 store_inst.setAlignment(it_ptr_alignment);9092 true => .@"volatile",
8634 store_inst.setVolatile(llvm.Bool.fromBool(is_volatile));9093 }, value, it_ptr.toValue(), it_ptr_alignment);
8635 }9094 const next_ptr = try self.wip.gep(.inbounds, elem_llvm_ty, it_ptr.toValue(), &.{
8636 const one_gep = [_]*llvm.Value{llvm_usize_ty.constInt(1, .False)};9095 try o.builder.intValue(usize_ty, 1),
8637 const next_ptr = self.builder.buildInBoundsGEP(elem_llvm_ty, it_ptr, &one_gep, one_gep.len, "");9096 }, "");
8638 _ = self.builder.buildBr(loop_block);9097 _ = try self.wip.br(loop_block);
8639
8640 self.builder.positionBuilderAtEnd(end_block);
86419098
8642 const incoming_values: [2]*llvm.Value = .{ next_ptr, dest_ptr };9099 self.wip.cursor = .{ .block = end_block };
8643 const incoming_blocks: [2]*llvm.BasicBlock = .{ body_block, entry_block };9100 try it_ptr.finish(&.{ next_ptr, dest_ptr }, &.{ body_block, entry_block }, &self.wip);
8644 it_ptr.addIncoming(&incoming_values, &incoming_blocks, 2);9101 return .none;
8645
8646 return null;
8647 }9102 }
86489103
8649 fn safeWasmMemset(9104 fn safeWasmMemset(
8650 self: *FuncGen,9105 self: *FuncGen,
8651 dest_ptr: *llvm.Value,9106 dest_ptr: Builder.Value,
8652 fill_byte: *llvm.Value,9107 fill_byte: Builder.Value,
8653 len: *llvm.Value,9108 len: Builder.Value,
8654 dest_ptr_align: u32,9109 dest_ptr_align: Builder.Alignment,
8655 is_volatile: bool,9110 is_volatile: bool,
8656 ) !void {9111 ) !void {
8657 const llvm_usize_ty = self.context.intType(self.dg.object.target.ptrBitWidth());9112 const o = self.dg.object;
8658 const cond = try self.cmp(len, llvm_usize_ty.constInt(0, .False), Type.usize, .neq);9113 const llvm_usize_ty = try o.lowerType(Type.usize);
8659 const memset_block = self.context.appendBasicBlock(self.llvm_func, "MemsetTrapSkip");9114 const cond = try self.cmp(len, try o.builder.intValue(llvm_usize_ty, 0), Type.usize, .neq);
8660 const end_block = self.context.appendBasicBlock(self.llvm_func, "MemsetTrapEnd");9115 const memset_block = try self.wip.block(1, "MemsetTrapSkip");
8661 _ = self.builder.buildCondBr(cond, memset_block, end_block);9116 const end_block = try self.wip.block(2, "MemsetTrapEnd");
8662 self.builder.positionBuilderAtEnd(memset_block);9117 _ = try self.wip.brCond(cond, memset_block, end_block);
8663 _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);9118 self.wip.cursor = .{ .block = memset_block };
8664 _ = self.builder.buildBr(end_block);9119 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemSet(
8665 self.builder.positionBuilderAtEnd(end_block);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 };
8666 }9128 }
86679129
8668 fn airMemcpy(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {9130 fn airMemcpy(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8669 const o = self.dg.object;9131 const o = self.dg.object;
8670 const mod = o.module;9132 const mod = o.module;
8671 const bin_op = self.air.instructions.items(.data)[inst].bin_op;9133 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -8673,9 +9135,9 @@ pub const FuncGen = struct {...@@ -8673,9 +9135,9 @@ pub const FuncGen = struct {
8673 const dest_ptr_ty = self.typeOf(bin_op.lhs);9135 const dest_ptr_ty = self.typeOf(bin_op.lhs);
8674 const src_slice = try self.resolveInst(bin_op.rhs);9136 const src_slice = try self.resolveInst(bin_op.rhs);
8675 const src_ptr_ty = self.typeOf(bin_op.rhs);9137 const src_ptr_ty = self.typeOf(bin_op.rhs);
8676 const src_ptr = self.sliceOrArrayPtr(src_slice, src_ptr_ty);9138 const src_ptr = try self.sliceOrArrayPtr(src_slice, src_ptr_ty);
8677 const len = self.sliceOrArrayLenInBytes(dest_slice, dest_ptr_ty);9139 const len = try self.sliceOrArrayLenInBytes(dest_slice, dest_ptr_ty);
8678 const dest_ptr = self.sliceOrArrayPtr(dest_slice, dest_ptr_ty);9140 const dest_ptr = try self.sliceOrArrayPtr(dest_slice, dest_ptr_ty);
8679 const is_volatile = src_ptr_ty.isVolatilePtr(mod) or dest_ptr_ty.isVolatilePtr(mod);9141 const is_volatile = src_ptr_ty.isVolatilePtr(mod) or dest_ptr_ty.isVolatilePtr(mod);
86809142
8681 // When bulk-memory is enabled, this will be lowered to WebAssembly's memory.copy instruction.9143 // When bulk-memory is enabled, this will be lowered to WebAssembly's memory.copy instruction.
...@@ -8687,84 +9149,81 @@ pub const FuncGen = struct {...@@ -8687,84 +9149,81 @@ pub const FuncGen = struct {
8687 std.Target.wasm.featureSetHas(o.target.cpu.features, .bulk_memory) and9149 std.Target.wasm.featureSetHas(o.target.cpu.features, .bulk_memory) and
8688 dest_ptr_ty.isSlice(mod))9150 dest_ptr_ty.isSlice(mod))
8689 {9151 {
8690 const llvm_usize_ty = self.context.intType(self.dg.object.target.ptrBitWidth());9152 const zero_usize = try o.builder.intValue(try o.lowerType(Type.usize), 0);
8691 const cond = try self.cmp(len, llvm_usize_ty.constInt(0, .False), Type.usize, .neq);9153 const cond = try self.cmp(len, zero_usize, Type.usize, .neq);
8692 const memcpy_block = self.context.appendBasicBlock(self.llvm_func, "MemcpyTrapSkip");9154 const memcpy_block = try self.wip.block(1, "MemcpyTrapSkip");
8693 const end_block = self.context.appendBasicBlock(self.llvm_func, "MemcpyTrapEnd");9155 const end_block = try self.wip.block(2, "MemcpyTrapEnd");
8694 _ = self.builder.buildCondBr(cond, memcpy_block, end_block);9156 _ = try self.wip.brCond(cond, memcpy_block, end_block);
8695 self.builder.positionBuilderAtEnd(memcpy_block);9157 self.wip.cursor = .{ .block = memcpy_block };
8696 _ = self.builder.buildMemCpy(9158 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy(
8697 dest_ptr,9159 dest_ptr.toLlvm(&self.wip),
8698 dest_ptr_ty.ptrAlignment(mod),9160 dest_ptr_ty.ptrAlignment(mod),
8699 src_ptr,9161 src_ptr.toLlvm(&self.wip),
8700 src_ptr_ty.ptrAlignment(mod),9162 src_ptr_ty.ptrAlignment(mod),
8701 len,9163 len.toLlvm(&self.wip),
8702 is_volatile,9164 is_volatile,
8703 );9165 ), &self.wip);
8704 _ = self.builder.buildBr(end_block);9166 _ = try self.wip.br(end_block);
8705 self.builder.positionBuilderAtEnd(end_block);9167 self.wip.cursor = .{ .block = end_block };
8706 return null;9168 return .none;
8707 }9169 }
87089170
8709 _ = self.builder.buildMemCpy(9171 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy(
8710 dest_ptr,9172 dest_ptr.toLlvm(&self.wip),
8711 dest_ptr_ty.ptrAlignment(mod),9173 dest_ptr_ty.ptrAlignment(mod),
8712 src_ptr,9174 src_ptr.toLlvm(&self.wip),
8713 src_ptr_ty.ptrAlignment(mod),9175 src_ptr_ty.ptrAlignment(mod),
8714 len,9176 len.toLlvm(&self.wip),
8715 is_volatile,9177 is_volatile,
8716 );9178 ), &self.wip);
8717 return null;9179 return .none;
8718 }9180 }
87199181
8720 fn airSetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {9182 fn airSetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8721 const o = self.dg.object;9183 const o = self.dg.object;
8722 const mod = o.module;9184 const mod = o.module;
8723 const bin_op = self.air.instructions.items(.data)[inst].bin_op;9185 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
8724 const un_ty = self.typeOf(bin_op.lhs).childType(mod);9186 const un_ty = self.typeOf(bin_op.lhs).childType(mod);
8725 const layout = un_ty.unionGetLayout(mod);9187 const layout = un_ty.unionGetLayout(mod);
8726 if (layout.tag_size == 0) return null;9188 if (layout.tag_size == 0) return .none;
8727 const union_ptr = try self.resolveInst(bin_op.lhs);9189 const union_ptr = try self.resolveInst(bin_op.lhs);
8728 const new_tag = try self.resolveInst(bin_op.rhs);9190 const new_tag = try self.resolveInst(bin_op.rhs);
8729 if (layout.payload_size == 0) {9191 if (layout.payload_size == 0) {
8730 // TODO alignment on this store9192 // TODO alignment on this store
8731 _ = self.builder.buildStore(new_tag, union_ptr);9193 _ = try self.wip.store(.normal, new_tag, union_ptr, .default);
8732 return null;9194 return .none;
8733 }9195 }
8734 const un_llvm_ty = try o.lowerType(un_ty);
8735 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);9196 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, "");
8737 // TODO alignment on this store9198 // TODO alignment on this store
8738 _ = self.builder.buildStore(new_tag, tag_field_ptr);9199 _ = try self.wip.store(.normal, new_tag, tag_field_ptr, .default);
8739 return null;9200 return .none;
8740 }9201 }
87419202
8742 fn airGetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {9203 fn airGetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8743 const o = self.dg.object;9204 const o = self.dg.object;
8744 const mod = o.module;9205 const mod = o.module;
8745 const ty_op = self.air.instructions.items(.data)[inst].ty_op;9206 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
8746 const un_ty = self.typeOf(ty_op.operand);9207 const un_ty = self.typeOf(ty_op.operand);
8747 const layout = un_ty.unionGetLayout(mod);9208 const layout = un_ty.unionGetLayout(mod);
8748 if (layout.tag_size == 0) return null;9209 if (layout.tag_size == 0) return .none;
8749 const union_handle = try self.resolveInst(ty_op.operand);9210 const union_handle = try self.resolveInst(ty_op.operand);
8750 if (isByRef(un_ty, mod)) {9211 if (isByRef(un_ty, mod)) {
8751 const llvm_un_ty = try o.lowerType(un_ty);9212 const llvm_un_ty = try o.lowerType(un_ty);
8752 if (layout.payload_size == 0) {9213 if (layout.payload_size == 0)
8753 return self.builder.buildLoad(llvm_un_ty, union_handle, "");9214 return self.wip.load(.normal, llvm_un_ty, union_handle, .default, "");
8754 }
8755 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);9215 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, "");9216 const tag_field_ptr = try self.wip.gepStruct(llvm_un_ty, union_handle, tag_index, "");
8757 return self.builder.buildLoad(llvm_un_ty.structGetTypeAtIndex(tag_index), tag_field_ptr, "");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, "");
8758 } else {9219 } else {
8759 if (layout.payload_size == 0) {9220 if (layout.payload_size == 0) return union_handle;
8760 return union_handle;
8761 }
8762 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);9221 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}, "");
8764 }9223 }
8765 }9224 }
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 {
8768 const un_op = self.air.instructions.items(.data)[inst].un_op;9227 const un_op = self.air.instructions.items(.data)[inst].un_op;
8769 const operand = try self.resolveInst(un_op);9228 const operand = try self.resolveInst(un_op);
8770 const operand_ty = self.typeOf(un_op);9229 const operand_ty = self.typeOf(un_op);
...@@ -8772,7 +9231,7 @@ pub const FuncGen = struct {...@@ -8772,7 +9231,7 @@ pub const FuncGen = struct {
8772 return self.buildFloatOp(op, operand_ty, 1, .{operand});9231 return self.buildFloatOp(op, operand_ty, 1, .{operand});
8773 }9232 }
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 {
8776 self.builder.setFastMath(want_fast_math);9235 self.builder.setFastMath(want_fast_math);
87779236
8778 const un_op = self.air.instructions.items(.data)[inst].un_op;9237 const un_op = self.air.instructions.items(.data)[inst].un_op;
...@@ -8782,60 +9241,64 @@ pub const FuncGen = struct {...@@ -8782,60 +9241,64 @@ pub const FuncGen = struct {
8782 return self.buildFloatOp(.neg, operand_ty, 1, .{operand});9241 return self.buildFloatOp(.neg, operand_ty, 1, .{operand});
8783 }9242 }
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 {
8786 const o = self.dg.object;9245 const o = self.dg.object;
8787 const mod = o.module;
8788 const ty_op = self.air.instructions.items(.data)[inst].ty_op;9246 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
8789 const operand_ty = self.typeOf(ty_op.operand);9247 const operand_ty = self.typeOf(ty_op.operand);
8790 const operand = try self.resolveInst(ty_op.operand);9248 const operand = try self.resolveInst(ty_op.operand);
87919249
8792 const llvm_i1 = self.context.intType(1);9250 const llvm_operand_ty = try o.lowerType(operand_ty);
8793 const operand_llvm_ty = try o.lowerType(operand_ty);9251 const llvm_fn_ty = try o.builder.fnType(llvm_operand_ty, &.{ llvm_operand_ty, .i1 }, .normal);
8794 const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty});9252 const fn_val = try self.getIntrinsic(llvm_fn_name, &.{llvm_operand_ty});
87959253
8796 const params = [_]*llvm.Value{ operand, llvm_i1.constNull() };9254 const params = [_]*llvm.Value{
8797 const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, "");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 );
8798 const result_ty = self.typeOfIndex(inst);9270 const result_ty = self.typeOfIndex(inst);
8799 const result_llvm_ty = try o.lowerType(result_ty);9271 return self.wip.conv(.unsigned, wrong_size_result, 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 }
8810 }9272 }
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 {
8813 const o = self.dg.object;9275 const o = self.dg.object;
8814 const mod = o.module;
8815 const ty_op = self.air.instructions.items(.data)[inst].ty_op;9276 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
8816 const operand_ty = self.typeOf(ty_op.operand);9277 const operand_ty = self.typeOf(ty_op.operand);
8817 const operand = try self.resolveInst(ty_op.operand);9278 const operand = try self.resolveInst(ty_op.operand);
88189279
8819 const params = [_]*llvm.Value{operand};9280 const llvm_operand_ty = try o.lowerType(operand_ty);
8820 const operand_llvm_ty = try o.lowerType(operand_ty);9281 const llvm_fn_ty = try o.builder.fnType(llvm_operand_ty, &.{llvm_operand_ty}, .normal);
8821 const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty});9282 const fn_val = try self.getIntrinsic(llvm_fn_name, &.{llvm_operand_ty});
88229283
8823 const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, "");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 );
8824 const result_ty = self.typeOfIndex(inst);9297 const result_ty = self.typeOfIndex(inst);
8825 const result_llvm_ty = try o.lowerType(result_ty);9298 return self.wip.conv(.unsigned, wrong_size_result, 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 }
8836 }9299 }
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 {
8839 const o = self.dg.object;9302 const o = self.dg.object;
8840 const mod = o.module;9303 const mod = o.module;
8841 const ty_op = self.air.instructions.items(.data)[inst].ty_op;9304 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -8844,52 +9307,47 @@ pub const FuncGen = struct {...@@ -8844,52 +9307,47 @@ pub const FuncGen = struct {
8844 assert(bits % 8 == 0);9307 assert(bits % 8 == 0);
88459308
8846 var operand = try self.resolveInst(ty_op.operand);9309 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
8849 if (bits % 16 == 8) {9312 if (bits % 16 == 8) {
8850 // If not an even byte-multiple, we need zero-extend + shift-left 1 byte9313 // If not an even byte-multiple, we need zero-extend + shift-left 1 byte
8851 // The truncated result at the end will be the correct bswap9314 // 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));
8853 if (operand_ty.zigTypeTag(mod) == .Vector) {9316 if (operand_ty.zigTypeTag(mod) == .Vector) {
8854 const vec_len = operand_ty.vectorLen(mod);9317 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);9321 const shift_amt =
8858 defer self.gpa.free(shifts);9322 try o.builder.splatValue(llvm_operand_ty, try o.builder.intConst(scalar_ty, 8));
88599323 const extended = try self.wip.cast(.zext, operand, llvm_operand_ty, "");
8860 for (shifts) |*elem| {9324 operand = try self.wip.bin(.shl, extended, shift_amt, "");
8861 elem.* = scalar_llvm_ty.constInt(8, .False);
8862 }
8863 const shift_vec = llvm.constVector(shifts.ptr, vec_len);
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 }
8872 bits = bits + 8;9326 bits = bits + 8;
8873 }9327 }
88749328
8875 const params = [_]*llvm.Value{operand};9329 const llvm_fn_ty = try o.builder.fnType(llvm_operand_ty, &.{llvm_operand_ty}, .normal);
8876 const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty});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
8880 const result_ty = self.typeOfIndex(inst);9346 const result_ty = self.typeOfIndex(inst);
8881 const result_llvm_ty = try o.lowerType(result_ty);9347 return self.wip.conv(.unsigned, wrong_size_result, 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 }
8890 }9348 }
88919349
8892 fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {9350 fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8893 const o = self.dg.object;9351 const o = self.dg.object;
8894 const mod = o.module;9352 const mod = o.module;
8895 const ty_op = self.air.instructions.items(.data)[inst].ty_op;9353 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -8897,50 +9355,53 @@ pub const FuncGen = struct {...@@ -8897,50 +9355,53 @@ pub const FuncGen = struct {
8897 const error_set_ty = self.air.getRefType(ty_op.ty);9355 const error_set_ty = self.air.getRefType(ty_op.ty);
88989356
8899 const names = error_set_ty.errorSetNames(mod);9357 const names = error_set_ty.errorSetNames(mod);
8900 const valid_block = self.context.appendBasicBlock(self.llvm_func, "Valid");9358 const valid_block = try self.wip.block(@intCast(names.len), "Valid");
8901 const invalid_block = self.context.appendBasicBlock(self.llvm_func, "Invalid");9359 const invalid_block = try self.wip.block(1, "Invalid");
8902 const end_block = self.context.appendBasicBlock(self.llvm_func, "End");9360 const end_block = try self.wip.block(2, "End");
8903 const switch_instr = self.builder.buildSwitch(operand, invalid_block, @as(c_uint, @intCast(names.len)));9361 var wip_switch = try self.wip.@"switch"(operand, invalid_block, @intCast(names.len));
9362 defer wip_switch.finish(&self.wip);
89049363
8905 for (names) |name| {9364 for (names) |name| {
8906 const err_int = @as(Module.ErrorInt, @intCast(mod.global_error_set.getIndex(name).?));9365 const err_int = mod.global_error_set.getIndex(name).?;
8907 const this_tag_int_value = try o.lowerValue(.{9366 const this_tag_int_value = try o.builder.intConst(Builder.Type.err_int, err_int);
8908 .ty = Type.err_int,9367 try wip_switch.addCase(this_tag_int_value, valid_block, &self.wip);
8909 .val = try mod.intValue(Type.err_int, err_int),9368 }
8910 });9369 self.wip.cursor = .{ .block = valid_block };
8911 switch_instr.addCase(this_tag_int_value, valid_block);9370 _ = try self.wip.br(end_block);
8912 }9371
8913 self.builder.positionBuilderAtEnd(valid_block);9372 self.wip.cursor = .{ .block = invalid_block };
8914 _ = self.builder.buildBr(end_block);9373 _ = try self.wip.br(end_block);
89159374
8916 self.builder.positionBuilderAtEnd(invalid_block);9375 self.wip.cursor = .{ .block = end_block };
8917 _ = self.builder.buildBr(end_block);9376 const phi = try self.wip.phi(.i1, "");
89189377 try phi.finish(
8919 self.builder.positionBuilderAtEnd(end_block);9378 &.{ Builder.Constant.true.toValue(), Builder.Constant.false.toValue() },
89209379 &.{ valid_block, invalid_block },
8921 const llvm_type = self.context.intType(1);9380 &self.wip,
8922 const incoming_values: [2]*llvm.Value = .{9381 );
8923 llvm_type.constInt(1, .False), llvm_type.constInt(0, .False),9382 return phi.toValue();
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;
8931 }9383 }
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;
8934 const un_op = self.air.instructions.items(.data)[inst].un_op;9387 const un_op = self.air.instructions.items(.data)[inst].un_op;
8935 const operand = try self.resolveInst(un_op);9388 const operand = try self.resolveInst(un_op);
8936 const enum_ty = self.typeOf(un_op);9389 const enum_ty = self.typeOf(un_op);
89379390
8938 const llvm_fn = try self.getIsNamedEnumValueFunction(enum_ty);9391 const llvm_fn = try self.getIsNamedEnumValueFunction(enum_ty);
8939 const params = [_]*llvm.Value{operand};9392 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
8940 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, "");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);
8941 }9402 }
89429403
8943 fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !*llvm.Value {9404 fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index {
8944 const o = self.dg.object;9405 const o = self.dg.object;
8945 const mod = o.module;9406 const mod = o.module;
8946 const enum_type = mod.intern_pool.indexToKey(enum_ty.toIntern()).enum_type;9407 const enum_type = mod.intern_pool.indexToKey(enum_ty.toIntern()).enum_type;
...@@ -8950,185 +9411,207 @@ pub const FuncGen = struct {...@@ -8950,185 +9411,207 @@ pub const FuncGen = struct {
8950 if (gop.found_existing) return gop.value_ptr.*;9411 if (gop.found_existing) return gop.value_ptr.*;
8951 errdefer assert(o.named_enum_map.remove(enum_type.decl));9412 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
8957 const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);9414 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)});9415 const llvm_fn_name = try o.builder.fmt("__zig_is_named_enum_value_{}", .{
89599416 fqn.fmt(&mod.intern_pool),
8960 const param_types = [_]*llvm.Type{try o.lowerType(enum_type.tag_ty.toType())};9417 });
89619418
8962 const llvm_ret_ty = try o.lowerType(Type.bool);9419 const fn_type = try o.builder.fnType(.i1, &.{
8963 const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False);9420 try o.lowerType(enum_type.tag_ty.toType()),
8964 const fn_val = o.llvm_module.addFunction(llvm_fn_name, fn_type);9421 }, .normal);
9422 const fn_val = o.llvm_module.addFunction(llvm_fn_name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));
8965 fn_val.setLinkage(.Internal);9423 fn_val.setLinkage(.Internal);
8966 fn_val.setFunctionCallConv(.Fast);9424 fn_val.setFunctionCallConv(.Fast);
8967 o.addCommonFnAttributes(fn_val);9425 o.addCommonFnAttributes(fn_val);
8968 gop.value_ptr.* = fn_val;
89699426
8970 const prev_block = self.builder.getInsertBlock();9427 var global = Builder.Global{
8971 const prev_debug_location = self.builder.getCurrentDebugLocation2();9428 .linkage = .internal,
8972 defer {9429 .type = fn_type,
8973 self.builder.positionBuilderAtEnd(prev_block);9430 .kind = .{ .function = @enumFromInt(o.builder.functions.items.len) },
8974 if (self.di_scope != null) {9431 };
8975 self.builder.setCurrentDebugLocation2(prev_debug_location);9432 var function = Builder.Function{
8976 }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);
8977 }9455 }
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");9459 wip.cursor = .{ .block = unnamed_block };
8980 self.builder.positionBuilderAtEnd(entry_block);9460 _ = try wip.ret(Builder.Constant.false.toValue());
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));
90009461
9001 self.builder.positionBuilderAtEnd(unnamed_block);9462 try wip.finish();
9002 _ = self.builder.buildRet(self.context.intType(1).constInt(0, .False));9463 return global.kind.function;
9003 return fn_val;
9004 }9464 }
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;
9007 const un_op = self.air.instructions.items(.data)[inst].un_op;9468 const un_op = self.air.instructions.items(.data)[inst].un_op;
9008 const operand = try self.resolveInst(un_op);9469 const operand = try self.resolveInst(un_op);
9009 const enum_ty = self.typeOf(un_op);9470 const enum_ty = self.typeOf(un_op);
90109471
9011 const llvm_fn = try self.getEnumTagNameFunction(enum_ty);9472 const llvm_fn = try self.getEnumTagNameFunction(enum_ty);
9012 const params = [_]*llvm.Value{operand};9473 const llvm_fn_ty = llvm_fn.typeOf(&o.builder);
9013 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, "");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 );
9014 }9487 }
90159488
9016 fn getEnumTagNameFunction(self: *FuncGen, enum_ty: Type) !*llvm.Value {9489 fn getEnumTagNameFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index {
9017 const o = self.dg.object;9490 const o = self.dg.object;
9018 const mod = o.module;9491 const mod = o.module;
9019 const enum_type = mod.intern_pool.indexToKey(enum_ty.toIntern()).enum_type;9492 const enum_type = mod.intern_pool.indexToKey(enum_ty.toIntern()).enum_type;
90209493
9021 // TODO: detect when the type changes and re-emit this function.9494 // TODO: detect when the type changes and re-emit this function.
9022 const gop = try o.decl_map.getOrPut(o.gpa, enum_type.decl);9495 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;
9024 errdefer assert(o.decl_map.remove(enum_type.decl));9497 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
9030 const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);9499 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)});9500 const llvm_fn_name = try o.builder.fmt("__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);
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);9505 const fn_type = try o.builder.fnType(ret_ty, &.{
9041 const fn_val = o.llvm_module.addFunction(llvm_fn_name, fn_type);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));
9042 fn_val.setLinkage(.Internal);9509 fn_val.setLinkage(.Internal);
9043 fn_val.setFunctionCallConv(.Fast);9510 fn_val.setFunctionCallConv(.Fast);
9044 o.addCommonFnAttributes(fn_val);9511 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");9513 var global = Builder.Global{
9061 const tag_int_value = fn_val.getParam(0);9514 .linkage = .internal,
9062 const switch_instr = self.builder.buildSwitch(tag_int_value, bad_value_block, @as(c_uint, @intCast(enum_type.names.len)));9515 .type = fn_type,
90639516 .kind = .{ .function = @enumFromInt(o.builder.functions.items.len) },
9064 const array_ptr_indices = [_]*llvm.Value{
9065 usize_llvm_ty.constNull(), usize_llvm_ty.constNull(),
9066 };9517 };
90679518 var function = Builder.Function{
9068 for (enum_type.names, 0..) |name_ip, field_index_usize| {9519 .global = @enumFromInt(o.builder.globals.count()),
9069 const field_index = @as(u32, @intCast(field_index_usize));9520 };
9070 const name = mod.intern_pool.stringToSlice(name_ip);9521 try o.builder.llvm.globals.append(self.gpa, fn_val);
9071 const str_init = self.context.constString(name.ptr, @as(c_uint, @intCast(name.len)), .False);9522 gop.value_ptr.* = try o.builder.addGlobal(llvm_fn_name, global);
9072 const str_init_llvm_ty = str_init.typeOf();9523 try o.builder.functions.append(self.gpa, function);
9073 const str_global = o.llvm_module.addGlobal(str_init_llvm_ty, "");9524
9074 str_global.setInitializer(str_init);9525 var wip = try Builder.WipFunction.init(&o.builder, global.kind.function);
9075 str_global.setLinkage(.Private);9526 defer wip.deinit();
9076 str_global.setGlobalConstant(.True);9527 wip.cursor = .{ .block = try wip.block(0, "Entry") };
9077 str_global.setUnnamedAddr(.True);9528
9078 str_global.setAlignment(1);9529 const bad_value_block = try wip.block(1, "BadValue");
90799530 const tag_int_value = wip.arg(0);
9080 const slice_fields = [_]*llvm.Value{9531 var wip_switch =
9081 str_init_llvm_ty.constInBoundsGEP(str_global, &array_ptr_indices, array_ptr_indices.len),9532 try wip.@"switch"(tag_int_value, bad_value_block, @intCast(enum_type.names.len));
9082 usize_llvm_ty.constInt(name.len, .False),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),
9083 };9557 };
9084 const slice_init = llvm_ret_ty.constNamedStruct(&slice_fields, slice_fields.len);9558 try o.builder.llvm.globals.append(o.gpa, str_llvm_global);
9085 const slice_global = o.llvm_module.addGlobal(slice_init.typeOf(), "");9559 const global_index = try o.builder.addGlobal(.empty, str_global);
9086 slice_global.setInitializer(slice_init);9560 try o.builder.variables.append(o.gpa, str_variable);
9087 slice_global.setLinkage(.Private);9561
9088 slice_global.setGlobalConstant(.True);9562 const slice_val = try o.builder.structValue(ret_ty, &.{
9089 slice_global.setUnnamedAddr(.True);9563 global_index.toConst(),
9090 slice_global.setAlignment(slice_alignment);9564 try o.builder.intConst(usize_ty, name.toSlice(&o.builder).?.len),
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),
9096 });9565 });
9097 switch_instr.addCase(this_tag_int_value, return_block);
90989566
9099 self.builder.positionBuilderAtEnd(return_block);9567 const return_block = try wip.block(1, "Name");
9100 const loaded = self.builder.buildLoad(llvm_ret_ty, slice_global, "");9568 const this_tag_int_value = try o.lowerValue(
9101 loaded.setAlignment(slice_alignment);9569 (try mod.enumValueFieldIndex(enum_ty, @intCast(field_index))).toIntern(),
9102 _ = self.builder.buildRet(loaded);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);
9103 }9575 }
91049576
9105 self.builder.positionBuilderAtEnd(bad_value_block);9577 wip.cursor = .{ .block = bad_value_block };
9106 _ = self.builder.buildUnreachable();9578 _ = try wip.@"unreachable"();
9107 return fn_val;9579
9580 try wip.finish();
9581 return global.kind.function;
9108 }9582 }
91099583
9110 fn getCmpLtErrorsLenFunction(self: *FuncGen) !*llvm.Value {9584 fn getCmpLtErrorsLenFunction(self: *FuncGen) !Builder.Function.Index {
9111 const o = self.dg.object;9585 const o = self.dg.object;
91129586
9113 if (o.llvm_module.getNamedFunction(lt_errors_fn_name)) |llvm_fn| {9587 const name = try o.builder.string(lt_errors_fn_name);
9114 return llvm_fn;9588 if (o.builder.getGlobal(name)) |llvm_fn| return llvm_fn.ptrConst(&o.builder).kind.function;
9115 }
91169589
9117 // Function signature: fn (anyerror) bool9590 // Function signature: fn (anyerror) bool
91189591
9119 const ret_llvm_ty = try o.lowerType(Type.bool);9592 const fn_type = try o.builder.fnType(.i1, &.{Builder.Type.err_int}, .normal);
9120 const anyerror_llvm_ty = try o.lowerType(Type.anyerror);9593 const llvm_fn = o.llvm_module.addFunction(name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));
9121 const param_types = [_]*llvm.Type{anyerror_llvm_ty};
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);
9125 llvm_fn.setLinkage(.Internal);9595 llvm_fn.setLinkage(.Internal);
9126 llvm_fn.setFunctionCallConv(.Fast);9596 llvm_fn.setFunctionCallConv(.Fast);
9127 o.addCommonFnAttributes(llvm_fn);9597 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;
9129 }9612 }
91309613
9131 fn airErrorName(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {9614 fn airErrorName(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9132 const o = self.dg.object;9615 const o = self.dg.object;
9133 const un_op = self.air.instructions.items(.data)[inst].un_op;9616 const un_op = self.air.instructions.items(.data)[inst].un_op;
9134 const operand = try self.resolveInst(un_op);9617 const operand = try self.resolveInst(un_op);
...@@ -9136,34 +9619,32 @@ pub const FuncGen = struct {...@@ -9136,34 +9619,32 @@ pub const FuncGen = struct {
9136 const slice_llvm_ty = try o.lowerType(slice_ty);9619 const slice_llvm_ty = try o.lowerType(slice_ty);
91379620
9138 const error_name_table_ptr = try self.getErrorNameTable();9621 const error_name_table_ptr = try self.getErrorNameTable();
9139 const ptr_slice_llvm_ty = self.context.pointerType(0);9622 const error_name_table =
9140 const error_name_table = self.builder.buildLoad(ptr_slice_llvm_ty, error_name_table_ptr, "");9623 try self.wip.load(.normal, .ptr, error_name_table_ptr.toValue(&o.builder), .default, "");
9141 const indices = [_]*llvm.Value{operand};9624 const error_name_ptr =
9142 const error_name_ptr = self.builder.buildInBoundsGEP(slice_llvm_ty, error_name_table, &indices, indices.len, "");9625 try self.wip.gep(.inbounds, slice_llvm_ty, error_name_table, &.{operand}, "");
9143 return self.builder.buildLoad(slice_llvm_ty, error_name_ptr, "");9626 return self.wip.load(.normal, slice_llvm_ty, error_name_ptr, .default, "");
9144 }9627 }
91459628
9146 fn airSplat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {9629 fn airSplat(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9147 const o = self.dg.object;9630 const o = self.dg.object;
9148 const mod = o.module;
9149 const ty_op = self.air.instructions.items(.data)[inst].ty_op;9631 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
9150 const scalar = try self.resolveInst(ty_op.operand);9632 const scalar = try self.resolveInst(ty_op.operand);
9151 const vector_ty = self.typeOfIndex(inst);9633 const vector_ty = self.typeOfIndex(inst);
9152 const len = vector_ty.vectorLen(mod);9634 return self.wip.splatVector(try o.lowerType(vector_ty), scalar, "");
9153 return self.builder.buildVectorSplat(len, scalar, "");
9154 }9635 }
91559636
9156 fn airSelect(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {9637 fn airSelect(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9157 const pl_op = self.air.instructions.items(.data)[inst].pl_op;9638 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
9158 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;9639 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
9159 const pred = try self.resolveInst(pl_op.operand);9640 const pred = try self.resolveInst(pl_op.operand);
9160 const a = try self.resolveInst(extra.lhs);9641 const a = try self.resolveInst(extra.lhs);
9161 const b = try self.resolveInst(extra.rhs);9642 const b = try self.resolveInst(extra.rhs);
91629643
9163 return self.builder.buildSelect(pred, a, b, "");9644 return self.wip.select(pred, a, b, "");
9164 }9645 }
91659646
9166 fn airShuffle(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {9647 fn airShuffle(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9167 const o = self.dg.object;9648 const o = self.dg.object;
9168 const mod = o.module;9649 const mod = o.module;
9169 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;9650 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -9179,24 +9660,25 @@ pub const FuncGen = struct {...@@ -9179,24 +9660,25 @@ pub const FuncGen = struct {
9179 // when changing code, so Zig uses negative numbers to index the9660 // when changing code, so Zig uses negative numbers to index the
9180 // second vector. These start at -1 and go down, and are easiest to use9661 // second vector. These start at -1 and go down, and are easiest to use
9181 // with the ~ operator. Here we convert between the two formats.9662 // 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);
9183 defer self.gpa.free(values);9664 defer self.gpa.free(values);
91849665
9185 const llvm_i32 = self.context.intType(32);
9186
9187 for (values, 0..) |*val, i| {9666 for (values, 0..) |*val, i| {
9188 const elem = try mask.elemValue(mod, i);9667 const elem = try mask.elemValue(mod, i);
9189 if (elem.isUndef(mod)) {9668 if (elem.isUndef(mod)) {
9190 val.* = llvm_i32.getUndef();9669 val.* = try o.builder.undefConst(.i32);
9191 } else {9670 } else {
9192 const int = elem.toSignedInt(mod);9671 const int = elem.toSignedInt(mod);
9193 const unsigned = if (int >= 0) @as(u32, @intCast(int)) else @as(u32, @intCast(~int + a_len));9672 const unsigned: u32 = @intCast(if (int >= 0) int else ~int + a_len);
9194 val.* = llvm_i32.constInt(unsigned, .False);9673 val.* = try o.builder.intConst(.i32, unsigned);
9195 }9674 }
9196 }9675 }
91979676
9198 const llvm_mask_value = llvm.constVector(values.ptr, mask_len);9677 const llvm_mask_value = try o.builder.vectorValue(
9199 return self.builder.buildShuffleVector(a, b, llvm_mask_value, "");9678 try o.builder.vectorType(.normal, mask_len, .i32),
9679 values,
9680 );
9681 return self.wip.shuffleVector(a, b, llvm_mask_value, "");
9200 }9682 }
92019683
9202 /// Reduce a vector by repeatedly applying `llvm_fn` to produce an accumulated result.9684 /// Reduce a vector by repeatedly applying `llvm_fn` to produce an accumulated result.
...@@ -9213,58 +9695,69 @@ pub const FuncGen = struct {...@@ -9213,58 +9695,69 @@ pub const FuncGen = struct {
9213 ///9695 ///
9214 fn buildReducedCall(9696 fn buildReducedCall(
9215 self: *FuncGen,9697 self: *FuncGen,
9216 llvm_fn: *llvm.Value,9698 llvm_fn: Builder.Function.Index,
9217 operand_vector: *llvm.Value,9699 operand_vector: Builder.Value,
9218 vector_len: usize,9700 vector_len: usize,
9219 accum_init: *llvm.Value,9701 accum_init: Builder.Value,
9220 ) !*llvm.Value {9702 ) !Builder.Value {
9221 const o = self.dg.object;9703 const o = self.dg.object;
9222 const llvm_usize_ty = try o.lowerType(Type.usize);9704 const usize_ty = try o.lowerType(Type.usize);
9223 const llvm_vector_len = llvm_usize_ty.constInt(vector_len, .False);9705 const llvm_vector_len = try o.builder.intValue(usize_ty, vector_len);
9224 const llvm_result_ty = accum_init.typeOf();9706 const llvm_result_ty = accum_init.typeOfWip(&self.wip);
92259707
9226 // Allocate and initialize our mutable variables9708 // Allocate and initialize our mutable variables
9227 const i_ptr = self.buildAlloca(llvm_usize_ty, null);9709 const i_ptr = try self.buildAlloca(usize_ty, .default);
9228 _ = self.builder.buildStore(llvm_usize_ty.constInt(0, .False), i_ptr);9710 _ = try self.wip.store(.normal, try o.builder.intValue(usize_ty, 0), i_ptr, .default);
9229 const accum_ptr = self.buildAlloca(llvm_result_ty, null);9711 const accum_ptr = try self.buildAlloca(llvm_result_ty, .default);
9230 _ = self.builder.buildStore(accum_init, accum_ptr);9712 _ = try self.wip.store(.normal, accum_init, accum_ptr, .default);
92319713
9232 // Setup the loop9714 // Setup the loop
9233 const loop = self.context.appendBasicBlock(self.llvm_func, "ReduceLoop");9715 const loop = try self.wip.block(2, "ReduceLoop");
9234 const loop_exit = self.context.appendBasicBlock(self.llvm_func, "AfterReduce");9716 const loop_exit = try self.wip.block(1, "AfterReduce");
9235 _ = self.builder.buildBr(loop);9717 _ = try self.wip.br(loop);
9236 {9718 {
9237 self.builder.positionBuilderAtEnd(loop);9719 self.wip.cursor = .{ .block = loop };
92389720
9239 // while (i < vec.len)9721 // while (i < vec.len)
9240 const i = self.builder.buildLoad(llvm_usize_ty, i_ptr, "");9722 const i = try self.wip.load(.normal, usize_ty, i_ptr, .default, "");
9241 const cond = self.builder.buildICmp(.ULT, i, llvm_vector_len, "");9723 const cond = try self.wip.icmp(.ult, i, llvm_vector_len, "");
9242 const loop_then = self.context.appendBasicBlock(self.llvm_func, "ReduceLoopThen");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
9246 {9728 {
9247 self.builder.positionBuilderAtEnd(loop_then);9729 self.wip.cursor = .{ .block = loop_then };
92489730
9249 // accum = f(accum, vec[i]);9731 // accum = f(accum, vec[i]);
9250 const accum = self.builder.buildLoad(llvm_result_ty, accum_ptr, "");9732 const accum = try self.wip.load(.normal, llvm_result_ty, accum_ptr, .default, "");
9251 const element = self.builder.buildExtractElement(operand_vector, i, "");9733 const element = try self.wip.extractElement(operand_vector, i, "");
9252 const params = [2]*llvm.Value{ accum, element };9734 const params = [2]*llvm.Value{ accum.toLlvm(&self.wip), element.toLlvm(&self.wip) };
9253 const new_accum = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .C, .Auto, "");9735 const new_accum = (try self.wip.unimplemented(llvm_result_ty, "")).finish(
9254 _ = self.builder.buildStore(new_accum, accum_ptr);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
9256 // i += 19749 // i += 1
9257 const new_i = self.builder.buildAdd(i, llvm_usize_ty.constInt(1, .False), "");9750 const new_i = try self.wip.bin(.add, i, try o.builder.intValue(usize_ty, 1), "");
9258 _ = self.builder.buildStore(new_i, i_ptr);9751 _ = try self.wip.store(.normal, new_i, i_ptr, .default);
9259 _ = self.builder.buildBr(loop);9752 _ = try self.wip.br(loop);
9260 }9753 }
9261 }9754 }
92629755
9263 self.builder.positionBuilderAtEnd(loop_exit);9756 self.wip.cursor = .{ .block = loop_exit };
9264 return self.builder.buildLoad(llvm_result_ty, accum_ptr, "");9757 return self.wip.load(.normal, llvm_result_ty, accum_ptr, .default, "");
9265 }9758 }
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 {
9268 self.builder.setFastMath(want_fast_math);9761 self.builder.setFastMath(want_fast_math);
9269 const o = self.dg.object;9762 const o = self.dg.object;
9270 const mod = o.module;9763 const mod = o.module;
...@@ -9274,40 +9767,70 @@ pub const FuncGen = struct {...@@ -9274,40 +9767,70 @@ pub const FuncGen = struct {
9274 const operand = try self.resolveInst(reduce.operand);9767 const operand = try self.resolveInst(reduce.operand);
9275 const operand_ty = self.typeOf(reduce.operand);9768 const operand_ty = self.typeOf(reduce.operand);
9276 const scalar_ty = self.typeOfIndex(inst);9769 const scalar_ty = self.typeOfIndex(inst);
9770 const llvm_scalar_ty = try o.lowerType(scalar_ty);
92779771
9278 switch (reduce.operation) {9772 switch (reduce.operation) {
9279 .And => return self.builder.buildAndReduce(operand),9773 .And => return (try self.wip.unimplemented(llvm_scalar_ty, ""))
9280 .Or => return self.builder.buildOrReduce(operand),9774 .finish(self.builder.buildAndReduce(operand.toLlvm(&self.wip)), &self.wip),
9281 .Xor => return self.builder.buildXorReduce(operand),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),
9282 .Min => switch (scalar_ty.zigTypeTag(mod)) {9779 .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 ),
9284 .Float => if (intrinsicsAllowed(scalar_ty, target)) {9787 .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);
9286 },9790 },
9287 else => unreachable,9791 else => unreachable,
9288 },9792 },
9289 .Max => switch (scalar_ty.zigTypeTag(mod)) {9793 .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 ),
9291 .Float => if (intrinsicsAllowed(scalar_ty, target)) {9801 .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);
9293 },9804 },
9294 else => unreachable,9805 else => unreachable,
9295 },9806 },
9296 .Add => switch (scalar_ty.zigTypeTag(mod)) {9807 .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),
9298 .Float => if (intrinsicsAllowed(scalar_ty, target)) {9810 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
9299 const scalar_llvm_ty = try o.lowerType(scalar_ty);9811 const neutral_value = try o.builder.fpConst(llvm_scalar_ty, -0.0);
9300 const neutral_value = scalar_llvm_ty.constReal(-0.0);9812 return (try self.wip.unimplemented(llvm_scalar_ty, "")).finish(
9301 return self.builder.buildFPAddReduce(neutral_value, operand);9813 self.builder.buildFPAddReduce(
9814 neutral_value.toLlvm(&o.builder),
9815 operand.toLlvm(&self.wip),
9816 ),
9817 &self.wip,
9818 );
9302 },9819 },
9303 else => unreachable,9820 else => unreachable,
9304 },9821 },
9305 .Mul => switch (scalar_ty.zigTypeTag(mod)) {9822 .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),
9307 .Float => if (intrinsicsAllowed(scalar_ty, target)) {9825 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
9308 const scalar_llvm_ty = try o.lowerType(scalar_ty);9826 const neutral_value = try o.builder.fpConst(llvm_scalar_ty, 1.0);
9309 const neutral_value = scalar_llvm_ty.constReal(1.0);9827 return (try self.wip.unimplemented(llvm_scalar_ty, "")).finish(
9310 return self.builder.buildFPMulReduce(neutral_value, operand);9828 self.builder.buildFPMulReduce(
9829 neutral_value.toLlvm(&o.builder),
9830 operand.toLlvm(&self.wip),
9831 ),
9832 &self.wip,
9833 );
9311 },9834 },
9312 else => unreachable,9835 else => unreachable,
9313 },9836 },
...@@ -9315,58 +9838,71 @@ pub const FuncGen = struct {...@@ -9315,58 +9838,71 @@ pub const FuncGen = struct {
93159838
9316 // Reduction could not be performed with intrinsics.9839 // Reduction could not be performed with intrinsics.
9317 // Use a manual loop over a softfloat call instead.9840 // Use a manual loop over a softfloat call instead.
9318 var fn_name_buf: [64]u8 = undefined;
9319 const float_bits = scalar_ty.floatBits(target);9841 const float_bits = scalar_ty.floatBits(target);
9320 const fn_name = switch (reduce.operation) {9842 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}", .{
9322 libcFloatPrefix(float_bits), libcFloatSuffix(float_bits),9844 libcFloatPrefix(float_bits), libcFloatSuffix(float_bits),
9323 }) catch unreachable,9845 }),
9324 .Max => std.fmt.bufPrintZ(&fn_name_buf, "{s}fmax{s}", .{9846 .Max => try o.builder.fmt("{s}fmax{s}", .{
9325 libcFloatPrefix(float_bits), libcFloatSuffix(float_bits),9847 libcFloatPrefix(float_bits), libcFloatSuffix(float_bits),
9326 }) catch unreachable,9848 }),
9327 .Add => std.fmt.bufPrintZ(&fn_name_buf, "__add{s}f3", .{9849 .Add => try o.builder.fmt("__add{s}f3", .{
9328 compilerRtFloatAbbrev(float_bits),9850 compilerRtFloatAbbrev(float_bits),
9329 }) catch unreachable,9851 }),
9330 .Mul => std.fmt.bufPrintZ(&fn_name_buf, "__mul{s}f3", .{9852 .Mul => try o.builder.fmt("__mul{s}f3", .{
9331 compilerRtFloatAbbrev(float_bits),9853 compilerRtFloatAbbrev(float_bits),
9332 }) catch unreachable,9854 }),
9333 else => unreachable,9855 else => unreachable,
9334 };9856 };
93359857
9336 const param_llvm_ty = try o.lowerType(scalar_ty);9858 const libc_fn =
9337 const param_types = [2]*llvm.Type{ param_llvm_ty, param_llvm_ty };9859 try self.getLibcFunction(fn_name, &.{ llvm_scalar_ty, llvm_scalar_ty }, llvm_scalar_ty);
9338 const libc_fn = self.getLibcFunction(fn_name, &param_types, param_llvm_ty);9860 const init_val = switch (llvm_scalar_ty) {
9339 const init_value = try o.lowerValue(.{9861 .i16 => try o.builder.intValue(.i16, @as(i16, @bitCast(
9340 .ty = scalar_ty,9862 @as(f16, switch (reduce.operation) {
9341 .val = try mod.floatValue(scalar_ty, switch (reduce.operation) {9863 .Min, .Max => std.math.nan(f16),
9342 .Min => std.math.nan(f32),9864 .Add => -0.0,
9343 .Max => std.math.nan(f32),9865 .Mul => 1.0,
9344 .Add => -0.0,9866 else => unreachable,
9345 .Mul => 1.0,9867 }),
9346 else => unreachable,9868 ))),
9347 }),9869 .i80 => try o.builder.intValue(.i80, @as(i80, @bitCast(
9348 });9870 @as(f80, switch (reduce.operation) {
9349 return self.buildReducedCall(libc_fn, operand, operand_ty.vectorLen(mod), init_value);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);
9350 }9888 }
93519889
9352 fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {9890 fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9353 const o = self.dg.object;9891 const o = self.dg.object;
9354 const mod = o.module;9892 const mod = o.module;
9355 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;9893 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
9356 const result_ty = self.typeOfIndex(inst);9894 const result_ty = self.typeOfIndex(inst);
9357 const len = @as(usize, @intCast(result_ty.arrayLen(mod)));9895 const len: usize = @intCast(result_ty.arrayLen(mod));
9358 const elements = @as([]const Air.Inst.Ref, @ptrCast(self.air.extra[ty_pl.payload..][0..len]));9896 const elements: []const Air.Inst.Ref = @ptrCast(self.air.extra[ty_pl.payload..][0..len]);
9359 const llvm_result_ty = try o.lowerType(result_ty);9897 const llvm_result_ty = try o.lowerType(result_ty);
93609898
9361 switch (result_ty.zigTypeTag(mod)) {9899 switch (result_ty.zigTypeTag(mod)) {
9362 .Vector => {9900 .Vector => {
9363 const llvm_u32 = self.context.intType(32);9901 var vector = try o.builder.poisonValue(llvm_result_ty);
9364
9365 var vector = llvm_result_ty.getUndef();
9366 for (elements, 0..) |elem, i| {9902 for (elements, 0..) |elem, i| {
9367 const index_u32 = llvm_u32.constInt(i, .False);9903 const index_u32 = try o.builder.intValue(.i32, i);
9368 const llvm_elem = try self.resolveInst(elem);9904 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, "");
9370 }9906 }
9371 return vector;9907 return vector;
9372 },9908 },
...@@ -9375,48 +9911,47 @@ pub const FuncGen = struct {...@@ -9375,48 +9911,47 @@ pub const FuncGen = struct {
9375 const struct_obj = mod.typeToStruct(result_ty).?;9911 const struct_obj = mod.typeToStruct(result_ty).?;
9376 assert(struct_obj.haveLayout());9912 assert(struct_obj.haveLayout());
9377 const big_bits = struct_obj.backing_int_ty.bitSize(mod);9913 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));
9379 const fields = struct_obj.fields.values();9915 const fields = struct_obj.fields.values();
9380 comptime assert(Type.packed_struct_layout_version == 2);9916 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);
9382 var running_bits: u16 = 0;9918 var running_bits: u16 = 0;
9383 for (elements, 0..) |elem, i| {9919 for (elements, 0..) |elem, i| {
9384 const field = fields[i];9920 const field = fields[i];
9385 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;9921 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
93869922
9387 const non_int_val = try self.resolveInst(elem);9923 const non_int_val = try self.resolveInst(elem);
9388 const ty_bit_size = @as(u16, @intCast(field.ty.bitSize(mod)));9924 const ty_bit_size: u16 = @intCast(field.ty.bitSize(mod));
9389 const small_int_ty = self.context.intType(ty_bit_size);9925 const small_int_ty = try o.builder.intType(ty_bit_size);
9390 const small_int_val = if (field.ty.isPtrAtRuntime(mod))9926 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, "")
9392 else9928 else
9393 self.builder.buildBitCast(non_int_val, small_int_ty, "");9929 try self.wip.cast(.bitcast, non_int_val, small_int_ty, "");
9394 const shift_rhs = int_llvm_ty.constInt(running_bits, .False);9930 const shift_rhs = try o.builder.intValue(int_ty, running_bits);
9395 // If the field is as large as the entire packed struct, this9931 // If the field is as large as the entire packed struct, this
9396 // zext would go from, e.g. i16 to i16. This is legal with9932 // zext would go from, e.g. i16 to i16. This is legal with
9397 // constZExtOrBitCast but not legal with constZExt.9933 // constZExtOrBitCast but not legal with constZExt.
9398 const extended_int_val = self.builder.buildZExtOrBitCast(small_int_val, int_llvm_ty, "");9934 const extended_int_val = try self.wip.conv(.unsigned, small_int_val, int_ty, "");
9399 const shifted = self.builder.buildShl(extended_int_val, shift_rhs, "");9935 const shifted = try self.wip.bin(.shl, extended_int_val, shift_rhs, "");
9400 running_int = self.builder.buildOr(running_int, shifted, "");9936 running_int = try self.wip.bin(.@"or", running_int, shifted, "");
9401 running_bits += ty_bit_size;9937 running_bits += ty_bit_size;
9402 }9938 }
9403 return running_int;9939 return running_int;
9404 }9940 }
94059941
9406 if (isByRef(result_ty, mod)) {9942 if (isByRef(result_ty, mod)) {
9407 const llvm_u32 = self.context.intType(32);
9408 // TODO in debug builds init to undef so that the padding will be 0xaa9943 // TODO in debug builds init to undef so that the padding will be 0xaa
9409 // even if we fully populate the fields.9944 // 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 };
9413 for (elements, 0..) |elem, i| {9948 for (elements, 0..) |elem, i| {
9414 if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue;9949 if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue;
94159950
9416 const llvm_elem = try self.resolveInst(elem);9951 const llvm_elem = try self.resolveInst(elem);
9417 const llvm_i = llvmField(result_ty, i, mod).?.index;9952 const llvm_i = llvmField(result_ty, i, mod).?.index;
9418 indices[1] = llvm_u32.constInt(llvm_i, .False);9953 const field_ptr =
9419 const field_ptr = self.builder.buildInBoundsGEP(llvm_result_ty, alloca_inst, &indices, indices.len, "");9954 try self.wip.gepStruct(llvm_result_ty, alloca_inst, llvm_i, "");
9420 const field_ptr_ty = try mod.ptrType(.{9955 const field_ptr_ty = try mod.ptrType(.{
9421 .child = self.typeOf(elem).toIntern(),9956 .child = self.typeOf(elem).toIntern(),
9422 .flags = .{9957 .flags = .{
...@@ -9425,18 +9960,18 @@ pub const FuncGen = struct {...@@ -9425,18 +9960,18 @@ pub const FuncGen = struct {
9425 ),9960 ),
9426 },9961 },
9427 });9962 });
9428 try self.store(field_ptr, field_ptr_ty, llvm_elem, .NotAtomic);9963 try self.store(field_ptr, field_ptr_ty, llvm_elem, .none);
9429 }9964 }
94309965
9431 return alloca_inst;9966 return alloca_inst;
9432 } else {9967 } else {
9433 var result = llvm_result_ty.getUndef();9968 var result = try o.builder.poisonValue(llvm_result_ty);
9434 for (elements, 0..) |elem, i| {9969 for (elements, 0..) |elem, i| {
9435 if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue;9970 if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue;
94369971
9437 const llvm_elem = try self.resolveInst(elem);9972 const llvm_elem = try self.resolveInst(elem);
9438 const llvm_i = llvmField(result_ty, i, mod).?.index;9973 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}, "");
9440 }9975 }
9441 return result;9976 return result;
9442 }9977 }
...@@ -9445,7 +9980,9 @@ pub const FuncGen = struct {...@@ -9445,7 +9980,9 @@ pub const FuncGen = struct {
9445 assert(isByRef(result_ty, mod));9980 assert(isByRef(result_ty, mod));
94469981
9447 const llvm_usize = try o.lowerType(Type.usize);9982 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
9450 const array_info = result_ty.arrayInfo(mod);9987 const array_info = result_ty.arrayInfo(mod);
9451 const elem_ptr_ty = try mod.ptrType(.{9988 const elem_ptr_ty = try mod.ptrType(.{
...@@ -9453,26 +9990,21 @@ pub const FuncGen = struct {...@@ -9453,26 +9990,21 @@ pub const FuncGen = struct {
9453 });9990 });
94549991
9455 for (elements, 0..) |elem, i| {9992 for (elements, 0..) |elem, i| {
9456 const indices: [2]*llvm.Value = .{9993 const elem_ptr = try self.wip.gep(.inbounds, llvm_result_ty, alloca_inst, &.{
9457 llvm_usize.constNull(),9994 usize_zero, try o.builder.intValue(llvm_usize, i),
9458 llvm_usize.constInt(@as(c_uint, @intCast(i)), .False),9995 }, "");
9459 };
9460 const elem_ptr = self.builder.buildInBoundsGEP(llvm_result_ty, alloca_inst, &indices, indices.len, "");
9461 const llvm_elem = try self.resolveInst(elem);9996 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);
9463 }9998 }
9464 if (array_info.sentinel) |sent_val| {9999 if (array_info.sentinel) |sent_val| {
9465 const indices: [2]*llvm.Value = .{10000 const elem_ptr = try self.wip.gep(.inbounds, llvm_result_ty, alloca_inst, &.{
9466 llvm_usize.constNull(),10001 usize_zero, try o.builder.intValue(llvm_usize, array_info.len),
9467 llvm_usize.constInt(@as(c_uint, @intCast(array_info.len)), .False),10002 }, "");
9468 };
9469 const elem_ptr = self.builder.buildInBoundsGEP(llvm_result_ty, alloca_inst, &indices, indices.len, "");
9470 const llvm_elem = try self.resolveValue(.{10003 const llvm_elem = try self.resolveValue(.{
9471 .ty = array_info.elem_type,10004 .ty = array_info.elem_type,
9472 .val = sent_val,10005 .val = sent_val,
9473 });10006 });
947410007 try self.store(elem_ptr, elem_ptr_ty, llvm_elem.toValue(), .none);
9475 try self.store(elem_ptr, elem_ptr_ty, llvm_elem, .NotAtomic);
9476 }10008 }
947710009
9478 return alloca_inst;10010 return alloca_inst;
...@@ -9481,7 +10013,7 @@ pub const FuncGen = struct {...@@ -9481,7 +10013,7 @@ pub const FuncGen = struct {
9481 }10013 }
9482 }10014 }
948310015
9484 fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {10016 fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9485 const o = self.dg.object;10017 const o = self.dg.object;
9486 const mod = o.module;10018 const mod = o.module;
9487 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;10019 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -9493,16 +10025,15 @@ pub const FuncGen = struct {...@@ -9493,16 +10025,15 @@ pub const FuncGen = struct {
949310025
9494 if (union_obj.layout == .Packed) {10026 if (union_obj.layout == .Packed) {
9495 const big_bits = union_ty.bitSize(mod);10027 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));
9497 const field = union_obj.fields.values()[extra.field_index];10029 const field = union_obj.fields.values()[extra.field_index];
9498 const non_int_val = try self.resolveInst(extra.init);10030 const non_int_val = try self.resolveInst(extra.init);
9499 const ty_bit_size = @as(u16, @intCast(field.ty.bitSize(mod)));10031 const small_int_ty = try o.builder.intType(@intCast(field.ty.bitSize(mod)));
9500 const small_int_ty = self.context.intType(ty_bit_size);
9501 const small_int_val = if (field.ty.isPtrAtRuntime(mod))10032 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, "")
9503 else10034 else
9504 self.builder.buildBitCast(non_int_val, small_int_ty, "");10035 try self.wip.cast(.bitcast, non_int_val, small_int_ty, "");
9505 return self.builder.buildZExtOrBitCast(small_int_val, int_llvm_ty, "");10036 return self.wip.conv(.unsigned, small_int_val, int_llvm_ty, "");
9506 }10037 }
950710038
9508 const tag_int = blk: {10039 const tag_int = blk: {
...@@ -9515,106 +10046,96 @@ pub const FuncGen = struct {...@@ -9515,106 +10046,96 @@ pub const FuncGen = struct {
9515 };10046 };
9516 if (layout.payload_size == 0) {10047 if (layout.payload_size == 0) {
9517 if (layout.tag_size == 0) {10048 if (layout.tag_size == 0) {
9518 return null;10049 return .none;
9519 }10050 }
9520 assert(!isByRef(union_ty, mod));10051 assert(!isByRef(union_ty, mod));
9521 return union_llvm_ty.constInt(tag_int, .False);10052 return o.builder.intValue(union_llvm_ty, tag_int);
9522 }10053 }
9523 assert(isByRef(union_ty, mod));10054 assert(isByRef(union_ty, mod));
9524 // The llvm type of the alloca will be the named LLVM union type, and will not10055 // The llvm type of the alloca will be the named LLVM union type, and will not
9525 // necessarily match the format that we need, depending on which tag is active.10056 // necessarily match the format that we need, depending on which tag is active.
9526 // We must construct the correct unnamed struct type here, in order to then set10057 // We must construct the correct unnamed struct type here, in order to then set
9527 // the fields appropriately.10058 // 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);
9529 const llvm_payload = try self.resolveInst(extra.init);10061 const llvm_payload = try self.resolveInst(extra.init);
9530 assert(union_obj.haveFieldTypes());10062 assert(union_obj.haveFieldTypes());
9531 const field = union_obj.fields.values()[extra.field_index];10063 const field = union_obj.fields.values()[extra.field_index];
9532 const field_llvm_ty = try o.lowerType(field.ty);10064 const field_llvm_ty = try o.lowerType(field.ty);
9533 const field_size = field.ty.abiSize(mod);10065 const field_size = field.ty.abiSize(mod);
9534 const field_align = field.normalAlignment(mod);10066 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
9536 const llvm_union_ty = t: {10071 const llvm_union_ty = t: {
9537 const payload = p: {10072 const payload_ty = p: {
9538 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) {10073 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) {
9539 const padding_len = @as(c_uint, @intCast(layout.payload_size));10074 const padding_len = layout.payload_size;
9540 break :p self.context.intType(8).arrayType(padding_len);10075 break :p try o.builder.arrayType(padding_len, .i8);
9541 }10076 }
9542 if (field_size == layout.payload_size) {10077 if (field_size == layout.payload_size) {
9543 break :p field_llvm_ty;10078 break :p field_llvm_ty;
9544 }10079 }
9545 const padding_len = @as(c_uint, @intCast(layout.payload_size - field_size));10080 const padding_len = layout.payload_size - field_size;
9546 const fields: [2]*llvm.Type = .{10081 break :p try o.builder.structType(.@"packed", &.{
9547 field_llvm_ty, self.context.intType(8).arrayType(padding_len),10082 field_llvm_ty, try o.builder.arrayType(padding_len, .i8),
9548 };10083 });
9549 break :p self.context.structType(&fields, fields.len, .True);
9550 };10084 };
9551 if (layout.tag_size == 0) {10085 if (layout.tag_size == 0) break :t try o.builder.structType(.normal, &.{payload_ty});
9552 const fields: [1]*llvm.Type = .{payload};10086 const tag_ty = try o.lowerType(union_obj.tag_ty);
9553 break :t self.context.structType(&fields, fields.len, .False);10087 var fields: [3]Builder.Type = undefined;
9554 }10088 var fields_len: usize = 2;
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;
9558 if (layout.tag_align >= layout.payload_align) {10089 if (layout.tag_align >= layout.payload_align) {
9559 fields = .{ tag_llvm_ty, payload, undefined };10090 fields = .{ tag_ty, payload_ty, undefined };
9560 } else {10091 } else {
9561 fields = .{ payload, tag_llvm_ty, undefined };10092 fields = .{ payload_ty, tag_ty, undefined };
9562 }10093 }
9563 if (layout.padding != 0) {10094 if (layout.padding != 0) {
9564 fields[2] = self.context.intType(8).arrayType(layout.padding);10095 fields[fields_len] = try o.builder.arrayType(layout.padding, .i8);
9565 fields_len = 3;10096 fields_len += 1;
9566 }10097 }
9567 break :t self.context.structType(&fields, fields_len, .False);10098 break :t try o.builder.structType(.normal, fields[0..fields_len]);
9568 };10099 };
956910100
9570 // Now we follow the layout as expressed above with GEP instructions to set the10101 // Now we follow the layout as expressed above with GEP instructions to set the
9571 // tag and the payload.10102 // tag and the payload.
9572 const index_type = self.context.intType(32);
9573
9574 const field_ptr_ty = try mod.ptrType(.{10103 const field_ptr_ty = try mod.ptrType(.{
9575 .child = field.ty.toIntern(),10104 .child = field.ty.toIntern(),
9576 .flags = .{10105 .flags = .{ .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_align) },
9577 .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_align),
9578 },
9579 });10106 });
9580 if (layout.tag_size == 0) {10107 if (layout.tag_size == 0) {
9581 const indices: [3]*llvm.Value = .{10108 const indices = [3]Builder.Value{ usize_zero, i32_zero, i32_zero };
9582 index_type.constNull(),10109 const len: usize = if (field_size == layout.payload_size) 2 else 3;
9583 index_type.constNull(),10110 const field_ptr =
9584 index_type.constNull(),10111 try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, indices[0..len], "");
9585 };10112 try self.store(field_ptr, field_ptr_ty, llvm_payload, .none);
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);
9589 return result_ptr;10113 return result_ptr;
9590 }10114 }
959110115
9592 {10116 {
9593 const indices: [3]*llvm.Value = .{10117 const payload_index = @intFromBool(layout.tag_align >= layout.payload_align);
9594 index_type.constNull(),10118 const indices: [3]Builder.Value =
9595 index_type.constInt(@intFromBool(layout.tag_align >= layout.payload_align), .False),10119 .{ usize_zero, try o.builder.intValue(.i32, payload_index), i32_zero };
9596 index_type.constNull(),10120 const len: usize = if (field_size == layout.payload_size) 2 else 3;
9597 };10121 const field_ptr =
9598 const len: c_uint = if (field_size == layout.payload_size) 2 else 3;10122 try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, indices[0..len], "");
9599 const field_ptr = self.builder.buildInBoundsGEP(llvm_union_ty, result_ptr, &indices, len, "");10123 try self.store(field_ptr, field_ptr_ty, llvm_payload, .none);
9600 try self.store(field_ptr, field_ptr_ty, llvm_payload, .NotAtomic);
9601 }10124 }
9602 {10125 {
9603 const indices: [2]*llvm.Value = .{10126 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);
9604 index_type.constNull(),10127 const indices: [2]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, tag_index) };
9605 index_type.constInt(@intFromBool(layout.tag_align < layout.payload_align), .False),10128 const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, &indices, "");
9606 };10129 const tag_ty = try o.lowerType(union_obj.tag_ty);
9607 const field_ptr = self.builder.buildInBoundsGEP(llvm_union_ty, result_ptr, &indices, indices.len, "");10130 const llvm_tag = try o.builder.intValue(tag_ty, tag_int);
9608 const tag_llvm_ty = try o.lowerType(union_obj.tag_ty);10131 const tag_alignment = Builder.Alignment.fromByteUnits(union_obj.tag_ty.abiAlignment(mod));
9609 const llvm_tag = tag_llvm_ty.constInt(tag_int, .False);10132 _ = try self.wip.store(.normal, llvm_tag, field_ptr, tag_alignment);
9610 const store_inst = self.builder.buildStore(llvm_tag, field_ptr);
9611 store_inst.setAlignment(union_obj.tag_ty.abiAlignment(mod));
9612 }10133 }
961310134
9614 return result_ptr;10135 return result_ptr;
9615 }10136 }
961610137
9617 fn airPrefetch(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {10138 fn airPrefetch(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9618 const o = self.dg.object;10139 const o = self.dg.object;
9619 const prefetch = self.air.instructions.items(.data)[inst].prefetch;10140 const prefetch = self.air.instructions.items(.data)[inst].prefetch;
962010141
...@@ -9643,10 +10164,10 @@ pub const FuncGen = struct {...@@ -9643,10 +10164,10 @@ pub const FuncGen = struct {
9643 .powerpcle,10164 .powerpcle,
9644 .powerpc64,10165 .powerpc64,
9645 .powerpc64le,10166 .powerpc64le,
9646 => return null,10167 => return .none,
9647 .arm, .armeb, .thumb, .thumbeb => {10168 .arm, .armeb, .thumb, .thumbeb => {
9648 switch (prefetch.rw) {10169 switch (prefetch.rw) {
9649 .write => return null,10170 .write => return .none,
9650 else => {},10171 else => {},
9651 }10172 }
9652 },10173 },
...@@ -9655,58 +10176,64 @@ pub const FuncGen = struct {...@@ -9655,58 +10176,64 @@ pub const FuncGen = struct {
9655 .data => {},10176 .data => {},
9656 }10177 }
965710178
9658 const llvm_ptr_u8 = self.context.pointerType(0);
9659 const llvm_u32 = self.context.intType(32);
9660
9661 const llvm_fn_name = "llvm.prefetch.p0";10179 const llvm_fn_name = "llvm.prefetch.p0";
9662 const fn_val = o.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {10180 // declare void @llvm.prefetch(i8*, i32, i32, i32)
9663 // declare void @llvm.prefetch(i8*, i32, i32, i32)10181 const llvm_fn_ty = try o.builder.fnType(.void, &.{ .ptr, .i32, .i32, .i32 }, .normal);
9664 const llvm_void = self.context.voidType();10182 const fn_val = o.llvm_module.getNamedFunction(llvm_fn_name) orelse
9665 const param_types = [_]*llvm.Type{10183 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
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 };
967110184
9672 const ptr = try self.resolveInst(prefetch.ptr);10185 const ptr = try self.resolveInst(prefetch.ptr);
967310186
9674 const params = [_]*llvm.Value{10187 const params = [_]*llvm.Value{
9675 ptr,10188 ptr.toLlvm(&self.wip),
9676 llvm_u32.constInt(@intFromEnum(prefetch.rw), .False),10189 (try o.builder.intConst(.i32, @intFromEnum(prefetch.rw))).toLlvm(&o.builder),
9677 llvm_u32.constInt(prefetch.locality, .False),10190 (try o.builder.intConst(.i32, prefetch.locality)).toLlvm(&o.builder),
9678 llvm_u32.constInt(@intFromEnum(prefetch.cache), .False),10191 (try o.builder.intConst(.i32, @intFromEnum(prefetch.cache))).toLlvm(&o.builder),
9679 };10192 };
9680 _ = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, "");10193 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
9681 return null;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;
9682 }10203 }
968310204
9684 fn airAddrSpaceCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {10205 fn airAddrSpaceCast(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9685 const o = self.dg.object;10206 const o = self.dg.object;
9686 const ty_op = self.air.instructions.items(.data)[inst].ty_op;10207 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
9687 const inst_ty = self.typeOfIndex(inst);10208 const inst_ty = self.typeOfIndex(inst);
9688 const operand = try self.resolveInst(ty_op.operand);10209 const operand = try self.resolveInst(ty_op.operand);
968910210
9690 const llvm_dest_ty = try o.lowerType(inst_ty);10211 return self.wip.cast(.addrspacecast, operand, try o.lowerType(inst_ty), "");
9691 return self.builder.buildAddrSpaceCast(operand, llvm_dest_ty, "");
9692 }10212 }
969310213
9694 fn amdgcnWorkIntrinsic(self: *FuncGen, dimension: u32, default: u32, comptime basename: []const u8) !?*llvm.Value {10214 fn amdgcnWorkIntrinsic(self: *FuncGen, dimension: u32, default: u32, comptime basename: []const u8) !Builder.Value {
9695 const llvm_u32 = self.context.intType(32);10215 const o = self.dg.object;
9696
9697 const llvm_fn_name = switch (dimension) {10216 const llvm_fn_name = switch (dimension) {
9698 0 => basename ++ ".x",10217 0 => basename ++ ".x",
9699 1 => basename ++ ".y",10218 1 => basename ++ ".y",
9700 2 => basename ++ ".z",10219 2 => basename ++ ".z",
9701 else => return llvm_u32.constInt(default, .False),10220 else => return o.builder.intValue(.i32, default),
9702 };10221 };
970310222
9704 const args: [0]*llvm.Value = .{};10223 const args: [0]*llvm.Value = .{};
9705 const llvm_fn = self.getIntrinsic(llvm_fn_name, &.{});10224 const llvm_fn = try self.getIntrinsic(llvm_fn_name, &.{});
9706 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");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);
9707 }10234 }
970810235
9709 fn airWorkItemId(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {10236 fn airWorkItemId(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9710 const o = self.dg.object;10237 const o = self.dg.object;
9711 const target = o.module.getTarget();10238 const target = o.module.getTarget();
9712 assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures10239 assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures
...@@ -9716,37 +10243,41 @@ pub const FuncGen = struct {...@@ -9716,37 +10243,41 @@ pub const FuncGen = struct {
9716 return self.amdgcnWorkIntrinsic(dimension, 0, "llvm.amdgcn.workitem.id");10243 return self.amdgcnWorkIntrinsic(dimension, 0, "llvm.amdgcn.workitem.id");
9717 }10244 }
971810245
9719 fn airWorkGroupSize(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {10246 fn airWorkGroupSize(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9720 const o = self.dg.object;10247 const o = self.dg.object;
9721 const target = o.module.getTarget();10248 const target = o.module.getTarget();
9722 assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures10249 assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures
972310250
9724 const pl_op = self.air.instructions.items(.data)[inst].pl_op;10251 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
9725 const dimension = pl_op.payload;10252 const dimension = pl_op.payload;
9726 const llvm_u32 = self.context.intType(32);10253 if (dimension >= 3) return o.builder.intValue(.i32, 1);
9727 if (dimension >= 3) {
9728 return llvm_u32.constInt(1, .False);
9729 }
973010254
9731 // Fetch the dispatch pointer, which points to this structure:10255 // Fetch the dispatch pointer, which points to this structure:
9732 // https://github.com/RadeonOpenCompute/ROCR-Runtime/blob/adae6c61e10d371f7cbc3d0e94ae2c070cab18a4/src/inc/hsa.h#L291310256 // 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", &.{});
9734 const args: [0]*llvm.Value = .{};10258 const args: [0]*llvm.Value = .{};
9735 const dispatch_ptr = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");10259 const llvm_ret_ty = try o.builder.ptrType(Builder.AddrSpace.amdgpu.constant);
9736 dispatch_ptr.setAlignment(4);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
9738 // Load the work_group_* member from the struct as u16.10271 // Load the work_group_* member from the struct as u16.
9739 // Just treat the dispatch pointer as an array of u16 to keep things simple.10272 // Just treat the dispatch pointer as an array of u16 to keep things simple.
9740 const offset = 2 + dimension;10273 const workgroup_size_ptr = try self.wip.gep(.inbounds, .i16, dispatch_ptr, &.{
9741 const index = [_]*llvm.Value{llvm_u32.constInt(offset, .False)};10274 try o.builder.intValue(try o.lowerType(Type.usize), 2 + dimension),
9742 const llvm_u16 = self.context.intType(16);10275 }, "");
9743 const workgroup_size_ptr = self.builder.buildInBoundsGEP(llvm_u16, dispatch_ptr, &index, index.len, "");10276 const workgroup_size_alignment = comptime Builder.Alignment.fromByteUnits(2);
9744 const workgroup_size = self.builder.buildLoad(llvm_u16, workgroup_size_ptr, "");10277 return self.wip.load(.normal, .i16, workgroup_size_ptr, workgroup_size_alignment, "");
9745 workgroup_size.setAlignment(2);
9746 return workgroup_size;
9747 }10278 }
974810279
9749 fn airWorkGroupId(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {10280 fn airWorkGroupId(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9750 const o = self.dg.object;10281 const o = self.dg.object;
9751 const target = o.module.getTarget();10282 const target = o.module.getTarget();
9752 assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures10283 assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures
...@@ -9756,65 +10287,82 @@ pub const FuncGen = struct {...@@ -9756,65 +10287,82 @@ pub const FuncGen = struct {
9756 return self.amdgcnWorkIntrinsic(dimension, 0, "llvm.amdgcn.workgroup.id");10287 return self.amdgcnWorkIntrinsic(dimension, 0, "llvm.amdgcn.workgroup.id");
9757 }10288 }
975810289
9759 fn getErrorNameTable(self: *FuncGen) !*llvm.Value {10290 fn getErrorNameTable(self: *FuncGen) Allocator.Error!Builder.Variable.Index {
9760 const o = self.dg.object;10291 const o = self.dg.object;
9761 if (o.error_name_table) |table| {10292 const table = o.error_name_table;
9762 return table;10293 if (table != .none) return table;
9763 }
976410294
9765 const mod = o.module;10295 const mod = o.module;
9766 const slice_ty = Type.slice_const_u8_sentinel_0;10296 const slice_ty = Type.slice_const_u8_sentinel_0;
9767 const slice_alignment = slice_ty.abiAlignment(mod);10297 const slice_alignment = slice_ty.abiAlignment(mod);
9768 const llvm_slice_ptr_ty = self.context.pointerType(0); // TODO: Address space10298 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");10300 const name = try o.builder.string("__zig_err_name_table");
9771 error_name_table_global.setInitializer(llvm_slice_ptr_ty.getUndef());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));
9772 error_name_table_global.setLinkage(.Private);10303 error_name_table_global.setLinkage(.Private);
9773 error_name_table_global.setGlobalConstant(.True);10304 error_name_table_global.setGlobalConstant(.True);
9774 error_name_table_global.setUnnamedAddr(.True);10305 error_name_table_global.setUnnamedAddr(.True);
9775 error_name_table_global.setAlignment(slice_alignment);10306 error_name_table_global.setAlignment(slice_alignment);
977610307
9777 o.error_name_table = error_name_table_global;10308 var global = Builder.Global{
9778 return error_name_table_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;
9779 }10326 }
978010327
9781 /// Assumes the optional is not pointer-like and payload has bits.10328 /// Assumes the optional is not pointer-like and payload has bits.
9782 fn optIsNonNull(10329 fn optCmpNull(
9783 self: *FuncGen,10330 self: *FuncGen,
9784 opt_llvm_ty: *llvm.Type,10331 cond: Builder.IntegerCondition,
9785 opt_handle: *llvm.Value,10332 opt_llvm_ty: Builder.Type,
10333 opt_handle: Builder.Value,
9786 is_by_ref: bool,10334 is_by_ref: bool,
9787 ) *llvm.Value {10335 ) Allocator.Error!Builder.Value {
9788 const non_null_llvm_ty = self.context.intType(8);10336 const o = self.dg.object;
9789 const field = b: {10337 const field = b: {
9790 if (is_by_ref) {10338 if (is_by_ref) {
9791 const field_ptr = self.builder.buildStructGEP(opt_llvm_ty, opt_handle, 1, "");10339 const field_ptr = try self.wip.gepStruct(opt_llvm_ty, opt_handle, 1, "");
9792 break :b self.builder.buildLoad(non_null_llvm_ty, field_ptr, "");10340 break :b try self.wip.load(.normal, .i8, field_ptr, .default, "");
9793 }10341 }
9794 break :b self.builder.buildExtractValue(opt_handle, 1, "");10342 break :b try self.wip.extractValue(opt_handle, &.{1}, "");
9795 };10343 };
9796 comptime assert(optional_layout_version == 3);10344 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), "");
9799 }10347 }
980010348
9801 /// Assumes the optional is not pointer-like and payload has bits.10349 /// Assumes the optional is not pointer-like and payload has bits.
9802 fn optPayloadHandle(10350 fn optPayloadHandle(
9803 fg: *FuncGen,10351 fg: *FuncGen,
9804 opt_llvm_ty: *llvm.Type,10352 opt_llvm_ty: Builder.Type,
9805 opt_handle: *llvm.Value,10353 opt_handle: Builder.Value,
9806 opt_ty: Type,10354 opt_ty: Type,
9807 can_elide_load: bool,10355 can_elide_load: bool,
9808 ) !*llvm.Value {10356 ) !Builder.Value {
9809 const o = fg.dg.object;10357 const o = fg.dg.object;
9810 const mod = o.module;10358 const mod = o.module;
9811 const payload_ty = opt_ty.optionalChild(mod);10359 const payload_ty = opt_ty.optionalChild(mod);
981210360
9813 if (isByRef(opt_ty, mod)) {10361 if (isByRef(opt_ty, mod)) {
9814 // We have a pointer and we need to return a pointer to the first field.10362 // 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));
9818 if (isByRef(payload_ty, mod)) {10366 if (isByRef(payload_ty, mod)) {
9819 if (can_elide_load)10367 if (can_elide_load)
9820 return payload_ptr;10368 return payload_ptr;
...@@ -9822,55 +10370,51 @@ pub const FuncGen = struct {...@@ -9822,55 +10370,51 @@ pub const FuncGen = struct {
9822 return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, false);10370 return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, false);
9823 }10371 }
9824 const payload_llvm_ty = try o.lowerType(payload_ty);10372 const payload_llvm_ty = try o.lowerType(payload_ty);
9825 const load_inst = fg.builder.buildLoad(payload_llvm_ty, payload_ptr, "");10373 return fg.wip.load(.normal, payload_llvm_ty, payload_ptr, payload_alignment, "");
9826 load_inst.setAlignment(payload_alignment);
9827 return load_inst;
9828 }10374 }
982910375
9830 assert(!isByRef(payload_ty, mod));10376 assert(!isByRef(payload_ty, mod));
9831 return fg.builder.buildExtractValue(opt_handle, 0, "");10377 return fg.wip.extractValue(opt_handle, &.{0}, "");
9832 }10378 }
983310379
9834 fn buildOptional(10380 fn buildOptional(
9835 self: *FuncGen,10381 self: *FuncGen,
9836 optional_ty: Type,10382 optional_ty: Type,
9837 payload: *llvm.Value,10383 payload: Builder.Value,
9838 non_null_bit: *llvm.Value,10384 non_null_bit: Builder.Value,
9839 ) !?*llvm.Value {10385 ) !Builder.Value {
9840 const o = self.dg.object;10386 const o = self.dg.object;
9841 const optional_llvm_ty = try o.lowerType(optional_ty);10387 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, "");
9843 const mod = o.module;10389 const mod = o.module;
984410390
9845 if (isByRef(optional_ty, mod)) {10391 if (isByRef(optional_ty, mod)) {
9846 const payload_alignment = optional_ty.abiAlignment(mod);10392 const payload_alignment = Builder.Alignment.fromByteUnits(optional_ty.abiAlignment(mod));
9847 const alloca_inst = self.buildAlloca(optional_llvm_ty, payload_alignment);10393 const alloca_inst = try self.buildAlloca(optional_llvm_ty, payload_alignment);
984810394
9849 {10395 {
9850 const field_ptr = self.builder.buildStructGEP(optional_llvm_ty, alloca_inst, 0, "");10396 const field_ptr = try self.wip.gepStruct(optional_llvm_ty, alloca_inst, 0, "");
9851 const store_inst = self.builder.buildStore(payload, field_ptr);10397 _ = try self.wip.store(.normal, payload, field_ptr, payload_alignment);
9852 store_inst.setAlignment(payload_alignment);
9853 }10398 }
9854 {10399 {
9855 const field_ptr = self.builder.buildStructGEP(optional_llvm_ty, alloca_inst, 1, "");10400 const non_null_alignment = comptime Builder.Alignment.fromByteUnits(1);
9856 const store_inst = self.builder.buildStore(non_null_field, field_ptr);10401 const field_ptr = try self.wip.gepStruct(optional_llvm_ty, alloca_inst, 1, "");
9857 store_inst.setAlignment(1);10402 _ = try self.wip.store(.normal, non_null_field, field_ptr, non_null_alignment);
9858 }10403 }
985910404
9860 return alloca_inst;10405 return alloca_inst;
9861 }10406 }
986210407
9863 const partial = self.builder.buildInsertValue(optional_llvm_ty.getUndef(), payload, 0, "");10408 return self.wip.buildAggregate(optional_llvm_ty, &.{ payload, non_null_field }, "");
9864 return self.builder.buildInsertValue(partial, non_null_field, 1, "");
9865 }10409 }
986610410
9867 fn fieldPtr(10411 fn fieldPtr(
9868 self: *FuncGen,10412 self: *FuncGen,
9869 inst: Air.Inst.Index,10413 inst: Air.Inst.Index,
9870 struct_ptr: *llvm.Value,10414 struct_ptr: Builder.Value,
9871 struct_ptr_ty: Type,10415 struct_ptr_ty: Type,
9872 field_index: u32,10416 field_index: u32,
9873 ) !?*llvm.Value {10417 ) !Builder.Value {
9874 const o = self.dg.object;10418 const o = self.dg.object;
9875 const mod = o.module;10419 const mod = o.module;
9876 const struct_ty = struct_ptr_ty.childType(mod);10420 const struct_ty = struct_ptr_ty.childType(mod);
...@@ -9892,26 +10436,25 @@ pub const FuncGen = struct {...@@ -9892,26 +10436,25 @@ pub const FuncGen = struct {
9892 // Offset our operand pointer by the correct number of bytes.10436 // Offset our operand pointer by the correct number of bytes.
9893 const byte_offset = struct_ty.packedStructFieldByteOffset(field_index, mod);10437 const byte_offset = struct_ty.packedStructFieldByteOffset(field_index, mod);
9894 if (byte_offset == 0) return struct_ptr;10438 if (byte_offset == 0) return struct_ptr;
9895 const byte_llvm_ty = self.context.intType(8);10439 const usize_ty = try o.lowerType(Type.usize);
9896 const llvm_usize = try o.lowerType(Type.usize);10440 const llvm_index = try o.builder.intValue(usize_ty, byte_offset);
9897 const llvm_index = llvm_usize.constInt(byte_offset, .False);10441 return self.wip.gep(.inbounds, .i8, struct_ptr, &.{llvm_index}, "");
9898 const indices: [1]*llvm.Value = .{llvm_index};
9899 return self.builder.buildInBoundsGEP(byte_llvm_ty, struct_ptr, &indices, indices.len, "");
9900 },10442 },
9901 else => {10443 else => {
9902 const struct_llvm_ty = try o.lowerPtrElemTy(struct_ty);10444 const struct_llvm_ty = try o.lowerPtrElemTy(struct_ty);
990310445
9904 if (llvmField(struct_ty, field_index, mod)) |llvm_field| {10446 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, "");
9906 } else {10448 } else {
9907 // If we found no index then this means this is a zero sized field at the10449 // If we found no index then this means this is a zero sized field at the
9908 // end of the struct. Treat our struct pointer as an array of two and get10450 // end of the struct. Treat our struct pointer as an array of two and get
9909 // the index to the element at index `1` to get a pointer to the end of10451 // the index to the element at index `1` to get a pointer to the end of
9910 // the struct.10452 // the struct.
9911 const llvm_u32 = self.context.intType(32);10453 const llvm_index = try o.builder.intValue(
9912 const llvm_index = llvm_u32.constInt(@intFromBool(struct_ty.hasRuntimeBitsIgnoreComptime(mod)), .False);10454 try o.lowerType(Type.usize),
9913 const indices: [1]*llvm.Value = .{llvm_index};10455 @intFromBool(struct_ty.hasRuntimeBitsIgnoreComptime(mod)),
9914 return self.builder.buildInBoundsGEP(struct_llvm_ty, struct_ptr, &indices, indices.len, "");10456 );
10457 return self.wip.gep(.inbounds, struct_llvm_ty, struct_ptr, &.{llvm_index}, "");
9915 }10458 }
9916 },10459 },
9917 },10460 },
...@@ -9920,126 +10463,128 @@ pub const FuncGen = struct {...@@ -9920,126 +10463,128 @@ pub const FuncGen = struct {
9920 if (layout.payload_size == 0 or struct_ty.containerLayout(mod) == .Packed) return struct_ptr;10463 if (layout.payload_size == 0 or struct_ty.containerLayout(mod) == .Packed) return struct_ptr;
9921 const payload_index = @intFromBool(layout.tag_align >= layout.payload_align);10464 const payload_index = @intFromBool(layout.tag_align >= layout.payload_align);
9922 const union_llvm_ty = try o.lowerType(struct_ty);10465 const union_llvm_ty = try o.lowerType(struct_ty);
9923 const union_field_ptr = self.builder.buildStructGEP(union_llvm_ty, struct_ptr, payload_index, "");10466 return self.wip.gepStruct(union_llvm_ty, struct_ptr, payload_index, "");
9924 return union_field_ptr;
9925 },10467 },
9926 else => unreachable,10468 else => unreachable,
9927 }10469 }
9928 }10470 }
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;
9931 const id = llvm.lookupIntrinsicID(name.ptr, name.len);10478 const id = llvm.lookupIntrinsicID(name.ptr, name.len);
9932 assert(id != 0);10479 assert(id != 0);
9933 const o = fg.dg.object;10480 const llvm_types = try o.gpa.alloc(*llvm.Type, types.len);
9934 return o.llvm_module.getIntrinsicDeclaration(id, types.ptr, 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);
9935 }10484 }
993610485
9937 /// Load a by-ref type by constructing a new alloca and performing a memcpy.10486 /// Load a by-ref type by constructing a new alloca and performing a memcpy.
9938 fn loadByRef(10487 fn loadByRef(
9939 fg: *FuncGen,10488 fg: *FuncGen,
9940 ptr: *llvm.Value,10489 ptr: Builder.Value,
9941 pointee_type: Type,10490 pointee_type: Type,
9942 ptr_alignment: u32,10491 ptr_alignment: Builder.Alignment,
9943 is_volatile: bool,10492 is_volatile: bool,
9944 ) !*llvm.Value {10493 ) !Builder.Value {
9945 const o = fg.dg.object;10494 const o = fg.dg.object;
9946 const mod = o.module;10495 const mod = o.module;
9947 const pointee_llvm_ty = try o.lowerType(pointee_type);10496 const pointee_llvm_ty = try o.lowerType(pointee_type);
9948 const result_align = @max(ptr_alignment, pointee_type.abiAlignment(mod));10497 const result_align = Builder.Alignment.fromByteUnits(
9949 const result_ptr = fg.buildAlloca(pointee_llvm_ty, result_align);10498 @max(ptr_alignment.toByteUnits() orelse 0, pointee_type.abiAlignment(mod)),
9950 const llvm_usize = fg.context.intType(Type.usize.intInfo(mod).bits);10499 );
10500 const result_ptr = try fg.buildAlloca(pointee_llvm_ty, result_align);
10501 const usize_ty = try o.lowerType(Type.usize);
9951 const size_bytes = pointee_type.abiSize(mod);10502 const size_bytes = pointee_type.abiSize(mod);
9952 _ = fg.builder.buildMemCpy(10503 _ = (try fg.wip.unimplemented(.void, "")).finish(fg.builder.buildMemCpy(
9953 result_ptr,10504 result_ptr.toLlvm(&fg.wip),
9954 result_align,10505 @intCast(result_align.toByteUnits() orelse 0),
9955 ptr,10506 ptr.toLlvm(&fg.wip),
9956 ptr_alignment,10507 @intCast(ptr_alignment.toByteUnits() orelse 0),
9957 llvm_usize.constInt(size_bytes, .False),10508 (try o.builder.intConst(usize_ty, size_bytes)).toLlvm(&o.builder),
9958 is_volatile,10509 is_volatile,
9959 );10510 ), &fg.wip);
9960 return result_ptr;10511 return result_ptr;
9961 }10512 }
996210513
9963 /// This function always performs a copy. For isByRef=true types, it creates a new10514 /// This function always performs a copy. For isByRef=true types, it creates a new
9964 /// alloca and copies the value into it, then returns the alloca instruction.10515 /// alloca and copies the value into it, then returns the alloca instruction.
9965 /// For isByRef=false types, it creates a load instruction and returns it.10516 /// 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 {
9967 const o = self.dg.object;10518 const o = self.dg.object;
9968 const mod = o.module;10519 const mod = o.module;
9969 const info = ptr_ty.ptrInfo(mod);10520 const info = ptr_ty.ptrInfo(mod);
9970 const elem_ty = info.child.toType();10521 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() orelse10524 const ptr_alignment = Builder.Alignment.fromByteUnits(
9974 elem_ty.abiAlignment(mod)));10525 info.flags.alignment.toByteUnitsOptional() orelse elem_ty.abiAlignment(mod),
9975 const ptr_volatile = llvm.Bool.fromBool(info.flags.is_volatile);10526 );
10527 const ptr_kind: Builder.MemoryAccessKind = switch (info.flags.is_volatile) {
10528 false => .normal,
10529 true => .@"volatile",
10530 };
997610531
9977 assert(info.flags.vector_index != .runtime);10532 assert(info.flags.vector_index != .runtime);
9978 if (info.flags.vector_index != .none) {10533 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));
9980 const vec_elem_ty = try o.lowerType(elem_ty);10535 const vec_elem_ty = try o.lowerType(elem_ty);
9981 const vec_ty = vec_elem_ty.vectorType(info.packed_offset.host_size);10536 const vec_ty = try o.builder.vectorType(.normal, info.packed_offset.host_size, vec_elem_ty);
9982
9983 const loaded_vector = self.builder.buildLoad(vec_ty, ptr, "");
9984 loaded_vector.setAlignment(ptr_alignment);
9985 loaded_vector.setVolatile(ptr_volatile);
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, "");
9988 }10540 }
998910541
9990 if (info.packed_offset.host_size == 0) {10542 if (info.packed_offset.host_size == 0) {
9991 if (isByRef(elem_ty, mod)) {10543 if (isByRef(elem_ty, mod)) {
9992 return self.loadByRef(ptr, elem_ty, ptr_alignment, info.flags.is_volatile);10544 return self.loadByRef(ptr, elem_ty, ptr_alignment, info.flags.is_volatile);
9993 }10545 }
9994 const elem_llvm_ty = try o.lowerType(elem_ty);10546 return self.wip.load(ptr_kind, try o.lowerType(elem_ty), ptr, ptr_alignment, "");
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;
9999 }10547 }
1000010548
10001 const int_elem_ty = self.context.intType(info.packed_offset.host_size * 8);10549 const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8));
10002 const containing_int = self.builder.buildLoad(int_elem_ty, ptr, "");10550 const containing_int = try self.wip.load(ptr_kind, containing_int_ty, ptr, ptr_alignment, "");
10003 containing_int.setAlignment(ptr_alignment);
10004 containing_int.setVolatile(ptr_volatile);
1000510551
10006 const elem_bits = @as(c_uint, @intCast(ptr_ty.childType(mod).bitSize(mod)));10552 const elem_bits = ptr_ty.childType(mod).bitSize(mod);
10007 const shift_amt = containing_int.typeOf().constInt(info.packed_offset.bit_offset, .False);10553 const shift_amt = try o.builder.intValue(containing_int_ty, info.packed_offset.bit_offset);
10008 const shifted_value = self.builder.buildLShr(containing_int, shift_amt, "");10554 const shifted_value = try self.wip.bin(.lshr, containing_int, shift_amt, "");
10009 const elem_llvm_ty = try o.lowerType(elem_ty);10555 const elem_llvm_ty = try o.lowerType(elem_ty);
1001010556
10011 if (isByRef(elem_ty, mod)) {10557 if (isByRef(elem_ty, mod)) {
10012 const result_align = elem_ty.abiAlignment(mod);10558 const result_align = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
10013 const result_ptr = self.buildAlloca(elem_llvm_ty, result_align);10559 const result_ptr = try self.buildAlloca(elem_llvm_ty, result_align);
1001410560
10015 const same_size_int = self.context.intType(elem_bits);10561 const same_size_int = try o.builder.intType(@intCast(elem_bits));
10016 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");10562 const truncated_int = try self.wip.cast(.trunc, shifted_value, same_size_int, "");
10017 const store_inst = self.builder.buildStore(truncated_int, result_ptr);10563 _ = try self.wip.store(.normal, truncated_int, result_ptr, result_align);
10018 store_inst.setAlignment(result_align);
10019 return result_ptr;10564 return result_ptr;
10020 }10565 }
1002110566
10022 if (elem_ty.zigTypeTag(mod) == .Float or elem_ty.zigTypeTag(mod) == .Vector) {10567 if (elem_ty.zigTypeTag(mod) == .Float or elem_ty.zigTypeTag(mod) == .Vector) {
10023 const same_size_int = self.context.intType(elem_bits);10568 const same_size_int = try o.builder.intType(@intCast(elem_bits));
10024 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");10569 const truncated_int = try self.wip.cast(.trunc, shifted_value, same_size_int, "");
10025 return self.builder.buildBitCast(truncated_int, elem_llvm_ty, "");10570 return self.wip.cast(.bitcast, truncated_int, elem_llvm_ty, "");
10026 }10571 }
1002710572
10028 if (elem_ty.isPtrAtRuntime(mod)) {10573 if (elem_ty.isPtrAtRuntime(mod)) {
10029 const same_size_int = self.context.intType(elem_bits);10574 const same_size_int = try o.builder.intType(@intCast(elem_bits));
10030 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");10575 const truncated_int = try self.wip.cast(.trunc, shifted_value, same_size_int, "");
10031 return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, "");10576 return self.wip.cast(.inttoptr, truncated_int, elem_llvm_ty, "");
10032 }10577 }
1003310578
10034 return self.builder.buildTrunc(shifted_value, elem_llvm_ty, "");10579 return self.wip.cast(.trunc, shifted_value, elem_llvm_ty, "");
10035 }10580 }
1003610581
10037 fn store(10582 fn store(
10038 self: *FuncGen,10583 self: *FuncGen,
10039 ptr: *llvm.Value,10584 ptr: Builder.Value,
10040 ptr_ty: Type,10585 ptr_ty: Type,
10041 elem: *llvm.Value,10586 elem: Builder.Value,
10042 ordering: llvm.AtomicOrdering,10587 ordering: Builder.AtomicOrdering,
10043 ) !void {10588 ) !void {
10044 const o = self.dg.object;10589 const o = self.dg.object;
10045 const mod = o.module;10590 const mod = o.module;
...@@ -10048,124 +10593,115 @@ pub const FuncGen = struct {...@@ -10048,124 +10593,115 @@ pub const FuncGen = struct {
10048 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) {10593 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) {
10049 return;10594 return;
10050 }10595 }
10051 const ptr_alignment = ptr_ty.ptrAlignment(mod);10596 const ptr_alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
10052 const ptr_volatile = llvm.Bool.fromBool(info.flags.is_volatile);10597 const ptr_kind: Builder.MemoryAccessKind = switch (info.flags.is_volatile) {
10598 false => .normal,
10599 true => .@"volatile",
10600 };
1005310601
10054 assert(info.flags.vector_index != .runtime);10602 assert(info.flags.vector_index != .runtime);
10055 if (info.flags.vector_index != .none) {10603 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));
10057 const vec_elem_ty = try o.lowerType(elem_ty);10605 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, "");10608 const loaded_vector = try self.wip.load(ptr_kind, vec_ty, ptr, ptr_alignment, "");
10061 loaded_vector.setAlignment(ptr_alignment);
10062 loaded_vector.setVolatile(ptr_volatile);
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);10612 assert(ordering == .none);
10067 assert(ordering == .NotAtomic);10613 _ = try self.wip.store(ptr_kind, modified_vector, ptr, ptr_alignment);
10068 store_inst.setAlignment(ptr_alignment);
10069 store_inst.setVolatile(ptr_volatile);
10070 return;10614 return;
10071 }10615 }
1007210616
10073 if (info.packed_offset.host_size != 0) {10617 if (info.packed_offset.host_size != 0) {
10074 const int_elem_ty = self.context.intType(info.packed_offset.host_size * 8);10618 const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8));
10075 const containing_int = self.builder.buildLoad(int_elem_ty, ptr, "");10619 assert(ordering == .none);
10076 assert(ordering == .NotAtomic);10620 const containing_int =
10077 containing_int.setAlignment(ptr_alignment);10621 try self.wip.load(ptr_kind, containing_int_ty, ptr, ptr_alignment, "");
10078 containing_int.setVolatile(ptr_volatile);10622 const elem_bits = ptr_ty.childType(mod).bitSize(mod);
10079 const elem_bits = @as(c_uint, @intCast(ptr_ty.childType(mod).bitSize(mod)));10623 const shift_amt = try o.builder.intConst(containing_int_ty, info.packed_offset.bit_offset);
10080 const containing_int_ty = containing_int.typeOf();
10081 const shift_amt = containing_int_ty.constInt(info.packed_offset.bit_offset, .False);
10082 // Convert to equally-sized integer type in order to perform the bit10624 // Convert to equally-sized integer type in order to perform the bit
10083 // operations on the value to store10625 // 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));
10085 const value_bits = if (elem_ty.isPtrAtRuntime(mod))10627 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, "")
10087 else10629 else
10088 self.builder.buildBitCast(elem, value_bits_type, "");10630 try self.wip.cast(.bitcast, elem, value_bits_type, "");
1008910631
10090 var mask_val = value_bits_type.constAllOnes();10632 var mask_val = try o.builder.intConst(value_bits_type, -1);
10091 mask_val = mask_val.constZExt(containing_int_ty);10633 mask_val = try o.builder.castConst(.zext, mask_val, containing_int_ty);
10092 mask_val = mask_val.constShl(shift_amt);10634 mask_val = try o.builder.binConst(.shl, mask_val, shift_amt);
10093 mask_val = mask_val.constNot();10635 mask_val =
1009410636 try o.builder.binConst(.xor, mask_val, try o.builder.intConst(containing_int_ty, -1));
10095 const anded_containing_int = self.builder.buildAnd(containing_int, mask_val, "");10637
10096 const extended_value = self.builder.buildZExt(value_bits, containing_int_ty, "");10638 const anded_containing_int =
10097 const shifted_value = self.builder.buildShl(extended_value, shift_amt, "");10639 try self.wip.bin(.@"and", containing_int, mask_val.toValue(), "");
10098 const ored_value = self.builder.buildOr(shifted_value, anded_containing_int, "");10640 const extended_value = try self.wip.cast(.zext, value_bits, containing_int_ty, "");
1009910641 const shifted_value = try self.wip.bin(.shl, extended_value, shift_amt.toValue(), "");
10100 const store_inst = self.builder.buildStore(ored_value, ptr);10642 const ored_value = try self.wip.bin(.@"or", shifted_value, anded_containing_int, "");
10101 assert(ordering == .NotAtomic);10643
10102 store_inst.setAlignment(ptr_alignment);10644 assert(ordering == .none);
10103 store_inst.setVolatile(ptr_volatile);10645 _ = try self.wip.store(ptr_kind, ored_value, ptr, ptr_alignment);
10104 return;10646 return;
10105 }10647 }
10106 if (!isByRef(elem_ty, mod)) {10648 if (!isByRef(elem_ty, mod)) {
10107 const store_inst = self.builder.buildStore(elem, ptr);10649 _ = try self.wip.storeAtomic(ptr_kind, elem, ptr, self.sync_scope, ordering, ptr_alignment);
10108 store_inst.setOrdering(ordering);
10109 store_inst.setAlignment(ptr_alignment);
10110 store_inst.setVolatile(ptr_volatile);
10111 return;10650 return;
10112 }10651 }
10113 assert(ordering == .NotAtomic);10652 assert(ordering == .none);
10114 const size_bytes = elem_ty.abiSize(mod);10653 const size_bytes = elem_ty.abiSize(mod);
10115 _ = self.builder.buildMemCpy(10654 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy(
10116 ptr,10655 ptr.toLlvm(&self.wip),
10117 ptr_alignment,10656 @intCast(ptr_alignment.toByteUnits() orelse 0),
10118 elem,10657 elem.toLlvm(&self.wip),
10119 elem_ty.abiAlignment(mod),10658 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),
10121 info.flags.is_volatile,10660 info.flags.is_volatile,
10122 );10661 ), &self.wip);
10123 }10662 }
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 {
10126 const VG_USERREQ__MAKE_MEM_UNDEFINED = 1296236545;10665 const VG_USERREQ__MAKE_MEM_UNDEFINED = 1296236545;
10127 const o = fg.dg.object;10666 const o = fg.dg.object;
10128 const target = o.module.getTarget();10667 const usize_ty = try o.lowerType(Type.usize);
10129 const usize_llvm_ty = fg.context.intType(target.ptrBitWidth());10668 const zero = try o.builder.intValue(usize_ty, 0);
10130 const zero = usize_llvm_ty.constInt(0, .False);10669 const req = try o.builder.intValue(usize_ty, VG_USERREQ__MAKE_MEM_UNDEFINED);
10131 const req = usize_llvm_ty.constInt(VG_USERREQ__MAKE_MEM_UNDEFINED, .False);10670 const ptr_as_usize = try fg.wip.cast(.ptrtoint, ptr, usize_ty, "");
10132 const ptr_as_usize = fg.builder.buildPtrToInt(ptr, usize_llvm_ty, "");10671 _ = try valgrindClientRequest(fg, zero, req, ptr_as_usize, len, zero, zero, zero);
10133 _ = valgrindClientRequest(fg, zero, req, ptr_as_usize, len, zero, zero, zero);
10134 }10672 }
1013510673
10136 fn valgrindClientRequest(10674 fn valgrindClientRequest(
10137 fg: *FuncGen,10675 fg: *FuncGen,
10138 default_value: *llvm.Value,10676 default_value: Builder.Value,
10139 request: *llvm.Value,10677 request: Builder.Value,
10140 a1: *llvm.Value,10678 a1: Builder.Value,
10141 a2: *llvm.Value,10679 a2: Builder.Value,
10142 a3: *llvm.Value,10680 a3: Builder.Value,
10143 a4: *llvm.Value,10681 a4: Builder.Value,
10144 a5: *llvm.Value,10682 a5: Builder.Value,
10145 ) *llvm.Value {10683 ) Allocator.Error!Builder.Value {
10146 const o = fg.dg.object;10684 const o = fg.dg.object;
10147 const mod = o.module;10685 const mod = o.module;
10148 const target = mod.getTarget();10686 const target = mod.getTarget();
10149 if (!target_util.hasValgrindSupport(target)) return default_value;10687 if (!target_util.hasValgrindSupport(target)) return default_value;
1015010688
10151 const usize_llvm_ty = fg.context.intType(target.ptrBitWidth());10689 const llvm_usize = try o.lowerType(Type.usize);
10152 const usize_alignment = @as(c_uint, @intCast(Type.usize.abiSize(mod)));10690 const usize_alignment = Builder.Alignment.fromByteUnits(Type.usize.abiAlignment(mod));
1015310691
10154 const array_llvm_ty = usize_llvm_ty.arrayType(6);10692 const array_llvm_ty = try o.builder.arrayType(6, llvm_usize);
10155 const array_ptr = fg.valgrind_client_request_array orelse a: {10693 const array_ptr = if (fg.valgrind_client_request_array == .none) a: {
10156 const array_ptr = fg.buildAlloca(array_llvm_ty, usize_alignment);10694 const array_ptr = try fg.buildAlloca(array_llvm_ty, usize_alignment);
10157 fg.valgrind_client_request_array = array_ptr;10695 fg.valgrind_client_request_array = array_ptr;
10158 break :a array_ptr;10696 break :a array_ptr;
10159 };10697 } else fg.valgrind_client_request_array;
10160 const array_elements = [_]*llvm.Value{ request, a1, a2, a3, a4, a5 };10698 const array_elements = [_]Builder.Value{ request, a1, a2, a3, a4, a5 };
10161 const zero = usize_llvm_ty.constInt(0, .False);10699 const zero = try o.builder.intValue(llvm_usize, 0);
10162 for (array_elements, 0..) |elem, i| {10700 for (array_elements, 0..) |elem, i| {
10163 const indexes = [_]*llvm.Value{10701 const elem_ptr = try fg.wip.gep(.inbounds, array_llvm_ty, array_ptr, &.{
10164 zero, usize_llvm_ty.constInt(@as(c_uint, @intCast(i)), .False),10702 zero, try o.builder.intValue(llvm_usize, i),
10165 };10703 }, "");
10166 const elem_ptr = fg.builder.buildInBoundsGEP(array_llvm_ty, array_ptr, &indexes, indexes.len, "");10704 _ = try fg.wip.store(.normal, elem, elem_ptr, usize_alignment);
10167 const store_inst = fg.builder.buildStore(elem, elem_ptr);
10168 store_inst.setAlignment(usize_alignment);
10169 }10705 }
1017010706
10171 const arch_specific: struct {10707 const arch_specific: struct {
...@@ -10199,10 +10735,9 @@ pub const FuncGen = struct {...@@ -10199,10 +10735,9 @@ pub const FuncGen = struct {
10199 else => unreachable,10735 else => unreachable,
10200 };10736 };
1020110737
10202 const array_ptr_as_usize = fg.builder.buildPtrToInt(array_ptr, usize_llvm_ty, "");10738 const fn_llvm_ty = (try o.builder.fnType(llvm_usize, &(.{llvm_usize} ** 2), .normal)).toLlvm(&o.builder);
10203 const args = [_]*llvm.Value{ array_ptr_as_usize, default_value };10739 const array_ptr_as_usize = try fg.wip.cast(.ptrtoint, array_ptr, llvm_usize, "");
10204 const param_types = [_]*llvm.Type{ usize_llvm_ty, usize_llvm_ty };10740 const args = [_]*llvm.Value{ array_ptr_as_usize.toLlvm(&fg.wip), default_value.toLlvm(&fg.wip) };
10205 const fn_llvm_ty = llvm.functionType(usize_llvm_ty, &param_types, args.len, .False);
10206 const asm_fn = llvm.getInlineAsm(10741 const asm_fn = llvm.getInlineAsm(
10207 fn_llvm_ty,10742 fn_llvm_ty,
10208 arch_specific.template.ptr,10743 arch_specific.template.ptr,
...@@ -10215,14 +10750,9 @@ pub const FuncGen = struct {...@@ -10215,14 +10750,9 @@ pub const FuncGen = struct {
10215 .False, // can throw10750 .False, // can throw
10216 );10751 );
1021710752
10218 const call = fg.builder.buildCall(10753 const call = (try fg.wip.unimplemented(llvm_usize, "")).finish(
10219 fn_llvm_ty,10754 fg.builder.buildCall(fn_llvm_ty, asm_fn, &args, args.len, .C, .Auto, ""),
10220 asm_fn,10755 &fg.wip,
10221 &args,
10222 args.len,
10223 .C,
10224 .Auto,
10225 "",
10226 );10756 );
10227 return call;10757 return call;
10228 }10758 }
...@@ -10432,14 +10962,14 @@ fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void {...@@ -10432,14 +10962,14 @@ fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void {
10432 }10962 }
10433}10963}
1043410964
10435fn toLlvmAtomicOrdering(atomic_order: std.builtin.AtomicOrder) llvm.AtomicOrdering {10965fn toLlvmAtomicOrdering(atomic_order: std.builtin.AtomicOrder) Builder.AtomicOrdering {
10436 return switch (atomic_order) {10966 return switch (atomic_order) {
10437 .Unordered => .Unordered,10967 .Unordered => .unordered,
10438 .Monotonic => .Monotonic,10968 .Monotonic => .monotonic,
10439 .Acquire => .Acquire,10969 .Acquire => .acquire,
10440 .Release => .Release,10970 .Release => .release,
10441 .AcqRel => .AcquireRelease,10971 .AcqRel => .acq_rel,
10442 .SeqCst => .SequentiallyConsistent,10972 .SeqCst => .seq_cst,
10443 };10973 };
10444}10974}
1044510975
...@@ -10494,45 +11024,67 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca...@@ -10494,45 +11024,67 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca
10494}11024}
1049511025
10496/// Convert a zig-address space to an llvm address space.11026/// 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 {
10498 return switch (target.cpu.arch) {11043 return switch (target.cpu.arch) {
10499 .x86, .x86_64 => switch (address_space) {11044 .x86, .x86_64 => &.{
10500 .generic => llvm.address_space.default,11045 .{ .zig = .generic, .llvm = .default },
10501 .gs => llvm.address_space.x86.gs,11046 .{ .zig = .gs, .llvm = Builder.AddrSpace.x86.gs },
10502 .fs => llvm.address_space.x86.fs,11047 .{ .zig = .fs, .llvm = Builder.AddrSpace.x86.fs },
10503 .ss => llvm.address_space.x86.ss,11048 .{ .zig = .ss, .llvm = Builder.AddrSpace.x86.ss },
10504 else => unreachable,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 },
10505 },11052 },
10506 .nvptx, .nvptx64 => switch (address_space) {11053 .nvptx, .nvptx64 => &.{
10507 .generic => llvm.address_space.default,11054 .{ .zig = .generic, .llvm = .default },
10508 .global => llvm.address_space.nvptx.global,11055 .{ .zig = .global, .llvm = Builder.AddrSpace.nvptx.global },
10509 .constant => llvm.address_space.nvptx.constant,11056 .{ .zig = .constant, .llvm = Builder.AddrSpace.nvptx.constant },
10510 .param => llvm.address_space.nvptx.param,11057 .{ .zig = .param, .llvm = Builder.AddrSpace.nvptx.param },
10511 .shared => llvm.address_space.nvptx.shared,11058 .{ .zig = .shared, .llvm = Builder.AddrSpace.nvptx.shared },
10512 .local => llvm.address_space.nvptx.local,11059 .{ .zig = .local, .llvm = Builder.AddrSpace.nvptx.local },
10513 else => unreachable,
10514 },11060 },
10515 .amdgcn => switch (address_space) {11061 .amdgcn => &.{
10516 .generic => llvm.address_space.amdgpu.flat,11062 .{ .zig = .generic, .llvm = Builder.AddrSpace.amdgpu.flat, .force_in_data_layout = true },
10517 .global => llvm.address_space.amdgpu.global,11063 .{ .zig = .global, .llvm = Builder.AddrSpace.amdgpu.global, .force_in_data_layout = true },
10518 .constant => llvm.address_space.amdgpu.constant,11064 .{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.region, .size = 32, .abi = 32 },
10519 .shared => llvm.address_space.amdgpu.local,11065 .{ .zig = .shared, .llvm = Builder.AddrSpace.amdgpu.local, .size = 32, .abi = 32 },
10520 .local => llvm.address_space.amdgpu.private,11066 .{ .zig = .constant, .llvm = Builder.AddrSpace.amdgpu.constant, .force_in_data_layout = true },
10521 else => unreachable,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 },
10522 },11070 },
10523 .avr => switch (address_space) {11071 .avr => &.{
10524 .generic => llvm.address_space.default,11072 .{ .zig = .generic, .llvm = .default, .abi = 8 },
10525 .flash => llvm.address_space.avr.flash,11073 .{ .zig = .flash, .llvm = Builder.AddrSpace.avr.flash, .abi = 8 },
10526 .flash1 => llvm.address_space.avr.flash1,11074 .{ .zig = .flash1, .llvm = Builder.AddrSpace.avr.flash1, .abi = 8 },
10527 .flash2 => llvm.address_space.avr.flash2,11075 .{ .zig = .flash2, .llvm = Builder.AddrSpace.avr.flash2, .abi = 8 },
10528 .flash3 => llvm.address_space.avr.flash3,11076 .{ .zig = .flash3, .llvm = Builder.AddrSpace.avr.flash3, .abi = 8 },
10529 .flash4 => llvm.address_space.avr.flash4,11077 .{ .zig = .flash4, .llvm = Builder.AddrSpace.avr.flash4, .abi = 8 },
10530 .flash5 => llvm.address_space.avr.flash5,11078 .{ .zig = .flash5, .llvm = Builder.AddrSpace.avr.flash5, .abi = 8 },
10531 else => unreachable,
10532 },11079 },
10533 else => switch (address_space) {11080 .wasm32, .wasm64 => &.{
10534 .generic => llvm.address_space.default,11081 .{ .zig = .generic, .llvm = .default, .force_in_data_layout = true },
10535 else => unreachable,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 },
10536 },11088 },
10537 };11089 };
10538}11090}
...@@ -10541,30 +11093,30 @@ fn toLlvmAddressSpace(address_space: std.builtin.AddressSpace, target: std.Targe...@@ -10541,30 +11093,30 @@ fn toLlvmAddressSpace(address_space: std.builtin.AddressSpace, target: std.Targe
10541/// different address, space and then cast back to the generic address space.11093/// different address, space and then cast back to the generic address space.
10542/// For example, on GPUs local variable declarations must be generated into the local address space.11094/// For example, on GPUs local variable declarations must be generated into the local address space.
10543/// This function returns the address space local values should be generated into.11095/// 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 {
10545 return switch (target.cpu.arch) {11097 return switch (target.cpu.arch) {
10546 // On amdgcn, locals should be generated into the private address space.11098 // On amdgcn, locals should be generated into the private address space.
10547 // To make Zig not impossible to use, these are then converted to addresses in the11099 // To make Zig not impossible to use, these are then converted to addresses in the
10548 // generic address space and treates as regular pointers. This is the way that HIP also does it.11100 // generic address space and treates as regular pointers. This is the way that HIP also does it.
10549 .amdgcn => llvm.address_space.amdgpu.private,11101 .amdgcn => Builder.AddrSpace.amdgpu.private,
10550 else => llvm.address_space.default,11102 else => .default,
10551 };11103 };
10552}11104}
1055311105
10554/// On some targets, global values that are in the generic address space must be generated into a11106/// On some targets, global values that are in the generic address space must be generated into a
10555/// different address space, and then cast back to the generic address space.11107/// 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 {
10557 return switch (target.cpu.arch) {11109 return switch (target.cpu.arch) {
10558 // On amdgcn, globals must be explicitly allocated and uploaded so that the program can access11110 // On amdgcn, globals must be explicitly allocated and uploaded so that the program can access
10559 // them.11111 // them.
10560 .amdgcn => llvm.address_space.amdgpu.global,11112 .amdgcn => Builder.AddrSpace.amdgpu.global,
10561 else => llvm.address_space.default,11113 else => .default,
10562 };11114 };
10563}11115}
1056411116
10565/// Return the actual address space that a value should be stored in if its a global address space.11117/// Return the actual address space that a value should be stored in if its a global address space.
10566/// When a value is placed in the resulting address space, it needs to be cast back into wanted_address_space.11118/// 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 {
10568 return switch (wanted_address_space) {11120 return switch (wanted_address_space) {
10569 .generic => llvmDefaultGlobalAddressSpace(target),11121 .generic => llvmDefaultGlobalAddressSpace(target),
10570 else => |as| toLlvmAddressSpace(as, target),11122 else => |as| toLlvmAddressSpace(as, target),
...@@ -10694,28 +11246,20 @@ fn firstParamSRetSystemV(ty: Type, mod: *Module) bool {...@@ -10694,28 +11246,20 @@ fn firstParamSRetSystemV(ty: Type, mod: *Module) bool {
10694/// In order to support the C calling convention, some return types need to be lowered11246/// In order to support the C calling convention, some return types need to be lowered
10695/// completely differently in the function prototype to honor the C ABI, and then11247/// completely differently in the function prototype to honor the C ABI, and then
10696/// be effectively bitcasted to the actual return type.11248/// 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 {
10698 const mod = o.module;11250 const mod = o.module;
10699 const return_type = fn_info.return_type.toType();11251 const return_type = fn_info.return_type.toType();
10700 if (!return_type.hasRuntimeBitsIgnoreComptime(mod)) {11252 if (!return_type.hasRuntimeBitsIgnoreComptime(mod)) {
10701 // If the return type is an error set or an error union, then we make this11253 // If the return type is an error set or an error union, then we make this
10702 // anyerror return type instead, so that it can be coerced into a function11254 // anyerror return type instead, so that it can be coerced into a function
10703 // pointer type which has anyerror as the return type.11255 // pointer type which has anyerror as the return type.
10704 if (return_type.isError(mod)) {11256 return if (return_type.isError(mod)) Builder.Type.err_int else .void;
10705 return o.lowerType(Type.anyerror);
10706 } else {
10707 return o.context.voidType();
10708 }
10709 }11257 }
10710 const target = mod.getTarget();11258 const target = mod.getTarget();
10711 switch (fn_info.cc) {11259 switch (fn_info.cc) {
10712 .Unspecified, .Inline => {11260 .Unspecified,
10713 if (isByRef(return_type, mod)) {11261 .Inline,
10714 return o.context.voidType();11262 => return if (isByRef(return_type, mod)) .void else o.lowerType(return_type),
10715 } else {
10716 return o.lowerType(return_type);
10717 }
10718 },
10719 .C => {11263 .C => {
10720 switch (target.cpu.arch) {11264 switch (target.cpu.arch) {
10721 .mips, .mipsel => return o.lowerType(return_type),11265 .mips, .mipsel => return o.lowerType(return_type),
...@@ -10729,50 +11273,37 @@ fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) !*llvm.Type {...@@ -10729,50 +11273,37 @@ fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) !*llvm.Type {
10729 }11273 }
10730 const classes = wasm_c_abi.classifyType(return_type, mod);11274 const classes = wasm_c_abi.classifyType(return_type, mod);
10731 if (classes[0] == .indirect or classes[0] == .none) {11275 if (classes[0] == .indirect or classes[0] == .none) {
10732 return o.context.voidType();11276 return .void;
10733 }11277 }
1073411278
10735 assert(classes[0] == .direct and classes[1] == .none);11279 assert(classes[0] == .direct and classes[1] == .none);
10736 const scalar_type = wasm_c_abi.scalarType(return_type, mod);11280 const scalar_type = wasm_c_abi.scalarType(return_type, mod);
10737 const abi_size = scalar_type.abiSize(mod);11281 return o.builder.intType(@intCast(scalar_type.abiSize(mod) * 8));
10738 return o.context.intType(@as(c_uint, @intCast(abi_size * 8)));
10739 },11282 },
10740 .aarch64, .aarch64_be => {11283 .aarch64, .aarch64_be => {
10741 switch (aarch64_c_abi.classifyType(return_type, mod)) {11284 switch (aarch64_c_abi.classifyType(return_type, mod)) {
10742 .memory => return o.context.voidType(),11285 .memory => return .void,
10743 .float_array => return o.lowerType(return_type),11286 .float_array => return o.lowerType(return_type),
10744 .byval => return o.lowerType(return_type),11287 .byval => return o.lowerType(return_type),
10745 .integer => {11288 .integer => return o.builder.intType(@intCast(return_type.bitSize(mod))),
10746 const bit_size = return_type.bitSize(mod);11289 .double_integer => return o.builder.arrayType(2, .i64),
10747 return o.context.intType(@as(c_uint, @intCast(bit_size)));
10748 },
10749 .double_integer => return o.context.intType(64).arrayType(2),
10750 }11290 }
10751 },11291 },
10752 .arm, .armeb => {11292 .arm, .armeb => {
10753 switch (arm_c_abi.classifyType(return_type, mod, .ret)) {11293 switch (arm_c_abi.classifyType(return_type, mod, .ret)) {
10754 .memory, .i64_array => return o.context.voidType(),11294 .memory, .i64_array => return .void,
10755 .i32_array => |len| if (len == 1) {11295 .i32_array => |len| return if (len == 1) .i32 else .void,
10756 return o.context.intType(32);
10757 } else {
10758 return o.context.voidType();
10759 },
10760 .byval => return o.lowerType(return_type),11296 .byval => return o.lowerType(return_type),
10761 }11297 }
10762 },11298 },
10763 .riscv32, .riscv64 => {11299 .riscv32, .riscv64 => {
10764 switch (riscv_c_abi.classifyType(return_type, mod)) {11300 switch (riscv_c_abi.classifyType(return_type, mod)) {
10765 .memory => return o.context.voidType(),11301 .memory => return .void,
10766 .integer => {11302 .integer => {
10767 const bit_size = return_type.bitSize(mod);11303 return o.builder.intType(@intCast(return_type.bitSize(mod)));
10768 return o.context.intType(@as(c_uint, @intCast(bit_size)));
10769 },11304 },
10770 .double_integer => {11305 .double_integer => {
10771 var llvm_types_buffer: [2]*llvm.Type = .{11306 return o.builder.structType(.normal, &.{ .i64, .i64 });
10772 o.context.intType(64),
10773 o.context.intType(64),
10774 };
10775 return o.context.structType(&llvm_types_buffer, 2, .False);
10776 },11307 },
10777 .byval => return o.lowerType(return_type),11308 .byval => return o.lowerType(return_type),
10778 }11309 }
...@@ -10783,18 +11314,12 @@ fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) !*llvm.Type {...@@ -10783,18 +11314,12 @@ fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) !*llvm.Type {
10783 },11314 },
10784 .Win64 => return lowerWin64FnRetTy(o, fn_info),11315 .Win64 => return lowerWin64FnRetTy(o, fn_info),
10785 .SysV => return lowerSystemVFnRetTy(o, fn_info),11316 .SysV => return lowerSystemVFnRetTy(o, fn_info),
10786 .Stdcall => {11317 .Stdcall => return if (isScalar(mod, return_type)) o.lowerType(return_type) else .void,
10787 if (isScalar(mod, return_type)) {
10788 return o.lowerType(return_type);
10789 } else {
10790 return o.context.voidType();
10791 }
10792 },
10793 else => return o.lowerType(return_type),11318 else => return o.lowerType(return_type),
10794 }11319 }
10795}11320}
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 {
10798 const mod = o.module;11323 const mod = o.module;
10799 const return_type = fn_info.return_type.toType();11324 const return_type = fn_info.return_type.toType();
10800 switch (x86_64_abi.classifyWindows(return_type, mod)) {11325 switch (x86_64_abi.classifyWindows(return_type, mod)) {
...@@ -10802,53 +11327,48 @@ fn lowerWin64FnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) !*llvm.Type {...@@ -10802,53 +11327,48 @@ fn lowerWin64FnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) !*llvm.Type {
10802 if (isScalar(mod, return_type)) {11327 if (isScalar(mod, return_type)) {
10803 return o.lowerType(return_type);11328 return o.lowerType(return_type);
10804 } else {11329 } else {
10805 const abi_size = return_type.abiSize(mod);11330 return o.builder.intType(@intCast(return_type.abiSize(mod) * 8));
10806 return o.context.intType(@as(c_uint, @intCast(abi_size * 8)));
10807 }11331 }
10808 },11332 },
10809 .win_i128 => return o.context.intType(64).vectorType(2),11333 .win_i128 => return o.builder.vectorType(.normal, 2, .i64),
10810 .memory => return o.context.voidType(),11334 .memory => return .void,
10811 .sse => return o.lowerType(return_type),11335 .sse => return o.lowerType(return_type),
10812 else => unreachable,11336 else => unreachable,
10813 }11337 }
10814}11338}
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 {
10817 const mod = o.module;11341 const mod = o.module;
10818 const return_type = fn_info.return_type.toType();11342 const return_type = fn_info.return_type.toType();
10819 if (isScalar(mod, return_type)) {11343 if (isScalar(mod, return_type)) {
10820 return o.lowerType(return_type);11344 return o.lowerType(return_type);
10821 }11345 }
10822 const classes = x86_64_abi.classifySystemV(return_type, mod, .ret);11346 const classes = x86_64_abi.classifySystemV(return_type, mod, .ret);
10823 if (classes[0] == .memory) {11347 if (classes[0] == .memory) return .void;
10824 return o.context.voidType();11348 var types_index: u32 = 0;
10825 }11349 var types_buffer: [8]Builder.Type = undefined;
10826 var llvm_types_buffer: [8]*llvm.Type = undefined;
10827 var llvm_types_index: u32 = 0;
10828 for (classes) |class| {11350 for (classes) |class| {
10829 switch (class) {11351 switch (class) {
10830 .integer => {11352 .integer => {
10831 llvm_types_buffer[llvm_types_index] = o.context.intType(64);11353 types_buffer[types_index] = .i64;
10832 llvm_types_index += 1;11354 types_index += 1;
10833 },11355 },
10834 .sse, .sseup => {11356 .sse, .sseup => {
10835 llvm_types_buffer[llvm_types_index] = o.context.doubleType();11357 types_buffer[types_index] = .double;
10836 llvm_types_index += 1;11358 types_index += 1;
10837 },11359 },
10838 .float => {11360 .float => {
10839 llvm_types_buffer[llvm_types_index] = o.context.floatType();11361 types_buffer[types_index] = .float;
10840 llvm_types_index += 1;11362 types_index += 1;
10841 },11363 },
10842 .float_combine => {11364 .float_combine => {
10843 llvm_types_buffer[llvm_types_index] = o.context.floatType().vectorType(2);11365 types_buffer[types_index] = try o.builder.vectorType(.normal, 2, .float);
10844 llvm_types_index += 1;11366 types_index += 1;
10845 },11367 },
10846 .x87 => {11368 .x87 => {
10847 if (llvm_types_index != 0 or classes[2] != .none) {11369 if (types_index != 0 or classes[2] != .none) return .void;
10848 return o.context.voidType();11370 types_buffer[types_index] = .x86_fp80;
10849 }11371 types_index += 1;
10850 llvm_types_buffer[llvm_types_index] = o.context.x86FP80Type();
10851 llvm_types_index += 1;
10852 },11372 },
10853 .x87up => continue,11373 .x87up => continue,
10854 .complex_x87 => {11374 .complex_x87 => {
...@@ -10860,10 +11380,9 @@ fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) !*llvm.Type...@@ -10860,10 +11380,9 @@ fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) !*llvm.Type
10860 }11380 }
10861 }11381 }
10862 if (classes[0] == .integer and classes[1] == .none) {11382 if (classes[0] == .integer and classes[1] == .none) {
10863 const abi_size = return_type.abiSize(mod);11383 return o.builder.intType(@intCast(return_type.abiSize(mod) * 8));
10864 return o.context.intType(@as(c_uint, @intCast(abi_size * 8)));
10865 }11384 }
10866 return o.context.structType(&llvm_types_buffer, llvm_types_index, .False);11385 return o.builder.structType(.normal, types_buffer[0..types_index]);
10867}11386}
1086811387
10869const ParamTypeIterator = struct {11388const ParamTypeIterator = struct {
...@@ -10871,8 +11390,8 @@ const ParamTypeIterator = struct {...@@ -10871,8 +11390,8 @@ const ParamTypeIterator = struct {
10871 fn_info: InternPool.Key.FuncType,11390 fn_info: InternPool.Key.FuncType,
10872 zig_index: u32,11391 zig_index: u32,
10873 llvm_index: u32,11392 llvm_index: u32,
10874 llvm_types_len: u32,11393 types_len: u32,
10875 llvm_types_buffer: [8]*llvm.Type,11394 types_buffer: [8]Builder.Type,
10876 byval_attr: bool,11395 byval_attr: bool,
1087711396
10878 const Lowering = union(enum) {11397 const Lowering = union(enum) {
...@@ -10889,7 +11408,7 @@ const ParamTypeIterator = struct {...@@ -10889,7 +11408,7 @@ const ParamTypeIterator = struct {
10889 i64_array: u8,11408 i64_array: u8,
10890 };11409 };
1089111410
10892 pub fn next(it: *ParamTypeIterator) ?Lowering {11411 pub fn next(it: *ParamTypeIterator) Allocator.Error!?Lowering {
10893 if (it.zig_index >= it.fn_info.param_types.len) return null;11412 if (it.zig_index >= it.fn_info.param_types.len) return null;
10894 const mod = it.object.module;11413 const mod = it.object.module;
10895 const ip = &mod.intern_pool;11414 const ip = &mod.intern_pool;
...@@ -10899,7 +11418,7 @@ const ParamTypeIterator = struct {...@@ -10899,7 +11418,7 @@ const ParamTypeIterator = struct {
10899 }11418 }
1090011419
10901 /// `airCall` uses this instead of `next` so that it can take into account variadic functions.11420 /// `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 {
10903 const mod = it.object.module;11422 const mod = it.object.module;
10904 const ip = &mod.intern_pool;11423 const ip = &mod.intern_pool;
10905 if (it.zig_index >= it.fn_info.param_types.len) {11424 if (it.zig_index >= it.fn_info.param_types.len) {
...@@ -10913,7 +11432,7 @@ const ParamTypeIterator = struct {...@@ -10913,7 +11432,7 @@ const ParamTypeIterator = struct {
10913 }11432 }
10914 }11433 }
1091511434
10916 fn nextInner(it: *ParamTypeIterator, ty: Type) ?Lowering {11435 fn nextInner(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering {
10917 const mod = it.object.module;11436 const mod = it.object.module;
10918 const target = mod.getTarget();11437 const target = mod.getTarget();
1091911438
...@@ -10968,8 +11487,8 @@ const ParamTypeIterator = struct {...@@ -10968,8 +11487,8 @@ const ParamTypeIterator = struct {
10968 .float_array => |len| return Lowering{ .float_array = len },11487 .float_array => |len| return Lowering{ .float_array = len },
10969 .byval => return .byval,11488 .byval => return .byval,
10970 .integer => {11489 .integer => {
10971 it.llvm_types_len = 1;11490 it.types_len = 1;
10972 it.llvm_types_buffer[0] = it.object.context.intType(64);11491 it.types_buffer[0] = .i64;
10973 return .multiple_llvm_types;11492 return .multiple_llvm_types;
10974 },11493 },
10975 .double_integer => return Lowering{ .i64_array = 2 },11494 .double_integer => return Lowering{ .i64_array = 2 },
...@@ -11063,7 +11582,7 @@ const ParamTypeIterator = struct {...@@ -11063,7 +11582,7 @@ const ParamTypeIterator = struct {
11063 }11582 }
11064 }11583 }
1106511584
11066 fn nextSystemV(it: *ParamTypeIterator, ty: Type) ?Lowering {11585 fn nextSystemV(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering {
11067 const mod = it.object.module;11586 const mod = it.object.module;
11068 const classes = x86_64_abi.classifySystemV(ty, mod, .arg);11587 const classes = x86_64_abi.classifySystemV(ty, mod, .arg);
11069 if (classes[0] == .memory) {11588 if (classes[0] == .memory) {
...@@ -11077,25 +11596,25 @@ const ParamTypeIterator = struct {...@@ -11077,25 +11596,25 @@ const ParamTypeIterator = struct {
11077 it.llvm_index += 1;11596 it.llvm_index += 1;
11078 return .byval;11597 return .byval;
11079 }11598 }
11080 var llvm_types_buffer: [8]*llvm.Type = undefined;11599 var types_index: u32 = 0;
11081 var llvm_types_index: u32 = 0;11600 var types_buffer: [8]Builder.Type = undefined;
11082 for (classes) |class| {11601 for (classes) |class| {
11083 switch (class) {11602 switch (class) {
11084 .integer => {11603 .integer => {
11085 llvm_types_buffer[llvm_types_index] = it.object.context.intType(64);11604 types_buffer[types_index] = .i64;
11086 llvm_types_index += 1;11605 types_index += 1;
11087 },11606 },
11088 .sse, .sseup => {11607 .sse, .sseup => {
11089 llvm_types_buffer[llvm_types_index] = it.object.context.doubleType();11608 types_buffer[types_index] = .double;
11090 llvm_types_index += 1;11609 types_index += 1;
11091 },11610 },
11092 .float => {11611 .float => {
11093 llvm_types_buffer[llvm_types_index] = it.object.context.floatType();11612 types_buffer[types_index] = .float;
11094 llvm_types_index += 1;11613 types_index += 1;
11095 },11614 },
11096 .float_combine => {11615 .float_combine => {
11097 llvm_types_buffer[llvm_types_index] = it.object.context.floatType().vectorType(2);11616 types_buffer[types_index] = try it.object.builder.vectorType(.normal, 2, .float);
11098 llvm_types_index += 1;11617 types_index += 1;
11099 },11618 },
11100 .x87 => {11619 .x87 => {
11101 it.zig_index += 1;11620 it.zig_index += 1;
...@@ -11117,9 +11636,9 @@ const ParamTypeIterator = struct {...@@ -11117,9 +11636,9 @@ const ParamTypeIterator = struct {
11117 it.llvm_index += 1;11636 it.llvm_index += 1;
11118 return .abi_sized_int;11637 return .abi_sized_int;
11119 }11638 }
11120 it.llvm_types_buffer = llvm_types_buffer;11639 it.types_len = types_index;
11121 it.llvm_types_len = llvm_types_index;11640 it.types_buffer = types_buffer;
11122 it.llvm_index += llvm_types_index;11641 it.llvm_index += types_index;
11123 it.zig_index += 1;11642 it.zig_index += 1;
11124 return .multiple_llvm_types;11643 return .multiple_llvm_types;
11125 }11644 }
...@@ -11131,8 +11650,8 @@ fn iterateParamTypes(object: *Object, fn_info: InternPool.Key.FuncType) ParamTyp...@@ -11131,8 +11650,8 @@ fn iterateParamTypes(object: *Object, fn_info: InternPool.Key.FuncType) ParamTyp
11131 .fn_info = fn_info,11650 .fn_info = fn_info,
11132 .zig_index = 0,11651 .zig_index = 0,
11133 .llvm_index = 0,11652 .llvm_index = 0,
11134 .llvm_types_buffer = undefined,11653 .types_len = 0,
11135 .llvm_types_len = 0,11654 .types_buffer = undefined,
11136 .byval_attr = false,11655 .byval_attr = false,
11137 };11656 };
11138}11657}
...@@ -11355,23 +11874,23 @@ const AnnotatedDITypePtr = enum(usize) {...@@ -11355,23 +11874,23 @@ const AnnotatedDITypePtr = enum(usize) {
11355 fn initFwd(di_type: *llvm.DIType) AnnotatedDITypePtr {11874 fn initFwd(di_type: *llvm.DIType) AnnotatedDITypePtr {
11356 const addr = @intFromPtr(di_type);11875 const addr = @intFromPtr(di_type);
11357 assert(@as(u1, @truncate(addr)) == 0);11876 assert(@as(u1, @truncate(addr)) == 0);
11358 return @as(AnnotatedDITypePtr, @enumFromInt(addr | 1));11877 return @enumFromInt(addr | 1);
11359 }11878 }
1136011879
11361 fn initFull(di_type: *llvm.DIType) AnnotatedDITypePtr {11880 fn initFull(di_type: *llvm.DIType) AnnotatedDITypePtr {
11362 const addr = @intFromPtr(di_type);11881 const addr = @intFromPtr(di_type);
11363 return @as(AnnotatedDITypePtr, @enumFromInt(addr));11882 return @enumFromInt(addr);
11364 }11883 }
1136511884
11366 fn init(di_type: *llvm.DIType, resolve: Object.DebugResolveStatus) AnnotatedDITypePtr {11885 fn init(di_type: *llvm.DIType, resolve: Object.DebugResolveStatus) AnnotatedDITypePtr {
11367 const addr = @intFromPtr(di_type);11886 const addr = @intFromPtr(di_type);
11368 const bit = @intFromBool(resolve == .fwd);11887 const bit = @intFromBool(resolve == .fwd);
11369 return @as(AnnotatedDITypePtr, @enumFromInt(addr | bit));11888 return @enumFromInt(addr | bit);
11370 }11889 }
1137111890
11372 fn toDIType(self: AnnotatedDITypePtr) *llvm.DIType {11891 fn toDIType(self: AnnotatedDITypePtr) *llvm.DIType {
11373 const fixed_addr = @intFromEnum(self) & ~@as(usize, 1);11892 const fixed_addr = @intFromEnum(self) & ~@as(usize, 1);
11374 return @as(*llvm.DIType, @ptrFromInt(fixed_addr));11893 return @ptrFromInt(fixed_addr);
11375 }11894 }
1137611895
11377 fn isFwdOnly(self: AnnotatedDITypePtr) bool {11896 fn isFwdOnly(self: AnnotatedDITypePtr) bool {
...@@ -11401,56 +11920,39 @@ fn compilerRtIntBits(bits: u16) u16 {...@@ -11401,56 +11920,39 @@ fn compilerRtIntBits(bits: u16) u16 {
11401}11920}
1140211921
11403fn buildAllocaInner(11922fn buildAllocaInner(
11404 context: *llvm.Context,11923 wip: *Builder.WipFunction,
11405 builder: *llvm.Builder,
11406 llvm_func: *llvm.Value,
11407 di_scope_non_null: bool,11924 di_scope_non_null: bool,
11408 llvm_ty: *llvm.Type,11925 llvm_ty: Builder.Type,
11409 maybe_alignment: ?c_uint,11926 alignment: Builder.Alignment,
11410 target: std.Target,11927 target: std.Target,
11411) *llvm.Value {11928) Allocator.Error!Builder.Value {
11412 const address_space = llvmAllocaAddressSpace(target);11929 const address_space = llvmAllocaAddressSpace(target);
1141311930
11414 const alloca = blk: {11931 const alloca = blk: {
11415 const prev_block = builder.getInsertBlock();11932 const prev_cursor = wip.cursor;
11416 const prev_debug_location = builder.getCurrentDebugLocation2();11933 const prev_debug_location = wip.llvm.builder.getCurrentDebugLocation2();
11417 defer {11934 defer {
11418 builder.positionBuilderAtEnd(prev_block);11935 wip.cursor = prev_cursor;
11419 if (di_scope_non_null) {11936 if (wip.cursor.block == .entry) wip.cursor.instruction += 1;
11420 builder.setCurrentDebugLocation2(prev_debug_location);11937 if (di_scope_non_null) wip.llvm.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);
11429 }11938 }
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, "");
11433 };11943 };
1143411944
11435 if (maybe_alignment) |alignment| {
11436 alloca.setAlignment(alignment);
11437 }
11438
11439 // The pointer returned from this function should have the generic address space,11945 // The pointer returned from this function should have the generic address space,
11440 // if this isn't the case then cast it to the generic address space.11946 // if this isn't the case then cast it to the generic address space.
11441 if (address_space != llvm.address_space.default) {11947 return wip.conv(.unneeded, alloca, .ptr, "");
11442 return builder.buildAddrSpaceCast(alloca, context.pointerType(llvm.address_space.default), "");
11443 }
11444
11445 return alloca;
11446}11948}
1144711949
11448fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u1 {11950fn 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));
11450}11952}
1145111953
11452fn errUnionErrorOffset(payload_ty: Type, mod: *Module) u1 {11954fn 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));
11454}11956}
1145511957
11456/// Returns true for asm constraint (e.g. "=*m", "=r") if it accepts a memory location11958/// 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 {...@@ -40,21 +40,42 @@ pub const Context = opaque {
40 pub const halfType = LLVMHalfTypeInContext;40 pub const halfType = LLVMHalfTypeInContext;
41 extern fn LLVMHalfTypeInContext(C: *Context) *Type;41 extern fn LLVMHalfTypeInContext(C: *Context) *Type;
4242
43 pub const bfloatType = LLVMBFloatTypeInContext;
44 extern fn LLVMBFloatTypeInContext(C: *Context) *Type;
45
43 pub const floatType = LLVMFloatTypeInContext;46 pub const floatType = LLVMFloatTypeInContext;
44 extern fn LLVMFloatTypeInContext(C: *Context) *Type;47 extern fn LLVMFloatTypeInContext(C: *Context) *Type;
4548
46 pub const doubleType = LLVMDoubleTypeInContext;49 pub const doubleType = LLVMDoubleTypeInContext;
47 extern fn LLVMDoubleTypeInContext(C: *Context) *Type;50 extern fn LLVMDoubleTypeInContext(C: *Context) *Type;
4851
49 pub const x86FP80Type = LLVMX86FP80TypeInContext;
50 extern fn LLVMX86FP80TypeInContext(C: *Context) *Type;
51
52 pub const fp128Type = LLVMFP128TypeInContext;52 pub const fp128Type = LLVMFP128TypeInContext;
53 extern fn LLVMFP128TypeInContext(C: *Context) *Type;53 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
55 pub const voidType = LLVMVoidTypeInContext;67 pub const voidType = LLVMVoidTypeInContext;
56 extern fn LLVMVoidTypeInContext(C: *Context) *Type;68 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
58 pub const structType = LLVMStructTypeInContext;79 pub const structType = LLVMStructTypeInContext;
59 extern fn LLVMStructTypeInContext(80 extern fn LLVMStructTypeInContext(
60 C: *Context,81 C: *Context,
...@@ -114,9 +135,6 @@ pub const Value = opaque {...@@ -114,9 +135,6 @@ pub const Value = opaque {
114 pub const getNextInstruction = LLVMGetNextInstruction;135 pub const getNextInstruction = LLVMGetNextInstruction;
115 extern fn LLVMGetNextInstruction(Inst: *Value) ?*Value;136 extern fn LLVMGetNextInstruction(Inst: *Value) ?*Value;
116137
117 pub const typeOf = LLVMTypeOf;
118 extern fn LLVMTypeOf(Val: *Value) *Type;
119
120 pub const setGlobalConstant = LLVMSetGlobalConstant;138 pub const setGlobalConstant = LLVMSetGlobalConstant;
121 extern fn LLVMSetGlobalConstant(GlobalVar: *Value, IsConstant: Bool) void;139 extern fn LLVMSetGlobalConstant(GlobalVar: *Value, IsConstant: Bool) void;
122140
...@@ -147,36 +165,135 @@ pub const Value = opaque {...@@ -147,36 +165,135 @@ pub const Value = opaque {
147 pub const setAliasee = LLVMAliasSetAliasee;165 pub const setAliasee = LLVMAliasSetAliasee;
148 extern fn LLVMAliasSetAliasee(Alias: *Value, Aliasee: *Value) void;166 extern fn LLVMAliasSetAliasee(Alias: *Value, Aliasee: *Value) void;
149167
150 pub const constBitCast = LLVMConstBitCast;168 pub const constZExtOrBitCast = LLVMConstZExtOrBitCast;
151 extern fn LLVMConstBitCast(ConstantVal: *Value, ToType: *Type) *Value;169 extern fn LLVMConstZExtOrBitCast(ConstantVal: *Value, ToType: *Type) *Value;
152170
153 pub const constIntToPtr = LLVMConstIntToPtr;171 pub const constNeg = LLVMConstNeg;
154 extern fn LLVMConstIntToPtr(ConstantVal: *Value, ToType: *Type) *Value;172 extern fn LLVMConstNeg(ConstantVal: *Value) *Value;
155173
156 pub const constPtrToInt = LLVMConstPtrToInt;174 pub const constNSWNeg = LLVMConstNSWNeg;
157 extern fn LLVMConstPtrToInt(ConstantVal: *Value, ToType: *Type) *Value;175 extern fn LLVMConstNSWNeg(ConstantVal: *Value) *Value;
158176
159 pub const constShl = LLVMConstShl;177 pub const constNUWNeg = LLVMConstNUWNeg;
160 extern fn LLVMConstShl(LHSConstant: *Value, RHSConstant: *Value) *Value;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
162 pub const constOr = LLVMConstOr;213 pub const constOr = LLVMConstOr;
163 extern fn LLVMConstOr(LHSConstant: *Value, RHSConstant: *Value) *Value;214 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
165 pub const constZExt = LLVMConstZExt;234 pub const constZExt = LLVMConstZExt;
166 extern fn LLVMConstZExt(ConstantVal: *Value, ToType: *Type) *Value;235 extern fn LLVMConstZExt(ConstantVal: *Value, ToType: *Type) *Value;
167236
168 pub const constZExtOrBitCast = LLVMConstZExtOrBitCast;237 pub const constFPTrunc = LLVMConstFPTrunc;
169 extern fn LLVMConstZExtOrBitCast(ConstantVal: *Value, ToType: *Type) *Value;238 extern fn LLVMConstFPTrunc(ConstantVal: *Value, ToType: *Type) *Value;
170239
171 pub const constNot = LLVMConstNot;240 pub const constFPExt = LLVMConstFPExt;
172 extern fn LLVMConstNot(ConstantVal: *Value) *Value;241 extern fn LLVMConstFPExt(ConstantVal: *Value, ToType: *Type) *Value;
173242
174 pub const constAdd = LLVMConstAdd;243 pub const constUIToFP = LLVMConstUIToFP;
175 extern fn LLVMConstAdd(LHSConstant: *Value, RHSConstant: *Value) *Value;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
177 pub const constAddrSpaceCast = LLVMConstAddrSpaceCast;264 pub const constAddrSpaceCast = LLVMConstAddrSpaceCast;
178 extern fn LLVMConstAddrSpaceCast(ConstantVal: *Value, ToType: *Type) *Value;265 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
180 pub const setWeak = LLVMSetWeak;297 pub const setWeak = LLVMSetWeak;
181 extern fn LLVMSetWeak(CmpXchgInst: *Value, IsWeak: Bool) void;298 extern fn LLVMSetWeak(CmpXchgInst: *Value, IsWeak: Bool) void;
182299
...@@ -186,6 +303,9 @@ pub const Value = opaque {...@@ -186,6 +303,9 @@ pub const Value = opaque {
186 pub const setVolatile = LLVMSetVolatile;303 pub const setVolatile = LLVMSetVolatile;
187 extern fn LLVMSetVolatile(MemoryAccessInst: *Value, IsVolatile: Bool) void;304 extern fn LLVMSetVolatile(MemoryAccessInst: *Value, IsVolatile: Bool) void;
188305
306 pub const setAtomicSingleThread = LLVMSetAtomicSingleThread;
307 extern fn LLVMSetAtomicSingleThread(AtomicInst: *Value, SingleThread: Bool) void;
308
189 pub const setAlignment = LLVMSetAlignment;309 pub const setAlignment = LLVMSetAlignment;
190 extern fn LLVMSetAlignment(V: *Value, Bytes: c_uint) void;310 extern fn LLVMSetAlignment(V: *Value, Bytes: c_uint) void;
191311
...@@ -231,17 +351,9 @@ pub const Value = opaque {...@@ -231,17 +351,9 @@ pub const Value = opaque {
231 pub const addCase = LLVMAddCase;351 pub const addCase = LLVMAddCase;
232 extern fn LLVMAddCase(Switch: *Value, OnVal: *Value, Dest: *BasicBlock) void;352 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
239 pub const replaceAllUsesWith = LLVMReplaceAllUsesWith;354 pub const replaceAllUsesWith = LLVMReplaceAllUsesWith;
240 extern fn LLVMReplaceAllUsesWith(OldVal: *Value, NewVal: *Value) void;355 extern fn LLVMReplaceAllUsesWith(OldVal: *Value, NewVal: *Value) void;
241356
242 pub const globalGetValueType = LLVMGlobalGetValueType;
243 extern fn LLVMGlobalGetValueType(Global: *Value) *Type;
244
245 pub const getLinkage = LLVMGetLinkage;357 pub const getLinkage = LLVMGetLinkage;
246 extern fn LLVMGetLinkage(Global: *Value) Linkage;358 extern fn LLVMGetLinkage(Global: *Value) Linkage;
247359
...@@ -259,6 +371,9 @@ pub const Value = opaque {...@@ -259,6 +371,9 @@ pub const Value = opaque {
259371
260 pub const attachMetaData = ZigLLVMAttachMetaData;372 pub const attachMetaData = ZigLLVMAttachMetaData;
261 extern fn ZigLLVMAttachMetaData(GlobalVar: *Value, DIG: *DIGlobalVariableExpression) void;373 extern fn ZigLLVMAttachMetaData(GlobalVar: *Value, DIG: *DIGlobalVariableExpression) void;
374
375 pub const dump = LLVMDumpValue;
376 extern fn LLVMDumpValue(Val: *Value) void;
262};377};
263378
264pub const Type = opaque {379pub const Type = opaque {
...@@ -290,12 +405,18 @@ pub const Type = opaque {...@@ -290,12 +405,18 @@ pub const Type = opaque {
290 pub const getUndef = LLVMGetUndef;405 pub const getUndef = LLVMGetUndef;
291 extern fn LLVMGetUndef(Ty: *Type) *Value;406 extern fn LLVMGetUndef(Ty: *Type) *Value;
292407
408 pub const getPoison = LLVMGetPoison;
409 extern fn LLVMGetPoison(Ty: *Type) *Value;
410
293 pub const arrayType = LLVMArrayType;411 pub const arrayType = LLVMArrayType;
294 extern fn LLVMArrayType(ElementType: *Type, ElementCount: c_uint) *Type;412 extern fn LLVMArrayType(ElementType: *Type, ElementCount: c_uint) *Type;
295413
296 pub const vectorType = LLVMVectorType;414 pub const vectorType = LLVMVectorType;
297 extern fn LLVMVectorType(ElementType: *Type, ElementCount: c_uint) *Type;415 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
299 pub const structSetBody = LLVMStructSetBody;420 pub const structSetBody = LLVMStructSetBody;
300 extern fn LLVMStructSetBody(421 extern fn LLVMStructSetBody(
301 StructTy: *Type,422 StructTy: *Type,
...@@ -304,23 +425,13 @@ pub const Type = opaque {...@@ -304,23 +425,13 @@ pub const Type = opaque {
304 Packed: Bool,425 Packed: Bool,
305 ) void;426 ) void;
306427
307 pub const structGetTypeAtIndex = LLVMStructGetTypeAtIndex;428 pub const constGEP = LLVMConstGEP2;
308 extern fn LLVMStructGetTypeAtIndex(StructTy: *Type, i: c_uint) *Type;429 extern fn LLVMConstGEP2(
309430 Ty: *Type,
310 pub const getTypeKind = LLVMGetTypeKind;431 ConstantVal: *Value,
311 extern fn LLVMGetTypeKind(Ty: *Type) TypeKind;432 ConstantIndices: [*]const *Value,
312433 NumIndices: c_uint,
313 pub const getElementType = LLVMGetElementType;434 ) *Value;
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;
324435
325 pub const constInBoundsGEP = LLVMConstInBoundsGEP2;436 pub const constInBoundsGEP = LLVMConstInBoundsGEP2;
326 extern fn LLVMConstInBoundsGEP2(437 extern fn LLVMConstInBoundsGEP2(
...@@ -329,6 +440,9 @@ pub const Type = opaque {...@@ -329,6 +440,9 @@ pub const Type = opaque {
329 ConstantIndices: [*]const *Value,440 ConstantIndices: [*]const *Value,
330 NumIndices: c_uint,441 NumIndices: c_uint,
331 ) *Value;442 ) *Value;
443
444 pub const dump = LLVMDumpType;
445 extern fn LLVMDumpType(Ty: *Type) void;
332};446};
333447
334pub const Module = opaque {448pub const Module = opaque {
...@@ -439,15 +553,18 @@ pub const VerifierFailureAction = enum(c_int) {...@@ -439,15 +553,18 @@ pub const VerifierFailureAction = enum(c_int) {
439 ReturnStatus,553 ReturnStatus,
440};554};
441555
442pub const constNeg = LLVMConstNeg;
443extern fn LLVMConstNeg(ConstantVal: *Value) *Value;
444
445pub const constVector = LLVMConstVector;556pub const constVector = LLVMConstVector;
446extern fn LLVMConstVector(557extern fn LLVMConstVector(
447 ScalarConstantVals: [*]*Value,558 ScalarConstantVals: [*]*Value,
448 Size: c_uint,559 Size: c_uint,
449) *Value;560) *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
451pub const getEnumAttributeKindForName = LLVMGetEnumAttributeKindForName;568pub const getEnumAttributeKindForName = LLVMGetEnumAttributeKindForName;
452extern fn LLVMGetEnumAttributeKindForName(Name: [*]const u8, SLen: usize) c_uint;569extern fn LLVMGetEnumAttributeKindForName(Name: [*]const u8, SLen: usize) c_uint;
453570
...@@ -484,7 +601,7 @@ pub const Builder = opaque {...@@ -484,7 +601,7 @@ pub const Builder = opaque {
484 extern fn LLVMPositionBuilder(601 extern fn LLVMPositionBuilder(
485 Builder: *Builder,602 Builder: *Builder,
486 Block: *BasicBlock,603 Block: *BasicBlock,
487 Instr: *Value,604 Instr: ?*Value,
488 ) void;605 ) void;
489606
490 pub const positionBuilderAtEnd = LLVMPositionBuilderAtEnd;607 pub const positionBuilderAtEnd = LLVMPositionBuilderAtEnd;
...@@ -678,6 +795,16 @@ pub const Builder = opaque {...@@ -678,6 +795,16 @@ pub const Builder = opaque {
678 pub const buildBitCast = LLVMBuildBitCast;795 pub const buildBitCast = LLVMBuildBitCast;
679 extern fn LLVMBuildBitCast(*Builder, Val: *Value, DestTy: *Type, Name: [*:0]const u8) *Value;796 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
681 pub const buildInBoundsGEP = LLVMBuildInBoundsGEP2;808 pub const buildInBoundsGEP = LLVMBuildInBoundsGEP2;
682 extern fn LLVMBuildInBoundsGEP2(809 extern fn LLVMBuildInBoundsGEP2(
683 B: *Builder,810 B: *Builder,
...@@ -731,14 +858,6 @@ pub const Builder = opaque {...@@ -731,14 +858,6 @@ pub const Builder = opaque {
731 Name: [*:0]const u8,858 Name: [*:0]const u8,
732 ) *Value;859 ) *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
742 pub const buildPtrToInt = LLVMBuildPtrToInt;861 pub const buildPtrToInt = LLVMBuildPtrToInt;
743 extern fn LLVMBuildPtrToInt(862 extern fn LLVMBuildPtrToInt(
744 *Builder,863 *Builder,
...@@ -755,15 +874,6 @@ pub const Builder = opaque {...@@ -755,15 +874,6 @@ pub const Builder = opaque {
755 Name: [*:0]const u8,874 Name: [*:0]const u8,
756 ) *Value;875 ) *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
767 pub const buildTrunc = LLVMBuildTrunc;877 pub const buildTrunc = LLVMBuildTrunc;
768 extern fn LLVMBuildTrunc(878 extern fn LLVMBuildTrunc(
769 *Builder,879 *Builder,
...@@ -1019,9 +1129,6 @@ pub const RealPredicate = enum(c_uint) {...@@ -1019,9 +1129,6 @@ pub const RealPredicate = enum(c_uint) {
1019pub const BasicBlock = opaque {1129pub const BasicBlock = opaque {
1020 pub const deleteBasicBlock = LLVMDeleteBasicBlock;1130 pub const deleteBasicBlock = LLVMDeleteBasicBlock;
1021 extern fn LLVMDeleteBasicBlock(BB: *BasicBlock) void;1131 extern fn LLVMDeleteBasicBlock(BB: *BasicBlock) void;
1022
1023 pub const getFirstInstruction = LLVMGetFirstInstruction;
1024 extern fn LLVMGetFirstInstruction(BB: *BasicBlock) ?*Value;
1025};1132};
10261133
1027pub const TargetMachine = opaque {1134pub const TargetMachine = opaque {
...@@ -1071,6 +1178,9 @@ pub const TargetData = opaque {...@@ -1071,6 +1178,9 @@ pub const TargetData = opaque {
10711178
1072 pub const abiSizeOfType = LLVMABISizeOfType;1179 pub const abiSizeOfType = LLVMABISizeOfType;
1073 extern fn LLVMABISizeOfType(TD: *TargetData, Ty: *Type) c_ulonglong;1180 extern fn LLVMABISizeOfType(TD: *TargetData, Ty: *Type) c_ulonglong;
1181
1182 pub const stringRep = LLVMCopyStringRepOfTargetData;
1183 extern fn LLVMCopyStringRepOfTargetData(TD: *TargetData) [*:0]const u8;
1074};1184};
10751185
1076pub const CodeModel = enum(c_int) {1186pub const CodeModel = enum(c_int) {
...@@ -1440,29 +1550,6 @@ pub const AtomicRMWBinOp = enum(c_int) {...@@ -1440,29 +1550,6 @@ pub const AtomicRMWBinOp = enum(c_int) {
1440 FMin,1550 FMin,
1441};1551};
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
1466pub const CallConv = enum(c_uint) {1553pub const CallConv = enum(c_uint) {
1467 C = 0,1554 C = 0,
1468 Fast = 8,1555 Fast = 8,
...@@ -1588,6 +1675,13 @@ pub const address_space = struct {...@@ -1588,6 +1675,13 @@ pub const address_space = struct {
1588 pub const constant_buffer_14: c_uint = 22;1675 pub const constant_buffer_14: c_uint = 22;
1589 pub const constant_buffer_15: c_uint = 23;1676 pub const constant_buffer_15: c_uint = 23;
1590 };1677 };
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 };
1591};1685};
15921686
1593pub const DIEnumerator = opaque {};1687pub const DIEnumerator = opaque {};
src/link.zig+1
...@@ -110,6 +110,7 @@ pub const Options = struct {...@@ -110,6 +110,7 @@ pub const Options = struct {
110 /// other objects.110 /// other objects.
111 /// Otherwise (depending on `use_lld`) this link code directly outputs and updates the final binary.111 /// Otherwise (depending on `use_lld`) this link code directly outputs and updates the final binary.
112 use_llvm: bool,112 use_llvm: bool,
113 use_lib_llvm: bool,
113 link_libc: bool,114 link_libc: bool,
114 link_libcpp: bool,115 link_libcpp: bool,
115 link_libunwind: bool,116 link_libunwind: bool,
src/main.zig+8
...@@ -439,6 +439,8 @@ const usage_build_generic =...@@ -439,6 +439,8 @@ const usage_build_generic =
439 \\ -fno-unwind-tables Never produce unwind table entries439 \\ -fno-unwind-tables Never produce unwind table entries
440 \\ -fLLVM Force using LLVM as the codegen backend440 \\ -fLLVM Force using LLVM as the codegen backend
441 \\ -fno-LLVM Prevent using LLVM as the codegen backend441 \\ -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
442 \\ -fClang Force using Clang as the C/C++ compilation backend444 \\ -fClang Force using Clang as the C/C++ compilation backend
443 \\ -fno-Clang Prevent using Clang as the C/C++ compilation backend445 \\ -fno-Clang Prevent using Clang as the C/C++ compilation backend
444 \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error446 \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error
...@@ -821,6 +823,7 @@ fn buildOutputType(...@@ -821,6 +823,7 @@ fn buildOutputType(
821 var stack_size_override: ?u64 = null;823 var stack_size_override: ?u64 = null;
822 var image_base_override: ?u64 = null;824 var image_base_override: ?u64 = null;
823 var use_llvm: ?bool = null;825 var use_llvm: ?bool = null;
826 var use_lib_llvm: ?bool = null;
824 var use_lld: ?bool = null;827 var use_lld: ?bool = null;
825 var use_clang: ?bool = null;828 var use_clang: ?bool = null;
826 var link_eh_frame_hdr = false;829 var link_eh_frame_hdr = false;
...@@ -1261,6 +1264,10 @@ fn buildOutputType(...@@ -1261,6 +1264,10 @@ fn buildOutputType(
1261 use_llvm = true;1264 use_llvm = true;
1262 } else if (mem.eql(u8, arg, "-fno-LLVM")) {1265 } else if (mem.eql(u8, arg, "-fno-LLVM")) {
1263 use_llvm = false;1266 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;
1264 } else if (mem.eql(u8, arg, "-fLLD")) {1271 } else if (mem.eql(u8, arg, "-fLLD")) {
1265 use_lld = true;1272 use_lld = true;
1266 } else if (mem.eql(u8, arg, "-fno-LLD")) {1273 } else if (mem.eql(u8, arg, "-fno-LLD")) {
...@@ -3119,6 +3126,7 @@ fn buildOutputType(...@@ -3119,6 +3126,7 @@ fn buildOutputType(
3119 .want_tsan = want_tsan,3126 .want_tsan = want_tsan,
3120 .want_compiler_rt = want_compiler_rt,3127 .want_compiler_rt = want_compiler_rt,
3121 .use_llvm = use_llvm,3128 .use_llvm = use_llvm,
3129 .use_lib_llvm = use_lib_llvm,
3122 .use_lld = use_lld,3130 .use_lld = use_lld,
3123 .use_clang = use_clang,3131 .use_clang = use_clang,
3124 .hash_style = hash_style,3132 .hash_style = hash_style,
src/zig_llvm.cpp-4
...@@ -560,10 +560,6 @@ LLVMValueRef ZigLLVMBuildUShlSat(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRe...@@ -560,10 +560,6 @@ LLVMValueRef ZigLLVMBuildUShlSat(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRe
560 return wrap(call_inst);560 return wrap(call_inst);
561}561}
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
567void ZigLLVMFnSetSubprogram(LLVMValueRef fn, ZigLLVMDISubprogram *subprogram) {563void ZigLLVMFnSetSubprogram(LLVMValueRef fn, ZigLLVMDISubprogram *subprogram) {
568 assert( isa<Function>(unwrap(fn)) );564 assert( isa<Function>(unwrap(fn)) );
569 Function *unwrapped_function = reinterpret_cast<Function*>(unwrap(fn));565 Function *unwrapped_function = reinterpret_cast<Function*>(unwrap(fn));