authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-07-24 02:16:00-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-07-24 02:16:00-07:00
logd21d1d4ba25701410b9ae99921326f8bfc8a44dd
treec56738ededf5966ce448e57be393996f76976426
parent98c7aec4e4ae7deac5e802a8c592c2d91b6b77af
parent3fc2e36de2d125b2de255b03abc24bea30899caf
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #16487 from jacobly0/llvm-builder

llvm: incremental Builder improvements

12 files changed, 2883 insertions(+), 863 deletions(-)

lib/std/Build/Step.zig+3-1
...@@ -294,7 +294,7 @@ pub fn evalZigProcess(...@@ -294,7 +294,7 @@ pub fn evalZigProcess(
294 s: *Step,294 s: *Step,
295 argv: []const []const u8,295 argv: []const []const u8,
296 prog_node: *std.Progress.Node,296 prog_node: *std.Progress.Node,
297) ![]const u8 {297) !?[]const u8 {
298 assert(argv.len != 0);298 assert(argv.len != 0);
299 const b = s.owner;299 const b = s.owner;
300 const arena = b.allocator;300 const arena = b.allocator;
...@@ -423,6 +423,8 @@ pub fn evalZigProcess(...@@ -423,6 +423,8 @@ pub fn evalZigProcess(
423 });423 });
424 }424 }
425425
426 if (s.cast(Compile)) |compile| if (compile.emit_bin == .no_emit) return result;
427
426 return result orelse return s.fail(428 return result orelse return s.fail(
427 "the following command failed to communicate the compilation result:\n{s}",429 "the following command failed to communicate the compilation result:\n{s}",
428 .{try allocPrintCmd(arena, null, argv)},430 .{try allocPrintCmd(arena, null, argv)},
lib/std/Build/Step/Compile.zig+4-3
...@@ -1997,7 +1997,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {...@@ -1997,7 +1997,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
1997 try zig_args.append(resolved_args_file);1997 try zig_args.append(resolved_args_file);
1998 }1998 }
19991999
2000 const output_bin_path = step.evalZigProcess(zig_args.items, prog_node) catch |err| switch (err) {2000 const maybe_output_bin_path = step.evalZigProcess(zig_args.items, prog_node) catch |err| switch (err) {
2001 error.NeedCompileErrorCheck => {2001 error.NeedCompileErrorCheck => {
2002 assert(self.expect_errors.len != 0);2002 assert(self.expect_errors.len != 0);
2003 try checkCompileErrors(self);2003 try checkCompileErrors(self);
...@@ -2005,10 +2005,11 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {...@@ -2005,10 +2005,11 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
2005 },2005 },
2006 else => |e| return e,2006 else => |e| return e,
2007 };2007 };
2008 const output_dir = fs.path.dirname(output_bin_path).?;
20092008
2010 // Update generated files2009 // Update generated files
2011 {2010 if (maybe_output_bin_path) |output_bin_path| {
2011 const output_dir = fs.path.dirname(output_bin_path).?;
2012
2012 self.output_dirname_source.path = output_dir;2013 self.output_dirname_source.path = output_dir;
20132014
2014 self.output_path_source.path = b.pathJoin(2015 self.output_path_source.path = b.pathJoin(
lib/std/Build/Step/TranslateC.zig+2-2
...@@ -148,8 +148,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {...@@ -148,8 +148,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
148148
149 const output_path = try step.evalZigProcess(argv_list.items, prog_node);149 const output_path = try step.evalZigProcess(argv_list.items, prog_node);
150150
151 self.out_basename = fs.path.basename(output_path);151 self.out_basename = fs.path.basename(output_path.?);
152 const output_dir = fs.path.dirname(output_path).?;152 const output_dir = fs.path.dirname(output_path.?).?;
153153
154 self.output_file.path = try fs.path.join(154 self.output_file.path = try fs.path.join(
155 b.allocator,155 b.allocator,
lib/std/target.zig+7-3
...@@ -1912,7 +1912,7 @@ pub const Target = struct {...@@ -1912,7 +1912,7 @@ pub const Target = struct {
1912 return switch (target.cpu.arch) {1912 return switch (target.cpu.arch) {
1913 .amdgcn => 4,1913 .amdgcn => 4,
1914 .x86 => switch (target.os.tag) {1914 .x86 => switch (target.os.tag) {
1915 .windows => 4,1915 .windows, .uefi => 4,
1916 else => 16,1916 else => 16,
1917 },1917 },
1918 .arm,1918 .arm,
...@@ -1931,8 +1931,6 @@ pub const Target = struct {...@@ -1931,8 +1931,6 @@ pub const Target = struct {
1931 .bpfel,1931 .bpfel,
1932 .mips64,1932 .mips64,
1933 .mips64el,1933 .mips64el,
1934 .powerpc64,
1935 .powerpc64le,
1936 .riscv32,1934 .riscv32,
1937 .riscv64,1935 .riscv64,
1938 .sparc64,1936 .sparc64,
...@@ -1941,6 +1939,12 @@ pub const Target = struct {...@@ -1941,6 +1939,12 @@ pub const Target = struct {
1941 .wasm32,1939 .wasm32,
1942 .wasm64,1940 .wasm64,
1943 => 16,1941 => 16,
1942 .powerpc64,
1943 .powerpc64le,
1944 => switch (target.os.tag) {
1945 else => 8,
1946 .linux => 16,
1947 },
1944 else => @divExact(target.ptrBitWidth(), 8),1948 else => @divExact(target.ptrBitWidth(), 8),
1945 };1949 };
1946 }1950 }
src/Compilation.zig+1
...@@ -1053,6 +1053,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1053,6 +1053,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1053 buf.appendSliceAssumeCapacity(",");1053 buf.appendSliceAssumeCapacity(",");
1054 }1054 }
1055 }1055 }
1056 if (buf.items.len == 0) break :blk "";
1056 assert(mem.endsWith(u8, buf.items, ","));1057 assert(mem.endsWith(u8, buf.items, ","));
1057 buf.items[buf.items.len - 1] = 0;1058 buf.items[buf.items.len - 1] = 0;
1058 buf.shrinkAndFree(buf.items.len);1059 buf.shrinkAndFree(buf.items.len);
src/codegen/llvm.zig+505-331
...@@ -340,7 +340,6 @@ const DataLayoutBuilder = struct {...@@ -340,7 +340,6 @@ const DataLayoutBuilder = struct {
340 _: std.fmt.FormatOptions,340 _: std.fmt.FormatOptions,
341 writer: anytype,341 writer: anytype,
342 ) @TypeOf(writer).Error!void {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()) {343 try writer.writeByte(switch (self.target.cpu.arch.endian()) {
345 .Little => 'e',344 .Little => 'e',
346 .Big => 'E',345 .Big => 'E',
...@@ -359,7 +358,7 @@ const DataLayoutBuilder = struct {...@@ -359,7 +358,7 @@ const DataLayoutBuilder = struct {
359 .macho => 'o', // Mach-O mangling: Private symbols get `L` prefix.358 .macho => 'o', // Mach-O mangling: Private symbols get `L` prefix.
360 // Other symbols get a `_` prefix.359 // Other symbols get a `_` prefix.
361 .coff => switch (self.target.os.tag) {360 .coff => switch (self.target.os.tag) {
362 .windows => switch (self.target.cpu.arch) {361 .uefi, .windows => switch (self.target.cpu.arch) {
363 .x86 => 'x', // Windows x86 COFF mangling: Private symbols get the usual362 .x86 => 'x', // Windows x86 COFF mangling: Private symbols get the usual
364 // prefix. Regular C symbols get a `_` prefix. Functions with `__stdcall`,363 // prefix. Regular C symbols get a `_` prefix. Functions with `__stdcall`,
365 //`__fastcall`, and `__vectorcall` have custom mangling that appends `@N`364 //`__fastcall`, and `__vectorcall` have custom mangling that appends `@N`
...@@ -407,7 +406,8 @@ const DataLayoutBuilder = struct {...@@ -407,7 +406,8 @@ const DataLayoutBuilder = struct {
407 };406 };
408 if (self.target.cpu.arch == .aarch64_32) continue;407 if (self.target.cpu.arch == .aarch64_32) continue;
409 if (!info.force_in_data_layout and matches_default and408 if (!info.force_in_data_layout and matches_default and
410 self.target.cpu.arch != .riscv64 and !is_aarch64_windows and409 self.target.cpu.arch != .riscv64 and !(self.target.cpu.arch == .aarch64 and
410 (self.target.os.tag == .uefi or self.target.os.tag == .windows)) and
411 self.target.cpu.arch != .bpfeb and self.target.cpu.arch != .bpfel) continue;411 self.target.cpu.arch != .bpfeb and self.target.cpu.arch != .bpfel) continue;
412 try writer.writeAll("-p");412 try writer.writeAll("-p");
413 if (info.llvm != .default) try writer.print("{d}", .{@intFromEnum(info.llvm)});413 if (info.llvm != .default) try writer.print("{d}", .{@intFromEnum(info.llvm)});
...@@ -423,7 +423,7 @@ const DataLayoutBuilder = struct {...@@ -423,7 +423,7 @@ const DataLayoutBuilder = struct {
423 if (self.target.cpu.arch == .s390x) try self.typeAlignment(.integer, 1, 8, 8, false, writer);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);424 try self.typeAlignment(.integer, 8, 8, 8, false, writer);
425 try self.typeAlignment(.integer, 16, 16, 16, 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);426 try self.typeAlignment(.integer, 32, 32, 32, false, writer);
427 try self.typeAlignment(.integer, 64, 32, 64, false, writer);427 try self.typeAlignment(.integer, 64, 32, 64, false, writer);
428 try self.typeAlignment(.integer, 128, 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);429 if (backendSupportsF16(self.target)) try self.typeAlignment(.float, 16, 16, 16, false, writer);
...@@ -453,8 +453,15 @@ const DataLayoutBuilder = struct {...@@ -453,8 +453,15 @@ const DataLayoutBuilder = struct {
453 try self.typeAlignment(.vector, 128, 128, 128, true, writer);453 try self.typeAlignment(.vector, 128, 128, 128, true, writer);
454 },454 },
455 }455 }
456 if (self.target.os.tag != .windows and self.target.cpu.arch != .avr)456 const swap_agg_nat = switch (self.target.cpu.arch) {
457 try self.typeAlignment(.aggregate, 0, 0, 64, false, writer);457 .x86, .x86_64 => switch (self.target.os.tag) {
458 .uefi, .windows => true,
459 else => false,
460 },
461 .avr => true,
462 else => false,
463 };
464 if (!swap_agg_nat) try self.typeAlignment(.aggregate, 0, 0, 64, false, writer);
458 for (@as([]const u24, switch (self.target.cpu.arch) {465 for (@as([]const u24, switch (self.target.cpu.arch) {
459 .avr => &.{8},466 .avr => &.{8},
460 .msp430 => &.{ 8, 16 },467 .msp430 => &.{ 8, 16 },
...@@ -498,6 +505,7 @@ const DataLayoutBuilder = struct {...@@ -498,6 +505,7 @@ const DataLayoutBuilder = struct {
498 0 => try writer.print("-n{d}", .{natural}),505 0 => try writer.print("-n{d}", .{natural}),
499 else => try writer.print(":{d}", .{natural}),506 else => try writer.print(":{d}", .{natural}),
500 };507 };
508 if (swap_agg_nat) try self.typeAlignment(.aggregate, 0, 0, 64, false, writer);
501 if (self.target.cpu.arch == .hexagon) {509 if (self.target.cpu.arch == .hexagon) {
502 try self.typeAlignment(.integer, 64, 64, 64, true, writer);510 try self.typeAlignment(.integer, 64, 64, 64, true, writer);
503 try self.typeAlignment(.integer, 32, 32, 32, true, writer);511 try self.typeAlignment(.integer, 32, 32, 32, true, writer);
...@@ -506,11 +514,9 @@ const DataLayoutBuilder = struct {...@@ -506,11 +514,9 @@ const DataLayoutBuilder = struct {
506 try self.typeAlignment(.float, 32, 32, 32, true, writer);514 try self.typeAlignment(.float, 32, 32, 32, true, writer);
507 try self.typeAlignment(.float, 64, 64, 64, true, writer);515 try self.typeAlignment(.float, 64, 64, 64, true, writer);
508 }516 }
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;517 const stack_abi = self.target.stackAlignment() * 8;
512 if (self.target.os.tag == .windows or self.target.cpu.arch == .msp430 or518 if (self.target.os.tag == .uefi or self.target.os.tag == .windows or
513 stack_abi != ptr_bit_width)519 self.target.cpu.arch == .msp430 or stack_abi != ptr_bit_width)
514 try writer.print("-S{d}", .{stack_abi});520 try writer.print("-S{d}", .{stack_abi});
515 switch (self.target.cpu.arch) {521 switch (self.target.cpu.arch) {
516 .hexagon, .ve => {522 .hexagon, .ve => {
...@@ -571,22 +577,21 @@ const DataLayoutBuilder = struct {...@@ -571,22 +577,21 @@ const DataLayoutBuilder = struct {
571 .integer => {577 .integer => {
572 if (self.target.ptrBitWidth() <= 16 and size >= 128) return;578 if (self.target.ptrBitWidth() <= 16 and size >= 128) return;
573 abi = @min(abi, self.target.maxIntAlignment() * 8);579 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) {580 switch (self.target.cpu.arch) {
587 .aarch64,581 .aarch64,
588 .aarch64_be,582 .aarch64_be,
589 .aarch64_32,583 .aarch64_32,
584 => if (size == 128) {
585 abi = size;
586 pref = size;
587 } else switch (self.target.os.tag) {
588 .macos => {},
589 .uefi, .windows => {
590 pref = size;
591 force_abi = size >= 32;
592 },
593 else => pref = @max(pref, 32),
594 },
590 .bpfeb,595 .bpfeb,
591 .bpfel,596 .bpfel,
592 .nvptx,597 .nvptx,
...@@ -597,6 +602,9 @@ const DataLayoutBuilder = struct {...@@ -597,6 +602,9 @@ const DataLayoutBuilder = struct {
597 pref = size;602 pref = size;
598 },603 },
599 .hexagon => force_abi = true,604 .hexagon => force_abi = true,
605 .mips,
606 .mipsel,
607 => pref = @max(pref, 32),
600 .mips64,608 .mips64,
601 .mips64el,609 .mips64el,
602 => if (size <= 32) {610 => if (size <= 32) {
...@@ -617,7 +625,8 @@ const DataLayoutBuilder = struct {...@@ -617,7 +625,8 @@ const DataLayoutBuilder = struct {
617 128 => abi = 64,625 128 => abi = 64,
618 else => {},626 else => {},
619 }627 }
620 } else if ((self.target.cpu.arch.isPPC64() and (size == 256 or size == 512)) or628 } else if ((self.target.cpu.arch.isPPC64() and self.target.os.tag == .linux and
629 (size == 256 or size == 512)) or
621 (self.target.cpu.arch.isNvptx() and (size == 16 or size == 32)))630 (self.target.cpu.arch.isNvptx() and (size == 16 or size == 32)))
622 {631 {
623 force_abi = true;632 force_abi = true;
...@@ -646,17 +655,21 @@ const DataLayoutBuilder = struct {...@@ -646,17 +655,21 @@ const DataLayoutBuilder = struct {
646 .hexagon => if (size == 32 or size == 64) {655 .hexagon => if (size == 32 or size == 64) {
647 force_abi = true;656 force_abi = true;
648 },657 },
649 .aarch64_32 => if (size == 128) {658 .aarch64_32, .amdgcn => if (size == 128) {
650 abi = size;659 abi = size;
651 pref = size;660 pref = size;
652 },661 },
662 .wasm32, .wasm64 => if (self.target.os.tag == .emscripten and size == 128) {
663 abi = 64;
664 pref = 64;
665 },
653 .ve => if (size == 64) {666 .ve => if (size == 64) {
654 abi = size;667 abi = size;
655 pref = size;668 pref = size;
656 },669 },
657 else => {},670 else => {},
658 },671 },
659 .aggregate => if (self.target.os.tag == .windows or672 .aggregate => if (self.target.os.tag == .uefi or self.target.os.tag == .windows or
660 self.target.cpu.arch.isARM() or self.target.cpu.arch.isThumb())673 self.target.cpu.arch.isARM() or self.target.cpu.arch.isThumb())
661 {674 {
662 pref = @min(pref, self.target.ptrBitWidth());675 pref = @min(pref, self.target.ptrBitWidth());
...@@ -794,7 +807,7 @@ pub const Object = struct {...@@ -794,7 +807,7 @@ pub const Object = struct {
794 builder.llvm.di_compile_unit = builder.llvm.di_builder.?.createCompileUnit(807 builder.llvm.di_compile_unit = builder.llvm.di_builder.?.createCompileUnit(
795 DW.LANG.C99,808 DW.LANG.C99,
796 builder.llvm.di_builder.?.createFile(options.root_name, compile_unit_dir_z),809 builder.llvm.di_builder.?.createFile(options.root_name, compile_unit_dir_z),
797 producer.toSlice(&builder).?,810 producer.slice(&builder).?,
798 options.optimize_mode != .Debug,811 options.optimize_mode != .Debug,
799 "", // flags812 "", // flags
800 0, // runtime version813 0, // runtime version
...@@ -830,7 +843,7 @@ pub const Object = struct {...@@ -830,7 +843,7 @@ pub const Object = struct {
830843
831 target_machine = llvm.TargetMachine.create(844 target_machine = llvm.TargetMachine.create(
832 builder.llvm.target.?,845 builder.llvm.target.?,
833 builder.target_triple.toSlice(&builder).?,846 builder.target_triple.slice(&builder).?,
834 if (options.target.cpu.model.llvm_name) |s| s.ptr else null,847 if (options.target.cpu.model.llvm_name) |s| s.ptr else null,
835 options.llvm_cpu_features,848 options.llvm_cpu_features,
836 opt_level,849 opt_level,
...@@ -861,7 +874,7 @@ pub const Object = struct {...@@ -861,7 +874,7 @@ pub const Object = struct {
861 defer llvm.disposeMessage(rep);874 defer llvm.disposeMessage(rep);
862 std.testing.expectEqualStrings(875 std.testing.expectEqualStrings(
863 std.mem.span(rep),876 std.mem.span(rep),
864 builder.data_layout.toSlice(&builder).?,877 builder.data_layout.slice(&builder).?,
865 ) catch unreachable;878 ) catch unreachable;
866 }879 }
867 }880 }
...@@ -963,7 +976,7 @@ pub const Object = struct {...@@ -963,7 +976,7 @@ pub const Object = struct {
963976
964 llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{977 llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{
965 global_index.toConst(),978 global_index.toConst(),
966 try o.builder.intConst(llvm_usize_ty, name.toSlice(&o.builder).?.len),979 try o.builder.intConst(llvm_usize_ty, name.slice(&o.builder).?.len),
967 });980 });
968 }981 }
969982
...@@ -1021,15 +1034,11 @@ pub const Object = struct {...@@ -1021,15 +1034,11 @@ pub const Object = struct {
10211034
1022 fn genModuleLevelAssembly(object: *Object) !void {1035 fn genModuleLevelAssembly(object: *Object) !void {
1023 const mod = object.module;1036 const mod = object.module;
1024 if (mod.global_assembly.count() == 0) return;1037
1025 var buffer = std.ArrayList(u8).init(mod.gpa);1038 const writer = object.builder.setModuleAsm();
1026 defer buffer.deinit();1039 var it = mod.global_assembly.valueIterator();
1027 var it = mod.global_assembly.iterator();1040 while (it.next()) |assembly| try writer.print("{s}\n", .{assembly.*});
1028 while (it.next()) |kv| {1041 try object.builder.finishModuleAsm();
1029 try buffer.appendSlice(kv.value_ptr.*);
1030 try buffer.append('\n');
1031 }
1032 object.llvm_module.setModuleInlineAsm2(buffer.items.ptr, buffer.items.len - 1);
1033 }1042 }
10341043
1035 fn resolveExportExternCollisions(object: *Object) !void {1044 fn resolveExportExternCollisions(object: *Object) !void {
...@@ -1223,6 +1232,7 @@ pub const Object = struct {...@@ -1223,6 +1232,7 @@ pub const Object = struct {
1223 const func = mod.funcInfo(func_index);1232 const func = mod.funcInfo(func_index);
1224 const decl_index = func.owner_decl;1233 const decl_index = func.owner_decl;
1225 const decl = mod.declPtr(decl_index);1234 const decl = mod.declPtr(decl_index);
1235 const fn_info = mod.typeToFunc(decl.ty).?;
1226 const target = mod.getTarget();1236 const target = mod.getTarget();
1227 const ip = &mod.intern_pool;1237 const ip = &mod.intern_pool;
12281238
...@@ -1237,28 +1247,43 @@ pub const Object = struct {...@@ -1237,28 +1247,43 @@ pub const Object = struct {
1237 const global = function.ptrConst(&o.builder).global;1247 const global = function.ptrConst(&o.builder).global;
1238 const llvm_func = global.toLlvm(&o.builder);1248 const llvm_func = global.toLlvm(&o.builder);
12391249
1250 var attributes = try function.ptrConst(&o.builder).attributes.toWip(&o.builder);
1251 defer attributes.deinit(&o.builder);
1252
1240 if (func.analysis(ip).is_noinline) {1253 if (func.analysis(ip).is_noinline) {
1254 try attributes.addFnAttr(.@"noinline", &o.builder);
1241 o.addFnAttr(llvm_func, "noinline");1255 o.addFnAttr(llvm_func, "noinline");
1242 } else {1256 } else {
1257 _ = try attributes.removeFnAttr(.@"noinline");
1243 Object.removeFnAttr(llvm_func, "noinline");1258 Object.removeFnAttr(llvm_func, "noinline");
1244 }1259 }
12451260
1246 if (func.analysis(ip).stack_alignment.toByteUnitsOptional()) |alignment| {1261 if (func.analysis(ip).stack_alignment.toByteUnitsOptional()) |alignment| {
1262 try attributes.addFnAttr(.{ .alignstack = Builder.Alignment.fromByteUnits(alignment) }, &o.builder);
1263 try attributes.addFnAttr(.@"noinline", &o.builder);
1247 o.addFnAttrInt(llvm_func, "alignstack", alignment);1264 o.addFnAttrInt(llvm_func, "alignstack", alignment);
1248 o.addFnAttr(llvm_func, "noinline");1265 o.addFnAttr(llvm_func, "noinline");
1249 } else {1266 } else {
1267 _ = try attributes.removeFnAttr(.alignstack);
1250 Object.removeFnAttr(llvm_func, "alignstack");1268 Object.removeFnAttr(llvm_func, "alignstack");
1251 }1269 }
12521270
1253 if (func.analysis(ip).is_cold) {1271 if (func.analysis(ip).is_cold) {
1272 try attributes.addFnAttr(.cold, &o.builder);
1254 o.addFnAttr(llvm_func, "cold");1273 o.addFnAttr(llvm_func, "cold");
1255 } else {1274 } else {
1275 _ = try attributes.removeFnAttr(.cold);
1256 Object.removeFnAttr(llvm_func, "cold");1276 Object.removeFnAttr(llvm_func, "cold");
1257 }1277 }
12581278
1259 // TODO: disable this if safety is off for the function scope1279 // TODO: disable this if safety is off for the function scope
1260 const ssp_buf_size = mod.comp.bin_file.options.stack_protector;1280 const ssp_buf_size = mod.comp.bin_file.options.stack_protector;
1261 if (ssp_buf_size != 0) {1281 if (ssp_buf_size != 0) {
1282 try attributes.addFnAttr(.sspstrong, &o.builder);
1283 try attributes.addFnAttr(.{ .string = .{
1284 .kind = try o.builder.string("stack-protector-buffer-size"),
1285 .value = try o.builder.fmt("{d}", .{ssp_buf_size}),
1286 } }, &o.builder);
1262 var buf: [12]u8 = undefined;1287 var buf: [12]u8 = undefined;
1263 const arg = std.fmt.bufPrintZ(&buf, "{d}", .{ssp_buf_size}) catch unreachable;1288 const arg = std.fmt.bufPrintZ(&buf, "{d}", .{ssp_buf_size}) catch unreachable;
1264 o.addFnAttr(llvm_func, "sspstrong");1289 o.addFnAttr(llvm_func, "sspstrong");
...@@ -1267,8 +1292,16 @@ pub const Object = struct {...@@ -1267,8 +1292,16 @@ pub const Object = struct {
12671292
1268 // TODO: disable this if safety is off for the function scope1293 // TODO: disable this if safety is off for the function scope
1269 if (mod.comp.bin_file.options.stack_check) {1294 if (mod.comp.bin_file.options.stack_check) {
1295 try attributes.addFnAttr(.{ .string = .{
1296 .kind = try o.builder.string("probe-stack"),
1297 .value = try o.builder.string("__zig_probe_stack"),
1298 } }, &o.builder);
1270 o.addFnAttrString(llvm_func, "probe-stack", "__zig_probe_stack");1299 o.addFnAttrString(llvm_func, "probe-stack", "__zig_probe_stack");
1271 } else if (target.os.tag == .uefi) {1300 } else if (target.os.tag == .uefi) {
1301 try attributes.addFnAttr(.{ .string = .{
1302 .kind = try o.builder.string("no-stack-arg-probe"),
1303 .value = .empty,
1304 } }, &o.builder);
1272 o.addFnAttrString(llvm_func, "no-stack-arg-probe", "");1305 o.addFnAttrString(llvm_func, "no-stack-arg-probe", "");
1273 }1306 }
12741307
...@@ -1286,18 +1319,22 @@ pub const Object = struct {...@@ -1286,18 +1319,22 @@ pub const Object = struct {
1286 var llvm_arg_i: u32 = 0;1319 var llvm_arg_i: u32 = 0;
12871320
1288 // This gets the LLVM values from the function and stores them in `dg.args`.1321 // This gets the LLVM values from the function and stores them in `dg.args`.
1289 const fn_info = mod.typeToFunc(decl.ty).?;
1290 const sret = firstParamSRet(fn_info, mod);1322 const sret = firstParamSRet(fn_info, mod);
1291 const ret_ptr: Builder.Value = if (sret) param: {1323 const ret_ptr: Builder.Value = if (sret) param: {
1292 const param = wip.arg(llvm_arg_i);1324 const param = wip.arg(llvm_arg_i);
1293 llvm_arg_i += 1;1325 llvm_arg_i += 1;
1294 break :param param;1326 break :param param;
1295 } else .none;1327 } else .none;
1296 const gpa = o.gpa;
12971328
1298 if (ccAbiPromoteInt(fn_info.cc, mod, fn_info.return_type.toType())) |s| switch (s) {1329 if (ccAbiPromoteInt(fn_info.cc, mod, fn_info.return_type.toType())) |s| switch (s) {
1299 .signed => o.addAttr(llvm_func, 0, "signext"),1330 .signed => {
1300 .unsigned => o.addAttr(llvm_func, 0, "zeroext"),1331 try attributes.addRetAttr(.signext, &o.builder);
1332 o.addAttr(llvm_func, 0, "signext");
1333 },
1334 .unsigned => {
1335 try attributes.addRetAttr(.zeroext, &o.builder);
1336 o.addAttr(llvm_func, 0, "zeroext");
1337 },
1301 };1338 };
13021339
1303 const err_return_tracing = fn_info.return_type.toType().isError(mod) and1340 const err_return_tracing = fn_info.return_type.toType().isError(mod) and
...@@ -1312,6 +1349,7 @@ pub const Object = struct {...@@ -1312,6 +1349,7 @@ pub const Object = struct {
1312 // This is the list of args we will use that correspond directly to the AIR arg1349 // This is the list of args we will use that correspond directly to the AIR arg
1313 // instructions. Depending on the calling convention, this list is not necessarily1350 // instructions. Depending on the calling convention, this list is not necessarily
1314 // a bijection with the actual LLVM parameters of the function.1351 // a bijection with the actual LLVM parameters of the function.
1352 const gpa = o.gpa;
1315 var args: std.ArrayListUnmanaged(Builder.Value) = .{};1353 var args: std.ArrayListUnmanaged(Builder.Value) = .{};
1316 defer args.deinit(gpa);1354 defer args.deinit(gpa);
13171355
...@@ -1337,7 +1375,7 @@ pub const Object = struct {...@@ -1337,7 +1375,7 @@ pub const Object = struct {
1337 } else {1375 } else {
1338 args.appendAssumeCapacity(param);1376 args.appendAssumeCapacity(param);
13391377
1340 o.addByValParamAttrs(llvm_func, param_ty, param_index, fn_info, @intCast(llvm_arg_i));1378 try o.addByValParamAttrsOld(&attributes, llvm_func, param_ty, param_index, fn_info, llvm_arg_i);
1341 }1379 }
1342 llvm_arg_i += 1;1380 llvm_arg_i += 1;
1343 },1381 },
...@@ -1347,7 +1385,7 @@ pub const Object = struct {...@@ -1347,7 +1385,7 @@ pub const Object = struct {
1347 const param = wip.arg(llvm_arg_i);1385 const param = wip.arg(llvm_arg_i);
1348 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));1386 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
13491387
1350 o.addByRefParamAttrs(llvm_func, @intCast(llvm_arg_i), @intCast(alignment.toByteUnits() orelse 0), it.byval_attr, param_llvm_ty);1388 try o.addByRefParamAttrsOld(&attributes, llvm_func, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty);
1351 llvm_arg_i += 1;1389 llvm_arg_i += 1;
13521390
1353 if (isByRef(param_ty, mod)) {1391 if (isByRef(param_ty, mod)) {
...@@ -1362,7 +1400,8 @@ pub const Object = struct {...@@ -1362,7 +1400,8 @@ pub const Object = struct {
1362 const param = wip.arg(llvm_arg_i);1400 const param = wip.arg(llvm_arg_i);
1363 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));1401 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
13641402
1365 o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "noundef");1403 try attributes.addParamAttr(llvm_arg_i, .noundef, &o.builder);
1404 o.addArgAttr(llvm_func, llvm_arg_i, "noundef");
1366 llvm_arg_i += 1;1405 llvm_arg_i += 1;
13671406
1368 if (isByRef(param_ty, mod)) {1407 if (isByRef(param_ty, mod)) {
...@@ -1398,21 +1437,28 @@ pub const Object = struct {...@@ -1398,21 +1437,28 @@ pub const Object = struct {
13981437
1399 if (math.cast(u5, it.zig_index - 1)) |i| {1438 if (math.cast(u5, it.zig_index - 1)) |i| {
1400 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {1439 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
1401 o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "noalias");1440 try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
1441 o.addArgAttr(llvm_func, llvm_arg_i, "noalias");
1402 }1442 }
1403 }1443 }
1404 if (param_ty.zigTypeTag(mod) != .Optional) {1444 if (param_ty.zigTypeTag(mod) != .Optional) {
1405 o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "nonnull");1445 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
1446 o.addArgAttr(llvm_func, llvm_arg_i, "nonnull");
1406 }1447 }
1407 if (ptr_info.flags.is_const) {1448 if (ptr_info.flags.is_const) {
1408 o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "readonly");1449 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
1450 o.addArgAttr(llvm_func, llvm_arg_i, "readonly");
1409 }1451 }
1410 const elem_align = ptr_info.flags.alignment.toByteUnitsOptional() orelse1452 const elem_align = Builder.Alignment.fromByteUnits(
1411 @max(ptr_info.child.toType().abiAlignment(mod), 1);1453 ptr_info.flags.alignment.toByteUnitsOptional() orelse
1412 o.addArgAttrInt(llvm_func, @intCast(llvm_arg_i), "align", elem_align);1454 @max(ptr_info.child.toType().abiAlignment(mod), 1),
1413 const ptr_param = wip.arg(llvm_arg_i + 0);1455 );
1414 const len_param = wip.arg(llvm_arg_i + 1);1456 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
1415 llvm_arg_i += 2;1457 o.addArgAttrInt(llvm_func, llvm_arg_i, "align", elem_align.toByteUnits() orelse 0);
1458 const ptr_param = wip.arg(llvm_arg_i);
1459 llvm_arg_i += 1;
1460 const len_param = wip.arg(llvm_arg_i);
1461 llvm_arg_i += 1;
14161462
1417 const slice_llvm_ty = try o.lowerType(param_ty);1463 const slice_llvm_ty = try o.lowerType(param_ty);
1418 args.appendAssumeCapacity(1464 args.appendAssumeCapacity(
...@@ -1482,6 +1528,8 @@ pub const Object = struct {...@@ -1482,6 +1528,8 @@ pub const Object = struct {
1482 }1528 }
1483 }1529 }
14841530
1531 function.ptr(&o.builder).attributes = try attributes.finish(&o.builder);
1532
1485 var di_file: ?*llvm.DIFile = null;1533 var di_file: ?*llvm.DIFile = null;
1486 var di_scope: ?*llvm.DIScope = null;1534 var di_scope: ?*llvm.DIScope = null;
14871535
...@@ -1618,7 +1666,7 @@ pub const Object = struct {...@@ -1618,7 +1666,7 @@ pub const Object = struct {
1618 llvm_global.setDLLStorageClass(.Default);1666 llvm_global.setDLLStorageClass(.Default);
1619 }1667 }
1620 if (self.di_map.get(decl)) |di_node| {1668 if (self.di_map.get(decl)) |di_node| {
1621 const decl_name_slice = decl_name.toSlice(&self.builder).?;1669 const decl_name_slice = decl_name.slice(&self.builder).?;
1622 if (try decl.isFunction(mod)) {1670 if (try decl.isFunction(mod)) {
1623 const di_func: *llvm.DISubprogram = @ptrCast(di_node);1671 const di_func: *llvm.DISubprogram = @ptrCast(di_node);
1624 const linkage_name = llvm.MDString.get(self.builder.llvm.context, decl_name_slice.ptr, decl_name_slice.len);1672 const linkage_name = llvm.MDString.get(self.builder.llvm.context, decl_name_slice.ptr, decl_name_slice.len);
...@@ -1655,7 +1703,7 @@ pub const Object = struct {...@@ -1655,7 +1703,7 @@ pub const Object = struct {
1655 llvm_global.setDLLStorageClass(.DLLExport);1703 llvm_global.setDLLStorageClass(.DLLExport);
1656 }1704 }
1657 if (self.di_map.get(decl)) |di_node| {1705 if (self.di_map.get(decl)) |di_node| {
1658 const exp_name_slice = exp_name.toSlice(&self.builder).?;1706 const exp_name_slice = exp_name.slice(&self.builder).?;
1659 if (try decl.isFunction(mod)) {1707 if (try decl.isFunction(mod)) {
1660 const di_func: *llvm.DISubprogram = @ptrCast(di_node);1708 const di_func: *llvm.DISubprogram = @ptrCast(di_node);
1661 const linkage_name = llvm.MDString.get(self.builder.llvm.context, exp_name_slice.ptr, exp_name_slice.len);1709 const linkage_name = llvm.MDString.get(self.builder.llvm.context, exp_name_slice.ptr, exp_name_slice.len);
...@@ -2816,7 +2864,7 @@ pub const Object = struct {...@@ -2816,7 +2864,7 @@ pub const Object = struct {
2816 const fqn = try o.builder.string(ip.stringToSlice(try decl.getFullyQualifiedName(mod)));2864 const fqn = try o.builder.string(ip.stringToSlice(try decl.getFullyQualifiedName(mod)));
28172865
2818 const llvm_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);2866 const llvm_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);
2819 const llvm_fn = o.llvm_module.addFunctionInAddressSpace(fqn.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder), @intFromEnum(llvm_addrspace));2867 const llvm_fn = o.llvm_module.addFunctionInAddressSpace(fqn.slice(&o.builder).?, fn_type.toLlvm(&o.builder), @intFromEnum(llvm_addrspace));
28202868
2821 var global = Builder.Global{2869 var global = Builder.Global{
2822 .type = fn_type,2870 .type = fn_type,
...@@ -2826,6 +2874,9 @@ pub const Object = struct {...@@ -2826,6 +2874,9 @@ pub const Object = struct {
2826 .global = @enumFromInt(o.builder.globals.count()),2874 .global = @enumFromInt(o.builder.globals.count()),
2827 };2875 };
28282876
2877 var attributes: Builder.FunctionAttributes.Wip = .{};
2878 defer attributes.deinit(&o.builder);
2879
2829 const is_extern = decl.isExtern(mod);2880 const is_extern = decl.isExtern(mod);
2830 if (!is_extern) {2881 if (!is_extern) {
2831 global.linkage = .internal;2882 global.linkage = .internal;
...@@ -2834,43 +2885,64 @@ pub const Object = struct {...@@ -2834,43 +2885,64 @@ pub const Object = struct {
2834 llvm_fn.setUnnamedAddr(.True);2885 llvm_fn.setUnnamedAddr(.True);
2835 } else {2886 } else {
2836 if (target.isWasm()) {2887 if (target.isWasm()) {
2888 try attributes.addFnAttr(.{ .string = .{
2889 .kind = try o.builder.string("wasm-import-name"),
2890 .value = try o.builder.string(ip.stringToSlice(decl.name)),
2891 } }, &o.builder);
2837 o.addFnAttrString(llvm_fn, "wasm-import-name", ip.stringToSlice(decl.name));2892 o.addFnAttrString(llvm_fn, "wasm-import-name", ip.stringToSlice(decl.name));
2838 if (ip.stringToSliceUnwrap(decl.getOwnedExternFunc(mod).?.lib_name)) |lib_name| {2893 if (ip.stringToSliceUnwrap(decl.getOwnedExternFunc(mod).?.lib_name)) |lib_name| {
2839 if (!std.mem.eql(u8, lib_name, "c")) {2894 if (!std.mem.eql(u8, lib_name, "c")) {
2895 try attributes.addFnAttr(.{ .string = .{
2896 .kind = try o.builder.string("wasm-import-module"),
2897 .value = try o.builder.string(lib_name),
2898 } }, &o.builder);
2840 o.addFnAttrString(llvm_fn, "wasm-import-module", lib_name);2899 o.addFnAttrString(llvm_fn, "wasm-import-module", lib_name);
2841 }2900 }
2842 }2901 }
2843 }2902 }
2844 }2903 }
28452904
2905 var llvm_arg_i: u32 = 0;
2846 if (sret) {2906 if (sret) {
2847 o.addArgAttr(llvm_fn, 0, "nonnull"); // Sret pointers must not be address 02907 // Sret pointers must not be address 0
2848 o.addArgAttr(llvm_fn, 0, "noalias");2908 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
2909 try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
2910 o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull"); // Sret pointers must not be address 0
2911 o.addArgAttr(llvm_fn, llvm_arg_i, "noalias");
28492912
2850 const raw_llvm_ret_ty = (try o.lowerType(fn_info.return_type.toType())).toLlvm(&o.builder);2913 const raw_llvm_ret_ty = try o.lowerType(fn_info.return_type.toType());
2851 llvm_fn.addSretAttr(raw_llvm_ret_ty);2914 try attributes.addParamAttr(llvm_arg_i, .{ .sret = raw_llvm_ret_ty }, &o.builder);
2915 llvm_fn.addSretAttr(raw_llvm_ret_ty.toLlvm(&o.builder));
2916
2917 llvm_arg_i += 1;
2852 }2918 }
28532919
2854 const err_return_tracing = fn_info.return_type.toType().isError(mod) and2920 const err_return_tracing = fn_info.return_type.toType().isError(mod) and
2855 mod.comp.bin_file.options.error_return_tracing;2921 mod.comp.bin_file.options.error_return_tracing;
28562922
2857 if (err_return_tracing) {2923 if (err_return_tracing) {
2858 o.addArgAttr(llvm_fn, @intFromBool(sret), "nonnull");2924 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
2925 o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");
2926 llvm_arg_i += 1;
2859 }2927 }
28602928
2861 switch (fn_info.cc) {2929 switch (fn_info.cc) {
2862 .Unspecified, .Inline => {2930 .Unspecified, .Inline => {
2931 function.call_conv = .fastcc;
2863 llvm_fn.setFunctionCallConv(.Fast);2932 llvm_fn.setFunctionCallConv(.Fast);
2864 },2933 },
2865 .Naked => {2934 .Naked => {
2935 try attributes.addFnAttr(.naked, &o.builder);
2866 o.addFnAttr(llvm_fn, "naked");2936 o.addFnAttr(llvm_fn, "naked");
2867 },2937 },
2868 .Async => {2938 .Async => {
2939 function.call_conv = .fastcc;
2869 llvm_fn.setFunctionCallConv(.Fast);2940 llvm_fn.setFunctionCallConv(.Fast);
2870 @panic("TODO: LLVM backend lower async function");2941 @panic("TODO: LLVM backend lower async function");
2871 },2942 },
2872 else => {2943 else => {
2873 llvm_fn.setFunctionCallConv(toLlvmCallConv(fn_info.cc, target));2944 function.call_conv = toLlvmCallConv(fn_info.cc, target);
2945 llvm_fn.setFunctionCallConv(@enumFromInt(@intFromEnum(function.call_conv)));
2874 },2946 },
2875 }2947 }
28762948
...@@ -2880,9 +2952,10 @@ pub const Object = struct {...@@ -2880,9 +2952,10 @@ pub const Object = struct {
2880 }2952 }
28812953
2882 // Function attributes that are independent of analysis results of the function body.2954 // Function attributes that are independent of analysis results of the function body.
2883 o.addCommonFnAttributes(llvm_fn);2955 try o.addCommonFnAttributes(&attributes, llvm_fn);
28842956
2885 if (fn_info.return_type == .noreturn_type) {2957 if (fn_info.return_type == .noreturn_type) {
2958 try attributes.addFnAttr(.noreturn, &o.builder);
2886 o.addFnAttr(llvm_fn, "noreturn");2959 o.addFnAttr(llvm_fn, "noreturn");
2887 }2960 }
28882961
...@@ -2890,23 +2963,24 @@ pub const Object = struct {...@@ -2890,23 +2963,24 @@ pub const Object = struct {
2890 // because functions with bodies are handled in `updateFunc`.2963 // because functions with bodies are handled in `updateFunc`.
2891 if (is_extern) {2964 if (is_extern) {
2892 var it = iterateParamTypes(o, fn_info);2965 var it = iterateParamTypes(o, fn_info);
2893 it.llvm_index += @intFromBool(sret);2966 it.llvm_index = llvm_arg_i;
2894 it.llvm_index += @intFromBool(err_return_tracing);
2895 while (try it.next()) |lowering| switch (lowering) {2967 while (try it.next()) |lowering| switch (lowering) {
2896 .byval => {2968 .byval => {
2897 const param_index = it.zig_index - 1;2969 const param_index = it.zig_index - 1;
2898 const param_ty = fn_info.param_types.get(ip)[param_index].toType();2970 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
2899 if (!isByRef(param_ty, mod)) {2971 if (!isByRef(param_ty, mod)) {
2900 o.addByValParamAttrs(llvm_fn, param_ty, param_index, fn_info, it.llvm_index - 1);2972 try o.addByValParamAttrsOld(&attributes, llvm_fn, param_ty, param_index, fn_info, it.llvm_index - 1);
2901 }2973 }
2902 },2974 },
2903 .byref => {2975 .byref => {
2904 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1];2976 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1];
2905 const param_llvm_ty = try o.lowerType(param_ty.toType());2977 const param_llvm_ty = try o.lowerType(param_ty.toType());
2906 const alignment = param_ty.toType().abiAlignment(mod);2978 const alignment =
2907 o.addByRefParamAttrs(llvm_fn, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);2979 Builder.Alignment.fromByteUnits(param_ty.toType().abiAlignment(mod));
2980 try o.addByRefParamAttrsOld(&attributes, llvm_fn, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
2908 },2981 },
2909 .byref_mut => {2982 .byref_mut => {
2983 try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder);
2910 o.addArgAttr(llvm_fn, it.llvm_index - 1, "noundef");2984 o.addArgAttr(llvm_fn, it.llvm_index - 1, "noundef");
2911 },2985 },
2912 // No attributes needed for these.2986 // No attributes needed for these.
...@@ -2924,25 +2998,42 @@ pub const Object = struct {...@@ -2924,25 +2998,42 @@ pub const Object = struct {
2924 };2998 };
2925 }2999 }
29263000
3001 function.attributes = try attributes.finish(&o.builder);
3002
2927 try o.builder.llvm.globals.append(o.gpa, llvm_fn);3003 try o.builder.llvm.globals.append(o.gpa, llvm_fn);
2928 gop.value_ptr.* = try o.builder.addGlobal(fqn, global);3004 gop.value_ptr.* = try o.builder.addGlobal(fqn, global);
2929 try o.builder.functions.append(o.gpa, function);3005 try o.builder.functions.append(o.gpa, function);
2930 return global.kind.function;3006 return global.kind.function;
2931 }3007 }
29323008
2933 fn addCommonFnAttributes(o: *Object, llvm_fn: *llvm.Value) void {3009 fn addCommonFnAttributes(
3010 o: *Object,
3011 attributes: *Builder.FunctionAttributes.Wip,
3012 llvm_fn: *llvm.Value,
3013 ) Allocator.Error!void {
2934 const comp = o.module.comp;3014 const comp = o.module.comp;
29353015
2936 if (!comp.bin_file.options.red_zone) {3016 if (!comp.bin_file.options.red_zone) {
3017 try attributes.addFnAttr(.noredzone, &o.builder);
2937 o.addFnAttr(llvm_fn, "noredzone");3018 o.addFnAttr(llvm_fn, "noredzone");
2938 }3019 }
2939 if (comp.bin_file.options.omit_frame_pointer) {3020 if (comp.bin_file.options.omit_frame_pointer) {
3021 try attributes.addFnAttr(.{ .string = .{
3022 .kind = try o.builder.string("frame-pointer"),
3023 .value = try o.builder.string("none"),
3024 } }, &o.builder);
2940 o.addFnAttrString(llvm_fn, "frame-pointer", "none");3025 o.addFnAttrString(llvm_fn, "frame-pointer", "none");
2941 } else {3026 } else {
3027 try attributes.addFnAttr(.{ .string = .{
3028 .kind = try o.builder.string("frame-pointer"),
3029 .value = try o.builder.string("all"),
3030 } }, &o.builder);
2942 o.addFnAttrString(llvm_fn, "frame-pointer", "all");3031 o.addFnAttrString(llvm_fn, "frame-pointer", "all");
2943 }3032 }
3033 try attributes.addFnAttr(.nounwind, &o.builder);
2944 o.addFnAttr(llvm_fn, "nounwind");3034 o.addFnAttr(llvm_fn, "nounwind");
2945 if (comp.unwind_tables) {3035 if (comp.unwind_tables) {
3036 try attributes.addFnAttr(.{ .uwtable = Builder.Attribute.UwTable.default }, &o.builder);
2946 o.addFnAttrInt(llvm_fn, "uwtable", 2);3037 o.addFnAttrInt(llvm_fn, "uwtable", 2);
2947 }3038 }
2948 if (comp.bin_file.options.skip_linker_dependencies or3039 if (comp.bin_file.options.skip_linker_dependencies or
...@@ -2953,22 +3044,38 @@ pub const Object = struct {...@@ -2953,22 +3044,38 @@ pub const Object = struct {
2953 // and llvm detects that the body is equivalent to memcpy, it may replace the3044 // and llvm detects that the body is equivalent to memcpy, it may replace the
2954 // body of memcpy with a call to memcpy, which would then cause a stack3045 // body of memcpy with a call to memcpy, which would then cause a stack
2955 // overflow instead of performing memcpy.3046 // overflow instead of performing memcpy.
3047 try attributes.addFnAttr(.nobuiltin, &o.builder);
2956 o.addFnAttr(llvm_fn, "nobuiltin");3048 o.addFnAttr(llvm_fn, "nobuiltin");
2957 }3049 }
2958 if (comp.bin_file.options.optimize_mode == .ReleaseSmall) {3050 if (comp.bin_file.options.optimize_mode == .ReleaseSmall) {
3051 try attributes.addFnAttr(.minsize, &o.builder);
3052 try attributes.addFnAttr(.optsize, &o.builder);
2959 o.addFnAttr(llvm_fn, "minsize");3053 o.addFnAttr(llvm_fn, "minsize");
2960 o.addFnAttr(llvm_fn, "optsize");3054 o.addFnAttr(llvm_fn, "optsize");
2961 }3055 }
2962 if (comp.bin_file.options.tsan) {3056 if (comp.bin_file.options.tsan) {
3057 try attributes.addFnAttr(.sanitize_thread, &o.builder);
2963 o.addFnAttr(llvm_fn, "sanitize_thread");3058 o.addFnAttr(llvm_fn, "sanitize_thread");
2964 }3059 }
2965 if (comp.getTarget().cpu.model.llvm_name) |s| {3060 if (comp.getTarget().cpu.model.llvm_name) |s| {
3061 try attributes.addFnAttr(.{ .string = .{
3062 .kind = try o.builder.string("target-cpu"),
3063 .value = try o.builder.string(s),
3064 } }, &o.builder);
2966 llvm_fn.addFunctionAttr("target-cpu", s);3065 llvm_fn.addFunctionAttr("target-cpu", s);
2967 }3066 }
2968 if (comp.bin_file.options.llvm_cpu_features) |s| {3067 if (comp.bin_file.options.llvm_cpu_features) |s| {
3068 try attributes.addFnAttr(.{ .string = .{
3069 .kind = try o.builder.string("target-features"),
3070 .value = try o.builder.string(std.mem.span(s)),
3071 } }, &o.builder);
2969 llvm_fn.addFunctionAttr("target-features", s);3072 llvm_fn.addFunctionAttr("target-features", s);
2970 }3073 }
2971 if (comp.getTarget().cpu.arch.isBpf()) {3074 if (comp.getTarget().cpu.arch.isBpf()) {
3075 try attributes.addFnAttr(.{ .string = .{
3076 .kind = try o.builder.string("no-builtins"),
3077 .value = .empty,
3078 } }, &o.builder);
2972 llvm_fn.addFunctionAttr("no-builtins", "");3079 llvm_fn.addFunctionAttr("no-builtins", "");
2973 }3080 }
2974 }3081 }
...@@ -3002,7 +3109,7 @@ pub const Object = struct {...@@ -3002,7 +3109,7 @@ pub const Object = struct {
3002 fqn;3109 fqn;
3003 const llvm_global = o.llvm_module.addGlobalInAddressSpace(3110 const llvm_global = o.llvm_module.addGlobalInAddressSpace(
3004 global.type.toLlvm(&o.builder),3111 global.type.toLlvm(&o.builder),
3005 fqn.toSlice(&o.builder).?,3112 fqn.slice(&o.builder).?,
3006 @intFromEnum(global.addr_space),3113 @intFromEnum(global.addr_space),
3007 );3114 );
30083115
...@@ -4403,47 +4510,114 @@ pub const Object = struct {...@@ -4403,47 +4510,114 @@ pub const Object = struct {
44034510
4404 fn addByValParamAttrs(4511 fn addByValParamAttrs(
4405 o: *Object,4512 o: *Object,
4513 attributes: *Builder.FunctionAttributes.Wip,
4514 param_ty: Type,
4515 param_index: u32,
4516 fn_info: InternPool.Key.FuncType,
4517 llvm_arg_i: u32,
4518 ) Allocator.Error!void {
4519 const mod = o.module;
4520 if (param_ty.isPtrAtRuntime(mod)) {
4521 const ptr_info = param_ty.ptrInfo(mod);
4522 if (math.cast(u5, param_index)) |i| {
4523 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
4524 try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
4525 }
4526 }
4527 if (!param_ty.isPtrLikeOptional(mod) and !ptr_info.flags.is_allowzero) {
4528 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
4529 }
4530 if (ptr_info.flags.is_const) {
4531 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
4532 }
4533 const elem_align = Builder.Alignment.fromByteUnits(
4534 ptr_info.flags.alignment.toByteUnitsOptional() orelse
4535 @max(ptr_info.child.toType().abiAlignment(mod), 1),
4536 );
4537 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
4538 } else if (ccAbiPromoteInt(fn_info.cc, mod, param_ty)) |s| switch (s) {
4539 .signed => try attributes.addParamAttr(llvm_arg_i, .signext, &o.builder),
4540 .unsigned => try attributes.addParamAttr(llvm_arg_i, .zeroext, &o.builder),
4541 };
4542 }
4543
4544 fn addByRefParamAttrs(
4545 o: *Object,
4546 attributes: *Builder.FunctionAttributes.Wip,
4547 llvm_arg_i: u32,
4548 alignment: Builder.Alignment,
4549 byval_attr: bool,
4550 param_llvm_ty: Builder.Type,
4551 ) Allocator.Error!void {
4552 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
4553 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
4554 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = alignment }, &o.builder);
4555 if (byval_attr) {
4556 try attributes.addParamAttr(llvm_arg_i, .{ .byval = param_llvm_ty }, &o.builder);
4557 }
4558 }
4559
4560 fn addByValParamAttrsOld(
4561 o: *Object,
4562 attributes: *Builder.FunctionAttributes.Wip,
4406 llvm_fn: *llvm.Value,4563 llvm_fn: *llvm.Value,
4407 param_ty: Type,4564 param_ty: Type,
4408 param_index: u32,4565 param_index: u32,
4409 fn_info: InternPool.Key.FuncType,4566 fn_info: InternPool.Key.FuncType,
4410 llvm_arg_i: u32,4567 llvm_arg_i: u32,
4411 ) void {4568 ) Allocator.Error!void {
4412 const mod = o.module;4569 const mod = o.module;
4413 if (param_ty.isPtrAtRuntime(mod)) {4570 if (param_ty.isPtrAtRuntime(mod)) {
4414 const ptr_info = param_ty.ptrInfo(mod);4571 const ptr_info = param_ty.ptrInfo(mod);
4415 if (math.cast(u5, param_index)) |i| {4572 if (math.cast(u5, param_index)) |i| {
4416 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {4573 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
4574 try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
4417 o.addArgAttr(llvm_fn, llvm_arg_i, "noalias");4575 o.addArgAttr(llvm_fn, llvm_arg_i, "noalias");
4418 }4576 }
4419 }4577 }
4420 if (!param_ty.isPtrLikeOptional(mod) and !ptr_info.flags.is_allowzero) {4578 if (!param_ty.isPtrLikeOptional(mod) and !ptr_info.flags.is_allowzero) {
4579 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
4421 o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");4580 o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");
4422 }4581 }
4423 if (ptr_info.flags.is_const) {4582 if (ptr_info.flags.is_const) {
4583 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
4424 o.addArgAttr(llvm_fn, llvm_arg_i, "readonly");4584 o.addArgAttr(llvm_fn, llvm_arg_i, "readonly");
4425 }4585 }
4426 const elem_align = ptr_info.flags.alignment.toByteUnitsOptional() orelse4586 const elem_align = Builder.Alignment.fromByteUnits(
4427 @max(ptr_info.child.toType().abiAlignment(mod), 1);4587 ptr_info.flags.alignment.toByteUnitsOptional() orelse
4428 o.addArgAttrInt(llvm_fn, llvm_arg_i, "align", elem_align);4588 @max(ptr_info.child.toType().abiAlignment(mod), 1),
4589 );
4590 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
4591 o.addArgAttrInt(llvm_fn, llvm_arg_i, "align", elem_align.toByteUnits() orelse 0);
4429 } else if (ccAbiPromoteInt(fn_info.cc, mod, param_ty)) |s| switch (s) {4592 } else if (ccAbiPromoteInt(fn_info.cc, mod, param_ty)) |s| switch (s) {
4430 .signed => o.addArgAttr(llvm_fn, llvm_arg_i, "signext"),4593 .signed => {
4431 .unsigned => o.addArgAttr(llvm_fn, llvm_arg_i, "zeroext"),4594 try attributes.addParamAttr(llvm_arg_i, .signext, &o.builder);
4595 o.addArgAttr(llvm_fn, llvm_arg_i, "signext");
4596 },
4597 .unsigned => {
4598 try attributes.addParamAttr(llvm_arg_i, .zeroext, &o.builder);
4599 o.addArgAttr(llvm_fn, llvm_arg_i, "zeroext");
4600 },
4432 };4601 };
4433 }4602 }
44344603
4435 fn addByRefParamAttrs(4604 fn addByRefParamAttrsOld(
4436 o: *Object,4605 o: *Object,
4606 attributes: *Builder.FunctionAttributes.Wip,
4437 llvm_fn: *llvm.Value,4607 llvm_fn: *llvm.Value,
4438 llvm_arg_i: u32,4608 llvm_arg_i: u32,
4439 alignment: u32,4609 alignment: Builder.Alignment,
4440 byval_attr: bool,4610 byval_attr: bool,
4441 param_llvm_ty: Builder.Type,4611 param_llvm_ty: Builder.Type,
4442 ) void {4612 ) Allocator.Error!void {
4613 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
4614 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
4615 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = alignment }, &o.builder);
4443 o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");4616 o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");
4444 o.addArgAttr(llvm_fn, llvm_arg_i, "readonly");4617 o.addArgAttr(llvm_fn, llvm_arg_i, "readonly");
4445 o.addArgAttrInt(llvm_fn, llvm_arg_i, "align", alignment);4618 o.addArgAttrInt(llvm_fn, llvm_arg_i, "align", alignment.toByteUnits() orelse 0);
4446 if (byval_attr) {4619 if (byval_attr) {
4620 try attributes.addParamAttr(llvm_arg_i, .{ .byval = param_llvm_ty }, &o.builder);
4447 llvm_fn.addByValAttr(llvm_arg_i, param_llvm_ty.toLlvm(&o.builder));4621 llvm_fn.addByValAttr(llvm_arg_i, param_llvm_ty.toLlvm(&o.builder));
4448 }4622 }
4449 }4623 }
...@@ -4841,10 +5015,10 @@ pub const FuncGen = struct {...@@ -4841,10 +5015,10 @@ pub const FuncGen = struct {
4841 .slice_ptr => try self.airSliceField(inst, 0),5015 .slice_ptr => try self.airSliceField(inst, 0),
4842 .slice_len => try self.airSliceField(inst, 1),5016 .slice_len => try self.airSliceField(inst, 1),
48435017
4844 .call => try self.airCall(inst, .Auto),5018 .call => try self.airCall(inst, .auto),
4845 .call_always_tail => try self.airCall(inst, .AlwaysTail),5019 .call_always_tail => try self.airCall(inst, .always_tail),
4846 .call_never_tail => try self.airCall(inst, .NeverTail),5020 .call_never_tail => try self.airCall(inst, .never_tail),
4847 .call_never_inline => try self.airCall(inst, .NeverInline),5021 .call_never_inline => try self.airCall(inst, .never_inline),
48485022
4849 .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0),5023 .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0),
4850 .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1),5024 .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1),
...@@ -4953,7 +5127,15 @@ pub const FuncGen = struct {...@@ -4953,7 +5127,15 @@ pub const FuncGen = struct {
4953 }5127 }
4954 }5128 }
49555129
4956 fn airCall(self: *FuncGen, inst: Air.Inst.Index, attr: llvm.CallAttr) !Builder.Value {5130 pub const CallAttr = enum {
5131 Auto,
5132 NeverTail,
5133 NeverInline,
5134 AlwaysTail,
5135 AlwaysInline,
5136 };
5137
5138 fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !Builder.Value {
4957 const pl_op = self.air.instructions.items(.data)[inst].pl_op;5139 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
4958 const extra = self.air.extraData(Air.Call, pl_op.payload);5140 const extra = self.air.extraData(Air.Call, pl_op.payload);
4959 const args: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra.end..][0..extra.data.args_len]);5141 const args: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra.end..][0..extra.data.args_len]);
...@@ -4972,14 +5154,25 @@ pub const FuncGen = struct {...@@ -4972,14 +5154,25 @@ pub const FuncGen = struct {
4972 const target = mod.getTarget();5154 const target = mod.getTarget();
4973 const sret = firstParamSRet(fn_info, mod);5155 const sret = firstParamSRet(fn_info, mod);
49745156
4975 var llvm_args = std.ArrayList(*llvm.Value).init(self.gpa);5157 var llvm_args = std.ArrayList(Builder.Value).init(self.gpa);
4976 defer llvm_args.deinit();5158 defer llvm_args.deinit();
49775159
5160 var attributes: Builder.FunctionAttributes.Wip = .{};
5161 defer attributes.deinit(&o.builder);
5162
5163 switch (modifier) {
5164 .auto, .never_tail, .always_tail => {},
5165 .never_inline => try attributes.addFnAttr(.@"noinline", &o.builder),
5166 .async_kw, .no_async, .always_inline, .compile_time => unreachable,
5167 }
5168
4978 const ret_ptr = if (!sret) null else blk: {5169 const ret_ptr = if (!sret) null else blk: {
4979 const llvm_ret_ty = try o.lowerType(return_type);5170 const llvm_ret_ty = try o.lowerType(return_type);
5171 try attributes.addParamAttr(0, .{ .sret = llvm_ret_ty }, &o.builder);
5172
4980 const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));5173 const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));
4981 const ret_ptr = try self.buildAlloca(llvm_ret_ty, alignment);5174 const ret_ptr = try self.buildAlloca(llvm_ret_ty, alignment);
4982 try llvm_args.append(ret_ptr.toLlvm(&self.wip));5175 try llvm_args.append(ret_ptr);
4983 break :blk ret_ptr;5176 break :blk ret_ptr;
4984 };5177 };
49855178
...@@ -4987,7 +5180,7 @@ pub const FuncGen = struct {...@@ -4987,7 +5180,7 @@ pub const FuncGen = struct {
4987 o.module.comp.bin_file.options.error_return_tracing;5180 o.module.comp.bin_file.options.error_return_tracing;
4988 if (err_return_tracing) {5181 if (err_return_tracing) {
4989 assert(self.err_ret_trace != .none);5182 assert(self.err_ret_trace != .none);
4990 try llvm_args.append(self.err_ret_trace.toLlvm(&self.wip));5183 try llvm_args.append(self.err_ret_trace);
4991 }5184 }
49925185
4993 var it = iterateParamTypes(o, fn_info);5186 var it = iterateParamTypes(o, fn_info);
...@@ -5001,9 +5194,9 @@ pub const FuncGen = struct {...@@ -5001,9 +5194,9 @@ pub const FuncGen = struct {
5001 if (isByRef(param_ty, mod)) {5194 if (isByRef(param_ty, mod)) {
5002 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));5195 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5003 const loaded = try self.wip.load(.normal, llvm_param_ty, llvm_arg, alignment, "");5196 const loaded = try self.wip.load(.normal, llvm_param_ty, llvm_arg, alignment, "");
5004 try llvm_args.append(loaded.toLlvm(&self.wip));5197 try llvm_args.append(loaded);
5005 } else {5198 } else {
5006 try llvm_args.append(llvm_arg.toLlvm(&self.wip));5199 try llvm_args.append(llvm_arg);
5007 }5200 }
5008 },5201 },
5009 .byref => {5202 .byref => {
...@@ -5011,13 +5204,13 @@ pub const FuncGen = struct {...@@ -5011,13 +5204,13 @@ pub const FuncGen = struct {
5011 const param_ty = self.typeOf(arg);5204 const param_ty = self.typeOf(arg);
5012 const llvm_arg = try self.resolveInst(arg);5205 const llvm_arg = try self.resolveInst(arg);
5013 if (isByRef(param_ty, mod)) {5206 if (isByRef(param_ty, mod)) {
5014 try llvm_args.append(llvm_arg.toLlvm(&self.wip));5207 try llvm_args.append(llvm_arg);
5015 } else {5208 } else {
5016 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));5209 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5017 const param_llvm_ty = llvm_arg.typeOfWip(&self.wip);5210 const param_llvm_ty = llvm_arg.typeOfWip(&self.wip);
5018 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);5211 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);
5019 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);5212 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);
5020 try llvm_args.append(arg_ptr.toLlvm(&self.wip));5213 try llvm_args.append(arg_ptr);
5021 }5214 }
5022 },5215 },
5023 .byref_mut => {5216 .byref_mut => {
...@@ -5034,7 +5227,7 @@ pub const FuncGen = struct {...@@ -5034,7 +5227,7 @@ pub const FuncGen = struct {
5034 } else {5227 } else {
5035 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);5228 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);
5036 }5229 }
5037 try llvm_args.append(arg_ptr.toLlvm(&self.wip));5230 try llvm_args.append(arg_ptr);
5038 },5231 },
5039 .abi_sized_int => {5232 .abi_sized_int => {
5040 const arg = args[it.zig_index - 1];5233 const arg = args[it.zig_index - 1];
...@@ -5045,7 +5238,7 @@ pub const FuncGen = struct {...@@ -5045,7 +5238,7 @@ pub const FuncGen = struct {
5045 if (isByRef(param_ty, mod)) {5238 if (isByRef(param_ty, mod)) {
5046 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));5239 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5047 const loaded = try self.wip.load(.normal, int_llvm_ty, llvm_arg, alignment, "");5240 const loaded = try self.wip.load(.normal, int_llvm_ty, llvm_arg, alignment, "");
5048 try llvm_args.append(loaded.toLlvm(&self.wip));5241 try llvm_args.append(loaded);
5049 } else {5242 } else {
5050 // LLVM does not allow bitcasting structs so we must allocate5243 // LLVM does not allow bitcasting structs so we must allocate
5051 // a local, store as one type, and then load as another type.5244 // a local, store as one type, and then load as another type.
...@@ -5056,7 +5249,7 @@ pub const FuncGen = struct {...@@ -5056,7 +5249,7 @@ pub const FuncGen = struct {
5056 const int_ptr = try self.buildAlloca(int_llvm_ty, alignment);5249 const int_ptr = try self.buildAlloca(int_llvm_ty, alignment);
5057 _ = try self.wip.store(.normal, llvm_arg, int_ptr, alignment);5250 _ = try self.wip.store(.normal, llvm_arg, int_ptr, alignment);
5058 const loaded = try self.wip.load(.normal, int_llvm_ty, int_ptr, alignment, "");5251 const loaded = try self.wip.load(.normal, int_llvm_ty, int_ptr, alignment, "");
5059 try llvm_args.append(loaded.toLlvm(&self.wip));5252 try llvm_args.append(loaded);
5060 }5253 }
5061 },5254 },
5062 .slice => {5255 .slice => {
...@@ -5064,7 +5257,7 @@ pub const FuncGen = struct {...@@ -5064,7 +5257,7 @@ pub const FuncGen = struct {
5064 const llvm_arg = try self.resolveInst(arg);5257 const llvm_arg = try self.resolveInst(arg);
5065 const ptr = try self.wip.extractValue(llvm_arg, &.{0}, "");5258 const ptr = try self.wip.extractValue(llvm_arg, &.{0}, "");
5066 const len = try self.wip.extractValue(llvm_arg, &.{1}, "");5259 const len = try self.wip.extractValue(llvm_arg, &.{1}, "");
5067 try llvm_args.appendSlice(&.{ ptr.toLlvm(&self.wip), len.toLlvm(&self.wip) });5260 try llvm_args.appendSlice(&.{ ptr, len });
5068 },5261 },
5069 .multiple_llvm_types => {5262 .multiple_llvm_types => {
5070 const arg = args[it.zig_index - 1];5263 const arg = args[it.zig_index - 1];
...@@ -5086,14 +5279,14 @@ pub const FuncGen = struct {...@@ -5086,14 +5279,14 @@ pub const FuncGen = struct {
5086 Builder.Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));5279 Builder.Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
5087 const field_ptr = try self.wip.gepStruct(llvm_ty, arg_ptr, i, "");5280 const field_ptr = try self.wip.gepStruct(llvm_ty, arg_ptr, i, "");
5088 const loaded = try self.wip.load(.normal, field_ty, field_ptr, alignment, "");5281 const loaded = try self.wip.load(.normal, field_ty, field_ptr, alignment, "");
5089 llvm_args.appendAssumeCapacity(loaded.toLlvm(&self.wip));5282 llvm_args.appendAssumeCapacity(loaded);
5090 }5283 }
5091 },5284 },
5092 .as_u16 => {5285 .as_u16 => {
5093 const arg = args[it.zig_index - 1];5286 const arg = args[it.zig_index - 1];
5094 const llvm_arg = try self.resolveInst(arg);5287 const llvm_arg = try self.resolveInst(arg);
5095 const casted = try self.wip.cast(.bitcast, llvm_arg, .i16, "");5288 const casted = try self.wip.cast(.bitcast, llvm_arg, .i16, "");
5096 try llvm_args.append(casted.toLlvm(&self.wip));5289 try llvm_args.append(casted);
5097 },5290 },
5098 .float_array => |count| {5291 .float_array => |count| {
5099 const arg = args[it.zig_index - 1];5292 const arg = args[it.zig_index - 1];
...@@ -5110,7 +5303,7 @@ pub const FuncGen = struct {...@@ -5110,7 +5303,7 @@ pub const FuncGen = struct {
5110 const array_ty = try o.builder.arrayType(count, float_ty);5303 const array_ty = try o.builder.arrayType(count, float_ty);
51115304
5112 const loaded = try self.wip.load(.normal, array_ty, llvm_arg, alignment, "");5305 const loaded = try self.wip.load(.normal, array_ty, llvm_arg, alignment, "");
5113 try llvm_args.append(loaded.toLlvm(&self.wip));5306 try llvm_args.append(loaded);
5114 },5307 },
5115 .i32_array, .i64_array => |arr_len| {5308 .i32_array, .i64_array => |arr_len| {
5116 const elem_size: u8 = if (lowering == .i32_array) 32 else 64;5309 const elem_size: u8 = if (lowering == .i32_array) 32 else 64;
...@@ -5127,24 +5320,10 @@ pub const FuncGen = struct {...@@ -5127,24 +5320,10 @@ pub const FuncGen = struct {
5127 const array_ty =5320 const array_ty =
5128 try o.builder.arrayType(arr_len, try o.builder.intType(@intCast(elem_size)));5321 try o.builder.arrayType(arr_len, try o.builder.intType(@intCast(elem_size)));
5129 const loaded = try self.wip.load(.normal, array_ty, llvm_arg, alignment, "");5322 const loaded = try self.wip.load(.normal, array_ty, llvm_arg, alignment, "");
5130 try llvm_args.append(loaded.toLlvm(&self.wip));5323 try llvm_args.append(loaded);
5131 },5324 },
5132 };5325 };
51335326
5134 const llvm_fn_ty = try o.lowerType(zig_fn_ty);
5135 const call = (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(
5136 self.builder.buildCall(
5137 llvm_fn_ty.toLlvm(&o.builder),
5138 llvm_fn.toLlvm(&self.wip),
5139 llvm_args.items.ptr,
5140 @intCast(llvm_args.items.len),
5141 toLlvmCallConv(fn_info.cc, target),
5142 attr,
5143 "",
5144 ),
5145 &self.wip,
5146 );
5147
5148 if (callee_ty.zigTypeTag(mod) == .Pointer) {5327 if (callee_ty.zigTypeTag(mod) == .Pointer) {
5149 // Add argument attributes for function pointer calls.5328 // Add argument attributes for function pointer calls.
5150 it = iterateParamTypes(o, fn_info);5329 it = iterateParamTypes(o, fn_info);
...@@ -5155,19 +5334,17 @@ pub const FuncGen = struct {...@@ -5155,19 +5334,17 @@ pub const FuncGen = struct {
5155 const param_index = it.zig_index - 1;5334 const param_index = it.zig_index - 1;
5156 const param_ty = fn_info.param_types.get(ip)[param_index].toType();5335 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
5157 if (!isByRef(param_ty, mod)) {5336 if (!isByRef(param_ty, mod)) {
5158 o.addByValParamAttrs(call.toLlvm(&self.wip), param_ty, param_index, fn_info, it.llvm_index - 1);5337 try o.addByValParamAttrs(&attributes, param_ty, param_index, fn_info, it.llvm_index - 1);
5159 }5338 }
5160 },5339 },
5161 .byref => {5340 .byref => {
5162 const param_index = it.zig_index - 1;5341 const param_index = it.zig_index - 1;
5163 const param_ty = fn_info.param_types.get(ip)[param_index].toType();5342 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
5164 const param_llvm_ty = try o.lowerType(param_ty);5343 const param_llvm_ty = try o.lowerType(param_ty);
5165 const alignment = param_ty.abiAlignment(mod);5344 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5166 o.addByRefParamAttrs(call.toLlvm(&self.wip), it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);5345 try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
5167 },
5168 .byref_mut => {
5169 o.addArgAttr(call.toLlvm(&self.wip), it.llvm_index - 1, "noundef");
5170 },5346 },
5347 .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),
5171 // No attributes needed for these.5348 // No attributes needed for these.
5172 .no_bits,5349 .no_bits,
5173 .abi_sized_int,5350 .abi_sized_int,
...@@ -5186,23 +5363,40 @@ pub const FuncGen = struct {...@@ -5186,23 +5363,40 @@ pub const FuncGen = struct {
51865363
5187 if (math.cast(u5, it.zig_index - 1)) |i| {5364 if (math.cast(u5, it.zig_index - 1)) |i| {
5188 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {5365 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
5189 o.addArgAttr(call.toLlvm(&self.wip), llvm_arg_i, "noalias");5366 try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
5190 }5367 }
5191 }5368 }
5192 if (param_ty.zigTypeTag(mod) != .Optional) {5369 if (param_ty.zigTypeTag(mod) != .Optional) {
5193 o.addArgAttr(call.toLlvm(&self.wip), llvm_arg_i, "nonnull");5370 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
5194 }5371 }
5195 if (ptr_info.flags.is_const) {5372 if (ptr_info.flags.is_const) {
5196 o.addArgAttr(call.toLlvm(&self.wip), llvm_arg_i, "readonly");5373 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
5197 }5374 }
5198 const elem_align = ptr_info.flags.alignment.toByteUnitsOptional() orelse5375 const elem_align = Builder.Alignment.fromByteUnits(
5199 @max(ptr_info.child.toType().abiAlignment(mod), 1);5376 ptr_info.flags.alignment.toByteUnitsOptional() orelse
5200 o.addArgAttrInt(call.toLlvm(&self.wip), llvm_arg_i, "align", elem_align);5377 @max(ptr_info.child.toType().abiAlignment(mod), 1),
5378 );
5379 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
5201 },5380 },
5202 };5381 };
5203 }5382 }
52045383
5205 if (fn_info.return_type == .noreturn_type and attr != .AlwaysTail) {5384 const call = try self.wip.call(
5385 switch (modifier) {
5386 .auto, .never_inline => .normal,
5387 .never_tail => .notail,
5388 .always_tail => .musttail,
5389 .async_kw, .no_async, .always_inline, .compile_time => unreachable,
5390 },
5391 toLlvmCallConv(fn_info.cc, target),
5392 try attributes.finish(&o.builder),
5393 try o.lowerType(zig_fn_ty),
5394 llvm_fn,
5395 llvm_args.items,
5396 "",
5397 );
5398
5399 if (fn_info.return_type == .noreturn_type and modifier != .always_tail) {
5206 return .none;5400 return .none;
5207 }5401 }
52085402
...@@ -5211,9 +5405,7 @@ pub const FuncGen = struct {...@@ -5211,9 +5405,7 @@ pub const FuncGen = struct {
5211 }5405 }
52125406
5213 const llvm_ret_ty = try o.lowerType(return_type);5407 const llvm_ret_ty = try o.lowerType(return_type);
5214
5215 if (ret_ptr) |rp| {5408 if (ret_ptr) |rp| {
5216 call.toLlvm(&self.wip).setCallSret(llvm_ret_ty.toLlvm(&o.builder));
5217 if (isByRef(return_type, mod)) {5409 if (isByRef(return_type, mod)) {
5218 return rp;5410 return rp;
5219 } else {5411 } else {
...@@ -5269,25 +5461,24 @@ pub const FuncGen = struct {...@@ -5269,25 +5461,24 @@ pub const FuncGen = struct {
5269 // ptr null, ; stack trace5461 // ptr null, ; stack trace
5270 // ptr @2, ; addr (null ?usize)5462 // ptr @2, ; addr (null ?usize)
5271 // )5463 // )
5272 const args = [4]*llvm.Value{
5273 msg_ptr.toLlvm(&o.builder),
5274 (try o.builder.intConst(llvm_usize, msg_len)).toLlvm(&o.builder),
5275 (try o.builder.nullConst(.ptr)).toLlvm(&o.builder),
5276 null_opt_addr_global.toLlvm(&o.builder),
5277 };
5278 const panic_func = mod.funcInfo(mod.panic_func_index);5464 const panic_func = mod.funcInfo(mod.panic_func_index);
5279 const panic_decl = mod.declPtr(panic_func.owner_decl);5465 const panic_decl = mod.declPtr(panic_func.owner_decl);
5280 const fn_info = mod.typeToFunc(panic_decl.ty).?;5466 const fn_info = mod.typeToFunc(panic_decl.ty).?;
5281 const panic_global = try o.resolveLlvmFunction(panic_func.owner_decl);5467 const panic_global = try o.resolveLlvmFunction(panic_func.owner_decl);
5282 _ = (try fg.wip.unimplemented(.void, "")).finish(fg.builder.buildCall(5468 _ = try fg.wip.call(
5283 (try o.lowerType(panic_decl.ty)).toLlvm(&o.builder),5469 .normal,
5284 panic_global.toLlvm(&o.builder),
5285 &args,
5286 args.len,
5287 toLlvmCallConv(fn_info.cc, target),5470 toLlvmCallConv(fn_info.cc, target),
5288 .Auto,5471 .none,
5472 panic_global.typeOf(&o.builder),
5473 panic_global.toValue(&o.builder),
5474 &.{
5475 msg_ptr.toValue(),
5476 try o.builder.intValue(llvm_usize, msg_len),
5477 try o.builder.nullValue(.ptr),
5478 null_opt_addr_global.toValue(),
5479 },
5289 "",5480 "",
5290 ), &fg.wip);5481 );
5291 _ = try fg.wip.@"unreachable"();5482 _ = try fg.wip.@"unreachable"();
5292 }5483 }
52935484
...@@ -5395,7 +5586,7 @@ pub const FuncGen = struct {...@@ -5395,7 +5586,7 @@ pub const FuncGen = struct {
5395 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));5586 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
53965587
5397 const args: [2]*llvm.Value = .{ dest_list.toLlvm(&self.wip), src_list.toLlvm(&self.wip) };5588 const args: [2]*llvm.Value = .{ dest_list.toLlvm(&self.wip), src_list.toLlvm(&self.wip) };
5398 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(5589 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
5399 llvm_fn_ty.toLlvm(&o.builder),5590 llvm_fn_ty.toLlvm(&o.builder),
5400 llvm_fn,5591 llvm_fn,
5401 &args,5592 &args,
...@@ -5422,7 +5613,7 @@ pub const FuncGen = struct {...@@ -5422,7 +5613,7 @@ pub const FuncGen = struct {
5422 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));5613 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
54235614
5424 const args: [1]*llvm.Value = .{list.toLlvm(&self.wip)};5615 const args: [1]*llvm.Value = .{list.toLlvm(&self.wip)};
5425 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(5616 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
5426 llvm_fn_ty.toLlvm(&o.builder),5617 llvm_fn_ty.toLlvm(&o.builder),
5427 llvm_fn,5618 llvm_fn,
5428 &args,5619 &args,
...@@ -5449,7 +5640,7 @@ pub const FuncGen = struct {...@@ -5449,7 +5640,7 @@ pub const FuncGen = struct {
5449 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));5640 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
54505641
5451 const args: [1]*llvm.Value = .{list.toLlvm(&self.wip)};5642 const args: [1]*llvm.Value = .{list.toLlvm(&self.wip)};
5452 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(5643 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
5453 llvm_fn_ty.toLlvm(&o.builder),5644 llvm_fn_ty.toLlvm(&o.builder),
5454 llvm_fn,5645 llvm_fn,
5455 &args,5646 &args,
...@@ -5495,16 +5686,15 @@ pub const FuncGen = struct {...@@ -5495,16 +5686,15 @@ pub const FuncGen = struct {
5495 const un_op = self.air.instructions.items(.data)[inst].un_op;5686 const un_op = self.air.instructions.items(.data)[inst].un_op;
5496 const operand = try self.resolveInst(un_op);5687 const operand = try self.resolveInst(un_op);
5497 const llvm_fn = try self.getCmpLtErrorsLenFunction();5688 const llvm_fn = try self.getCmpLtErrorsLenFunction();
5498 const args: [1]*llvm.Value = .{operand.toLlvm(&self.wip)};5689 return self.wip.call(
5499 return (try self.wip.unimplemented(.i1, "")).finish(self.builder.buildCall(5690 .normal,
5500 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),5691 .fastcc,
5501 llvm_fn.toLlvm(&o.builder),5692 .none,
5502 &args,5693 llvm_fn.typeOf(&o.builder),
5503 args.len,5694 llvm_fn.toValue(&o.builder),
5504 .Fast,5695 &.{operand},
5505 .Auto,
5506 "",5696 "",
5507 ), &self.wip);5697 );
5508 }5698 }
55095699
5510 fn cmp(5700 fn cmp(
...@@ -5953,16 +6143,15 @@ pub const FuncGen = struct {...@@ -5953,16 +6143,15 @@ pub const FuncGen = struct {
5953 }6143 }
59546144
5955 const libc_fn = try self.getLibcFunction(fn_name, &.{param_type}, dest_llvm_ty);6145 const libc_fn = try self.getLibcFunction(fn_name, &.{param_type}, dest_llvm_ty);
5956 const params = [1]*llvm.Value{extended.toLlvm(&self.wip)};6146 return self.wip.call(
5957 return (try self.wip.unimplemented(dest_llvm_ty, "")).finish(self.builder.buildCall(6147 .normal,
5958 libc_fn.typeOf(&o.builder).toLlvm(&o.builder),6148 .ccc,
5959 libc_fn.toLlvm(&o.builder),6149 .none,
5960 &params,6150 libc_fn.typeOf(&o.builder),
5961 params.len,6151 libc_fn.toValue(&o.builder),
5962 .C,6152 &.{extended},
5963 .Auto,
5964 "",6153 "",
5965 ), &self.wip);6154 );
5966 }6155 }
59676156
5968 fn airIntFromFloat(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {6157 fn airIntFromFloat(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
...@@ -6013,16 +6202,15 @@ pub const FuncGen = struct {...@@ -6013,16 +6202,15 @@ pub const FuncGen = struct {
60136202
6014 const operand_llvm_ty = try o.lowerType(operand_ty);6203 const operand_llvm_ty = try o.lowerType(operand_ty);
6015 const libc_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, libc_ret_ty);6204 const libc_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, libc_ret_ty);
6016 const params = [1]*llvm.Value{operand.toLlvm(&self.wip)};6205 var result = try self.wip.call(
6017 var result = (try self.wip.unimplemented(libc_ret_ty, "")).finish(self.builder.buildCall(6206 .normal,
6018 libc_fn.typeOf(&o.builder).toLlvm(&o.builder),6207 .ccc,
6019 libc_fn.toLlvm(&o.builder),6208 .none,
6020 &params,6209 libc_fn.typeOf(&o.builder),
6021 params.len,6210 libc_fn.toValue(&o.builder),
6022 .C,6211 &.{operand},
6023 .Auto,
6024 "",6212 "",
6025 ), &self.wip);6213 );
60266214
6027 if (libc_ret_ty != ret_ty) result = try self.wip.cast(.bitcast, result, ret_ty, "");6215 if (libc_ret_ty != ret_ty) result = try self.wip.cast(.bitcast, result, ret_ty, "");
6028 if (ret_ty != dest_llvm_ty) result = try self.wip.cast(.trunc, result, dest_llvm_ty, "");6216 if (ret_ty != dest_llvm_ty) result = try self.wip.cast(.trunc, result, dest_llvm_ty, "");
...@@ -6588,7 +6776,7 @@ pub const FuncGen = struct {...@@ -6588,7 +6776,7 @@ pub const FuncGen = struct {
65886776
6589 const max_param_count = inputs.len + outputs.len;6777 const max_param_count = inputs.len + outputs.len;
6590 const llvm_param_types = try arena.alloc(Builder.Type, max_param_count);6778 const llvm_param_types = try arena.alloc(Builder.Type, max_param_count);
6591 const llvm_param_values = try arena.alloc(*llvm.Value, max_param_count);6779 const llvm_param_values = try arena.alloc(Builder.Value, max_param_count);
6592 // This stores whether we need to add an elementtype attribute and6780 // This stores whether we need to add an elementtype attribute and
6593 // if so, the element type itself.6781 // if so, the element type itself.
6594 const llvm_param_attrs = try arena.alloc(Builder.Type, max_param_count);6782 const llvm_param_attrs = try arena.alloc(Builder.Type, max_param_count);
...@@ -6628,7 +6816,7 @@ pub const FuncGen = struct {...@@ -6628,7 +6816,7 @@ pub const FuncGen = struct {
6628 // Pass the result by reference as an indirect output (e.g. "=*m")6816 // Pass the result by reference as an indirect output (e.g. "=*m")
6629 llvm_constraints.appendAssumeCapacity('*');6817 llvm_constraints.appendAssumeCapacity('*');
66306818
6631 llvm_param_values[llvm_param_i] = output_inst.toLlvm(&self.wip);6819 llvm_param_values[llvm_param_i] = output_inst;
6632 llvm_param_types[llvm_param_i] = output_inst.typeOfWip(&self.wip);6820 llvm_param_types[llvm_param_i] = output_inst.typeOfWip(&self.wip);
6633 llvm_param_attrs[llvm_param_i] = elem_llvm_ty;6821 llvm_param_attrs[llvm_param_i] = elem_llvm_ty;
6634 llvm_param_i += 1;6822 llvm_param_i += 1;
...@@ -6678,25 +6866,25 @@ pub const FuncGen = struct {...@@ -6678,25 +6866,25 @@ pub const FuncGen = struct {
6678 if (isByRef(arg_ty, mod)) {6866 if (isByRef(arg_ty, mod)) {
6679 llvm_elem_ty = try o.lowerPtrElemTy(arg_ty);6867 llvm_elem_ty = try o.lowerPtrElemTy(arg_ty);
6680 if (constraintAllowsMemory(constraint)) {6868 if (constraintAllowsMemory(constraint)) {
6681 llvm_param_values[llvm_param_i] = arg_llvm_value.toLlvm(&self.wip);6869 llvm_param_values[llvm_param_i] = arg_llvm_value;
6682 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);6870 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
6683 } else {6871 } else {
6684 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));6872 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
6685 const arg_llvm_ty = try o.lowerType(arg_ty);6873 const arg_llvm_ty = try o.lowerType(arg_ty);
6686 const load_inst =6874 const load_inst =
6687 try self.wip.load(.normal, arg_llvm_ty, arg_llvm_value, alignment, "");6875 try self.wip.load(.normal, arg_llvm_ty, arg_llvm_value, alignment, "");
6688 llvm_param_values[llvm_param_i] = load_inst.toLlvm(&self.wip);6876 llvm_param_values[llvm_param_i] = load_inst;
6689 llvm_param_types[llvm_param_i] = arg_llvm_ty;6877 llvm_param_types[llvm_param_i] = arg_llvm_ty;
6690 }6878 }
6691 } else {6879 } else {
6692 if (constraintAllowsRegister(constraint)) {6880 if (constraintAllowsRegister(constraint)) {
6693 llvm_param_values[llvm_param_i] = arg_llvm_value.toLlvm(&self.wip);6881 llvm_param_values[llvm_param_i] = arg_llvm_value;
6694 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);6882 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
6695 } else {6883 } else {
6696 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));6884 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
6697 const arg_ptr = try self.buildAlloca(arg_llvm_value.typeOfWip(&self.wip), alignment);6885 const arg_ptr = try self.buildAlloca(arg_llvm_value.typeOfWip(&self.wip), alignment);
6698 _ = try self.wip.store(.normal, arg_llvm_value, arg_ptr, alignment);6886 _ = try self.wip.store(.normal, arg_llvm_value, arg_ptr, alignment);
6699 llvm_param_values[llvm_param_i] = arg_ptr.toLlvm(&self.wip);6887 llvm_param_values[llvm_param_i] = arg_ptr;
6700 llvm_param_types[llvm_param_i] = arg_ptr.typeOfWip(&self.wip);6888 llvm_param_types[llvm_param_i] = arg_ptr.typeOfWip(&self.wip);
6701 }6889 }
6702 }6890 }
...@@ -6843,38 +7031,26 @@ pub const FuncGen = struct {...@@ -6843,38 +7031,26 @@ pub const FuncGen = struct {
6843 }7031 }
6844 }7032 }
68457033
7034 var attributes: Builder.FunctionAttributes.Wip = .{};
7035 defer attributes.deinit(&o.builder);
7036 for (llvm_param_attrs[0..param_count], 0..) |llvm_elem_ty, i| if (llvm_elem_ty != .none)
7037 try attributes.addParamAttr(i, .{ .elementtype = llvm_elem_ty }, &o.builder);
7038
6846 const ret_llvm_ty = switch (return_count) {7039 const ret_llvm_ty = switch (return_count) {
6847 0 => .void,7040 0 => .void,
6848 1 => llvm_ret_types[0],7041 1 => llvm_ret_types[0],
6849 else => try o.builder.structType(.normal, llvm_ret_types),7042 else => try o.builder.structType(.normal, llvm_ret_types),
6850 };7043 };
6851
6852 const llvm_fn_ty = try o.builder.fnType(ret_llvm_ty, llvm_param_types[0..param_count], .normal);7044 const llvm_fn_ty = try o.builder.fnType(ret_llvm_ty, llvm_param_types[0..param_count], .normal);
6853 const asm_fn = llvm.getInlineAsm(7045 const call = try self.wip.callAsm(
6854 llvm_fn_ty.toLlvm(&o.builder),7046 try attributes.finish(&o.builder),
6855 rendered_template.items.ptr,7047 llvm_fn_ty,
6856 rendered_template.items.len,7048 .{ .sideeffect = is_volatile },
6857 llvm_constraints.items.ptr,7049 try o.builder.string(rendered_template.items),
6858 llvm_constraints.items.len,7050 try o.builder.string(llvm_constraints.items),
6859 llvm.Bool.fromBool(is_volatile),7051 llvm_param_values[0..param_count],
6860 .False,
6861 .ATT,
6862 .False,
6863 );
6864 const call = (try self.wip.unimplemented(ret_llvm_ty, "")).finish(self.builder.buildCall(
6865 llvm_fn_ty.toLlvm(&o.builder),
6866 asm_fn,
6867 llvm_param_values.ptr,
6868 @intCast(param_count),
6869 .C,
6870 .Auto,
6871 "",7052 "",
6872 ), &self.wip);7053 );
6873 for (llvm_param_attrs[0..param_count], 0..) |llvm_elem_ty, i| {
6874 if (llvm_elem_ty != .none) {
6875 llvm.setCallElemTypeAttr(call.toLlvm(&self.wip), i, llvm_elem_ty.toLlvm(&o.builder));
6876 }
6877 }
68787054
6879 var ret_val = call;7055 var ret_val = call;
6880 llvm_ret_i = 0;7056 llvm_ret_i = 0;
...@@ -7287,7 +7463,7 @@ pub const FuncGen = struct {...@@ -7287,7 +7463,7 @@ pub const FuncGen = struct {
7287 const args: [1]*llvm.Value = .{7463 const args: [1]*llvm.Value = .{
7288 (try o.builder.intConst(.i32, index)).toLlvm(&o.builder),7464 (try o.builder.intConst(.i32, index)).toLlvm(&o.builder),
7289 };7465 };
7290 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCall(7466 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCallOld(
7291 (try o.builder.fnType(.i32, &.{.i32}, .normal)).toLlvm(&o.builder),7467 (try o.builder.fnType(.i32, &.{.i32}, .normal)).toLlvm(&o.builder),
7292 llvm_fn,7468 llvm_fn,
7293 &args,7469 &args,
...@@ -7308,7 +7484,7 @@ pub const FuncGen = struct {...@@ -7308,7 +7484,7 @@ pub const FuncGen = struct {
7308 (try o.builder.intConst(.i32, index)).toLlvm(&o.builder),7484 (try o.builder.intConst(.i32, index)).toLlvm(&o.builder),
7309 operand.toLlvm(&self.wip),7485 operand.toLlvm(&self.wip),
7310 };7486 };
7311 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCall(7487 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCallOld(
7312 (try o.builder.fnType(.i32, &.{ .i32, .i32 }, .normal)).toLlvm(&o.builder),7488 (try o.builder.fnType(.i32, &.{ .i32, .i32 }, .normal)).toLlvm(&o.builder),
7313 llvm_fn,7489 llvm_fn,
7314 &args,7490 &args,
...@@ -7425,7 +7601,7 @@ pub const FuncGen = struct {...@@ -7425,7 +7601,7 @@ pub const FuncGen = struct {
7425 });7601 });
7426 const llvm_fn_ty = try o.builder.fnType(llvm_ret_ty, &.{ llvm_inst_ty, llvm_inst_ty }, .normal);7602 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});7603 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(7604 const result_struct = (try fg.wip.unimplemented(llvm_ret_ty, "")).finish(fg.builder.buildCallOld(
7429 llvm_fn_ty.toLlvm(&o.builder),7605 llvm_fn_ty.toLlvm(&o.builder),
7430 llvm_fn,7606 llvm_fn,
7431 &[_]*llvm.Value{ lhs.toLlvm(&fg.wip), rhs.toLlvm(&fg.wip) },7607 &[_]*llvm.Value{ lhs.toLlvm(&fg.wip), rhs.toLlvm(&fg.wip) },
...@@ -7768,7 +7944,7 @@ pub const FuncGen = struct {...@@ -7768,7 +7944,7 @@ pub const FuncGen = struct {
7768 );7944 );
7769 const llvm_fn_ty = try o.builder.fnType(llvm_ret_ty, &.{ llvm_lhs_ty, llvm_lhs_ty }, .normal);7945 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(7946 const result_struct = (try self.wip.unimplemented(llvm_ret_ty, "")).finish(
7771 self.builder.buildCall(7947 self.builder.buildCallOld(
7772 llvm_fn_ty.toLlvm(&o.builder),7948 llvm_fn_ty.toLlvm(&o.builder),
7773 llvm_fn,7949 llvm_fn,
7774 &[_]*llvm.Value{ lhs.toLlvm(&self.wip), rhs.toLlvm(&self.wip) },7950 &[_]*llvm.Value{ lhs.toLlvm(&self.wip), rhs.toLlvm(&self.wip) },
...@@ -7818,29 +7994,23 @@ pub const FuncGen = struct {...@@ -7818,29 +7994,23 @@ pub const FuncGen = struct {
7818 const o = self.dg.object;7994 const o = self.dg.object;
7819 assert(args_vectors.len <= 3);7995 assert(args_vectors.len <= 3);
78207996
7821 const llvm_fn_ty = llvm_fn.typeOf(&o.builder);
7822 const llvm_scalar_ty = llvm_fn_ty.functionReturn(&o.builder);
7823
7824 var i: usize = 0;7997 var i: usize = 0;
7825 var result = result_vector;7998 var result = result_vector;
7826 while (i < vector_len) : (i += 1) {7999 while (i < vector_len) : (i += 1) {
7827 const index_i32 = try o.builder.intValue(.i32, i);8000 const index_i32 = try o.builder.intValue(.i32, i);
78288001
7829 var args: [3]*llvm.Value = undefined;8002 var args: [3]Builder.Value = undefined;
7830 for (args[0..args_vectors.len], args_vectors) |*arg_elem, arg_vector| {8003 for (args[0..args_vectors.len], args_vectors) |*arg_elem, arg_vector| {
7831 arg_elem.* = (try self.wip.extractElement(arg_vector, index_i32, "")).toLlvm(&self.wip);8004 arg_elem.* = try self.wip.extractElement(arg_vector, index_i32, "");
7832 }8005 }
7833 const result_elem = (try self.wip.unimplemented(llvm_scalar_ty, "")).finish(8006 const result_elem = try self.wip.call(
7834 self.builder.buildCall(8007 .normal,
7835 llvm_fn_ty.toLlvm(&o.builder),8008 .ccc,
7836 llvm_fn.toLlvm(&o.builder),8009 .none,
7837 &args,8010 llvm_fn.typeOf(&o.builder),
7838 @intCast(args_vectors.len),8011 llvm_fn.toValue(&o.builder),
7839 .C,8012 args[0..args_vectors.len],
7840 .Auto,8013 "",
7841 "",
7842 ),
7843 &self.wip,
7844 );8014 );
7845 result = try self.wip.insertElement(result, result_elem, index_i32, "");8015 result = try self.wip.insertElement(result, result_elem, index_i32, "");
7846 }8016 }
...@@ -7861,7 +8031,7 @@ pub const FuncGen = struct {...@@ -7861,7 +8031,7 @@ pub const FuncGen = struct {
7861 };8031 };
78628032
7863 const fn_type = try o.builder.fnType(return_type, param_types, .normal);8033 const fn_type = try o.builder.fnType(return_type, param_types, .normal);
7864 const f = o.llvm_module.addFunction(fn_name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));8034 const f = o.llvm_module.addFunction(fn_name.slice(&o.builder).?, fn_type.toLlvm(&o.builder));
78658035
7866 var global = Builder.Global{8036 var global = Builder.Global{
7867 .type = fn_type,8037 .type = fn_type,
...@@ -7942,20 +8112,15 @@ pub const FuncGen = struct {...@@ -7942,20 +8112,15 @@ pub const FuncGen = struct {
7942 return self.wip.icmp(int_cond, result, zero_vector, "");8112 return self.wip.icmp(int_cond, result, zero_vector, "");
7943 }8113 }
79448114
7945 const llvm_fn_ty = libc_fn.typeOf(&o.builder);8115 const result = try self.wip.call(
7946 const llvm_params = [2]*llvm.Value{ params[0].toLlvm(&self.wip), params[1].toLlvm(&self.wip) };8116 .normal,
7947 const result = (try self.wip.unimplemented(8117 .ccc,
7948 llvm_fn_ty.functionReturn(&o.builder),8118 .none,
7949 "",8119 libc_fn.typeOf(&o.builder),
7950 )).finish(self.builder.buildCall(8120 libc_fn.toValue(&o.builder),
7951 libc_fn.typeOf(&o.builder).toLlvm(&o.builder),8121 &params,
7952 libc_fn.toLlvm(&o.builder),
7953 &llvm_params,
7954 llvm_params.len,
7955 .C,
7956 .Auto,
7957 "",8122 "",
7958 ), &self.wip);8123 );
7959 return self.wip.icmp(int_cond, result, zero.toValue(), "");8124 return self.wip.icmp(int_cond, result, zero.toValue(), "");
7960 }8125 }
79618126
...@@ -8085,7 +8250,7 @@ pub const FuncGen = struct {...@@ -8085,7 +8250,7 @@ pub const FuncGen = struct {
8085 );8250 );
8086 var llvm_params: [params_len]*llvm.Value = undefined;8251 var llvm_params: [params_len]*llvm.Value = undefined;
8087 for (&llvm_params, params) |*llvm_param, param| llvm_param.* = param.toLlvm(&self.wip);8252 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(8253 return (try self.wip.unimplemented(llvm_ty, "")).finish(self.builder.buildCallOld(
8089 llvm_fn_ty.toLlvm(&o.builder),8254 llvm_fn_ty.toLlvm(&o.builder),
8090 llvm_fn,8255 llvm_fn,
8091 &llvm_params,8256 &llvm_params,
...@@ -8311,17 +8476,16 @@ pub const FuncGen = struct {...@@ -8311,17 +8476,16 @@ pub const FuncGen = struct {
8311 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),8476 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
8312 });8477 });
83138478
8314 const llvm_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);8479 const libc_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);
8315 const params = [1]*llvm.Value{operand.toLlvm(&self.wip)};8480 return self.wip.call(
8316 return (try self.wip.unimplemented(dest_llvm_ty, "")).finish(self.builder.buildCall(8481 .normal,
8317 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),8482 .ccc,
8318 llvm_fn.toLlvm(&o.builder),8483 .none,
8319 &params,8484 libc_fn.typeOf(&o.builder),
8320 params.len,8485 libc_fn.toValue(&o.builder),
8321 .C,8486 &.{operand},
8322 .Auto,
8323 "",8487 "",
8324 ), &self.wip);8488 );
8325 }8489 }
8326 }8490 }
83278491
...@@ -8346,17 +8510,16 @@ pub const FuncGen = struct {...@@ -8346,17 +8510,16 @@ pub const FuncGen = struct {
8346 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),8510 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
8347 });8511 });
83488512
8349 const llvm_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);8513 const libc_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);
8350 const params = [1]*llvm.Value{operand.toLlvm(&self.wip)};8514 return self.wip.call(
8351 return (try self.wip.unimplemented(dest_llvm_ty, "")).finish(self.builder.buildCall(8515 .normal,
8352 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),8516 .ccc,
8353 llvm_fn.toLlvm(&o.builder),8517 .none,
8354 &params,8518 libc_fn.typeOf(&o.builder),
8355 params.len,8519 libc_fn.toValue(&o.builder),
8356 .C,8520 &.{operand},
8357 .Auto,
8358 "",8521 "",
8359 ), &self.wip);8522 );
8360 }8523 }
8361 }8524 }
83628525
...@@ -8657,7 +8820,7 @@ pub const FuncGen = struct {...@@ -8657,7 +8820,7 @@ pub const FuncGen = struct {
8657 _ = inst;8820 _ = inst;
8658 const o = self.dg.object;8821 const o = self.dg.object;
8659 const llvm_fn = try self.getIntrinsic("llvm.trap", &.{});8822 const llvm_fn = try self.getIntrinsic("llvm.trap", &.{});
8660 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(8823 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
8661 (try o.builder.fnType(.void, &.{}, .normal)).toLlvm(&o.builder),8824 (try o.builder.fnType(.void, &.{}, .normal)).toLlvm(&o.builder),
8662 llvm_fn,8825 llvm_fn,
8663 undefined,8826 undefined,
...@@ -8674,7 +8837,7 @@ pub const FuncGen = struct {...@@ -8674,7 +8837,7 @@ pub const FuncGen = struct {
8674 _ = inst;8837 _ = inst;
8675 const o = self.dg.object;8838 const o = self.dg.object;
8676 const llvm_fn = try self.getIntrinsic("llvm.debugtrap", &.{});8839 const llvm_fn = try self.getIntrinsic("llvm.debugtrap", &.{});
8677 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(8840 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
8678 (try o.builder.fnType(.void, &.{}, .normal)).toLlvm(&o.builder),8841 (try o.builder.fnType(.void, &.{}, .normal)).toLlvm(&o.builder),
8679 llvm_fn,8842 llvm_fn,
8680 undefined,8843 undefined,
...@@ -8701,7 +8864,7 @@ pub const FuncGen = struct {...@@ -8701,7 +8864,7 @@ pub const FuncGen = struct {
8701 const params = [_]*llvm.Value{8864 const params = [_]*llvm.Value{
8702 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),8865 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
8703 };8866 };
8704 const ptr_val = (try self.wip.unimplemented(.ptr, "")).finish(self.builder.buildCall(8867 const ptr_val = (try self.wip.unimplemented(.ptr, "")).finish(self.builder.buildCallOld(
8705 (try o.builder.fnType(.ptr, &.{.i32}, .normal)).toLlvm(&o.builder),8868 (try o.builder.fnType(.ptr, &.{.i32}, .normal)).toLlvm(&o.builder),
8706 llvm_fn,8869 llvm_fn,
8707 &params,8870 &params,
...@@ -8727,7 +8890,7 @@ pub const FuncGen = struct {...@@ -8727,7 +8890,7 @@ pub const FuncGen = struct {
8727 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),8890 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
8728 };8891 };
8729 const ptr_val = (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(8892 const ptr_val = (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(
8730 self.builder.buildCall(8893 self.builder.buildCallOld(
8731 llvm_fn_ty.toLlvm(&o.builder),8894 llvm_fn_ty.toLlvm(&o.builder),
8732 llvm_fn,8895 llvm_fn,
8733 &params,8896 &params,
...@@ -9256,7 +9419,7 @@ pub const FuncGen = struct {...@@ -9256,7 +9419,7 @@ pub const FuncGen = struct {
9256 Builder.Constant.false.toLlvm(&o.builder),9419 Builder.Constant.false.toLlvm(&o.builder),
9257 };9420 };
9258 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(9421 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
9259 self.builder.buildCall(9422 self.builder.buildCallOld(
9260 llvm_fn_ty.toLlvm(&o.builder),9423 llvm_fn_ty.toLlvm(&o.builder),
9261 fn_val,9424 fn_val,
9262 &params,9425 &params,
...@@ -9283,7 +9446,7 @@ pub const FuncGen = struct {...@@ -9283,7 +9446,7 @@ pub const FuncGen = struct {
92839446
9284 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};9447 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
9285 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(9448 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
9286 self.builder.buildCall(9449 self.builder.buildCallOld(
9287 llvm_fn_ty.toLlvm(&o.builder),9450 llvm_fn_ty.toLlvm(&o.builder),
9288 fn_val,9451 fn_val,
9289 &params,9452 &params,
...@@ -9331,7 +9494,7 @@ pub const FuncGen = struct {...@@ -9331,7 +9494,7 @@ pub const FuncGen = struct {
93319494
9332 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};9495 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
9333 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(9496 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
9334 self.builder.buildCall(9497 self.builder.buildCallOld(
9335 llvm_fn_ty.toLlvm(&o.builder),9498 llvm_fn_ty.toLlvm(&o.builder),
9336 fn_val,9499 fn_val,
9337 &params,9500 &params,
...@@ -9389,16 +9552,15 @@ pub const FuncGen = struct {...@@ -9389,16 +9552,15 @@ pub const FuncGen = struct {
9389 const enum_ty = self.typeOf(un_op);9552 const enum_ty = self.typeOf(un_op);
93909553
9391 const llvm_fn = try self.getIsNamedEnumValueFunction(enum_ty);9554 const llvm_fn = try self.getIsNamedEnumValueFunction(enum_ty);
9392 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};9555 return self.wip.call(
9393 return (try self.wip.unimplemented(.i1, "")).finish(self.builder.buildCall(9556 .normal,
9394 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),9557 .fastcc,
9395 llvm_fn.toLlvm(&o.builder),9558 .none,
9396 &params,9559 llvm_fn.typeOf(&o.builder),
9397 params.len,9560 llvm_fn.toValue(&o.builder),
9398 .Fast,9561 &.{operand},
9399 .Auto,
9400 "",9562 "",
9401 ), &self.wip);9563 );
9402 }9564 }
94039565
9404 fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index {9566 fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index {
...@@ -9416,13 +9578,16 @@ pub const FuncGen = struct {...@@ -9416,13 +9578,16 @@ pub const FuncGen = struct {
9416 fqn.fmt(&mod.intern_pool),9578 fqn.fmt(&mod.intern_pool),
9417 });9579 });
94189580
9581 var attributes: Builder.FunctionAttributes.Wip = .{};
9582 defer attributes.deinit(&o.builder);
9583
9419 const fn_type = try o.builder.fnType(.i1, &.{9584 const fn_type = try o.builder.fnType(.i1, &.{
9420 try o.lowerType(enum_type.tag_ty.toType()),9585 try o.lowerType(enum_type.tag_ty.toType()),
9421 }, .normal);9586 }, .normal);
9422 const fn_val = o.llvm_module.addFunction(llvm_fn_name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));9587 const fn_val = o.llvm_module.addFunction(llvm_fn_name.slice(&o.builder).?, fn_type.toLlvm(&o.builder));
9423 fn_val.setLinkage(.Internal);9588 fn_val.setLinkage(.Internal);
9424 fn_val.setFunctionCallConv(.Fast);9589 fn_val.setFunctionCallConv(.Fast);
9425 o.addCommonFnAttributes(fn_val);9590 try o.addCommonFnAttributes(&attributes, fn_val);
94269591
9427 var global = Builder.Global{9592 var global = Builder.Global{
9428 .linkage = .internal,9593 .linkage = .internal,
...@@ -9431,6 +9596,8 @@ pub const FuncGen = struct {...@@ -9431,6 +9596,8 @@ pub const FuncGen = struct {
9431 };9596 };
9432 var function = Builder.Function{9597 var function = Builder.Function{
9433 .global = @enumFromInt(o.builder.globals.count()),9598 .global = @enumFromInt(o.builder.globals.count()),
9599 .call_conv = .fastcc,
9600 .attributes = try attributes.finish(&o.builder),
9434 };9601 };
9435 try o.builder.llvm.globals.append(self.gpa, fn_val);9602 try o.builder.llvm.globals.append(self.gpa, fn_val);
9436 _ = try o.builder.addGlobal(llvm_fn_name, global);9603 _ = try o.builder.addGlobal(llvm_fn_name, global);
...@@ -9470,19 +9637,14 @@ pub const FuncGen = struct {...@@ -9470,19 +9637,14 @@ pub const FuncGen = struct {
9470 const enum_ty = self.typeOf(un_op);9637 const enum_ty = self.typeOf(un_op);
94719638
9472 const llvm_fn = try self.getEnumTagNameFunction(enum_ty);9639 const llvm_fn = try self.getEnumTagNameFunction(enum_ty);
9473 const llvm_fn_ty = llvm_fn.typeOf(&o.builder);9640 return self.wip.call(
9474 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};9641 .normal,
9475 return (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(9642 .fastcc,
9476 self.builder.buildCall(9643 .none,
9477 llvm_fn_ty.toLlvm(&o.builder),9644 llvm_fn.typeOf(&o.builder),
9478 llvm_fn.toLlvm(&o.builder),9645 llvm_fn.toValue(&o.builder),
9479 &params,9646 &.{operand},
9480 params.len,9647 "",
9481 .Fast,
9482 .Auto,
9483 "",
9484 ),
9485 &self.wip,
9486 );9648 );
9487 }9649 }
94889650
...@@ -9499,16 +9661,19 @@ pub const FuncGen = struct {...@@ -9499,16 +9661,19 @@ pub const FuncGen = struct {
9499 const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);9661 const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);
9500 const llvm_fn_name = try o.builder.fmt("__zig_tag_name_{}", .{fqn.fmt(&mod.intern_pool)});9662 const llvm_fn_name = try o.builder.fmt("__zig_tag_name_{}", .{fqn.fmt(&mod.intern_pool)});
95019663
9664 var attributes: Builder.FunctionAttributes.Wip = .{};
9665 defer attributes.deinit(&o.builder);
9666
9502 const ret_ty = try o.lowerType(Type.slice_const_u8_sentinel_0);9667 const ret_ty = try o.lowerType(Type.slice_const_u8_sentinel_0);
9503 const usize_ty = try o.lowerType(Type.usize);9668 const usize_ty = try o.lowerType(Type.usize);
95049669
9505 const fn_type = try o.builder.fnType(ret_ty, &.{9670 const fn_type = try o.builder.fnType(ret_ty, &.{
9506 try o.lowerType(enum_type.tag_ty.toType()),9671 try o.lowerType(enum_type.tag_ty.toType()),
9507 }, .normal);9672 }, .normal);
9508 const fn_val = o.llvm_module.addFunction(llvm_fn_name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));9673 const fn_val = o.llvm_module.addFunction(llvm_fn_name.slice(&o.builder).?, fn_type.toLlvm(&o.builder));
9509 fn_val.setLinkage(.Internal);9674 fn_val.setLinkage(.Internal);
9510 fn_val.setFunctionCallConv(.Fast);9675 fn_val.setFunctionCallConv(.Fast);
9511 o.addCommonFnAttributes(fn_val);9676 try o.addCommonFnAttributes(&attributes, fn_val);
95129677
9513 var global = Builder.Global{9678 var global = Builder.Global{
9514 .linkage = .internal,9679 .linkage = .internal,
...@@ -9517,6 +9682,8 @@ pub const FuncGen = struct {...@@ -9517,6 +9682,8 @@ pub const FuncGen = struct {
9517 };9682 };
9518 var function = Builder.Function{9683 var function = Builder.Function{
9519 .global = @enumFromInt(o.builder.globals.count()),9684 .global = @enumFromInt(o.builder.globals.count()),
9685 .call_conv = .fastcc,
9686 .attributes = try attributes.finish(&o.builder),
9520 };9687 };
9521 try o.builder.llvm.globals.append(self.gpa, fn_val);9688 try o.builder.llvm.globals.append(self.gpa, fn_val);
9522 gop.value_ptr.* = try o.builder.addGlobal(llvm_fn_name, global);9689 gop.value_ptr.* = try o.builder.addGlobal(llvm_fn_name, global);
...@@ -9561,7 +9728,7 @@ pub const FuncGen = struct {...@@ -9561,7 +9728,7 @@ pub const FuncGen = struct {
95619728
9562 const slice_val = try o.builder.structValue(ret_ty, &.{9729 const slice_val = try o.builder.structValue(ret_ty, &.{
9563 global_index.toConst(),9730 global_index.toConst(),
9564 try o.builder.intConst(usize_ty, name.toSlice(&o.builder).?.len),9731 try o.builder.intConst(usize_ty, name.slice(&o.builder).?.len),
9565 });9732 });
95669733
9567 const return_block = try wip.block(1, "Name");9734 const return_block = try wip.block(1, "Name");
...@@ -9590,11 +9757,14 @@ pub const FuncGen = struct {...@@ -9590,11 +9757,14 @@ pub const FuncGen = struct {
9590 // Function signature: fn (anyerror) bool9757 // Function signature: fn (anyerror) bool
95919758
9592 const fn_type = try o.builder.fnType(.i1, &.{Builder.Type.err_int}, .normal);9759 const fn_type = try o.builder.fnType(.i1, &.{Builder.Type.err_int}, .normal);
9593 const llvm_fn = o.llvm_module.addFunction(name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));9760 const llvm_fn = o.llvm_module.addFunction(name.slice(&o.builder).?, fn_type.toLlvm(&o.builder));
9761
9762 var attributes: Builder.FunctionAttributes.Wip = .{};
9763 defer attributes.deinit(&o.builder);
95949764
9595 llvm_fn.setLinkage(.Internal);9765 llvm_fn.setLinkage(.Internal);
9596 llvm_fn.setFunctionCallConv(.Fast);9766 llvm_fn.setFunctionCallConv(.Fast);
9597 o.addCommonFnAttributes(llvm_fn);9767 try o.addCommonFnAttributes(&attributes, llvm_fn);
95989768
9599 var global = Builder.Global{9769 var global = Builder.Global{
9600 .linkage = .internal,9770 .linkage = .internal,
...@@ -9603,6 +9773,8 @@ pub const FuncGen = struct {...@@ -9603,6 +9773,8 @@ pub const FuncGen = struct {
9603 };9773 };
9604 var function = Builder.Function{9774 var function = Builder.Function{
9605 .global = @enumFromInt(o.builder.globals.count()),9775 .global = @enumFromInt(o.builder.globals.count()),
9776 .call_conv = .fastcc,
9777 .attributes = try attributes.finish(&o.builder),
9606 };9778 };
96079779
9608 try o.builder.llvm.globals.append(self.gpa, llvm_fn);9780 try o.builder.llvm.globals.append(self.gpa, llvm_fn);
...@@ -9731,18 +9903,14 @@ pub const FuncGen = struct {...@@ -9731,18 +9903,14 @@ pub const FuncGen = struct {
9731 // accum = f(accum, vec[i]);9903 // accum = f(accum, vec[i]);
9732 const accum = try self.wip.load(.normal, llvm_result_ty, accum_ptr, .default, "");9904 const accum = try self.wip.load(.normal, llvm_result_ty, accum_ptr, .default, "");
9733 const element = try self.wip.extractElement(operand_vector, i, "");9905 const element = try self.wip.extractElement(operand_vector, i, "");
9734 const params = [2]*llvm.Value{ accum.toLlvm(&self.wip), element.toLlvm(&self.wip) };9906 const new_accum = try self.wip.call(
9735 const new_accum = (try self.wip.unimplemented(llvm_result_ty, "")).finish(9907 .normal,
9736 self.builder.buildCall(9908 .ccc,
9737 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),9909 .none,
9738 llvm_fn.toLlvm(&o.builder),9910 llvm_fn.typeOf(&o.builder),
9739 &params,9911 llvm_fn.toValue(&o.builder),
9740 params.len,9912 &.{ accum, element },
9741 .C,9913 "",
9742 .Auto,
9743 "",
9744 ),
9745 &self.wip,
9746 );9914 );
9747 _ = try self.wip.store(.normal, new_accum, accum_ptr, .default);9915 _ = try self.wip.store(.normal, new_accum, accum_ptr, .default);
97489916
...@@ -10190,7 +10358,7 @@ pub const FuncGen = struct {...@@ -10190,7 +10358,7 @@ pub const FuncGen = struct {
10190 (try o.builder.intConst(.i32, prefetch.locality)).toLlvm(&o.builder),10358 (try o.builder.intConst(.i32, prefetch.locality)).toLlvm(&o.builder),
10191 (try o.builder.intConst(.i32, @intFromEnum(prefetch.cache))).toLlvm(&o.builder),10359 (try o.builder.intConst(.i32, @intFromEnum(prefetch.cache))).toLlvm(&o.builder),
10192 };10360 };
10193 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(10361 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
10194 llvm_fn_ty.toLlvm(&o.builder),10362 llvm_fn_ty.toLlvm(&o.builder),
10195 fn_val,10363 fn_val,
10196 &params,10364 &params,
...@@ -10222,7 +10390,7 @@ pub const FuncGen = struct {...@@ -10222,7 +10390,7 @@ pub const FuncGen = struct {
1022210390
10223 const args: [0]*llvm.Value = .{};10391 const args: [0]*llvm.Value = .{};
10224 const llvm_fn = try self.getIntrinsic(llvm_fn_name, &.{});10392 const llvm_fn = try self.getIntrinsic(llvm_fn_name, &.{});
10225 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCall(10393 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCallOld(
10226 (try o.builder.fnType(.i32, &.{}, .normal)).toLlvm(&o.builder),10394 (try o.builder.fnType(.i32, &.{}, .normal)).toLlvm(&o.builder),
10227 llvm_fn,10395 llvm_fn,
10228 &args,10396 &args,
...@@ -10252,12 +10420,15 @@ pub const FuncGen = struct {...@@ -10252,12 +10420,15 @@ pub const FuncGen = struct {
10252 const dimension = pl_op.payload;10420 const dimension = pl_op.payload;
10253 if (dimension >= 3) return o.builder.intValue(.i32, 1);10421 if (dimension >= 3) return o.builder.intValue(.i32, 1);
1025410422
10423 var attributes: Builder.FunctionAttributes.Wip = .{};
10424 defer attributes.deinit(&o.builder);
10425
10255 // Fetch the dispatch pointer, which points to this structure:10426 // Fetch the dispatch pointer, which points to this structure:
10256 // https://github.com/RadeonOpenCompute/ROCR-Runtime/blob/adae6c61e10d371f7cbc3d0e94ae2c070cab18a4/src/inc/hsa.h#L291310427 // https://github.com/RadeonOpenCompute/ROCR-Runtime/blob/adae6c61e10d371f7cbc3d0e94ae2c070cab18a4/src/inc/hsa.h#L2913
10257 const llvm_fn = try self.getIntrinsic("llvm.amdgcn.dispatch.ptr", &.{});10428 const llvm_fn = try self.getIntrinsic("llvm.amdgcn.dispatch.ptr", &.{});
10258 const args: [0]*llvm.Value = .{};10429 const args: [0]*llvm.Value = .{};
10259 const llvm_ret_ty = try o.builder.ptrType(Builder.AddrSpace.amdgpu.constant);10430 const llvm_ret_ty = try o.builder.ptrType(Builder.AddrSpace.amdgpu.constant);
10260 const dispatch_ptr = (try self.wip.unimplemented(llvm_ret_ty, "")).finish(self.builder.buildCall(10431 const dispatch_ptr = (try self.wip.unimplemented(llvm_ret_ty, "")).finish(self.builder.buildCallOld(
10261 (try o.builder.fnType(llvm_ret_ty, &.{}, .normal)).toLlvm(&o.builder),10432 (try o.builder.fnType(llvm_ret_ty, &.{}, .normal)).toLlvm(&o.builder),
10262 llvm_fn,10433 llvm_fn,
10263 &args,10434 &args,
...@@ -10266,6 +10437,9 @@ pub const FuncGen = struct {...@@ -10266,6 +10437,9 @@ pub const FuncGen = struct {
10266 .Auto,10437 .Auto,
10267 "",10438 "",
10268 ), &self.wip);10439 ), &self.wip);
10440 try attributes.addRetAttr(.{
10441 .@"align" = comptime Builder.Alignment.fromByteUnits(4),
10442 }, &o.builder);
10269 o.addAttrInt(dispatch_ptr.toLlvm(&self.wip), 0, "align", 4);10443 o.addAttrInt(dispatch_ptr.toLlvm(&self.wip), 0, "align", 4);
1027010444
10271 // Load the work_group_* member from the struct as u16.10445 // Load the work_group_* member from the struct as u16.
...@@ -10298,7 +10472,7 @@ pub const FuncGen = struct {...@@ -10298,7 +10472,7 @@ pub const FuncGen = struct {
10298 const undef_init = try o.builder.undefConst(.ptr); // TODO: Address space10472 const undef_init = try o.builder.undefConst(.ptr); // TODO: Address space
1029910473
10300 const name = try o.builder.string("__zig_err_name_table");10474 const name = try o.builder.string("__zig_err_name_table");
10301 const error_name_table_global = o.llvm_module.addGlobal(Builder.Type.ptr.toLlvm(&o.builder), name.toSlice(&o.builder).?);10475 const error_name_table_global = o.llvm_module.addGlobal(Builder.Type.ptr.toLlvm(&o.builder), name.slice(&o.builder).?);
10302 error_name_table_global.setInitializer(undef_init.toLlvm(&o.builder));10476 error_name_table_global.setInitializer(undef_init.toLlvm(&o.builder));
10303 error_name_table_global.setLinkage(.Private);10477 error_name_table_global.setLinkage(.Private);
10304 error_name_table_global.setGlobalConstant(.True);10478 error_name_table_global.setGlobalConstant(.True);
...@@ -10751,7 +10925,7 @@ pub const FuncGen = struct {...@@ -10751,7 +10925,7 @@ pub const FuncGen = struct {
10751 );10925 );
1075210926
10753 const call = (try fg.wip.unimplemented(llvm_usize, "")).finish(10927 const call = (try fg.wip.unimplemented(llvm_usize, "")).finish(
10754 fg.builder.buildCall(fn_llvm_ty, asm_fn, &args, args.len, .C, .Auto, ""),10928 fg.builder.buildCallOld(fn_llvm_ty, asm_fn, &args, args.len, .C, .Auto, ""),
10755 &fg.wip,10929 &fg.wip,
10756 );10930 );
10757 return call;10931 return call;
...@@ -10991,33 +11165,33 @@ fn toLlvmAtomicRmwBinOp(...@@ -10991,33 +11165,33 @@ fn toLlvmAtomicRmwBinOp(
10991 };11165 };
10992}11166}
1099311167
10994fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.CallConv {11168fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) Builder.CallConv {
10995 return switch (cc) {11169 return switch (cc) {
10996 .Unspecified, .Inline, .Async => .Fast,11170 .Unspecified, .Inline, .Async => .fastcc,
10997 .C, .Naked => .C,11171 .C, .Naked => .ccc,
10998 .Stdcall => .X86_StdCall,11172 .Stdcall => .x86_stdcallcc,
10999 .Fastcall => .X86_FastCall,11173 .Fastcall => .x86_fastcallcc,
11000 .Vectorcall => return switch (target.cpu.arch) {11174 .Vectorcall => return switch (target.cpu.arch) {
11001 .x86, .x86_64 => .X86_VectorCall,11175 .x86, .x86_64 => .x86_vectorcallcc,
11002 .aarch64, .aarch64_be, .aarch64_32 => .AArch64_VectorCall,11176 .aarch64, .aarch64_be, .aarch64_32 => .aarch64_vector_pcs,
11003 else => unreachable,11177 else => unreachable,
11004 },11178 },
11005 .Thiscall => .X86_ThisCall,11179 .Thiscall => .x86_thiscallcc,
11006 .APCS => .ARM_APCS,11180 .APCS => .arm_apcscc,
11007 .AAPCS => .ARM_AAPCS,11181 .AAPCS => .arm_aapcscc,
11008 .AAPCSVFP => .ARM_AAPCS_VFP,11182 .AAPCSVFP => .arm_aapcs_vfpcc,
11009 .Interrupt => return switch (target.cpu.arch) {11183 .Interrupt => return switch (target.cpu.arch) {
11010 .x86, .x86_64 => .X86_INTR,11184 .x86, .x86_64 => .x86_intrcc,
11011 .avr => .AVR_INTR,11185 .avr => .avr_intrcc,
11012 .msp430 => .MSP430_INTR,11186 .msp430 => .msp430_intrcc,
11013 else => unreachable,11187 else => unreachable,
11014 },11188 },
11015 .Signal => .AVR_SIGNAL,11189 .Signal => .avr_signalcc,
11016 .SysV => .X86_64_SysV,11190 .SysV => .x86_64_sysvcc,
11017 .Win64 => .Win64,11191 .Win64 => .win64cc,
11018 .Kernel => return switch (target.cpu.arch) {11192 .Kernel => return switch (target.cpu.arch) {
11019 .nvptx, .nvptx64 => .PTX_Kernel,11193 .nvptx, .nvptx64 => .ptx_kernel,
11020 .amdgcn => .AMDGPU_KERNEL,11194 .amdgcn => .amdgpu_kernel,
11021 else => unreachable,11195 else => unreachable,
11022 },11196 },
11023 };11197 };
src/codegen/llvm/Builder.zig+2190-510
...@@ -4,22 +4,25 @@ strip: bool,...@@ -4,22 +4,25 @@ strip: bool,
44
5llvm: if (build_options.have_llvm) struct {5llvm: if (build_options.have_llvm) struct {
6 context: *llvm.Context,6 context: *llvm.Context,
7 module: ?*llvm.Module = null,7 module: ?*llvm.Module,
8 target: ?*llvm.Target = null,8 target: ?*llvm.Target,
9 di_builder: ?*llvm.DIBuilder = null,9 di_builder: ?*llvm.DIBuilder,
10 di_compile_unit: ?*llvm.DICompileUnit = null,10 di_compile_unit: ?*llvm.DICompileUnit,
11 types: std.ArrayListUnmanaged(*llvm.Type) = .{},11 attribute_kind_ids: ?*[Attribute.Kind.len]c_uint,
12 globals: std.ArrayListUnmanaged(*llvm.Value) = .{},12 attributes: std.ArrayListUnmanaged(*llvm.Attribute),
13 constants: std.ArrayListUnmanaged(*llvm.Value) = .{},13 types: std.ArrayListUnmanaged(*llvm.Type),
14 globals: std.ArrayListUnmanaged(*llvm.Value),
15 constants: std.ArrayListUnmanaged(*llvm.Value),
14} else void,16} else void,
1517
16source_filename: String,18source_filename: String,
17data_layout: String,19data_layout: String,
18target_triple: String,20target_triple: String,
21module_asm: std.ArrayListUnmanaged(u8),
1922
20string_map: std.AutoArrayHashMapUnmanaged(void, void),23string_map: std.AutoArrayHashMapUnmanaged(void, void),
21string_bytes: std.ArrayListUnmanaged(u8),
22string_indices: std.ArrayListUnmanaged(u32),24string_indices: std.ArrayListUnmanaged(u32),
25string_bytes: std.ArrayListUnmanaged(u8),
2326
24types: std.AutoArrayHashMapUnmanaged(String, Type),27types: std.AutoArrayHashMapUnmanaged(String, Type),
25next_unnamed_type: String,28next_unnamed_type: String,
...@@ -28,6 +31,11 @@ type_map: std.AutoArrayHashMapUnmanaged(void, void),...@@ -28,6 +31,11 @@ type_map: std.AutoArrayHashMapUnmanaged(void, void),
28type_items: std.ArrayListUnmanaged(Type.Item),31type_items: std.ArrayListUnmanaged(Type.Item),
29type_extra: std.ArrayListUnmanaged(u32),32type_extra: std.ArrayListUnmanaged(u32),
3033
34attributes: std.AutoArrayHashMapUnmanaged(Attribute.Storage, void),
35attributes_map: std.AutoArrayHashMapUnmanaged(void, void),
36attributes_indices: std.ArrayListUnmanaged(u32),
37attributes_extra: std.ArrayListUnmanaged(u32),
38
31globals: std.AutoArrayHashMapUnmanaged(String, Global),39globals: std.AutoArrayHashMapUnmanaged(String, Global),
32next_unnamed_global: String,40next_unnamed_global: String,
33next_replaced_global: String,41next_replaced_global: String,
...@@ -41,6 +49,7 @@ constant_items: std.MultiArrayList(Constant.Item),...@@ -41,6 +49,7 @@ constant_items: std.MultiArrayList(Constant.Item),
41constant_extra: std.ArrayListUnmanaged(u32),49constant_extra: std.ArrayListUnmanaged(u32),
42constant_limbs: std.ArrayListUnmanaged(std.math.big.Limb),50constant_limbs: std.ArrayListUnmanaged(std.math.big.Limb),
4351
52pub const expected_args_len = 16;
44pub const expected_fields_len = 32;53pub const expected_fields_len = 32;
45pub const expected_gep_indices_len = 8;54pub const expected_gep_indices_len = 8;
46pub const expected_cases_len = 8;55pub const expected_cases_len = 8;
...@@ -65,7 +74,7 @@ pub const String = enum(u32) {...@@ -65,7 +74,7 @@ pub const String = enum(u32) {
65 return self.toIndex() == null;74 return self.toIndex() == null;
66 }75 }
6776
68 pub fn toSlice(self: String, b: *const Builder) ?[:0]const u8 {77 pub fn slice(self: String, b: *const Builder) ?[:0]const u8 {
69 const index = self.toIndex() orelse return null;78 const index = self.toIndex() orelse return null;
70 const start = b.string_indices.items[index];79 const start = b.string_indices.items[index];
71 const end = b.string_indices.items[index + 1];80 const end = b.string_indices.items[index + 1];
...@@ -85,20 +94,14 @@ pub const String = enum(u32) {...@@ -85,20 +94,14 @@ pub const String = enum(u32) {
85 if (comptime std.mem.indexOfNone(u8, fmt_str, "@\"")) |_|94 if (comptime std.mem.indexOfNone(u8, fmt_str, "@\"")) |_|
86 @compileError("invalid format string: '" ++ fmt_str ++ "'");95 @compileError("invalid format string: '" ++ fmt_str ++ "'");
87 assert(data.string != .none);96 assert(data.string != .none);
88 const slice = data.string.toSlice(data.builder) orelse97 const sentinel_slice = data.string.slice(data.builder) orelse
89 return writer.print("{d}", .{@intFromEnum(data.string)});98 return writer.print("{d}", .{@intFromEnum(data.string)});
90 const full_slice = slice[0 .. slice.len + comptime @intFromBool(99 try printEscapedString(sentinel_slice[0 .. sentinel_slice.len + comptime @intFromBool(
91 std.mem.indexOfScalar(u8, fmt_str, '@') != null,100 std.mem.indexOfScalar(u8, fmt_str, '@') != null,
92 )];101 )], if (comptime std.mem.indexOfScalar(u8, fmt_str, '"')) |_|
93 const need_quotes = (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) or102 .always_quote
94 !isValidIdentifier(full_slice);103 else
95 if (need_quotes) try writer.writeByte('"');104 .quote_unless_valid_identifier, writer);
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 }105 }
103 pub fn fmt(self: String, builder: *const Builder) std.fmt.Formatter(format) {106 pub fn fmt(self: String, builder: *const Builder) std.fmt.Formatter(format) {
104 return .{ .data = .{ .string = self, .builder = builder } };107 return .{ .data = .{ .string = self, .builder = builder } };
...@@ -108,6 +111,7 @@ pub const String = enum(u32) {...@@ -108,6 +111,7 @@ pub const String = enum(u32) {
108 return @enumFromInt(@as(u32, @intCast((index orelse return .none) +111 return @enumFromInt(@as(u32, @intCast((index orelse return .none) +
109 @intFromEnum(String.empty))));112 @intFromEnum(String.empty))));
110 }113 }
114
111 fn toIndex(self: String) ?usize {115 fn toIndex(self: String) ?usize {
112 return std.math.sub(u32, @intFromEnum(self), @intFromEnum(String.empty)) catch null;116 return std.math.sub(u32, @intFromEnum(self), @intFromEnum(String.empty)) catch null;
113 }117 }
...@@ -118,7 +122,7 @@ pub const String = enum(u32) {...@@ -118,7 +122,7 @@ pub const String = enum(u32) {
118 return @truncate(std.hash.Wyhash.hash(0, key));122 return @truncate(std.hash.Wyhash.hash(0, key));
119 }123 }
120 pub fn eql(ctx: Adapter, lhs_key: []const u8, _: void, rhs_index: usize) bool {124 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).?);125 return std.mem.eql(u8, lhs_key, String.fromIndex(rhs_index).slice(ctx.builder).?);
122 }126 }
123 };127 };
124};128};
...@@ -290,6 +294,17 @@ pub const Type = enum(u32) {...@@ -290,6 +294,17 @@ pub const Type = enum(u32) {
290 };294 };
291 }295 }
292296
297 pub fn pointerAddrSpace(self: Type, builder: *const Builder) AddrSpace {
298 switch (self) {
299 .ptr => return .default,
300 else => {
301 const item = builder.type_items.items[@intFromEnum(self)];
302 assert(item.tag == .pointer);
303 return @enumFromInt(item.data);
304 },
305 }
306 }
307
293 pub fn isFunction(self: Type, builder: *const Builder) bool {308 pub fn isFunction(self: Type, builder: *const Builder) bool {
294 return switch (self.tag(builder)) {309 return switch (self.tag(builder)) {
295 .function, .vararg_function => true,310 .function, .vararg_function => true,
...@@ -606,7 +621,7 @@ pub const Type = enum(u32) {...@@ -606,7 +621,7 @@ pub const Type = enum(u32) {
606 var extra = data.builder.typeExtraDataTrail(Type.Target, item.data);621 var extra = data.builder.typeExtraDataTrail(Type.Target, item.data);
607 const types = extra.trail.next(extra.data.types_len, Type, data.builder);622 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);623 const ints = extra.trail.next(extra.data.ints_len, u32, data.builder);
609 try writer.print("t{s}", .{extra.data.name.toSlice(data.builder).?});624 try writer.print("t{s}", .{extra.data.name.slice(data.builder).?});
610 for (types) |ty| try writer.print("_{m}", .{ty.fmt(data.builder)});625 for (types) |ty| try writer.print("_{m}", .{ty.fmt(data.builder)});
611 for (ints) |int| try writer.print("_{d}", .{int});626 for (ints) |int| try writer.print("_{d}", .{int});
612 try writer.writeByte('t');627 try writer.writeByte('t');
...@@ -641,7 +656,7 @@ pub const Type = enum(u32) {...@@ -641,7 +656,7 @@ pub const Type = enum(u32) {
641 .named_structure => {656 .named_structure => {
642 const extra = data.builder.typeExtraData(Type.NamedStructure, item.data);657 const extra = data.builder.typeExtraData(Type.NamedStructure, item.data);
643 try writer.writeAll("s_");658 try writer.writeAll("s_");
644 if (extra.id.toSlice(data.builder)) |id| try writer.writeAll(id);659 if (extra.id.slice(data.builder)) |id| try writer.writeAll(id);
645 },660 },
646 }661 }
647 return;662 return;
...@@ -823,6 +838,849 @@ pub const Type = enum(u32) {...@@ -823,6 +838,849 @@ pub const Type = enum(u32) {
823 }838 }
824};839};
825840
841pub const Attribute = union(Kind) {
842 // Parameter Attributes
843 zeroext,
844 signext,
845 inreg,
846 byval: Type,
847 byref: Type,
848 preallocated: Type,
849 inalloca: Type,
850 sret: Type,
851 elementtype: Type,
852 @"align": Alignment,
853 @"noalias",
854 nocapture,
855 nofree,
856 nest,
857 returned,
858 nonnull,
859 dereferenceable: u32,
860 dereferenceable_or_null: u32,
861 swiftself,
862 swiftasync,
863 swifterror,
864 immarg,
865 noundef,
866 nofpclass: FpClass,
867 alignstack: Alignment,
868 allocalign,
869 allocptr,
870 readnone,
871 readonly,
872 writeonly,
873
874 // Function Attributes
875 //alignstack: Alignment,
876 allockind: AllocKind,
877 allocsize: AllocSize,
878 alwaysinline,
879 builtin,
880 cold,
881 convergent,
882 disable_sanitizer_information,
883 fn_ret_thunk_extern,
884 hot,
885 inlinehint,
886 jumptable,
887 memory: Memory,
888 minsize,
889 naked,
890 nobuiltin,
891 nocallback,
892 noduplicate,
893 //nofree,
894 noimplicitfloat,
895 @"noinline",
896 nomerge,
897 nonlazybind,
898 noprofile,
899 skipprofile,
900 noredzone,
901 noreturn,
902 norecurse,
903 willreturn,
904 nosync,
905 nounwind,
906 nosanitize_bounds,
907 nosanitize_coverage,
908 null_pointer_is_valid,
909 optforfuzzing,
910 optnone,
911 optsize,
912 //preallocated: Type,
913 returns_twice,
914 safestack,
915 sanitize_address,
916 sanitize_memory,
917 sanitize_thread,
918 sanitize_hwaddress,
919 sanitize_memtag,
920 speculative_load_hardening,
921 speculatable,
922 ssp,
923 sspstrong,
924 sspreq,
925 strictfp,
926 uwtable: UwTable,
927 nocf_check,
928 shadowcallstack,
929 mustprogress,
930 vscale_range: VScaleRange,
931
932 // Global Attributes
933 no_sanitize_address,
934 no_sanitize_hwaddress,
935 //sanitize_memtag,
936 sanitize_address_dyninit,
937
938 string: struct { kind: String, value: String },
939 none: noreturn,
940
941 pub const Index = enum(u32) {
942 _,
943
944 pub fn getKind(self: Index, builder: *const Builder) Kind {
945 return self.toStorage(builder).kind;
946 }
947
948 pub fn toAttribute(self: Index, builder: *const Builder) Attribute {
949 @setEvalBranchQuota(2_000);
950 const storage = self.toStorage(builder);
951 if (storage.kind.toString()) |kind| return .{ .string = .{
952 .kind = kind,
953 .value = @enumFromInt(storage.value),
954 } } else return switch (storage.kind) {
955 inline .zeroext,
956 .signext,
957 .inreg,
958 .byval,
959 .byref,
960 .preallocated,
961 .inalloca,
962 .sret,
963 .elementtype,
964 .@"align",
965 .@"noalias",
966 .nocapture,
967 .nofree,
968 .nest,
969 .returned,
970 .nonnull,
971 .dereferenceable,
972 .dereferenceable_or_null,
973 .swiftself,
974 .swiftasync,
975 .swifterror,
976 .immarg,
977 .noundef,
978 .nofpclass,
979 .alignstack,
980 .allocalign,
981 .allocptr,
982 .readnone,
983 .readonly,
984 .writeonly,
985 //.alignstack,
986 .allockind,
987 .allocsize,
988 .alwaysinline,
989 .builtin,
990 .cold,
991 .convergent,
992 .disable_sanitizer_information,
993 .fn_ret_thunk_extern,
994 .hot,
995 .inlinehint,
996 .jumptable,
997 .memory,
998 .minsize,
999 .naked,
1000 .nobuiltin,
1001 .nocallback,
1002 .noduplicate,
1003 //.nofree,
1004 .noimplicitfloat,
1005 .@"noinline",
1006 .nomerge,
1007 .nonlazybind,
1008 .noprofile,
1009 .skipprofile,
1010 .noredzone,
1011 .noreturn,
1012 .norecurse,
1013 .willreturn,
1014 .nosync,
1015 .nounwind,
1016 .nosanitize_bounds,
1017 .nosanitize_coverage,
1018 .null_pointer_is_valid,
1019 .optforfuzzing,
1020 .optnone,
1021 .optsize,
1022 //.preallocated,
1023 .returns_twice,
1024 .safestack,
1025 .sanitize_address,
1026 .sanitize_memory,
1027 .sanitize_thread,
1028 .sanitize_hwaddress,
1029 .sanitize_memtag,
1030 .speculative_load_hardening,
1031 .speculatable,
1032 .ssp,
1033 .sspstrong,
1034 .sspreq,
1035 .strictfp,
1036 .uwtable,
1037 .nocf_check,
1038 .shadowcallstack,
1039 .mustprogress,
1040 .vscale_range,
1041 .no_sanitize_address,
1042 .no_sanitize_hwaddress,
1043 .sanitize_address_dyninit,
1044 => |kind| {
1045 const field = @typeInfo(Attribute).Union.fields[@intFromEnum(kind)];
1046 comptime assert(std.mem.eql(u8, @tagName(kind), field.name));
1047 return @unionInit(Attribute, field.name, switch (field.type) {
1048 void => {},
1049 u32 => storage.value,
1050 Alignment, String, Type, UwTable => @enumFromInt(storage.value),
1051 AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(storage.value),
1052 else => @compileError("bad payload type: " ++ @typeName(field.type)),
1053 });
1054 },
1055 .string, .none => unreachable,
1056 _ => unreachable,
1057 };
1058 }
1059
1060 const FormatData = struct {
1061 attribute_index: Index,
1062 builder: *const Builder,
1063 };
1064 fn format(
1065 data: FormatData,
1066 comptime fmt_str: []const u8,
1067 _: std.fmt.FormatOptions,
1068 writer: anytype,
1069 ) @TypeOf(writer).Error!void {
1070 if (comptime std.mem.indexOfNone(u8, fmt_str, "\"#")) |_|
1071 @compileError("invalid format string: '" ++ fmt_str ++ "'");
1072 const attribute = data.attribute_index.toAttribute(data.builder);
1073 switch (attribute) {
1074 .zeroext,
1075 .signext,
1076 .inreg,
1077 .@"noalias",
1078 .nocapture,
1079 .nofree,
1080 .nest,
1081 .returned,
1082 .nonnull,
1083 .swiftself,
1084 .swiftasync,
1085 .swifterror,
1086 .immarg,
1087 .noundef,
1088 .allocalign,
1089 .allocptr,
1090 .readnone,
1091 .readonly,
1092 .writeonly,
1093 .alwaysinline,
1094 .builtin,
1095 .cold,
1096 .convergent,
1097 .disable_sanitizer_information,
1098 .fn_ret_thunk_extern,
1099 .hot,
1100 .inlinehint,
1101 .jumptable,
1102 .minsize,
1103 .naked,
1104 .nobuiltin,
1105 .nocallback,
1106 .noduplicate,
1107 .noimplicitfloat,
1108 .@"noinline",
1109 .nomerge,
1110 .nonlazybind,
1111 .noprofile,
1112 .skipprofile,
1113 .noredzone,
1114 .noreturn,
1115 .norecurse,
1116 .willreturn,
1117 .nosync,
1118 .nounwind,
1119 .nosanitize_bounds,
1120 .nosanitize_coverage,
1121 .null_pointer_is_valid,
1122 .optforfuzzing,
1123 .optnone,
1124 .optsize,
1125 .returns_twice,
1126 .safestack,
1127 .sanitize_address,
1128 .sanitize_memory,
1129 .sanitize_thread,
1130 .sanitize_hwaddress,
1131 .sanitize_memtag,
1132 .speculative_load_hardening,
1133 .speculatable,
1134 .ssp,
1135 .sspstrong,
1136 .sspreq,
1137 .strictfp,
1138 .nocf_check,
1139 .shadowcallstack,
1140 .mustprogress,
1141 .no_sanitize_address,
1142 .no_sanitize_hwaddress,
1143 .sanitize_address_dyninit,
1144 => try writer.print(" {s}", .{@tagName(attribute)}),
1145 .byval,
1146 .byref,
1147 .preallocated,
1148 .inalloca,
1149 .sret,
1150 .elementtype,
1151 => |ty| try writer.print(" {s}({%})", .{ @tagName(attribute), ty.fmt(data.builder) }),
1152 .@"align" => |alignment| try writer.print("{}", .{alignment}),
1153 .dereferenceable,
1154 .dereferenceable_or_null,
1155 => |size| try writer.print(" {s}({d})", .{ @tagName(attribute), size }),
1156 .nofpclass => |fpclass| {
1157 const Int = @typeInfo(FpClass).Struct.backing_integer.?;
1158 try writer.print("{s}(", .{@tagName(attribute)});
1159 var any = false;
1160 var remaining: Int = @bitCast(fpclass);
1161 inline for (@typeInfo(FpClass).Struct.decls) |decl| {
1162 if (!decl.is_pub) continue;
1163 const pattern: Int = @bitCast(@field(FpClass, decl.name));
1164 if (remaining & pattern == pattern) {
1165 if (!any) {
1166 try writer.writeByte(' ');
1167 any = true;
1168 }
1169 try writer.writeAll(decl.name);
1170 remaining &= ~pattern;
1171 }
1172 }
1173 try writer.writeByte(')');
1174 },
1175 .alignstack => |alignment| try writer.print(
1176 if (comptime std.mem.indexOfScalar(u8, fmt_str, '#') != null)
1177 "{s}={d}"
1178 else
1179 "{s}({d})",
1180 .{ @tagName(attribute), alignment.toByteUnits() orelse return },
1181 ),
1182 .allockind => |allockind| {
1183 try writer.print("{s}(\"", .{@tagName(attribute)});
1184 var any = false;
1185 inline for (@typeInfo(AllocKind).Struct.fields) |field| {
1186 if (comptime std.mem.eql(u8, field.name, "_")) continue;
1187 if (@field(allockind, field.name)) {
1188 if (!any) {
1189 try writer.writeByte(',');
1190 any = true;
1191 }
1192 try writer.writeAll(field.name);
1193 }
1194 }
1195 try writer.writeAll("\")");
1196 },
1197 .allocsize => |allocsize| {
1198 try writer.print("{s}({d}", .{ @tagName(attribute), allocsize.elem_size });
1199 if (allocsize.num_elems != AllocSize.none)
1200 try writer.print(",{d}", .{allocsize.num_elems});
1201 try writer.writeByte(')');
1202 },
1203 .memory => |memory| try writer.print("{s}({s}, argmem: {s}, inaccessiblemem: {s})", .{
1204 @tagName(attribute),
1205 @tagName(memory.other),
1206 @tagName(memory.argmem),
1207 @tagName(memory.inaccessiblemem),
1208 }),
1209 .uwtable => |uwtable| if (uwtable != .none) {
1210 try writer.writeAll(@tagName(attribute));
1211 if (uwtable != UwTable.default) try writer.print("({s})", .{@tagName(uwtable)});
1212 },
1213 .vscale_range => |vscale_range| try writer.print("{s}({d},{d})", .{
1214 @tagName(attribute),
1215 vscale_range.min.toByteUnits().?,
1216 vscale_range.max.toByteUnits() orelse 0,
1217 }),
1218 .string => |string_attr| if (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) {
1219 try writer.print(" {\"}", .{string_attr.kind.fmt(data.builder)});
1220 if (string_attr.value != .empty)
1221 try writer.print("={\"}", .{string_attr.value.fmt(data.builder)});
1222 },
1223 .none => unreachable,
1224 }
1225 }
1226 pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(format) {
1227 return .{ .data = .{ .attribute_index = self, .builder = builder } };
1228 }
1229
1230 fn toStorage(self: Index, builder: *const Builder) Storage {
1231 return builder.attributes.keys()[@intFromEnum(self)];
1232 }
1233
1234 fn toLlvm(self: Index, builder: *const Builder) *llvm.Attribute {
1235 assert(builder.useLibLlvm());
1236 return builder.llvm.attributes.items[@intFromEnum(self)];
1237 }
1238 };
1239
1240 pub const Kind = enum(u32) {
1241 // Parameter Attributes
1242 zeroext,
1243 signext,
1244 inreg,
1245 byval,
1246 byref,
1247 preallocated,
1248 inalloca,
1249 sret,
1250 elementtype,
1251 @"align",
1252 @"noalias",
1253 nocapture,
1254 nofree,
1255 nest,
1256 returned,
1257 nonnull,
1258 dereferenceable,
1259 dereferenceable_or_null,
1260 swiftself,
1261 swiftasync,
1262 swifterror,
1263 immarg,
1264 noundef,
1265 nofpclass,
1266 alignstack,
1267 allocalign,
1268 allocptr,
1269 readnone,
1270 readonly,
1271 writeonly,
1272
1273 // Function Attributes
1274 //alignstack,
1275 allockind,
1276 allocsize,
1277 alwaysinline,
1278 builtin,
1279 cold,
1280 convergent,
1281 disable_sanitizer_information,
1282 fn_ret_thunk_extern,
1283 hot,
1284 inlinehint,
1285 jumptable,
1286 memory,
1287 minsize,
1288 naked,
1289 nobuiltin,
1290 nocallback,
1291 noduplicate,
1292 //nofree,
1293 noimplicitfloat,
1294 @"noinline",
1295 nomerge,
1296 nonlazybind,
1297 noprofile,
1298 skipprofile,
1299 noredzone,
1300 noreturn,
1301 norecurse,
1302 willreturn,
1303 nosync,
1304 nounwind,
1305 nosanitize_bounds,
1306 nosanitize_coverage,
1307 null_pointer_is_valid,
1308 optforfuzzing,
1309 optnone,
1310 optsize,
1311 //preallocated,
1312 returns_twice,
1313 safestack,
1314 sanitize_address,
1315 sanitize_memory,
1316 sanitize_thread,
1317 sanitize_hwaddress,
1318 sanitize_memtag,
1319 speculative_load_hardening,
1320 speculatable,
1321 ssp,
1322 sspstrong,
1323 sspreq,
1324 strictfp,
1325 uwtable,
1326 nocf_check,
1327 shadowcallstack,
1328 mustprogress,
1329 vscale_range,
1330
1331 // Global Attributes
1332 no_sanitize_address,
1333 no_sanitize_hwaddress,
1334 //sanitize_memtag,
1335 sanitize_address_dyninit,
1336
1337 string = std.math.maxInt(u31) - 1,
1338 none = std.math.maxInt(u31),
1339 _,
1340
1341 pub const len = @typeInfo(Kind).Enum.fields.len - 2;
1342
1343 pub fn fromString(str: String) Kind {
1344 assert(!str.isAnon());
1345 return @enumFromInt(@intFromEnum(str));
1346 }
1347
1348 fn toString(self: Kind) ?String {
1349 const str: String = @enumFromInt(@intFromEnum(self));
1350 return if (str.isAnon()) null else str;
1351 }
1352 };
1353
1354 pub const FpClass = packed struct(u32) {
1355 signaling_nan: bool = false,
1356 quiet_nan: bool = false,
1357 negative_infinity: bool = false,
1358 negative_normal: bool = false,
1359 negative_subnormal: bool = false,
1360 negative_zero: bool = false,
1361 positive_zero: bool = false,
1362 positive_subnormal: bool = false,
1363 positive_normal: bool = false,
1364 positive_infinity: bool = false,
1365 _: u22 = 0,
1366
1367 pub const all = FpClass{
1368 .signaling_nan = true,
1369 .quiet_nan = true,
1370 .negative_infinity = true,
1371 .negative_normal = true,
1372 .negative_subnormal = true,
1373 .negative_zero = true,
1374 .positive_zero = true,
1375 .positive_subnormal = true,
1376 .positive_normal = true,
1377 .positive_infinity = true,
1378 };
1379
1380 pub const nan = FpClass{ .signaling_nan = true, .quiet_nan = true };
1381 pub const snan = FpClass{ .signaling_nan = true };
1382 pub const qnan = FpClass{ .quiet_nan = true };
1383
1384 pub const inf = FpClass{ .negative_infinity = true, .positive_infinity = true };
1385 pub const ninf = FpClass{ .negative_infinity = true };
1386 pub const pinf = FpClass{ .positive_infinity = true };
1387
1388 pub const zero = FpClass{ .positive_zero = true, .negative_zero = true };
1389 pub const nzero = FpClass{ .negative_zero = true };
1390 pub const pzero = FpClass{ .positive_zero = true };
1391
1392 pub const sub = FpClass{ .positive_subnormal = true, .negative_subnormal = true };
1393 pub const nsub = FpClass{ .negative_subnormal = true };
1394 pub const psub = FpClass{ .positive_subnormal = true };
1395
1396 pub const norm = FpClass{ .positive_normal = true, .negative_normal = true };
1397 pub const nnorm = FpClass{ .negative_normal = true };
1398 pub const pnorm = FpClass{ .positive_normal = true };
1399 };
1400
1401 pub const AllocKind = packed struct(u32) {
1402 alloc: bool,
1403 realloc: bool,
1404 free: bool,
1405 uninitialized: bool,
1406 zeroed: bool,
1407 aligned: bool,
1408 _: u26 = 0,
1409 };
1410
1411 pub const AllocSize = packed struct(u32) {
1412 elem_size: u16,
1413 num_elems: u16,
1414
1415 pub const none = std.math.maxInt(u16);
1416
1417 fn toLlvm(self: AllocSize) packed struct(u64) { num_elems: u32, elem_size: u32 } {
1418 return .{ .num_elems = switch (self.num_elems) {
1419 else => self.num_elems,
1420 none => std.math.maxInt(u32),
1421 }, .elem_size = self.elem_size };
1422 }
1423 };
1424
1425 pub const Memory = packed struct(u32) {
1426 argmem: Effect,
1427 inaccessiblemem: Effect,
1428 other: Effect,
1429 _: u26 = 0,
1430
1431 pub const Effect = enum(u2) { none, read, write, readwrite };
1432 };
1433
1434 pub const UwTable = enum(u32) {
1435 none,
1436 sync,
1437 @"async",
1438
1439 pub const default = UwTable.@"async";
1440 };
1441
1442 pub const VScaleRange = packed struct(u32) {
1443 min: Alignment,
1444 max: Alignment,
1445 _: u20 = 0,
1446
1447 fn toLlvm(self: VScaleRange) packed struct(u64) { max: u32, min: u32 } {
1448 return .{
1449 .max = @intCast(self.max.toByteUnits() orelse 0),
1450 .min = @intCast(self.min.toByteUnits().?),
1451 };
1452 }
1453 };
1454
1455 pub fn getKind(self: Attribute) Kind {
1456 return switch (self) {
1457 else => self,
1458 .string => |string_attr| Kind.fromString(string_attr.kind),
1459 };
1460 }
1461
1462 const Storage = extern struct {
1463 kind: Kind,
1464 value: u32,
1465 };
1466
1467 fn toStorage(self: Attribute) Storage {
1468 return switch (self) {
1469 inline else => |value| .{ .kind = @as(Kind, self), .value = switch (@TypeOf(value)) {
1470 void => 0,
1471 u32 => value,
1472 Alignment, String, Type, UwTable => @intFromEnum(value),
1473 AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(value),
1474 else => @compileError("bad payload type: " ++ @typeName(@TypeOf(value))),
1475 } },
1476 .string => |string_attr| .{
1477 .kind = Kind.fromString(string_attr.kind),
1478 .value = @intFromEnum(string_attr.value),
1479 },
1480 .none => unreachable,
1481 };
1482 }
1483};
1484
1485pub const Attributes = enum(u32) {
1486 none,
1487 _,
1488
1489 pub fn slice(self: Attributes, builder: *const Builder) []const Attribute.Index {
1490 const start = builder.attributes_indices.items[@intFromEnum(self)];
1491 const end = builder.attributes_indices.items[@intFromEnum(self) + 1];
1492 return @ptrCast(builder.attributes_extra.items[start..end]);
1493 }
1494
1495 const FormatData = struct {
1496 attributes: Attributes,
1497 builder: *const Builder,
1498 };
1499 fn format(
1500 data: FormatData,
1501 comptime fmt_str: []const u8,
1502 fmt_opts: std.fmt.FormatOptions,
1503 writer: anytype,
1504 ) @TypeOf(writer).Error!void {
1505 for (data.attributes.slice(data.builder)) |attribute_index| try Attribute.Index.format(.{
1506 .attribute_index = attribute_index,
1507 .builder = data.builder,
1508 }, fmt_str, fmt_opts, writer);
1509 }
1510 pub fn fmt(self: Attributes, builder: *const Builder) std.fmt.Formatter(format) {
1511 return .{ .data = .{ .attributes = self, .builder = builder } };
1512 }
1513};
1514
1515pub const FunctionAttributes = enum(u32) {
1516 none,
1517 _,
1518
1519 const function_index = 0;
1520 const return_index = 1;
1521 const params_index = 2;
1522
1523 pub const Wip = struct {
1524 maps: Maps = .{},
1525
1526 const Map = std.AutoArrayHashMapUnmanaged(Attribute.Kind, Attribute.Index);
1527 const Maps = std.ArrayListUnmanaged(Map);
1528
1529 pub fn deinit(self: *Wip, builder: *const Builder) void {
1530 for (self.maps.items) |*map| map.deinit(builder.gpa);
1531 self.maps.deinit(builder.gpa);
1532 self.* = undefined;
1533 }
1534
1535 pub fn addFnAttr(self: *Wip, attribute: Attribute, builder: *Builder) Allocator.Error!void {
1536 try self.addAttr(function_index, attribute, builder);
1537 }
1538
1539 pub fn addFnAttrIndex(
1540 self: *Wip,
1541 attribute_index: Attribute.Index,
1542 builder: *const Builder,
1543 ) Allocator.Error!void {
1544 try self.addAttrIndex(function_index, attribute_index, builder);
1545 }
1546
1547 pub fn removeFnAttr(self: *Wip, attribute_kind: Attribute.Kind) Allocator.Error!bool {
1548 return self.removeAttr(function_index, attribute_kind);
1549 }
1550
1551 pub fn addRetAttr(self: *Wip, attribute: Attribute, builder: *Builder) Allocator.Error!void {
1552 try self.addAttr(return_index, attribute, builder);
1553 }
1554
1555 pub fn addRetAttrIndex(
1556 self: *Wip,
1557 attribute_index: Attribute.Index,
1558 builder: *const Builder,
1559 ) Allocator.Error!void {
1560 try self.addAttrIndex(return_index, attribute_index, builder);
1561 }
1562
1563 pub fn removeRetAttr(self: *Wip, attribute_kind: Attribute.Kind) Allocator.Error!bool {
1564 return self.removeAttr(return_index, attribute_kind);
1565 }
1566
1567 pub fn addParamAttr(
1568 self: *Wip,
1569 param_index: usize,
1570 attribute: Attribute,
1571 builder: *Builder,
1572 ) Allocator.Error!void {
1573 try self.addAttr(params_index + param_index, attribute, builder);
1574 }
1575
1576 pub fn addParamAttrIndex(
1577 self: *Wip,
1578 param_index: usize,
1579 attribute_index: Attribute.Index,
1580 builder: *const Builder,
1581 ) Allocator.Error!void {
1582 try self.addAttrIndex(params_index + param_index, attribute_index, builder);
1583 }
1584
1585 pub fn removeParamAttr(
1586 self: *Wip,
1587 param_index: usize,
1588 attribute_kind: Attribute.Kind,
1589 ) Allocator.Error!bool {
1590 return self.removeAttr(params_index + param_index, attribute_kind);
1591 }
1592
1593 pub fn finish(self: *const Wip, builder: *Builder) Allocator.Error!FunctionAttributes {
1594 const attributes = try builder.gpa.alloc(Attributes, self.maps.items.len);
1595 defer builder.gpa.free(attributes);
1596 for (attributes, self.maps.items) |*attribute, map|
1597 attribute.* = try builder.attrs(map.values());
1598 return builder.fnAttrs(attributes);
1599 }
1600
1601 fn addAttr(
1602 self: *Wip,
1603 index: usize,
1604 attribute: Attribute,
1605 builder: *Builder,
1606 ) Allocator.Error!void {
1607 const map = try self.getOrPutMap(builder.gpa, index);
1608 try map.put(builder.gpa, attribute.getKind(), try builder.attr(attribute));
1609 }
1610
1611 fn addAttrIndex(
1612 self: *Wip,
1613 index: usize,
1614 attribute_index: Attribute.Index,
1615 builder: *const Builder,
1616 ) Allocator.Error!void {
1617 const map = try self.getOrPutMap(builder.gpa, index);
1618 try map.put(builder.gpa, attribute_index.getKind(builder), attribute_index);
1619 }
1620
1621 fn removeAttr(self: *Wip, index: usize, attribute_kind: Attribute.Kind) Allocator.Error!bool {
1622 const map = self.getMap(index) orelse return false;
1623 return map.swapRemove(attribute_kind);
1624 }
1625
1626 fn getOrPutMap(self: *Wip, allocator: Allocator, index: usize) Allocator.Error!*Map {
1627 if (index >= self.maps.items.len)
1628 try self.maps.appendNTimes(allocator, .{}, index + 1 - self.maps.items.len);
1629 return &self.maps.items[index];
1630 }
1631
1632 fn getMap(self: *Wip, index: usize) ?*Map {
1633 return if (index >= self.maps.items.len) null else &self.maps.items[index];
1634 }
1635
1636 fn ensureTotalLength(self: *Wip, new_len: usize) Allocator.Error!void {
1637 try self.maps.appendNTimes(
1638 .{},
1639 std.math.sub(usize, new_len, self.maps.items.len) catch return,
1640 );
1641 }
1642 };
1643
1644 pub fn func(self: FunctionAttributes, builder: *const Builder) Attributes {
1645 return self.get(function_index, builder);
1646 }
1647
1648 pub fn ret(self: FunctionAttributes, builder: *const Builder) Attributes {
1649 return self.get(return_index, builder);
1650 }
1651
1652 pub fn param(self: FunctionAttributes, param_index: usize, builder: *const Builder) Attributes {
1653 return self.get(params_index + param_index, builder);
1654 }
1655
1656 pub fn toWip(self: FunctionAttributes, builder: *const Builder) Allocator.Error!Wip {
1657 var wip: Wip = .{};
1658 errdefer wip.deinit(builder);
1659 const attributes_slice = self.slice(builder);
1660 try wip.maps.ensureTotalCapacityPrecise(builder.gpa, attributes_slice.len);
1661 for (attributes_slice) |attributes| {
1662 const map = wip.maps.addOneAssumeCapacity();
1663 map.* = .{};
1664 const attribute_slice = attributes.slice(builder);
1665 try map.ensureTotalCapacity(builder.gpa, attribute_slice.len);
1666 for (attributes.slice(builder)) |attribute|
1667 map.putAssumeCapacityNoClobber(attribute.getKind(builder), attribute);
1668 }
1669 return wip;
1670 }
1671
1672 fn get(self: FunctionAttributes, index: usize, builder: *const Builder) Attributes {
1673 const attribute_slice = self.slice(builder);
1674 return if (index < attribute_slice.len) attribute_slice[index] else .none;
1675 }
1676
1677 fn slice(self: FunctionAttributes, builder: *const Builder) []const Attributes {
1678 const start = builder.attributes_indices.items[@intFromEnum(self)];
1679 const end = builder.attributes_indices.items[@intFromEnum(self) + 1];
1680 return @ptrCast(builder.attributes_extra.items[start..end]);
1681 }
1682};
1683
826pub const Linkage = enum {1684pub const Linkage = enum {
827 external,1685 external,
828 private,1686 private,
...@@ -1053,6 +1911,127 @@ pub const Alignment = enum(u6) {...@@ -1053,6 +1911,127 @@ pub const Alignment = enum(u6) {
1053 }1911 }
1054};1912};
10551913
1914pub const CallConv = enum(u10) {
1915 ccc,
1916
1917 fastcc = 8,
1918 coldcc,
1919 ghccc,
1920
1921 webkit_jscc = 12,
1922 anyregcc,
1923 preserve_mostcc,
1924 preserve_allcc,
1925 swiftcc,
1926 cxx_fast_tlscc,
1927 tailcc,
1928 cfguard_checkcc,
1929 swifttailcc,
1930
1931 x86_stdcallcc = 64,
1932 x86_fastcallcc,
1933 arm_apcscc,
1934 arm_aapcscc,
1935 arm_aapcs_vfpcc,
1936 msp430_intrcc,
1937 x86_thiscallcc,
1938 ptx_kernel,
1939 ptx_device,
1940
1941 spir_func = 75,
1942 spir_kernel,
1943 intel_ocl_bicc,
1944 x86_64_sysvcc,
1945 win64cc,
1946 x86_vectorcallcc,
1947 hhvmcc,
1948 hhvm_ccc,
1949 x86_intrcc,
1950 avr_intrcc,
1951 avr_signalcc,
1952
1953 amdgpu_vs = 87,
1954 amdgpu_gs,
1955 amdgpu_ps,
1956 amdgpu_cs,
1957 amdgpu_kernel,
1958 x86_regcallcc,
1959 amdgpu_hs,
1960
1961 amdgpu_ls = 95,
1962 amdgpu_es,
1963 aarch64_vector_pcs,
1964 aarch64_sve_vector_pcs,
1965
1966 amdgpu_gfx = 100,
1967
1968 aarch64_sme_preservemost_from_x0 = 102,
1969 aarch64_sme_preservemost_from_x2,
1970
1971 _,
1972
1973 pub const default = CallConv.ccc;
1974
1975 pub fn format(
1976 self: CallConv,
1977 comptime _: []const u8,
1978 _: std.fmt.FormatOptions,
1979 writer: anytype,
1980 ) @TypeOf(writer).Error!void {
1981 switch (self) {
1982 default => {},
1983 .fastcc,
1984 .coldcc,
1985 .ghccc,
1986 .webkit_jscc,
1987 .anyregcc,
1988 .preserve_mostcc,
1989 .preserve_allcc,
1990 .swiftcc,
1991 .cxx_fast_tlscc,
1992 .tailcc,
1993 .cfguard_checkcc,
1994 .swifttailcc,
1995 .x86_stdcallcc,
1996 .x86_fastcallcc,
1997 .arm_apcscc,
1998 .arm_aapcscc,
1999 .arm_aapcs_vfpcc,
2000 .msp430_intrcc,
2001 .x86_thiscallcc,
2002 .ptx_kernel,
2003 .ptx_device,
2004 .spir_func,
2005 .spir_kernel,
2006 .intel_ocl_bicc,
2007 .x86_64_sysvcc,
2008 .win64cc,
2009 .x86_vectorcallcc,
2010 .hhvmcc,
2011 .hhvm_ccc,
2012 .x86_intrcc,
2013 .avr_intrcc,
2014 .avr_signalcc,
2015 .amdgpu_vs,
2016 .amdgpu_gs,
2017 .amdgpu_ps,
2018 .amdgpu_cs,
2019 .amdgpu_kernel,
2020 .x86_regcallcc,
2021 .amdgpu_hs,
2022 .amdgpu_ls,
2023 .amdgpu_es,
2024 .aarch64_vector_pcs,
2025 .aarch64_sve_vector_pcs,
2026 .amdgpu_gfx,
2027 .aarch64_sme_preservemost_from_x0,
2028 .aarch64_sme_preservemost_from_x2,
2029 => try writer.print(" {s}", .{@tagName(self)}),
2030 _ => try writer.print(" cc{d}", .{@intFromEnum(self)}),
2031 }
2032 }
2033};
2034
1056pub const Global = struct {2035pub const Global = struct {
1057 linkage: Linkage = .external,2036 linkage: Linkage = .external,
1058 preemption: Preemption = .dso_preemptable,2037 preemption: Preemption = .dso_preemptable,
...@@ -1170,7 +2149,7 @@ pub const Global = struct {...@@ -1170,7 +2149,7 @@ pub const Global = struct {
1170 fn updateName(self: Index, builder: *const Builder) void {2149 fn updateName(self: Index, builder: *const Builder) void {
1171 if (!builder.useLibLlvm()) return;2150 if (!builder.useLibLlvm()) return;
1172 const index = @intFromEnum(self.unwrap(builder));2151 const index = @intFromEnum(self.unwrap(builder));
1173 const name_slice = self.name(builder).toSlice(builder) orelse "";2152 const name_slice = self.name(builder).slice(builder) orelse "";
1174 builder.llvm.globals.items[index].setValueName2(name_slice.ptr, name_slice.len);2153 builder.llvm.globals.items[index].setValueName2(name_slice.ptr, name_slice.len);
1175 }2154 }
11762155
...@@ -1301,6 +2280,8 @@ pub const Variable = struct {...@@ -1301,6 +2280,8 @@ pub const Variable = struct {
13012280
1302pub const Function = struct {2281pub const Function = struct {
1303 global: Global.Index,2282 global: Global.Index,
2283 call_conv: CallConv = CallConv.default,
2284 attributes: FunctionAttributes = .none,
1304 section: String = .none,2285 section: String = .none,
1305 alignment: Alignment = .default,2286 alignment: Alignment = .default,
1306 blocks: []const Block = &.{},2287 blocks: []const Block = &.{},
...@@ -1364,6 +2345,8 @@ pub const Function = struct {...@@ -1364,6 +2345,8 @@ pub const Function = struct {
1364 block,2345 block,
1365 br,2346 br,
1366 br_cond,2347 br_cond,
2348 call,
2349 @"call fast",
1367 extractelement,2350 extractelement,
1368 extractvalue,2351 extractvalue,
1369 fadd,2352 fadd,
...@@ -1454,6 +2437,10 @@ pub const Function = struct {...@@ -1454,6 +2437,10 @@ pub const Function = struct {
1454 @"mul nsw",2437 @"mul nsw",
1455 @"mul nuw",2438 @"mul nuw",
1456 @"mul nuw nsw",2439 @"mul nuw nsw",
2440 @"musttail call",
2441 @"musttail call fast",
2442 @"notail call",
2443 @"notail call fast",
1457 @"or",2444 @"or",
1458 phi,2445 phi,
1459 @"phi fast",2446 @"phi fast",
...@@ -1481,6 +2468,8 @@ pub const Function = struct {...@@ -1481,6 +2468,8 @@ pub const Function = struct {
1481 @"sub nuw",2468 @"sub nuw",
1482 @"sub nuw nsw",2469 @"sub nuw nsw",
1483 @"switch",2470 @"switch",
2471 @"tail call",
2472 @"tail call fast",
1484 trunc,2473 trunc,
1485 udiv,2474 udiv,
1486 @"udiv exact",2475 @"udiv exact",
...@@ -1511,6 +2500,7 @@ pub const Function = struct {...@@ -1511,6 +2500,7 @@ pub const Function = struct {
1511 .br_cond,2500 .br_cond,
1512 .ret,2501 .ret,
1513 .@"ret void",2502 .@"ret void",
2503 .@"switch",
1514 .@"unreachable",2504 .@"unreachable",
1515 => true,2505 => true,
1516 else => false,2506 else => false,
...@@ -1528,8 +2518,19 @@ pub const Function = struct {...@@ -1528,8 +2518,19 @@ pub const Function = struct {
1528 .@"store atomic",2518 .@"store atomic",
1529 .@"store atomic volatile",2519 .@"store atomic volatile",
1530 .@"store volatile",2520 .@"store volatile",
2521 .@"switch",
1531 .@"unreachable",2522 .@"unreachable",
1532 => false,2523 => false,
2524 .call,
2525 .@"call fast",
2526 .@"musttail call",
2527 .@"musttail call fast",
2528 .@"notail call",
2529 .@"notail call fast",
2530 .@"tail call",
2531 .@"tail call fast",
2532 .unimplemented,
2533 => self.typeOfWip(wip) != .void,
1533 else => true,2534 else => true,
1534 };2535 };
1535 }2536 }
...@@ -1625,6 +2626,15 @@ pub const Function = struct {...@@ -1625,6 +2626,15 @@ pub const Function = struct {
1625 .@"switch",2626 .@"switch",
1626 .@"unreachable",2627 .@"unreachable",
1627 => .none,2628 => .none,
2629 .call,
2630 .@"call fast",
2631 .@"musttail call",
2632 .@"musttail call fast",
2633 .@"notail call",
2634 .@"notail call fast",
2635 .@"tail call",
2636 .@"tail call fast",
2637 => wip.extraData(Call, instruction.data).ty.functionReturn(wip.builder),
1628 .extractelement => wip.extraData(ExtractElement, instruction.data)2638 .extractelement => wip.extraData(ExtractElement, instruction.data)
1629 .val.typeOfWip(wip).childType(wip.builder),2639 .val.typeOfWip(wip).childType(wip.builder),
1630 .extractvalue => {2640 .extractvalue => {
...@@ -1813,6 +2823,15 @@ pub const Function = struct {...@@ -1813,6 +2823,15 @@ pub const Function = struct {
1813 .@"switch",2823 .@"switch",
1814 .@"unreachable",2824 .@"unreachable",
1815 => .none,2825 => .none,
2826 .call,
2827 .@"call fast",
2828 .@"musttail call",
2829 .@"musttail call fast",
2830 .@"notail call",
2831 .@"notail call fast",
2832 .@"tail call",
2833 .@"tail call fast",
2834 => function.extraData(Call, instruction.data).ty.functionReturn(builder),
1816 .extractelement => function.extraData(ExtractElement, instruction.data)2835 .extractelement => function.extraData(ExtractElement, instruction.data)
1817 .val.typeOf(function_index, builder).childType(builder),2836 .val.typeOf(function_index, builder).childType(builder),
1818 .extractvalue => {2837 .extractvalue => {
...@@ -1955,7 +2974,7 @@ pub const Function = struct {...@@ -1955,7 +2974,7 @@ pub const Function = struct {
1955 return if (wip.builder.strip)2974 return if (wip.builder.strip)
1956 ""2975 ""
1957 else2976 else
1958 wip.names.items[@intFromEnum(self)].toSlice(wip.builder).?;2977 wip.names.items[@intFromEnum(self)].slice(wip.builder).?;
1959 }2978 }
1960 };2979 };
19612980
...@@ -2063,6 +3082,30 @@ pub const Function = struct {...@@ -2063,6 +3082,30 @@ pub const Function = struct {
2063 rhs: Value,3082 rhs: Value,
2064 };3083 };
20653084
3085 pub const Call = struct {
3086 info: Info,
3087 attributes: FunctionAttributes,
3088 ty: Type,
3089 callee: Value,
3090 args_len: u32,
3091 //args: [args_len]Value,
3092
3093 pub const Kind = enum {
3094 normal,
3095 fast,
3096 musttail,
3097 musttail_fast,
3098 notail,
3099 notail_fast,
3100 tail,
3101 tail_fast,
3102 };
3103 pub const Info = packed struct(u32) {
3104 call_conv: CallConv,
3105 _: u22 = undefined,
3106 };
3107 };
3108
2066 pub const VaArg = struct {3109 pub const VaArg = struct {
2067 list: Value,3110 list: Value,
2068 type: Type,3111 type: Type,
...@@ -2117,8 +3160,17 @@ pub const Function = struct {...@@ -2117,8 +3160,17 @@ pub const Function = struct {
2117 inline for (fields, self.extra[index..][0..fields.len]) |field, value|3160 inline for (fields, self.extra[index..][0..fields.len]) |field, value|
2118 @field(result, field.name) = switch (field.type) {3161 @field(result, field.name) = switch (field.type) {
2119 u32 => value,3162 u32 => value,
2120 Alignment, AtomicOrdering, Block.Index, Type, Value => @enumFromInt(value),3163 Alignment,
2121 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),3164 AtomicOrdering,
3165 Block.Index,
3166 FunctionAttributes,
3167 Type,
3168 Value,
3169 => @enumFromInt(value),
3170 MemoryAccessInfo,
3171 Instruction.Alloca.Info,
3172 Instruction.Call.Info,
3173 => @bitCast(value),
2122 else => @compileError("bad field type: " ++ @typeName(field.type)),3174 else => @compileError("bad field type: " ++ @typeName(field.type)),
2123 };3175 };
2124 return .{3176 return .{
...@@ -2243,7 +3295,7 @@ pub const WipFunction = struct {...@@ -2243,7 +3295,7 @@ pub const WipFunction = struct {
2243 if (self.builder.useLibLlvm()) self.llvm.blocks.appendAssumeCapacity(3295 if (self.builder.useLibLlvm()) self.llvm.blocks.appendAssumeCapacity(
2244 self.builder.llvm.context.appendBasicBlock(3296 self.builder.llvm.context.appendBasicBlock(
2245 self.function.toLlvm(self.builder),3297 self.function.toLlvm(self.builder),
2246 final_name.toSlice(self.builder).?,3298 final_name.slice(self.builder).?,
2247 ),3299 ),
2248 );3300 );
2249 return index;3301 return index;
...@@ -2755,7 +3807,7 @@ pub const WipFunction = struct {...@@ -2755,7 +3807,7 @@ pub const WipFunction = struct {
2755 @intFromEnum(addr_space),3807 @intFromEnum(addr_space),
2756 instruction.llvmName(self),3808 instruction.llvmName(self),
2757 );3809 );
2758 if (alignment.toByteUnits()) |a| llvm_instruction.setAlignment(@intCast(a));3810 if (alignment.toByteUnits()) |bytes| llvm_instruction.setAlignment(@intCast(bytes));
2759 self.llvm.instructions.appendAssumeCapacity(llvm_instruction);3811 self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
2760 }3812 }
2761 return instruction.toValue();3813 return instruction.toValue();
...@@ -2811,7 +3863,7 @@ pub const WipFunction = struct {...@@ -2811,7 +3863,7 @@ pub const WipFunction = struct {
2811 instruction.llvmName(self),3863 instruction.llvmName(self),
2812 );3864 );
2813 if (ordering != .none) llvm_instruction.setOrdering(@enumFromInt(@intFromEnum(ordering)));3865 if (ordering != .none) llvm_instruction.setOrdering(@enumFromInt(@intFromEnum(ordering)));
2814 if (alignment.toByteUnits()) |a| llvm_instruction.setAlignment(@intCast(a));3866 if (alignment.toByteUnits()) |bytes| llvm_instruction.setAlignment(@intCast(bytes));
2815 self.llvm.instructions.appendAssumeCapacity(llvm_instruction);3867 self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
2816 }3868 }
2817 return instruction.toValue();3869 return instruction.toValue();
...@@ -2865,7 +3917,7 @@ pub const WipFunction = struct {...@@ -2865,7 +3917,7 @@ pub const WipFunction = struct {
2865 .@"volatile" => llvm_instruction.setVolatile(.True),3917 .@"volatile" => llvm_instruction.setVolatile(.True),
2866 }3918 }
2867 if (ordering != .none) llvm_instruction.setOrdering(@enumFromInt(@intFromEnum(ordering)));3919 if (ordering != .none) llvm_instruction.setOrdering(@enumFromInt(@intFromEnum(ordering)));
2868 if (alignment.toByteUnits()) |a| llvm_instruction.setAlignment(@intCast(a));3920 if (alignment.toByteUnits()) |bytes| llvm_instruction.setAlignment(@intCast(bytes));
2869 self.llvm.instructions.appendAssumeCapacity(llvm_instruction);3921 self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
2870 }3922 }
2871 return instruction;3923 return instruction;
...@@ -3162,6 +4214,102 @@ pub const WipFunction = struct {...@@ -3162,6 +4214,102 @@ pub const WipFunction = struct {
3162 return self.selectTag(.@"select fast", cond, lhs, rhs, name);4214 return self.selectTag(.@"select fast", cond, lhs, rhs, name);
3163 }4215 }
31644216
4217 pub fn call(
4218 self: *WipFunction,
4219 kind: Instruction.Call.Kind,
4220 call_conv: CallConv,
4221 function_attributes: FunctionAttributes,
4222 ty: Type,
4223 callee: Value,
4224 args: []const Value,
4225 name: []const u8,
4226 ) Allocator.Error!Value {
4227 const ret_ty = ty.functionReturn(self.builder);
4228 assert(ty.isFunction(self.builder));
4229 assert(callee.typeOfWip(self).isPointer(self.builder));
4230 const params = ty.functionParameters(self.builder);
4231 for (params, args[0..params.len]) |param, arg_val| assert(param == arg_val.typeOfWip(self));
4232
4233 try self.ensureUnusedExtraCapacity(1, Instruction.Call, args.len);
4234 const instruction = try self.addInst(switch (ret_ty) {
4235 .void => null,
4236 else => name,
4237 }, .{
4238 .tag = .call,
4239 .data = self.addExtraAssumeCapacity(Instruction.Call{
4240 .info = .{ .call_conv = call_conv },
4241 .attributes = function_attributes,
4242 .ty = ty,
4243 .callee = callee,
4244 .args_len = @intCast(args.len),
4245 }),
4246 });
4247 self.extra.appendSliceAssumeCapacity(@ptrCast(args));
4248 if (self.builder.useLibLlvm()) {
4249 const ExpectedContents = [expected_args_len]*llvm.Value;
4250 var stack align(@alignOf(ExpectedContents)) =
4251 std.heap.stackFallback(@sizeOf(ExpectedContents), self.builder.gpa);
4252 const allocator = stack.get();
4253
4254 const llvm_args = try allocator.alloc(*llvm.Value, args.len);
4255 defer allocator.free(llvm_args);
4256 for (llvm_args, args) |*llvm_arg, arg_val| llvm_arg.* = arg_val.toLlvm(self);
4257
4258 switch (kind) {
4259 .normal,
4260 .musttail,
4261 .notail,
4262 .tail,
4263 => self.llvm.builder.setFastMath(false),
4264 .fast,
4265 .musttail_fast,
4266 .notail_fast,
4267 .tail_fast,
4268 => self.llvm.builder.setFastMath(true),
4269 }
4270 const llvm_instruction = self.llvm.builder.buildCall(
4271 ty.toLlvm(self.builder),
4272 callee.toLlvm(self),
4273 llvm_args.ptr,
4274 @intCast(llvm_args.len),
4275 switch (ret_ty) {
4276 .void => "",
4277 else => instruction.llvmName(self),
4278 },
4279 );
4280 llvm_instruction.setInstructionCallConv(@enumFromInt(@intFromEnum(call_conv)));
4281 llvm_instruction.setTailCallKind(switch (kind) {
4282 .normal, .fast => .None,
4283 .musttail, .musttail_fast => .MustTail,
4284 .notail, .notail_fast => .NoTail,
4285 .tail, .tail_fast => .Tail,
4286 });
4287 for (0.., function_attributes.slice(self.builder)) |index, attributes| {
4288 const attribute_index = @as(llvm.AttributeIndex, @intCast(index)) -% 1;
4289 for (attributes.slice(self.builder)) |attribute| llvm_instruction.addCallSiteAttribute(
4290 attribute_index,
4291 attribute.toLlvm(self.builder),
4292 );
4293 }
4294 self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
4295 }
4296 return instruction.toValue();
4297 }
4298
4299 pub fn callAsm(
4300 self: *WipFunction,
4301 function_attributes: FunctionAttributes,
4302 ty: Type,
4303 kind: Constant.Asm.Info,
4304 assembly: String,
4305 constraints: String,
4306 args: []const Value,
4307 name: []const u8,
4308 ) Allocator.Error!Value {
4309 const callee = try self.builder.asmValue(ty, kind, assembly, constraints);
4310 return self.call(.normal, CallConv.default, function_attributes, ty, callee, args, name);
4311 }
4312
3165 pub fn vaArg(self: *WipFunction, list: Value, ty: Type, name: []const u8) Allocator.Error!Value {4313 pub fn vaArg(self: *WipFunction, list: Value, ty: Type, name: []const u8) Allocator.Error!Value {
3166 try self.ensureUnusedExtraCapacity(1, Instruction.VaArg, 0);4314 try self.ensureUnusedExtraCapacity(1, Instruction.VaArg, 0);
3167 const instruction = try self.addInst(name, .{4315 const instruction = try self.addInst(name, .{
...@@ -3246,8 +4394,17 @@ pub const WipFunction = struct {...@@ -3246,8 +4394,17 @@ pub const WipFunction = struct {
3246 const value = @field(extra, field.name);4394 const value = @field(extra, field.name);
3247 wip_extra.items[wip_extra.index] = switch (field.type) {4395 wip_extra.items[wip_extra.index] = switch (field.type) {
3248 u32 => value,4396 u32 => value,
3249 Alignment, AtomicOrdering, Block.Index, Type, Value => @intFromEnum(value),4397 Alignment,
3250 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),4398 AtomicOrdering,
4399 Block.Index,
4400 FunctionAttributes,
4401 Type,
4402 Value,
4403 => @intFromEnum(value),
4404 MemoryAccessInfo,
4405 Instruction.Alloca.Info,
4406 Instruction.Call.Info,
4407 => @bitCast(value),
3251 else => @compileError("bad field type: " ++ @typeName(field.type)),4408 else => @compileError("bad field type: " ++ @typeName(field.type)),
3252 };4409 };
3253 wip_extra.index += 1;4410 wip_extra.index += 1;
...@@ -3256,13 +4413,14 @@ pub const WipFunction = struct {...@@ -3256,13 +4413,14 @@ pub const WipFunction = struct {
3256 }4413 }
32574414
3258 fn appendSlice(wip_extra: *@This(), slice: anytype) void {4415 fn appendSlice(wip_extra: *@This(), slice: anytype) void {
3259 if (@typeInfo(@TypeOf(slice)).Pointer.child == Value) @compileError("use appendValues");4416 if (@typeInfo(@TypeOf(slice)).Pointer.child == Value)
4417 @compileError("use appendMappedValues");
3260 const data: []const u32 = @ptrCast(slice);4418 const data: []const u32 = @ptrCast(slice);
3261 @memcpy(wip_extra.items[wip_extra.index..][0..data.len], data);4419 @memcpy(wip_extra.items[wip_extra.index..][0..data.len], data);
3262 wip_extra.index += @intCast(data.len);4420 wip_extra.index += @intCast(data.len);
3263 }4421 }
32644422
3265 fn appendValues(wip_extra: *@This(), vals: []const Value, ctx: anytype) void {4423 fn appendMappedValues(wip_extra: *@This(), vals: []const Value, ctx: anytype) void {
3266 for (wip_extra.items[wip_extra.index..][0..vals.len], vals) |*extra, val|4424 for (wip_extra.items[wip_extra.index..][0..vals.len], vals) |*extra, val|
3267 extra.* = @intFromEnum(ctx.map(val));4425 extra.* = @intFromEnum(ctx.map(val));
3268 wip_extra.index += @intCast(vals.len);4426 wip_extra.index += @intCast(vals.len);
...@@ -3494,6 +4652,26 @@ pub const WipFunction = struct {...@@ -3494,6 +4652,26 @@ pub const WipFunction = struct {
3494 .@"else" = extra.@"else",4652 .@"else" = extra.@"else",
3495 });4653 });
3496 },4654 },
4655 .call,
4656 .@"call fast",
4657 .@"musttail call",
4658 .@"musttail call fast",
4659 .@"notail call",
4660 .@"notail call fast",
4661 .@"tail call",
4662 .@"tail call fast",
4663 => {
4664 var extra = self.extraDataTrail(Instruction.Call, instruction.data);
4665 const args = extra.trail.next(extra.data.args_len, Value, self);
4666 instruction.data = wip_extra.addExtra(Instruction.Call{
4667 .info = extra.data.info,
4668 .attributes = extra.data.attributes,
4669 .ty = extra.data.ty,
4670 .callee = instructions.map(extra.data.callee),
4671 .args_len = extra.data.args_len,
4672 });
4673 wip_extra.appendMappedValues(args, instructions);
4674 },
3497 .extractvalue => {4675 .extractvalue => {
3498 var extra = self.extraDataTrail(Instruction.ExtractValue, instruction.data);4676 var extra = self.extraDataTrail(Instruction.ExtractValue, instruction.data);
3499 const indices = extra.trail.next(extra.data.indices_len, u32, self);4677 const indices = extra.trail.next(extra.data.indices_len, u32, self);
...@@ -3517,7 +4695,7 @@ pub const WipFunction = struct {...@@ -3517,7 +4695,7 @@ pub const WipFunction = struct {
3517 .base = instructions.map(extra.data.base),4695 .base = instructions.map(extra.data.base),
3518 .indices_len = extra.data.indices_len,4696 .indices_len = extra.data.indices_len,
3519 });4697 });
3520 wip_extra.appendValues(indices, instructions);4698 wip_extra.appendMappedValues(indices, instructions);
3521 },4699 },
3522 .insertelement => {4700 .insertelement => {
3523 const extra = self.extraData(Instruction.InsertElement, instruction.data);4701 const extra = self.extraData(Instruction.InsertElement, instruction.data);
...@@ -3559,7 +4737,7 @@ pub const WipFunction = struct {...@@ -3559,7 +4737,7 @@ pub const WipFunction = struct {
3559 instruction.data = wip_extra.addExtra(Instruction.Phi{4737 instruction.data = wip_extra.addExtra(Instruction.Phi{
3560 .type = extra.data.type,4738 .type = extra.data.type,
3561 });4739 });
3562 wip_extra.appendValues(incoming_vals, instructions);4740 wip_extra.appendMappedValues(incoming_vals, instructions);
3563 wip_extra.appendSlice(incoming_blocks);4741 wip_extra.appendSlice(incoming_blocks);
3564 },4742 },
3565 .select,4743 .select,
...@@ -3932,8 +5110,17 @@ pub const WipFunction = struct {...@@ -3932,8 +5110,17 @@ pub const WipFunction = struct {
3932 const value = @field(extra, field.name);5110 const value = @field(extra, field.name);
3933 self.extra.appendAssumeCapacity(switch (field.type) {5111 self.extra.appendAssumeCapacity(switch (field.type) {
3934 u32 => value,5112 u32 => value,
3935 Alignment, AtomicOrdering, Block.Index, Type, Value => @intFromEnum(value),5113 Alignment,
3936 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),5114 AtomicOrdering,
5115 Block.Index,
5116 FunctionAttributes,
5117 Type,
5118 Value,
5119 => @intFromEnum(value),
5120 MemoryAccessInfo,
5121 Instruction.Alloca.Info,
5122 Instruction.Call.Info,
5123 => @bitCast(value),
3937 else => @compileError("bad field type: " ++ @typeName(field.type)),5124 else => @compileError("bad field type: " ++ @typeName(field.type)),
3938 });5125 });
3939 }5126 }
...@@ -3971,8 +5158,17 @@ pub const WipFunction = struct {...@@ -3971,8 +5158,17 @@ pub const WipFunction = struct {
3971 inline for (fields, self.extra.items[index..][0..fields.len]) |field, value|5158 inline for (fields, self.extra.items[index..][0..fields.len]) |field, value|
3972 @field(result, field.name) = switch (field.type) {5159 @field(result, field.name) = switch (field.type) {
3973 u32 => value,5160 u32 => value,
3974 Alignment, AtomicOrdering, Block.Index, Type, Value => @enumFromInt(value),5161 Alignment,
3975 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),5162 AtomicOrdering,
5163 Block.Index,
5164 FunctionAttributes,
5165 Type,
5166 Value,
5167 => @enumFromInt(value),
5168 MemoryAccessInfo,
5169 Instruction.Alloca.Info,
5170 Instruction.Call.Info,
5171 => @bitCast(value),
3976 else => @compileError("bad field type: " ++ @typeName(field.type)),5172 else => @compileError("bad field type: " ++ @typeName(field.type)),
3977 };5173 };
3978 return .{5174 return .{
...@@ -4092,7 +5288,7 @@ pub const Constant = enum(u32) {...@@ -4092,7 +5288,7 @@ pub const Constant = enum(u32) {
40925288
4093 const first_global: Constant = @enumFromInt(1 << 30);5289 const first_global: Constant = @enumFromInt(1 << 30);
40945290
4095 pub const Tag = enum(u6) {5291 pub const Tag = enum(u7) {
4096 positive_integer,5292 positive_integer,
4097 negative_integer,5293 negative_integer,
4098 half,5294 half,
...@@ -4152,6 +5348,22 @@ pub const Constant = enum(u32) {...@@ -4152,6 +5348,22 @@ pub const Constant = enum(u32) {
4152 @"and",5348 @"and",
4153 @"or",5349 @"or",
4154 xor,5350 xor,
5351 @"asm",
5352 @"asm sideeffect",
5353 @"asm alignstack",
5354 @"asm sideeffect alignstack",
5355 @"asm inteldialect",
5356 @"asm sideeffect inteldialect",
5357 @"asm alignstack inteldialect",
5358 @"asm sideeffect alignstack inteldialect",
5359 @"asm unwind",
5360 @"asm sideeffect unwind",
5361 @"asm alignstack unwind",
5362 @"asm sideeffect alignstack unwind",
5363 @"asm inteldialect unwind",
5364 @"asm sideeffect inteldialect unwind",
5365 @"asm alignstack inteldialect unwind",
5366 @"asm sideeffect alignstack inteldialect unwind",
4155 };5367 };
41565368
4157 pub const Item = struct {5369 pub const Item = struct {
...@@ -4247,6 +5459,19 @@ pub const Constant = enum(u32) {...@@ -4247,6 +5459,19 @@ pub const Constant = enum(u32) {
4247 rhs: Constant,5459 rhs: Constant,
4248 };5460 };
42495461
5462 pub const Asm = extern struct {
5463 type: Type,
5464 assembly: String,
5465 constraints: String,
5466
5467 pub const Info = packed struct {
5468 sideeffect: bool = false,
5469 alignstack: bool = false,
5470 inteldialect: bool = false,
5471 unwind: bool = false,
5472 };
5473 };
5474
4250 pub fn unwrap(self: Constant) union(enum) {5475 pub fn unwrap(self: Constant) union(enum) {
4251 constant: u30,5476 constant: u30,
4252 global: Global.Index,5477 global: Global.Index,
...@@ -4294,7 +5519,7 @@ pub const Constant = enum(u32) {...@@ -4294,7 +5519,7 @@ pub const Constant = enum(u32) {
4294 .string,5519 .string,
4295 .string_null,5520 .string_null,
4296 => builder.arrayTypeAssumeCapacity(5521 => builder.arrayTypeAssumeCapacity(
4297 @as(String, @enumFromInt(item.data)).toSlice(builder).?.len +5522 @as(String, @enumFromInt(item.data)).slice(builder).?.len +
4298 @intFromBool(item.tag == .string_null),5523 @intFromBool(item.tag == .string_null),
4299 .i8,5524 .i8,
4300 ),5525 ),
...@@ -4365,6 +5590,23 @@ pub const Constant = enum(u32) {...@@ -4365,6 +5590,23 @@ pub const Constant = enum(u32) {
4365 .@"or",5590 .@"or",
4366 .xor,5591 .xor,
4367 => builder.constantExtraData(Binary, item.data).lhs.typeOf(builder),5592 => builder.constantExtraData(Binary, item.data).lhs.typeOf(builder),
5593 .@"asm",
5594 .@"asm sideeffect",
5595 .@"asm alignstack",
5596 .@"asm sideeffect alignstack",
5597 .@"asm inteldialect",
5598 .@"asm sideeffect inteldialect",
5599 .@"asm alignstack inteldialect",
5600 .@"asm sideeffect alignstack inteldialect",
5601 .@"asm unwind",
5602 .@"asm sideeffect unwind",
5603 .@"asm alignstack unwind",
5604 .@"asm sideeffect alignstack unwind",
5605 .@"asm inteldialect unwind",
5606 .@"asm sideeffect inteldialect unwind",
5607 .@"asm alignstack inteldialect unwind",
5608 .@"asm sideeffect alignstack inteldialect unwind",
5609 => .ptr,
4368 };5610 };
4369 },5611 },
4370 .global => |global| return builder.ptrTypeAssumeCapacity(5612 .global => |global| return builder.ptrTypeAssumeCapacity(
...@@ -4712,6 +5954,30 @@ pub const Constant = enum(u32) {...@@ -4712,6 +5954,30 @@ pub const Constant = enum(u32) {
4712 extra.rhs.fmt(data.builder),5954 extra.rhs.fmt(data.builder),
4713 });5955 });
4714 },5956 },
5957 .@"asm",
5958 .@"asm sideeffect",
5959 .@"asm alignstack",
5960 .@"asm sideeffect alignstack",
5961 .@"asm inteldialect",
5962 .@"asm sideeffect inteldialect",
5963 .@"asm alignstack inteldialect",
5964 .@"asm sideeffect alignstack inteldialect",
5965 .@"asm unwind",
5966 .@"asm sideeffect unwind",
5967 .@"asm alignstack unwind",
5968 .@"asm sideeffect alignstack unwind",
5969 .@"asm inteldialect unwind",
5970 .@"asm sideeffect inteldialect unwind",
5971 .@"asm alignstack inteldialect unwind",
5972 .@"asm sideeffect alignstack inteldialect unwind",
5973 => |tag| {
5974 const extra = data.builder.constantExtraData(Asm, item.data);
5975 try writer.print("{s} {\"}, {\"}", .{
5976 @tagName(tag),
5977 extra.assembly.fmt(data.builder),
5978 extra.constraints.fmt(data.builder),
5979 });
5980 },
4715 }5981 }
4716 },5982 },
4717 .global => |global| try writer.print("{}", .{global.fmt(data.builder)}),5983 .global => |global| try writer.print("{}", .{global.fmt(data.builder)}),
...@@ -4819,10 +6085,11 @@ pub fn init(options: Options) InitError!Builder {...@@ -4819,10 +6085,11 @@ pub fn init(options: Options) InitError!Builder {
4819 .source_filename = .none,6085 .source_filename = .none,
4820 .data_layout = .none,6086 .data_layout = .none,
4821 .target_triple = .none,6087 .target_triple = .none,
6088 .module_asm = .{},
48226089
4823 .string_map = .{},6090 .string_map = .{},
4824 .string_bytes = .{},
4825 .string_indices = .{},6091 .string_indices = .{},
6092 .string_bytes = .{},
48266093
4827 .types = .{},6094 .types = .{},
4828 .next_unnamed_type = @enumFromInt(0),6095 .next_unnamed_type = @enumFromInt(0),
...@@ -4831,6 +6098,11 @@ pub fn init(options: Options) InitError!Builder {...@@ -4831,6 +6098,11 @@ pub fn init(options: Options) InitError!Builder {
4831 .type_items = .{},6098 .type_items = .{},
4832 .type_extra = .{},6099 .type_extra = .{},
48336100
6101 .attributes = .{},
6102 .attributes_map = .{},
6103 .attributes_indices = .{},
6104 .attributes_extra = .{},
6105
4834 .globals = .{},6106 .globals = .{},
4835 .next_unnamed_global = @enumFromInt(0),6107 .next_unnamed_global = @enumFromInt(0),
4836 .next_replaced_global = .none,6108 .next_replaced_global = .none,
...@@ -4844,7 +6116,18 @@ pub fn init(options: Options) InitError!Builder {...@@ -4844,7 +6116,18 @@ pub fn init(options: Options) InitError!Builder {
4844 .constant_extra = .{},6116 .constant_extra = .{},
4845 .constant_limbs = .{},6117 .constant_limbs = .{},
4846 };6118 };
4847 if (self.useLibLlvm()) self.llvm = .{ .context = llvm.Context.create() };6119 if (self.useLibLlvm()) self.llvm = .{
6120 .context = llvm.Context.create(),
6121 .module = null,
6122 .target = null,
6123 .di_builder = null,
6124 .di_compile_unit = null,
6125 .attribute_kind_ids = null,
6126 .attributes = .{},
6127 .types = .{},
6128 .globals = .{},
6129 .constants = .{},
6130 };
4848 errdefer self.deinit();6131 errdefer self.deinit();
48496132
4850 try self.string_indices.append(self.gpa, 0);6133 try self.string_indices.append(self.gpa, 0);
...@@ -4853,7 +6136,7 @@ pub fn init(options: Options) InitError!Builder {...@@ -4853,7 +6136,7 @@ pub fn init(options: Options) InitError!Builder {
4853 if (options.name.len > 0) self.source_filename = try self.string(options.name);6136 if (options.name.len > 0) self.source_filename = try self.string(options.name);
4854 self.initializeLLVMTarget(options.target.cpu.arch);6137 self.initializeLLVMTarget(options.target.cpu.arch);
4855 if (self.useLibLlvm()) self.llvm.module = llvm.Module.createWithName(6138 if (self.useLibLlvm()) self.llvm.module = llvm.Module.createWithName(
4856 (self.source_filename.toSlice(&self) orelse "").ptr,6139 (self.source_filename.slice(&self) orelse "").ptr,
4857 self.llvm.context,6140 self.llvm.context,
4858 );6141 );
48596142
...@@ -4864,20 +6147,20 @@ pub fn init(options: Options) InitError!Builder {...@@ -4864,20 +6147,20 @@ pub fn init(options: Options) InitError!Builder {
4864 var error_message: [*:0]const u8 = undefined;6147 var error_message: [*:0]const u8 = undefined;
4865 var target: *llvm.Target = undefined;6148 var target: *llvm.Target = undefined;
4866 if (llvm.Target.getFromTriple(6149 if (llvm.Target.getFromTriple(
4867 self.target_triple.toSlice(&self).?,6150 self.target_triple.slice(&self).?,
4868 &target,6151 &target,
4869 &error_message,6152 &error_message,
4870 ).toBool()) {6153 ).toBool()) {
4871 defer llvm.disposeMessage(error_message);6154 defer llvm.disposeMessage(error_message);
48726155
4873 log.err("LLVM failed to parse '{s}': {s}", .{6156 log.err("LLVM failed to parse '{s}': {s}", .{
4874 self.target_triple.toSlice(&self).?,6157 self.target_triple.slice(&self).?,
4875 error_message,6158 error_message,
4876 });6159 });
4877 return InitError.InvalidLlvmTriple;6160 return InitError.InvalidLlvmTriple;
4878 }6161 }
4879 self.llvm.target = target;6162 self.llvm.target = target;
4880 self.llvm.module.?.setTarget(self.target_triple.toSlice(&self).?);6163 self.llvm.module.?.setTarget(self.target_triple.slice(&self).?);
4881 }6164 }
4882 }6165 }
48836166
...@@ -4902,6 +6185,16 @@ pub fn init(options: Options) InitError!Builder {...@@ -4902,6 +6185,16 @@ pub fn init(options: Options) InitError!Builder {
4902 assert(self.ptrTypeAssumeCapacity(@enumFromInt(addr_space)) == .ptr);6185 assert(self.ptrTypeAssumeCapacity(@enumFromInt(addr_space)) == .ptr);
4903 }6186 }
49046187
6188 {
6189 if (self.useLibLlvm()) {
6190 self.llvm.attribute_kind_ids = try self.gpa.create([Attribute.Kind.len]c_uint);
6191 @memset(self.llvm.attribute_kind_ids.?, 0);
6192 }
6193 try self.attributes_indices.append(self.gpa, 0);
6194 assert(try self.attrs(&.{}) == .none);
6195 assert(try self.fnAttrs(&.{}) == .none);
6196 }
6197
4905 assert(try self.intConst(.i1, 0) == .false);6198 assert(try self.intConst(.i1, 0) == .false);
4906 assert(try self.intConst(.i1, 1) == .true);6199 assert(try self.intConst(.i1, 1) == .true);
4907 assert(try self.noneConst(.token) == .none);6200 assert(try self.noneConst(.token) == .none);
...@@ -4910,9 +6203,11 @@ pub fn init(options: Options) InitError!Builder {...@@ -4910,9 +6203,11 @@ pub fn init(options: Options) InitError!Builder {
4910}6203}
49116204
4912pub fn deinit(self: *Builder) void {6205pub fn deinit(self: *Builder) void {
6206 self.module_asm.deinit(self.gpa);
6207
4913 self.string_map.deinit(self.gpa);6208 self.string_map.deinit(self.gpa);
4914 self.string_bytes.deinit(self.gpa);
4915 self.string_indices.deinit(self.gpa);6209 self.string_indices.deinit(self.gpa);
6210 self.string_bytes.deinit(self.gpa);
49166211
4917 self.types.deinit(self.gpa);6212 self.types.deinit(self.gpa);
4918 self.next_unique_type_id.deinit(self.gpa);6213 self.next_unique_type_id.deinit(self.gpa);
...@@ -4920,6 +6215,11 @@ pub fn deinit(self: *Builder) void {...@@ -4920,6 +6215,11 @@ pub fn deinit(self: *Builder) void {
4920 self.type_items.deinit(self.gpa);6215 self.type_items.deinit(self.gpa);
4921 self.type_extra.deinit(self.gpa);6216 self.type_extra.deinit(self.gpa);
49226217
6218 self.attributes.deinit(self.gpa);
6219 self.attributes_map.deinit(self.gpa);
6220 self.attributes_indices.deinit(self.gpa);
6221 self.attributes_extra.deinit(self.gpa);
6222
4923 self.globals.deinit(self.gpa);6223 self.globals.deinit(self.gpa);
4924 self.next_unique_global_id.deinit(self.gpa);6224 self.next_unique_global_id.deinit(self.gpa);
4925 self.aliases.deinit(self.gpa);6225 self.aliases.deinit(self.gpa);
...@@ -4936,6 +6236,8 @@ pub fn deinit(self: *Builder) void {...@@ -4936,6 +6236,8 @@ pub fn deinit(self: *Builder) void {
4936 self.llvm.constants.deinit(self.gpa);6236 self.llvm.constants.deinit(self.gpa);
4937 self.llvm.globals.deinit(self.gpa);6237 self.llvm.globals.deinit(self.gpa);
4938 self.llvm.types.deinit(self.gpa);6238 self.llvm.types.deinit(self.gpa);
6239 self.llvm.attributes.deinit(self.gpa);
6240 if (self.llvm.attribute_kind_ids) |attribute_kind_ids| self.gpa.destroy(attribute_kind_ids);
4939 if (self.llvm.di_builder) |di_builder| di_builder.dispose();6241 if (self.llvm.di_builder) |di_builder| di_builder.dispose();
4940 if (self.llvm.module) |module| module.dispose();6242 if (self.llvm.module) |module| module.dispose();
4941 self.llvm.context.dispose();6243 self.llvm.context.dispose();
...@@ -5136,6 +6438,22 @@ pub fn initializeLLVMTarget(self: *const Builder, arch: std.Target.Cpu.Arch) voi...@@ -5136,6 +6438,22 @@ pub fn initializeLLVMTarget(self: *const Builder, arch: std.Target.Cpu.Arch) voi
5136 }6438 }
5137}6439}
51386440
6441pub fn setModuleAsm(self: *Builder) std.ArrayListUnmanaged(u8).Writer {
6442 self.module_asm.clearRetainingCapacity();
6443 return self.appendModuleAsm();
6444}
6445
6446pub fn appendModuleAsm(self: *Builder) std.ArrayListUnmanaged(u8).Writer {
6447 return self.module_asm.writer(self.gpa);
6448}
6449
6450pub fn finishModuleAsm(self: *Builder) Allocator.Error!void {
6451 if (self.module_asm.getLastOrNull()) |last| if (last != '\n')
6452 try self.module_asm.append(self.gpa, '\n');
6453 if (self.useLibLlvm())
6454 self.llvm.module.?.setModuleInlineAsm(self.module_asm.items.ptr, self.module_asm.items.len);
6455}
6456
5139pub fn string(self: *Builder, bytes: []const u8) Allocator.Error!String {6457pub fn string(self: *Builder, bytes: []const u8) Allocator.Error!String {
5140 try self.string_bytes.ensureUnusedCapacity(self.gpa, bytes.len + 1);6458 try self.string_bytes.ensureUnusedCapacity(self.gpa, bytes.len + 1);
5141 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);6459 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
...@@ -5230,7 +6548,7 @@ pub fn structType(...@@ -5230,7 +6548,7 @@ pub fn structType(
52306548
5231pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type {6549pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type {
5232 try self.string_map.ensureUnusedCapacity(self.gpa, 1);6550 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
5233 if (name.toSlice(self)) |id| {6551 if (name.slice(self)) |id| {
5234 const count: usize = comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)});6552 const count: usize = comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)});
5235 try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);6553 try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);
5236 }6554 }
...@@ -5268,6 +6586,99 @@ pub fn namedTypeSetBody(...@@ -5268,6 +6586,99 @@ pub fn namedTypeSetBody(
5268 }6586 }
5269}6587}
52706588
6589pub fn attr(self: *Builder, attribute: Attribute) Allocator.Error!Attribute.Index {
6590 try self.attributes.ensureUnusedCapacity(self.gpa, 1);
6591 if (self.useLibLlvm()) try self.llvm.attributes.ensureUnusedCapacity(self.gpa, 1);
6592
6593 const gop = self.attributes.getOrPutAssumeCapacity(attribute.toStorage());
6594 if (!gop.found_existing) {
6595 gop.value_ptr.* = {};
6596 if (self.useLibLlvm()) self.llvm.attributes.appendAssumeCapacity(switch (attribute) {
6597 else => llvm_attr: {
6598 const kind_id = &self.llvm.attribute_kind_ids.?[@intFromEnum(attribute)];
6599 if (kind_id.* == 0) {
6600 const name = @tagName(attribute);
6601 kind_id.* = llvm.getEnumAttributeKindForName(name.ptr, name.len);
6602 assert(kind_id.* != 0);
6603 }
6604 break :llvm_attr switch (attribute) {
6605 else => switch (attribute) {
6606 inline else => |value| self.llvm.context.createEnumAttribute(
6607 kind_id.*,
6608 switch (@TypeOf(value)) {
6609 void => 0,
6610 u32 => value,
6611 Attribute.FpClass,
6612 Attribute.AllocKind,
6613 Attribute.Memory,
6614 => @as(u32, @bitCast(value)),
6615 Alignment => value.toByteUnits() orelse 0,
6616 Attribute.AllocSize,
6617 Attribute.VScaleRange,
6618 => @bitCast(value.toLlvm()),
6619 Attribute.UwTable => @intFromEnum(value),
6620 else => @compileError(
6621 "bad payload type: " ++ @typeName(@TypeOf(value)),
6622 ),
6623 },
6624 ),
6625 .byval,
6626 .byref,
6627 .preallocated,
6628 .inalloca,
6629 .sret,
6630 .elementtype,
6631 .string,
6632 .none,
6633 => unreachable,
6634 },
6635 .byval,
6636 .byref,
6637 .preallocated,
6638 .inalloca,
6639 .sret,
6640 .elementtype,
6641 => |ty| self.llvm.context.createTypeAttribute(kind_id.*, ty.toLlvm(self)),
6642 .string, .none => unreachable,
6643 };
6644 },
6645 .string => |string_attr| llvm_attr: {
6646 const kind = string_attr.kind.slice(self).?;
6647 const value = string_attr.value.slice(self).?;
6648 break :llvm_attr self.llvm.context.createStringAttribute(
6649 kind.ptr,
6650 @intCast(kind.len),
6651 value.ptr,
6652 @intCast(value.len),
6653 );
6654 },
6655 .none => unreachable,
6656 });
6657 }
6658 return @enumFromInt(gop.index);
6659}
6660
6661pub fn attrs(self: *Builder, attributes: []Attribute.Index) Allocator.Error!Attributes {
6662 std.sort.heap(Attribute.Index, attributes, self, struct {
6663 pub fn lessThan(builder: *const Builder, lhs: Attribute.Index, rhs: Attribute.Index) bool {
6664 const lhs_kind = lhs.getKind(builder);
6665 const rhs_kind = rhs.getKind(builder);
6666 assert(lhs_kind != rhs_kind);
6667 return @intFromEnum(lhs_kind) < @intFromEnum(rhs_kind);
6668 }
6669 }.lessThan);
6670 return @enumFromInt(try self.attrGeneric(@ptrCast(attributes)));
6671}
6672
6673pub fn fnAttrs(self: *Builder, fn_attributes: []const Attributes) Allocator.Error!FunctionAttributes {
6674 return @enumFromInt(try self.attrGeneric(@ptrCast(
6675 fn_attributes[0..if (std.mem.lastIndexOfNone(Attributes, fn_attributes, &.{.none})) |last|
6676 last + 1
6677 else
6678 0],
6679 )));
6680}
6681
5271pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index {6682pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index {
5272 assert(!name.isAnon());6683 assert(!name.isAnon());
5273 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);6684 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
...@@ -5295,7 +6706,7 @@ pub fn addGlobalAssumeCapacity(self: *Builder, name: String, global: Global) Glo...@@ -5295,7 +6706,7 @@ pub fn addGlobalAssumeCapacity(self: *Builder, name: String, global: Global) Glo
52956706
5296 const unique_gop = self.next_unique_global_id.getOrPutAssumeCapacity(name);6707 const unique_gop = self.next_unique_global_id.getOrPutAssumeCapacity(name);
5297 if (!unique_gop.found_existing) unique_gop.value_ptr.* = 2;6708 if (!unique_gop.found_existing) unique_gop.value_ptr.* = 2;
5298 id = self.fmtAssumeCapacity("{s}.{d}", .{ name.toSlice(self).?, unique_gop.value_ptr.* });6709 id = self.fmtAssumeCapacity("{s}.{d}", .{ name.slice(self).?, unique_gop.value_ptr.* });
5299 unique_gop.value_ptr.* += 1;6710 unique_gop.value_ptr.* += 1;
5300 }6711 }
5301}6712}
...@@ -5309,8 +6720,9 @@ pub fn intConst(self: *Builder, ty: Type, value: anytype) Allocator.Error!Consta...@@ -5309,8 +6720,9 @@ pub fn intConst(self: *Builder, ty: Type, value: anytype) Allocator.Error!Consta
5309 switch (@typeInfo(@TypeOf(value))) {6720 switch (@typeInfo(@TypeOf(value))) {
5310 .Int => |info| std.math.big.int.calcTwosCompLimbCount(info.bits),6721 .Int => |info| std.math.big.int.calcTwosCompLimbCount(info.bits),
5311 .ComptimeInt => std.math.big.int.calcLimbLen(value),6722 .ComptimeInt => std.math.big.int.calcLimbLen(value),
5312 else => @compileError("intConst expected an integral value, got " ++6723 else => @compileError(
5313 @typeName(@TypeOf(value))),6724 "intConst expected an integral value, got " ++ @typeName(@TypeOf(value)),
6725 ),
5314 }6726 }
5315 ]std.math.big.Limb = undefined;6727 ]std.math.big.Limb = undefined;
5316 return self.bigIntConst(ty, std.math.big.int.Mutable.init(&limbs, value).toConst());6728 return self.bigIntConst(ty, std.math.big.int.Mutable.init(&limbs, value).toConst());
...@@ -5721,6 +7133,27 @@ pub fn binValue(self: *Builder, tag: Constant.Tag, lhs: Constant, rhs: Constant)...@@ -5721,6 +7133,27 @@ pub fn binValue(self: *Builder, tag: Constant.Tag, lhs: Constant, rhs: Constant)
5721 return (try self.binConst(tag, lhs, rhs)).toValue();7133 return (try self.binConst(tag, lhs, rhs)).toValue();
5722}7134}
57237135
7136pub fn asmConst(
7137 self: *Builder,
7138 ty: Type,
7139 info: Constant.Asm.Info,
7140 assembly: String,
7141 constraints: String,
7142) Allocator.Error!Constant {
7143 try self.ensureUnusedConstantCapacity(1, Constant.Asm, 0);
7144 return self.asmConstAssumeCapacity(ty, info, assembly, constraints);
7145}
7146
7147pub fn asmValue(
7148 self: *Builder,
7149 ty: Type,
7150 info: Constant.Asm.Info,
7151 assembly: String,
7152 constraints: String,
7153) Allocator.Error!Value {
7154 return (try self.asmConst(ty, info, assembly, constraints)).toValue();
7155}
7156
5724pub fn dump(self: *Builder) void {7157pub fn dump(self: *Builder) void {
5725 if (self.useLibLlvm())7158 if (self.useLibLlvm())
5726 self.llvm.module.?.dump()7159 self.llvm.module.?.dump()
...@@ -5766,457 +7199,604 @@ pub fn printUnbuffered(...@@ -5766,457 +7199,604 @@ pub fn printUnbuffered(
5766 self: *Builder,7199 self: *Builder,
5767 writer: anytype,7200 writer: anytype,
5768) (@TypeOf(writer).Error || Allocator.Error)!void {7201) (@TypeOf(writer).Error || Allocator.Error)!void {
5769 if (self.source_filename != .none) try writer.print(7202 var need_newline = false;
5770 \\; ModuleID = '{s}'7203
5771 \\source_filename = {"}7204 if (self.source_filename != .none or self.data_layout != .none or self.target_triple != .none) {
5772 \\7205 if (need_newline) try writer.writeByte('\n');
5773 , .{ self.source_filename.toSlice(self).?, self.source_filename.fmt(self) });7206 if (self.source_filename != .none) try writer.print(
5774 if (self.data_layout != .none) try writer.print(7207 \\; ModuleID = '{s}'
5775 \\target datalayout = {"}7208 \\source_filename = {"}
5776 \\
5777 , .{self.data_layout.fmt(self)});
5778 if (self.target_triple != .none) try writer.print(
5779 \\target triple = {"}
5780 \\
5781 , .{self.target_triple.fmt(self)});
5782 try writer.writeByte('\n');
5783 for (self.types.keys(), self.types.values()) |id, ty| try writer.print(
5784 \\%{} = type {}
5785 \\
5786 , .{ id.fmt(self), ty.fmt(self) });
5787 try writer.writeByte('\n');
5788 for (self.variables.items) |variable| {
5789 if (variable.global.getReplacement(self) != .none) continue;
5790 const global = variable.global.ptrConst(self);
5791 try writer.print(
5792 \\{} ={}{}{}{}{}{}{}{} {s} {%}{ }{,}
5793 \\7209 \\
5794 , .{7210 , .{ self.source_filename.slice(self).?, self.source_filename.fmt(self) });
5795 variable.global.fmt(self),7211 if (self.data_layout != .none) try writer.print(
5796 global.linkage,7212 \\target datalayout = {"}
5797 global.preemption,7213 \\
5798 global.visibility,7214 , .{self.data_layout.fmt(self)});
5799 global.dll_storage_class,7215 if (self.target_triple != .none) try writer.print(
5800 variable.thread_local,7216 \\target triple = {"}
5801 global.unnamed_addr,7217 \\
5802 global.addr_space,7218 , .{self.target_triple.fmt(self)});
5803 global.externally_initialized,7219 need_newline = true;
5804 @tagName(variable.mutability),
5805 global.type.fmt(self),
5806 variable.init.fmt(self),
5807 variable.alignment,
5808 });
5809 }7220 }
5810 try writer.writeByte('\n');7221
5811 for (0.., self.functions.items) |function_i, function| {7222 if (self.module_asm.items.len > 0) {
5812 const function_index: Function.Index = @enumFromInt(function_i);7223 if (need_newline) try writer.writeByte('\n');
5813 if (function.global.getReplacement(self) != .none) continue;7224 var line_it = std.mem.tokenizeScalar(u8, self.module_asm.items, '\n');
5814 const global = function.global.ptrConst(self);7225 while (line_it.next()) |line| {
5815 const params_len = global.type.functionParameters(self).len;7226 try writer.writeAll("module asm ");
5816 try writer.print(7227 try printEscapedString(line, .always_quote, writer);
5817 \\{s}{}{}{}{} {} {}(7228 try writer.writeByte('\n');
5818 , .{
5819 if (function.instructions.len > 0) "define" else "declare",
5820 global.linkage,
5821 global.preemption,
5822 global.visibility,
5823 global.dll_storage_class,
5824 global.type.functionReturn(self).fmt(self),
5825 function.global.fmt(self),
5826 });
5827 for (0..params_len) |arg| {
5828 if (arg > 0) try writer.writeAll(", ");
5829 if (function.instructions.len > 0)
5830 try writer.print("{%}", .{function.arg(@intCast(arg)).fmt(function_index, self)})
5831 else
5832 try writer.print("{%}", .{global.type.functionParameters(self)[arg].fmt(self)});
5833 }7229 }
5834 switch (global.type.functionKind(self)) {7230 need_newline = true;
5835 .normal => {},7231 }
5836 .vararg => {7232
5837 if (params_len > 0) try writer.writeAll(", ");7233 if (self.types.count() > 0) {
5838 try writer.writeAll("...");7234 if (need_newline) try writer.writeByte('\n');
5839 },7235 for (self.types.keys(), self.types.values()) |id, ty| try writer.print(
7236 \\%{} = type {}
7237 \\
7238 , .{ id.fmt(self), ty.fmt(self) });
7239 need_newline = true;
7240 }
7241
7242 if (self.variables.items.len > 0) {
7243 if (need_newline) try writer.writeByte('\n');
7244 for (self.variables.items) |variable| {
7245 if (variable.global.getReplacement(self) != .none) continue;
7246 const global = variable.global.ptrConst(self);
7247 try writer.print(
7248 \\{} ={}{}{}{}{}{}{}{} {s} {%}{ }{,}
7249 \\
7250 , .{
7251 variable.global.fmt(self),
7252 global.linkage,
7253 global.preemption,
7254 global.visibility,
7255 global.dll_storage_class,
7256 variable.thread_local,
7257 global.unnamed_addr,
7258 global.addr_space,
7259 global.externally_initialized,
7260 @tagName(variable.mutability),
7261 global.type.fmt(self),
7262 variable.init.fmt(self),
7263 variable.alignment,
7264 });
5840 }7265 }
5841 try writer.print("){}{}", .{ global.unnamed_addr, function.alignment });7266 need_newline = true;
5842 if (function.instructions.len > 0) {7267 }
5843 var block_incoming_len: u32 = undefined;7268
5844 try writer.writeAll(" {\n");7269 var attribute_groups: std.AutoArrayHashMapUnmanaged(Attributes, void) = .{};
5845 for (params_len..function.instructions.len) |instruction_i| {7270 defer attribute_groups.deinit(self.gpa);
5846 const instruction_index: Function.Instruction.Index = @enumFromInt(instruction_i);7271
5847 const instruction = function.instructions.get(@intFromEnum(instruction_index));7272 if (self.functions.items.len > 0) {
5848 switch (instruction.tag) {7273 if (need_newline) try writer.writeByte('\n');
5849 .add,7274 for (0.., self.functions.items) |function_i, function| {
5850 .@"add nsw",7275 if (function_i > 0) try writer.writeByte('\n');
5851 .@"add nuw",7276 const function_index: Function.Index = @enumFromInt(function_i);
5852 .@"add nuw nsw",7277 if (function.global.getReplacement(self) != .none) continue;
5853 .@"and",7278 const global = function.global.ptrConst(self);
5854 .ashr,7279 const params_len = global.type.functionParameters(self).len;
5855 .@"ashr exact",7280 const function_attributes = function.attributes.func(self);
5856 .fadd,7281 if (function_attributes != .none) try writer.print(
5857 .@"fadd fast",7282 \\; Function Attrs:{}
5858 .@"fcmp false",7283 \\
5859 .@"fcmp fast false",7284 , .{function_attributes.fmt(self)});
5860 .@"fcmp fast oeq",7285 try writer.print(
5861 .@"fcmp fast oge",7286 \\{s}{}{}{}{}{}{"} {} {}(
5862 .@"fcmp fast ogt",7287 , .{
5863 .@"fcmp fast ole",7288 if (function.instructions.len > 0) "define" else "declare",
5864 .@"fcmp fast olt",7289 global.linkage,
5865 .@"fcmp fast one",7290 global.preemption,
5866 .@"fcmp fast ord",7291 global.visibility,
5867 .@"fcmp fast true",7292 global.dll_storage_class,
5868 .@"fcmp fast ueq",7293 function.call_conv,
5869 .@"fcmp fast uge",7294 function.attributes.ret(self).fmt(self),
5870 .@"fcmp fast ugt",7295 global.type.functionReturn(self).fmt(self),
5871 .@"fcmp fast ule",7296 function.global.fmt(self),
5872 .@"fcmp fast ult",7297 });
5873 .@"fcmp fast une",7298 for (0..params_len) |arg| {
5874 .@"fcmp fast uno",7299 if (arg > 0) try writer.writeAll(", ");
5875 .@"fcmp oeq",7300 try writer.print(
5876 .@"fcmp oge",7301 \\{%}{"}
5877 .@"fcmp ogt",7302 , .{
5878 .@"fcmp ole",7303 global.type.functionParameters(self)[arg].fmt(self),
5879 .@"fcmp olt",7304 function.attributes.param(arg, self).fmt(self),
5880 .@"fcmp one",7305 });
5881 .@"fcmp ord",7306 if (function.instructions.len > 0)
5882 .@"fcmp true",7307 try writer.print(" {}", .{function.arg(@intCast(arg)).fmt(function_index, self)});
5883 .@"fcmp ueq",7308 }
5884 .@"fcmp uge",7309 switch (global.type.functionKind(self)) {
5885 .@"fcmp ugt",7310 .normal => {},
5886 .@"fcmp ule",7311 .vararg => {
5887 .@"fcmp ult",7312 if (params_len > 0) try writer.writeAll(", ");
5888 .@"fcmp une",7313 try writer.writeAll("...");
5889 .@"fcmp uno",7314 },
5890 .fdiv,7315 }
5891 .@"fdiv fast",7316 try writer.print("){}{}", .{ global.unnamed_addr, global.addr_space });
5892 .fmul,7317 if (function_attributes != .none) try writer.print(" #{d}", .{
5893 .@"fmul fast",7318 (try attribute_groups.getOrPutValue(self.gpa, function_attributes, {})).index,
5894 .frem,7319 });
5895 .@"frem fast",7320 try writer.print("{}", .{function.alignment});
5896 .fsub,7321 if (function.instructions.len > 0) {
5897 .@"fsub fast",7322 var block_incoming_len: u32 = undefined;
5898 .@"icmp eq",7323 try writer.writeAll(" {\n");
5899 .@"icmp ne",7324 for (params_len..function.instructions.len) |instruction_i| {
5900 .@"icmp sge",7325 const instruction_index: Function.Instruction.Index = @enumFromInt(instruction_i);
5901 .@"icmp sgt",7326 const instruction = function.instructions.get(@intFromEnum(instruction_index));
5902 .@"icmp sle",7327 switch (instruction.tag) {
5903 .@"icmp slt",7328 .add,
5904 .@"icmp uge",7329 .@"add nsw",
5905 .@"icmp ugt",7330 .@"add nuw",
5906 .@"icmp ule",7331 .@"add nuw nsw",
5907 .@"icmp ult",7332 .@"and",
5908 .lshr,7333 .ashr,
5909 .@"lshr exact",7334 .@"ashr exact",
5910 .mul,7335 .fadd,
5911 .@"mul nsw",7336 .@"fadd fast",
5912 .@"mul nuw",7337 .@"fcmp false",
5913 .@"mul nuw nsw",7338 .@"fcmp fast false",
5914 .@"or",7339 .@"fcmp fast oeq",
5915 .sdiv,7340 .@"fcmp fast oge",
5916 .@"sdiv exact",7341 .@"fcmp fast ogt",
5917 .srem,7342 .@"fcmp fast ole",
5918 .shl,7343 .@"fcmp fast olt",
5919 .@"shl nsw",7344 .@"fcmp fast one",
5920 .@"shl nuw",7345 .@"fcmp fast ord",
5921 .@"shl nuw nsw",7346 .@"fcmp fast true",
5922 .sub,7347 .@"fcmp fast ueq",
5923 .@"sub nsw",7348 .@"fcmp fast uge",
5924 .@"sub nuw",7349 .@"fcmp fast ugt",
5925 .@"sub nuw nsw",7350 .@"fcmp fast ule",
5926 .udiv,7351 .@"fcmp fast ult",
5927 .@"udiv exact",7352 .@"fcmp fast une",
5928 .urem,7353 .@"fcmp fast uno",
5929 .xor,7354 .@"fcmp oeq",
5930 => |tag| {7355 .@"fcmp oge",
5931 const extra = function.extraData(Function.Instruction.Binary, instruction.data);7356 .@"fcmp ogt",
5932 try writer.print(" %{} = {s} {%}, {}\n", .{7357 .@"fcmp ole",
5933 instruction_index.name(&function).fmt(self),7358 .@"fcmp olt",
5934 @tagName(tag),7359 .@"fcmp one",
5935 extra.lhs.fmt(function_index, self),7360 .@"fcmp ord",
5936 extra.rhs.fmt(function_index, self),7361 .@"fcmp true",
5937 });7362 .@"fcmp ueq",
5938 },7363 .@"fcmp uge",
5939 .addrspacecast,7364 .@"fcmp ugt",
5940 .bitcast,7365 .@"fcmp ule",
5941 .fpext,7366 .@"fcmp ult",
5942 .fptosi,7367 .@"fcmp une",
5943 .fptoui,7368 .@"fcmp uno",
5944 .fptrunc,7369 .fdiv,
5945 .inttoptr,7370 .@"fdiv fast",
5946 .ptrtoint,7371 .fmul,
5947 .sext,7372 .@"fmul fast",
5948 .sitofp,7373 .frem,
5949 .trunc,7374 .@"frem fast",
5950 .uitofp,7375 .fsub,
5951 .zext,7376 .@"fsub fast",
5952 => |tag| {7377 .@"icmp eq",
5953 const extra = function.extraData(Function.Instruction.Cast, instruction.data);7378 .@"icmp ne",
5954 try writer.print(" %{} = {s} {%} to {%}\n", .{7379 .@"icmp sge",
5955 instruction_index.name(&function).fmt(self),7380 .@"icmp sgt",
5956 @tagName(tag),7381 .@"icmp sle",
5957 extra.val.fmt(function_index, self),7382 .@"icmp slt",
5958 extra.type.fmt(self),7383 .@"icmp uge",
5959 });7384 .@"icmp ugt",
5960 },7385 .@"icmp ule",
5961 .alloca,7386 .@"icmp ult",
5962 .@"alloca inalloca",7387 .lshr,
5963 => |tag| {7388 .@"lshr exact",
5964 const extra = function.extraData(Function.Instruction.Alloca, instruction.data);7389 .mul,
5965 try writer.print(" %{} = {s} {%}{,%}{,}{,}\n", .{7390 .@"mul nsw",
5966 instruction_index.name(&function).fmt(self),7391 .@"mul nuw",
5967 @tagName(tag),7392 .@"mul nuw nsw",
5968 extra.type.fmt(self),7393 .@"or",
5969 extra.len.fmt(function_index, self),7394 .sdiv,
5970 extra.info.alignment,7395 .@"sdiv exact",
5971 extra.info.addr_space,7396 .srem,
5972 });7397 .shl,
5973 },7398 .@"shl nsw",
5974 .arg => unreachable,7399 .@"shl nuw",
5975 .block => {7400 .@"shl nuw nsw",
5976 block_incoming_len = instruction.data;7401 .sub,
5977 const name = instruction_index.name(&function);7402 .@"sub nsw",
5978 if (@intFromEnum(instruction_index) > params_len) try writer.writeByte('\n');7403 .@"sub nuw",
5979 try writer.print("{}:\n", .{name.fmt(self)});7404 .@"sub nuw nsw",
5980 },7405 .udiv,
5981 .br => |tag| {7406 .@"udiv exact",
5982 const target: Function.Block.Index = @enumFromInt(instruction.data);7407 .urem,
5983 try writer.print(" {s} {%}\n", .{7408 .xor,
5984 @tagName(tag), target.toInst(&function).fmt(function_index, self),7409 => |tag| {
5985 });7410 const extra =
5986 },7411 function.extraData(Function.Instruction.Binary, instruction.data);
5987 .br_cond => {7412 try writer.print(" %{} = {s} {%}, {}\n", .{
5988 const extra = function.extraData(Function.Instruction.BrCond, instruction.data);7413 instruction_index.name(&function).fmt(self),
5989 try writer.print(" br {%}, {%}, {%}\n", .{7414 @tagName(tag),
5990 extra.cond.fmt(function_index, self),7415 extra.lhs.fmt(function_index, self),
5991 extra.then.toInst(&function).fmt(function_index, self),7416 extra.rhs.fmt(function_index, self),
5992 extra.@"else".toInst(&function).fmt(function_index, self),
5993 });
5994 },
5995 .extractelement => |tag| {
5996 const extra =
5997 function.extraData(Function.Instruction.ExtractElement, instruction.data);
5998 try writer.print(" %{} = {s} {%}, {%}\n", .{
5999 instruction_index.name(&function).fmt(self),
6000 @tagName(tag),
6001 extra.val.fmt(function_index, self),
6002 extra.index.fmt(function_index, self),
6003 });
6004 },
6005 .extractvalue => |tag| {
6006 var extra =
6007 function.extraDataTrail(Function.Instruction.ExtractValue, instruction.data);
6008 const indices = extra.trail.next(extra.data.indices_len, u32, &function);
6009 try writer.print(" %{} = {s} {%}", .{
6010 instruction_index.name(&function).fmt(self),
6011 @tagName(tag),
6012 extra.data.val.fmt(function_index, self),
6013 });
6014 for (indices) |index| try writer.print(", {d}", .{index});
6015 try writer.writeByte('\n');
6016 },
6017 .fence => |tag| {
6018 const info: MemoryAccessInfo = @bitCast(instruction.data);
6019 try writer.print(" {s}{}{}", .{ @tagName(tag), info.scope, info.ordering });
6020 },
6021 .fneg,
6022 .@"fneg fast",
6023 .ret,
6024 => |tag| {
6025 const val: Value = @enumFromInt(instruction.data);
6026 try writer.print(" {s} {%}\n", .{
6027 @tagName(tag),
6028 val.fmt(function_index, self),
6029 });
6030 },
6031 .getelementptr,
6032 .@"getelementptr inbounds",
6033 => |tag| {
6034 var extra = function.extraDataTrail(
6035 Function.Instruction.GetElementPtr,
6036 instruction.data,
6037 );
6038 const indices = extra.trail.next(extra.data.indices_len, Value, &function);
6039 try writer.print(" %{} = {s} {%}, {%}", .{
6040 instruction_index.name(&function).fmt(self),
6041 @tagName(tag),
6042 extra.data.type.fmt(self),
6043 extra.data.base.fmt(function_index, self),
6044 });
6045 for (indices) |index| try writer.print(", {%}", .{
6046 index.fmt(function_index, self),
6047 });
6048 try writer.writeByte('\n');
6049 },
6050 .insertelement => |tag| {
6051 const extra =
6052 function.extraData(Function.Instruction.InsertElement, instruction.data);
6053 try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
6054 instruction_index.name(&function).fmt(self),
6055 @tagName(tag),
6056 extra.val.fmt(function_index, self),
6057 extra.elem.fmt(function_index, self),
6058 extra.index.fmt(function_index, self),
6059 });
6060 },
6061 .insertvalue => |tag| {
6062 var extra =
6063 function.extraDataTrail(Function.Instruction.InsertValue, instruction.data);
6064 const indices = extra.trail.next(extra.data.indices_len, u32, &function);
6065 try writer.print(" %{} = {s} {%}, {%}", .{
6066 instruction_index.name(&function).fmt(self),
6067 @tagName(tag),
6068 extra.data.val.fmt(function_index, self),
6069 extra.data.elem.fmt(function_index, self),
6070 });
6071 for (indices) |index| try writer.print(", {d}", .{index});
6072 try writer.writeByte('\n');
6073 },
6074 .@"llvm.maxnum.",
6075 .@"llvm.minnum.",
6076 .@"llvm.sadd.sat.",
6077 .@"llvm.smax.",
6078 .@"llvm.smin.",
6079 .@"llvm.smul.fix.sat.",
6080 .@"llvm.sshl.sat.",
6081 .@"llvm.ssub.sat.",
6082 .@"llvm.uadd.sat.",
6083 .@"llvm.umax.",
6084 .@"llvm.umin.",
6085 .@"llvm.umul.fix.sat.",
6086 .@"llvm.ushl.sat.",
6087 .@"llvm.usub.sat.",
6088 => |tag| {
6089 const extra = function.extraData(Function.Instruction.Binary, instruction.data);
6090 const ty = instruction_index.typeOf(function_index, self);
6091 try writer.print(" %{} = call {%} @{s}{m}({%}, {%})\n", .{
6092 instruction_index.name(&function).fmt(self),
6093 ty.fmt(self),
6094 @tagName(tag),
6095 ty.fmt(self),
6096 extra.lhs.fmt(function_index, self),
6097 extra.rhs.fmt(function_index, self),
6098 });
6099 },
6100 .load,
6101 .@"load atomic",
6102 .@"load atomic volatile",
6103 .@"load volatile",
6104 => |tag| {
6105 const extra = function.extraData(Function.Instruction.Load, instruction.data);
6106 try writer.print(" %{} = {s} {%}, {%}{}{}{,}\n", .{
6107 instruction_index.name(&function).fmt(self),
6108 @tagName(tag),
6109 extra.type.fmt(self),
6110 extra.ptr.fmt(function_index, self),
6111 extra.info.scope,
6112 extra.info.ordering,
6113 extra.info.alignment,
6114 });
6115 },
6116 .phi,
6117 .@"phi fast",
6118 => |tag| {
6119 var extra = function.extraDataTrail(Function.Instruction.Phi, instruction.data);
6120 const vals = extra.trail.next(block_incoming_len, Value, &function);
6121 const blocks =
6122 extra.trail.next(block_incoming_len, Function.Block.Index, &function);
6123 try writer.print(" %{} = {s} {%} ", .{
6124 instruction_index.name(&function).fmt(self),
6125 @tagName(tag),
6126 vals[0].typeOf(function_index, self).fmt(self),
6127 });
6128 for (0.., vals, blocks) |incoming_index, incoming_val, incoming_block| {
6129 if (incoming_index > 0) try writer.writeAll(", ");
6130 try writer.print("[ {}, {} ]", .{
6131 incoming_val.fmt(function_index, self),
6132 incoming_block.toInst(&function).fmt(function_index, self),
6133 });7417 });
6134 }7418 },
6135 try writer.writeByte('\n');7419 .addrspacecast,
6136 },7420 .bitcast,
6137 .@"ret void",7421 .fpext,
6138 .@"unreachable",7422 .fptosi,
6139 => |tag| try writer.print(" {s}\n", .{@tagName(tag)}),7423 .fptoui,
6140 .select,7424 .fptrunc,
6141 .@"select fast",7425 .inttoptr,
6142 => |tag| {7426 .ptrtoint,
6143 const extra = function.extraData(Function.Instruction.Select, instruction.data);7427 .sext,
6144 try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{7428 .sitofp,
6145 instruction_index.name(&function).fmt(self),7429 .trunc,
6146 @tagName(tag),7430 .uitofp,
6147 extra.cond.fmt(function_index, self),7431 .zext,
6148 extra.lhs.fmt(function_index, self),7432 => |tag| {
6149 extra.rhs.fmt(function_index, self),7433 const extra =
6150 });7434 function.extraData(Function.Instruction.Cast, instruction.data);
6151 },7435 try writer.print(" %{} = {s} {%} to {%}\n", .{
6152 .shufflevector => |tag| {
6153 const extra =
6154 function.extraData(Function.Instruction.ShuffleVector, instruction.data);
6155 try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
6156 instruction_index.name(&function).fmt(self),
6157 @tagName(tag),
6158 extra.lhs.fmt(function_index, self),
6159 extra.rhs.fmt(function_index, self),
6160 extra.mask.fmt(function_index, self),
6161 });
6162 },
6163 .store,
6164 .@"store atomic",
6165 .@"store atomic volatile",
6166 .@"store volatile",
6167 => |tag| {
6168 const extra = function.extraData(Function.Instruction.Store, instruction.data);
6169 try writer.print(" {s} {%}, {%}{}{}{,}\n", .{
6170 @tagName(tag),
6171 extra.val.fmt(function_index, self),
6172 extra.ptr.fmt(function_index, self),
6173 extra.info.scope,
6174 extra.info.ordering,
6175 extra.info.alignment,
6176 });
6177 },
6178 .@"switch" => |tag| {
6179 var extra =
6180 function.extraDataTrail(Function.Instruction.Switch, instruction.data);
6181 const vals = extra.trail.next(extra.data.cases_len, Constant, &function);
6182 const blocks =
6183 extra.trail.next(extra.data.cases_len, Function.Block.Index, &function);
6184 try writer.print(" {s} {%}, {%} [", .{
6185 @tagName(tag),
6186 extra.data.val.fmt(function_index, self),
6187 extra.data.default.toInst(&function).fmt(function_index, self),
6188 });
6189 for (vals, blocks) |case_val, case_block| try writer.print(" {%}, {%}\n", .{
6190 case_val.fmt(self),
6191 case_block.toInst(&function).fmt(function_index, self),
6192 });
6193 try writer.writeAll(" ]\n");
6194 },
6195 .unimplemented => |tag| {
6196 const ty: Type = @enumFromInt(instruction.data);
6197 try writer.writeAll(" ");
6198 switch (ty) {
6199 .none, .void => {},
6200 else => try writer.print("%{} = ", .{
6201 instruction_index.name(&function).fmt(self),7436 instruction_index.name(&function).fmt(self),
6202 }),7437 @tagName(tag),
6203 }7438 extra.val.fmt(function_index, self),
6204 try writer.print("{s} {%}\n", .{ @tagName(tag), ty.fmt(self) });7439 extra.type.fmt(self),
6205 },7440 });
6206 .va_arg => |tag| {7441 },
6207 const extra = function.extraData(Function.Instruction.VaArg, instruction.data);7442 .alloca,
6208 try writer.print(" %{} = {s} {%}, {%}\n", .{7443 .@"alloca inalloca",
6209 instruction_index.name(&function).fmt(self),7444 => |tag| {
6210 @tagName(tag),7445 const extra =
6211 extra.list.fmt(function_index, self),7446 function.extraData(Function.Instruction.Alloca, instruction.data);
6212 extra.type.fmt(self),7447 try writer.print(" %{} = {s} {%}{,%}{,}{,}\n", .{
6213 });7448 instruction_index.name(&function).fmt(self),
6214 },7449 @tagName(tag),
7450 extra.type.fmt(self),
7451 extra.len.fmt(function_index, self),
7452 extra.info.alignment,
7453 extra.info.addr_space,
7454 });
7455 },
7456 .arg => unreachable,
7457 .block => {
7458 block_incoming_len = instruction.data;
7459 const name = instruction_index.name(&function);
7460 if (@intFromEnum(instruction_index) > params_len)
7461 try writer.writeByte('\n');
7462 try writer.print("{}:\n", .{name.fmt(self)});
7463 },
7464 .br => |tag| {
7465 const target: Function.Block.Index = @enumFromInt(instruction.data);
7466 try writer.print(" {s} {%}\n", .{
7467 @tagName(tag), target.toInst(&function).fmt(function_index, self),
7468 });
7469 },
7470 .br_cond => {
7471 const extra =
7472 function.extraData(Function.Instruction.BrCond, instruction.data);
7473 try writer.print(" br {%}, {%}, {%}\n", .{
7474 extra.cond.fmt(function_index, self),
7475 extra.then.toInst(&function).fmt(function_index, self),
7476 extra.@"else".toInst(&function).fmt(function_index, self),
7477 });
7478 },
7479 .call,
7480 .@"call fast",
7481 .@"musttail call",
7482 .@"musttail call fast",
7483 .@"notail call",
7484 .@"notail call fast",
7485 .@"tail call",
7486 .@"tail call fast",
7487 => |tag| {
7488 var extra =
7489 function.extraDataTrail(Function.Instruction.Call, instruction.data);
7490 const args = extra.trail.next(extra.data.args_len, Value, &function);
7491 try writer.writeAll(" ");
7492 const ret_ty = extra.data.ty.functionReturn(self);
7493 switch (ret_ty) {
7494 .void => {},
7495 else => try writer.print("%{} = ", .{
7496 instruction_index.name(&function).fmt(self),
7497 }),
7498 .none => unreachable,
7499 }
7500 try writer.print("{s}{}{}{} {%} {}(", .{
7501 @tagName(tag),
7502 extra.data.info.call_conv,
7503 extra.data.attributes.ret(self).fmt(self),
7504 extra.data.callee.typeOf(function_index, self).pointerAddrSpace(self),
7505 switch (extra.data.ty.functionKind(self)) {
7506 .normal => ret_ty,
7507 .vararg => extra.data.ty,
7508 }.fmt(self),
7509 extra.data.callee.fmt(function_index, self),
7510 });
7511 for (0.., args) |arg_index, arg| {
7512 if (arg_index > 0) try writer.writeAll(", ");
7513 try writer.print("{%}{} {}", .{
7514 arg.typeOf(function_index, self).fmt(self),
7515 extra.data.attributes.param(arg_index, self).fmt(self),
7516 arg.fmt(function_index, self),
7517 });
7518 }
7519 try writer.writeByte(')');
7520 const call_function_attributes = extra.data.attributes.func(self);
7521 if (call_function_attributes != .none) try writer.print(" #{d}", .{
7522 (try attribute_groups.getOrPutValue(
7523 self.gpa,
7524 call_function_attributes,
7525 {},
7526 )).index,
7527 });
7528 try writer.writeByte('\n');
7529 },
7530 .extractelement => |tag| {
7531 const extra = function.extraData(
7532 Function.Instruction.ExtractElement,
7533 instruction.data,
7534 );
7535 try writer.print(" %{} = {s} {%}, {%}\n", .{
7536 instruction_index.name(&function).fmt(self),
7537 @tagName(tag),
7538 extra.val.fmt(function_index, self),
7539 extra.index.fmt(function_index, self),
7540 });
7541 },
7542 .extractvalue => |tag| {
7543 var extra = function.extraDataTrail(
7544 Function.Instruction.ExtractValue,
7545 instruction.data,
7546 );
7547 const indices = extra.trail.next(extra.data.indices_len, u32, &function);
7548 try writer.print(" %{} = {s} {%}", .{
7549 instruction_index.name(&function).fmt(self),
7550 @tagName(tag),
7551 extra.data.val.fmt(function_index, self),
7552 });
7553 for (indices) |index| try writer.print(", {d}", .{index});
7554 try writer.writeByte('\n');
7555 },
7556 .fence => |tag| {
7557 const info: MemoryAccessInfo = @bitCast(instruction.data);
7558 try writer.print(" {s}{}{}", .{ @tagName(tag), info.scope, info.ordering });
7559 },
7560 .fneg,
7561 .@"fneg fast",
7562 .ret,
7563 => |tag| {
7564 const val: Value = @enumFromInt(instruction.data);
7565 try writer.print(" {s} {%}\n", .{
7566 @tagName(tag),
7567 val.fmt(function_index, self),
7568 });
7569 },
7570 .getelementptr,
7571 .@"getelementptr inbounds",
7572 => |tag| {
7573 var extra = function.extraDataTrail(
7574 Function.Instruction.GetElementPtr,
7575 instruction.data,
7576 );
7577 const indices = extra.trail.next(extra.data.indices_len, Value, &function);
7578 try writer.print(" %{} = {s} {%}, {%}", .{
7579 instruction_index.name(&function).fmt(self),
7580 @tagName(tag),
7581 extra.data.type.fmt(self),
7582 extra.data.base.fmt(function_index, self),
7583 });
7584 for (indices) |index| try writer.print(", {%}", .{
7585 index.fmt(function_index, self),
7586 });
7587 try writer.writeByte('\n');
7588 },
7589 .insertelement => |tag| {
7590 const extra = function.extraData(
7591 Function.Instruction.InsertElement,
7592 instruction.data,
7593 );
7594 try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
7595 instruction_index.name(&function).fmt(self),
7596 @tagName(tag),
7597 extra.val.fmt(function_index, self),
7598 extra.elem.fmt(function_index, self),
7599 extra.index.fmt(function_index, self),
7600 });
7601 },
7602 .insertvalue => |tag| {
7603 var extra = function.extraDataTrail(
7604 Function.Instruction.InsertValue,
7605 instruction.data,
7606 );
7607 const indices = extra.trail.next(extra.data.indices_len, u32, &function);
7608 try writer.print(" %{} = {s} {%}, {%}", .{
7609 instruction_index.name(&function).fmt(self),
7610 @tagName(tag),
7611 extra.data.val.fmt(function_index, self),
7612 extra.data.elem.fmt(function_index, self),
7613 });
7614 for (indices) |index| try writer.print(", {d}", .{index});
7615 try writer.writeByte('\n');
7616 },
7617 .@"llvm.maxnum.",
7618 .@"llvm.minnum.",
7619 .@"llvm.sadd.sat.",
7620 .@"llvm.smax.",
7621 .@"llvm.smin.",
7622 .@"llvm.smul.fix.sat.",
7623 .@"llvm.sshl.sat.",
7624 .@"llvm.ssub.sat.",
7625 .@"llvm.uadd.sat.",
7626 .@"llvm.umax.",
7627 .@"llvm.umin.",
7628 .@"llvm.umul.fix.sat.",
7629 .@"llvm.ushl.sat.",
7630 .@"llvm.usub.sat.",
7631 => |tag| {
7632 const extra =
7633 function.extraData(Function.Instruction.Binary, instruction.data);
7634 const ty = instruction_index.typeOf(function_index, self);
7635 try writer.print(" %{} = call {%} @{s}{m}({%}, {%}{s})\n", .{
7636 instruction_index.name(&function).fmt(self),
7637 ty.fmt(self),
7638 @tagName(tag),
7639 ty.fmt(self),
7640 extra.lhs.fmt(function_index, self),
7641 extra.rhs.fmt(function_index, self),
7642 switch (tag) {
7643 .@"llvm.smul.fix.sat.",
7644 .@"llvm.umul.fix.sat.",
7645 => ", i32 0",
7646 else => "",
7647 },
7648 });
7649 },
7650 .load,
7651 .@"load atomic",
7652 .@"load atomic volatile",
7653 .@"load volatile",
7654 => |tag| {
7655 const extra =
7656 function.extraData(Function.Instruction.Load, instruction.data);
7657 try writer.print(" %{} = {s} {%}, {%}{}{}{,}\n", .{
7658 instruction_index.name(&function).fmt(self),
7659 @tagName(tag),
7660 extra.type.fmt(self),
7661 extra.ptr.fmt(function_index, self),
7662 extra.info.scope,
7663 extra.info.ordering,
7664 extra.info.alignment,
7665 });
7666 },
7667 .phi,
7668 .@"phi fast",
7669 => |tag| {
7670 var extra =
7671 function.extraDataTrail(Function.Instruction.Phi, instruction.data);
7672 const vals = extra.trail.next(block_incoming_len, Value, &function);
7673 const blocks =
7674 extra.trail.next(block_incoming_len, Function.Block.Index, &function);
7675 try writer.print(" %{} = {s} {%} ", .{
7676 instruction_index.name(&function).fmt(self),
7677 @tagName(tag),
7678 vals[0].typeOf(function_index, self).fmt(self),
7679 });
7680 for (0.., vals, blocks) |incoming_index, incoming_val, incoming_block| {
7681 if (incoming_index > 0) try writer.writeAll(", ");
7682 try writer.print("[ {}, {} ]", .{
7683 incoming_val.fmt(function_index, self),
7684 incoming_block.toInst(&function).fmt(function_index, self),
7685 });
7686 }
7687 try writer.writeByte('\n');
7688 },
7689 .@"ret void",
7690 .@"unreachable",
7691 => |tag| try writer.print(" {s}\n", .{@tagName(tag)}),
7692 .select,
7693 .@"select fast",
7694 => |tag| {
7695 const extra =
7696 function.extraData(Function.Instruction.Select, instruction.data);
7697 try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
7698 instruction_index.name(&function).fmt(self),
7699 @tagName(tag),
7700 extra.cond.fmt(function_index, self),
7701 extra.lhs.fmt(function_index, self),
7702 extra.rhs.fmt(function_index, self),
7703 });
7704 },
7705 .shufflevector => |tag| {
7706 const extra = function.extraData(
7707 Function.Instruction.ShuffleVector,
7708 instruction.data,
7709 );
7710 try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
7711 instruction_index.name(&function).fmt(self),
7712 @tagName(tag),
7713 extra.lhs.fmt(function_index, self),
7714 extra.rhs.fmt(function_index, self),
7715 extra.mask.fmt(function_index, self),
7716 });
7717 },
7718 .store,
7719 .@"store atomic",
7720 .@"store atomic volatile",
7721 .@"store volatile",
7722 => |tag| {
7723 const extra =
7724 function.extraData(Function.Instruction.Store, instruction.data);
7725 try writer.print(" {s} {%}, {%}{}{}{,}\n", .{
7726 @tagName(tag),
7727 extra.val.fmt(function_index, self),
7728 extra.ptr.fmt(function_index, self),
7729 extra.info.scope,
7730 extra.info.ordering,
7731 extra.info.alignment,
7732 });
7733 },
7734 .@"switch" => |tag| {
7735 var extra =
7736 function.extraDataTrail(Function.Instruction.Switch, instruction.data);
7737 const vals = extra.trail.next(extra.data.cases_len, Constant, &function);
7738 const blocks =
7739 extra.trail.next(extra.data.cases_len, Function.Block.Index, &function);
7740 try writer.print(" {s} {%}, {%} [\n", .{
7741 @tagName(tag),
7742 extra.data.val.fmt(function_index, self),
7743 extra.data.default.toInst(&function).fmt(function_index, self),
7744 });
7745 for (vals, blocks) |case_val, case_block| try writer.print(
7746 " {%}, {%}\n",
7747 .{
7748 case_val.fmt(self),
7749 case_block.toInst(&function).fmt(function_index, self),
7750 },
7751 );
7752 try writer.writeAll(" ]\n");
7753 },
7754 .unimplemented => |tag| {
7755 const ty: Type = @enumFromInt(instruction.data);
7756 if (true) {
7757 try writer.writeAll(" ");
7758 switch (ty) {
7759 .none, .void => {},
7760 else => try writer.print("%{} = ", .{
7761 instruction_index.name(&function).fmt(self),
7762 }),
7763 }
7764 try writer.print("{s} {%}\n", .{ @tagName(tag), ty.fmt(self) });
7765 } else switch (ty) {
7766 .none, .void => {},
7767 else => try writer.print(" %{} = load {%}, ptr undef\n", .{
7768 instruction_index.name(&function).fmt(self),
7769 ty.fmt(self),
7770 }),
7771 }
7772 },
7773 .va_arg => |tag| {
7774 const extra =
7775 function.extraData(Function.Instruction.VaArg, instruction.data);
7776 try writer.print(" %{} = {s} {%}, {%}\n", .{
7777 instruction_index.name(&function).fmt(self),
7778 @tagName(tag),
7779 extra.list.fmt(function_index, self),
7780 extra.type.fmt(self),
7781 });
7782 },
7783 }
6215 }7784 }
7785 try writer.writeByte('}');
6216 }7786 }
6217 try writer.writeByte('}');7787 try writer.writeByte('\n');
6218 }7788 }
6219 try writer.writeAll("\n\n");7789 need_newline = true;
7790 }
7791
7792 if (attribute_groups.count() > 0) {
7793 if (need_newline) try writer.writeByte('\n') else need_newline = true;
7794 for (0.., attribute_groups.keys()) |attribute_group_index, attribute_group|
7795 try writer.print(
7796 \\attributes #{d} = {{{#"} }}
7797 \\
7798 , .{ attribute_group_index, attribute_group.fmt(self) });
7799 need_newline = true;
6220 }7800 }
6221}7801}
62227802
...@@ -6227,7 +7807,7 @@ pub inline fn useLibLlvm(self: *const Builder) bool {...@@ -6227,7 +7807,7 @@ pub inline fn useLibLlvm(self: *const Builder) bool {
6227const NoExtra = struct {};7807const NoExtra = struct {};
62287808
6229fn isValidIdentifier(id: []const u8) bool {7809fn isValidIdentifier(id: []const u8) bool {
6230 for (id, 0..) |character, index| switch (character) {7810 for (id, 0..) |byte, index| switch (byte) {
6231 '$', '-', '.', 'A'...'Z', '_', 'a'...'z' => {},7811 '$', '-', '.', 'A'...'Z', '_', 'a'...'z' => {},
6232 '0'...'9' => if (index == 0) return false,7812 '0'...'9' => if (index == 0) return false,
6233 else => return false,7813 else => return false,
...@@ -6235,10 +7815,29 @@ fn isValidIdentifier(id: []const u8) bool {...@@ -6235,10 +7815,29 @@ fn isValidIdentifier(id: []const u8) bool {
6235 return true;7815 return true;
6236}7816}
62377817
7818const QuoteBehavior = enum { always_quote, quote_unless_valid_identifier };
7819fn printEscapedString(
7820 slice: []const u8,
7821 quotes: QuoteBehavior,
7822 writer: anytype,
7823) @TypeOf(writer).Error!void {
7824 const need_quotes = switch (quotes) {
7825 .always_quote => true,
7826 .quote_unless_valid_identifier => !isValidIdentifier(slice),
7827 };
7828 if (need_quotes) try writer.writeByte('"');
7829 for (slice) |byte| switch (byte) {
7830 '\\' => try writer.writeAll("\\\\"),
7831 ' '...'"' - 1, '"' + 1...'\\' - 1, '\\' + 1...'~' => try writer.writeByte(byte),
7832 else => try writer.print("\\{X:0>2}", .{byte}),
7833 };
7834 if (need_quotes) try writer.writeByte('"');
7835}
7836
6238fn ensureUnusedGlobalCapacity(self: *Builder, name: String) Allocator.Error!void {7837fn ensureUnusedGlobalCapacity(self: *Builder, name: String) Allocator.Error!void {
6239 if (self.useLibLlvm()) try self.llvm.globals.ensureUnusedCapacity(self.gpa, 1);7838 if (self.useLibLlvm()) try self.llvm.globals.ensureUnusedCapacity(self.gpa, 1);
6240 try self.string_map.ensureUnusedCapacity(self.gpa, 1);7839 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
6241 if (name.toSlice(self)) |id| {7840 if (name.slice(self)) |id| {
6242 const count: usize = comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)});7841 const count: usize = comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)});
6243 try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);7842 try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);
6244 }7843 }
...@@ -6528,14 +8127,14 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {...@@ -6528,14 +8127,14 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {
6528 const result: Type = @enumFromInt(gop.index);8127 const result: Type = @enumFromInt(gop.index);
6529 type_gop.value_ptr.* = result;8128 type_gop.value_ptr.* = result;
6530 if (self.useLibLlvm()) self.llvm.types.appendAssumeCapacity(8129 if (self.useLibLlvm()) self.llvm.types.appendAssumeCapacity(
6531 self.llvm.context.structCreateNamed(id.toSlice(self) orelse ""),8130 self.llvm.context.structCreateNamed(id.slice(self) orelse ""),
6532 );8131 );
6533 return result;8132 return result;
6534 }8133 }
65358134
6536 const unique_gop = self.next_unique_type_id.getOrPutAssumeCapacity(name);8135 const unique_gop = self.next_unique_type_id.getOrPutAssumeCapacity(name);
6537 if (!unique_gop.found_existing) unique_gop.value_ptr.* = 2;8136 if (!unique_gop.found_existing) unique_gop.value_ptr.* = 2;
6538 id = self.fmtAssumeCapacity("{s}.{d}", .{ name.toSlice(self).?, unique_gop.value_ptr.* });8137 id = self.fmtAssumeCapacity("{s}.{d}", .{ name.slice(self).?, unique_gop.value_ptr.* });
6539 unique_gop.value_ptr.* += 1;8138 unique_gop.value_ptr.* += 1;
6540 }8139 }
6541}8140}
...@@ -6636,6 +8235,30 @@ fn typeExtraData(self: *const Builder, comptime T: type, index: Type.Item.ExtraI...@@ -6636,6 +8235,30 @@ fn typeExtraData(self: *const Builder, comptime T: type, index: Type.Item.ExtraI
6636 return self.typeExtraDataTrail(T, index).data;8235 return self.typeExtraDataTrail(T, index).data;
6637}8236}
66388237
8238fn attrGeneric(self: *Builder, data: []const u32) Allocator.Error!u32 {
8239 try self.attributes_map.ensureUnusedCapacity(self.gpa, 1);
8240 try self.attributes_indices.ensureUnusedCapacity(self.gpa, 1);
8241 try self.attributes_extra.ensureUnusedCapacity(self.gpa, data.len);
8242
8243 const Adapter = struct {
8244 builder: *const Builder,
8245 pub fn hash(_: @This(), key: []const u32) u32 {
8246 return @truncate(std.hash.Wyhash.hash(1, std.mem.sliceAsBytes(key)));
8247 }
8248 pub fn eql(ctx: @This(), lhs_key: []const u32, _: void, rhs_index: usize) bool {
8249 const start = ctx.builder.attributes_indices.items[rhs_index];
8250 const end = ctx.builder.attributes_indices.items[rhs_index + 1];
8251 return std.mem.eql(u32, lhs_key, ctx.builder.attributes_extra.items[start..end]);
8252 }
8253 };
8254 const gop = self.attributes_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
8255 if (!gop.found_existing) {
8256 self.attributes_extra.appendSliceAssumeCapacity(data);
8257 self.attributes_indices.appendAssumeCapacity(@intCast(self.attributes_extra.items.len));
8258 }
8259 return @intCast(gop.index);
8260}
8261
6639fn bigIntConstAssumeCapacity(8262fn bigIntConstAssumeCapacity(
6640 self: *Builder,8263 self: *Builder,
6641 ty: Type,8264 ty: Type,
...@@ -7073,7 +8696,7 @@ fn arrayConstAssumeCapacity(...@@ -7073,7 +8696,7 @@ fn arrayConstAssumeCapacity(
7073}8696}
70748697
7075fn stringConstAssumeCapacity(self: *Builder, val: String) Constant {8698fn stringConstAssumeCapacity(self: *Builder, val: String) Constant {
7076 const slice = val.toSlice(self).?;8699 const slice = val.slice(self).?;
7077 const ty = self.arrayTypeAssumeCapacity(slice.len, .i8);8700 const ty = self.arrayTypeAssumeCapacity(slice.len, .i8);
7078 if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty);8701 if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty);
7079 const result = self.getOrPutConstantNoExtraAssumeCapacity(8702 const result = self.getOrPutConstantNoExtraAssumeCapacity(
...@@ -7086,7 +8709,7 @@ fn stringConstAssumeCapacity(self: *Builder, val: String) Constant {...@@ -7086,7 +8709,7 @@ fn stringConstAssumeCapacity(self: *Builder, val: String) Constant {
7086}8709}
70878710
7088fn stringNullConstAssumeCapacity(self: *Builder, val: String) Constant {8711fn stringNullConstAssumeCapacity(self: *Builder, val: String) Constant {
7089 const slice = val.toSlice(self).?;8712 const slice = val.slice(self).?;
7090 const ty = self.arrayTypeAssumeCapacity(slice.len + 1, .i8);8713 const ty = self.arrayTypeAssumeCapacity(slice.len + 1, .i8);
7091 if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty);8714 if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty);
7092 const result = self.getOrPutConstantNoExtraAssumeCapacity(8715 const result = self.getOrPutConstantNoExtraAssumeCapacity(
...@@ -7737,30 +9360,30 @@ fn binConstAssumeCapacity(...@@ -7737,30 +9360,30 @@ fn binConstAssumeCapacity(
7737 => {},9360 => {},
7738 else => unreachable,9361 else => unreachable,
7739 }9362 }
7740 const Key = struct { tag: Constant.Tag, bin: Constant.Binary };9363 const Key = struct { tag: Constant.Tag, extra: Constant.Binary };
7741 const Adapter = struct {9364 const Adapter = struct {
7742 builder: *const Builder,9365 builder: *const Builder,
7743 pub fn hash(_: @This(), key: Key) u32 {9366 pub fn hash(_: @This(), key: Key) u32 {
7744 return @truncate(std.hash.Wyhash.hash(9367 return @truncate(std.hash.Wyhash.hash(
7745 std.hash.uint32(@intFromEnum(key.tag)),9368 std.hash.uint32(@intFromEnum(key.tag)),
7746 std.mem.asBytes(&key.bin),9369 std.mem.asBytes(&key.extra),
7747 ));9370 ));
7748 }9371 }
7749 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {9372 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
7750 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;9373 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
7751 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];9374 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
7752 const rhs_extra = ctx.builder.constantExtraData(Constant.Binary, rhs_data);9375 const rhs_extra = ctx.builder.constantExtraData(Constant.Binary, rhs_data);
7753 return std.meta.eql(lhs_key.bin, rhs_extra);9376 return std.meta.eql(lhs_key.extra, rhs_extra);
7754 }9377 }
7755 };9378 };
7756 const data = Key{ .tag = tag, .bin = .{ .lhs = lhs, .rhs = rhs } };9379 const data = Key{ .tag = tag, .extra = .{ .lhs = lhs, .rhs = rhs } };
7757 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });9380 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
7758 if (!gop.found_existing) {9381 if (!gop.found_existing) {
7759 gop.key_ptr.* = {};9382 gop.key_ptr.* = {};
7760 gop.value_ptr.* = {};9383 gop.value_ptr.* = {};
7761 self.constant_items.appendAssumeCapacity(.{9384 self.constant_items.appendAssumeCapacity(.{
7762 .tag = tag,9385 .tag = tag,
7763 .data = self.addConstantExtraAssumeCapacity(data.bin),9386 .data = self.addConstantExtraAssumeCapacity(data.extra),
7764 });9387 });
7765 if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(switch (tag) {9388 if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(switch (tag) {
7766 .add => &llvm.Value.constAdd,9389 .add => &llvm.Value.constAdd,
...@@ -7778,6 +9401,63 @@ fn binConstAssumeCapacity(...@@ -7778,6 +9401,63 @@ fn binConstAssumeCapacity(
7778 return @enumFromInt(gop.index);9401 return @enumFromInt(gop.index);
7779}9402}
77809403
9404fn asmConstAssumeCapacity(
9405 self: *Builder,
9406 ty: Type,
9407 info: Constant.Asm.Info,
9408 assembly: String,
9409 constraints: String,
9410) Constant {
9411 assert(ty.functionKind(self) == .normal);
9412
9413 const Key = struct { tag: Constant.Tag, extra: Constant.Asm };
9414 const Adapter = struct {
9415 builder: *const Builder,
9416 pub fn hash(_: @This(), key: Key) u32 {
9417 return @truncate(std.hash.Wyhash.hash(
9418 std.hash.uint32(@intFromEnum(key.tag)),
9419 std.mem.asBytes(&key.extra),
9420 ));
9421 }
9422 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
9423 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
9424 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
9425 const rhs_extra = ctx.builder.constantExtraData(Constant.Asm, rhs_data);
9426 return std.meta.eql(lhs_key.extra, rhs_extra);
9427 }
9428 };
9429
9430 const data = Key{
9431 .tag = @enumFromInt(@intFromEnum(Constant.Tag.@"asm") + @as(u4, @bitCast(info))),
9432 .extra = .{ .type = ty, .assembly = assembly, .constraints = constraints },
9433 };
9434 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
9435 if (!gop.found_existing) {
9436 gop.key_ptr.* = {};
9437 gop.value_ptr.* = {};
9438 self.constant_items.appendAssumeCapacity(.{
9439 .tag = data.tag,
9440 .data = self.addConstantExtraAssumeCapacity(data.extra),
9441 });
9442 if (self.useLibLlvm()) {
9443 const assembly_slice = assembly.slice(self).?;
9444 const constraints_slice = constraints.slice(self).?;
9445 self.llvm.constants.appendAssumeCapacity(llvm.getInlineAsm(
9446 ty.toLlvm(self),
9447 assembly_slice.ptr,
9448 assembly_slice.len,
9449 constraints_slice.ptr,
9450 constraints_slice.len,
9451 llvm.Bool.fromBool(info.sideeffect),
9452 llvm.Bool.fromBool(info.alignstack),
9453 if (info.inteldialect) .Intel else .ATT,
9454 llvm.Bool.fromBool(info.unwind),
9455 ));
9456 }
9457 }
9458 return @enumFromInt(gop.index);
9459}
9460
7781fn ensureUnusedConstantCapacity(9461fn ensureUnusedConstantCapacity(
7782 self: *Builder,9462 self: *Builder,
7783 count: usize,9463 count: usize,
...@@ -7868,7 +9548,7 @@ fn addConstantExtraAssumeCapacity(self: *Builder, extra: anytype) Constant.Item....@@ -7868,7 +9548,7 @@ fn addConstantExtraAssumeCapacity(self: *Builder, extra: anytype) Constant.Item.
7868 const value = @field(extra, field.name);9548 const value = @field(extra, field.name);
7869 self.constant_extra.appendAssumeCapacity(switch (field.type) {9549 self.constant_extra.appendAssumeCapacity(switch (field.type) {
7870 u32 => value,9550 u32 => value,
7871 Type, Constant, Function.Index, Function.Block.Index => @intFromEnum(value),9551 String, Type, Constant, Function.Index, Function.Block.Index => @intFromEnum(value),
7872 Constant.GetElementPtr.Info => @bitCast(value),9552 Constant.GetElementPtr.Info => @bitCast(value),
7873 else => @compileError("bad field type: " ++ @typeName(field.type)),9553 else => @compileError("bad field type: " ++ @typeName(field.type)),
7874 });9554 });
...@@ -7907,7 +9587,7 @@ fn constantExtraDataTrail(...@@ -7907,7 +9587,7 @@ fn constantExtraDataTrail(
7907 inline for (fields, self.constant_extra.items[index..][0..fields.len]) |field, value|9587 inline for (fields, self.constant_extra.items[index..][0..fields.len]) |field, value|
7908 @field(result, field.name) = switch (field.type) {9588 @field(result, field.name) = switch (field.type) {
7909 u32 => value,9589 u32 => value,
7910 Type, Constant, Function.Index, Function.Block.Index => @enumFromInt(value),9590 String, Type, Constant, Function.Index, Function.Block.Index => @enumFromInt(value),
7911 Constant.GetElementPtr.Info => @bitCast(value),9591 Constant.GetElementPtr.Info => @bitCast(value),
7912 else => @compileError("bad field type: " ++ @typeName(field.type)),9592 else => @compileError("bad field type: " ++ @typeName(field.type)),
7913 };9593 };
src/codegen/llvm/bindings.zig+33-7
...@@ -26,10 +26,13 @@ pub const Context = opaque {...@@ -26,10 +26,13 @@ pub const Context = opaque {
26 extern fn LLVMContextDispose(C: *Context) void;26 extern fn LLVMContextDispose(C: *Context) void;
2727
28 pub const createEnumAttribute = LLVMCreateEnumAttribute;28 pub const createEnumAttribute = LLVMCreateEnumAttribute;
29 extern fn LLVMCreateEnumAttribute(*Context, KindID: c_uint, Val: u64) *Attribute;29 extern fn LLVMCreateEnumAttribute(C: *Context, KindID: c_uint, Val: u64) *Attribute;
30
31 pub const createTypeAttribute = LLVMCreateTypeAttribute;
32 extern fn LLVMCreateTypeAttribute(C: *Context, KindID: c_uint, Type: *Type) *Attribute;
3033
31 pub const createStringAttribute = LLVMCreateStringAttribute;34 pub const createStringAttribute = LLVMCreateStringAttribute;
32 extern fn LLVMCreateStringAttribute(*Context, Key: [*]const u8, Key_Len: c_uint, Value: [*]const u8, Value_Len: c_uint) *Attribute;35 extern fn LLVMCreateStringAttribute(C: *Context, Key: [*]const u8, Key_Len: c_uint, Value: [*]const u8, Value_Len: c_uint) *Attribute;
3336
34 pub const pointerType = LLVMPointerTypeInContext;37 pub const pointerType = LLVMPointerTypeInContext;
35 extern fn LLVMPointerTypeInContext(C: *Context, AddressSpace: c_uint) *Type;38 extern fn LLVMPointerTypeInContext(C: *Context, AddressSpace: c_uint) *Type;
...@@ -309,12 +312,18 @@ pub const Value = opaque {...@@ -309,12 +312,18 @@ pub const Value = opaque {
309 pub const setAlignment = LLVMSetAlignment;312 pub const setAlignment = LLVMSetAlignment;
310 extern fn LLVMSetAlignment(V: *Value, Bytes: c_uint) void;313 extern fn LLVMSetAlignment(V: *Value, Bytes: c_uint) void;
311314
312 pub const getFunctionCallConv = LLVMGetFunctionCallConv;
313 extern fn LLVMGetFunctionCallConv(Fn: *Value) CallConv;
314
315 pub const setFunctionCallConv = LLVMSetFunctionCallConv;315 pub const setFunctionCallConv = LLVMSetFunctionCallConv;
316 extern fn LLVMSetFunctionCallConv(Fn: *Value, CC: CallConv) void;316 extern fn LLVMSetFunctionCallConv(Fn: *Value, CC: CallConv) void;
317317
318 pub const setInstructionCallConv = LLVMSetInstructionCallConv;
319 extern fn LLVMSetInstructionCallConv(Instr: *Value, CC: CallConv) void;
320
321 pub const setTailCallKind = ZigLLVMSetTailCallKind;
322 extern fn ZigLLVMSetTailCallKind(CallInst: *Value, TailCallKind: TailCallKind) void;
323
324 pub const addCallSiteAttribute = LLVMAddCallSiteAttribute;
325 extern fn LLVMAddCallSiteAttribute(C: *Value, Idx: AttributeIndex, A: *Attribute) void;
326
318 pub const fnSetSubprogram = ZigLLVMFnSetSubprogram;327 pub const fnSetSubprogram = ZigLLVMFnSetSubprogram;
319 extern fn ZigLLVMFnSetSubprogram(f: *Value, subprogram: *DISubprogram) void;328 extern fn ZigLLVMFnSetSubprogram(f: *Value, subprogram: *DISubprogram) void;
320329
...@@ -531,7 +540,7 @@ pub const Module = opaque {...@@ -531,7 +540,7 @@ pub const Module = opaque {
531 pub const createDIBuilder = ZigLLVMCreateDIBuilder;540 pub const createDIBuilder = ZigLLVMCreateDIBuilder;
532 extern fn ZigLLVMCreateDIBuilder(module: *Module, allow_unresolved: bool) *DIBuilder;541 extern fn ZigLLVMCreateDIBuilder(module: *Module, allow_unresolved: bool) *DIBuilder;
533542
534 pub const setModuleInlineAsm2 = LLVMSetModuleInlineAsm2;543 pub const setModuleInlineAsm = LLVMSetModuleInlineAsm2;
535 extern fn LLVMSetModuleInlineAsm2(M: *Module, Asm: [*]const u8, Len: usize) void;544 extern fn LLVMSetModuleInlineAsm2(M: *Module, Asm: [*]const u8, Len: usize) void;
536545
537 pub const printModuleToFile = LLVMPrintModuleToFile;546 pub const printModuleToFile = LLVMPrintModuleToFile;
...@@ -642,7 +651,17 @@ pub const Builder = opaque {...@@ -642,7 +651,17 @@ pub const Builder = opaque {
642 Name: [*:0]const u8,651 Name: [*:0]const u8,
643 ) *Value;652 ) *Value;
644653
645 pub const buildCall = ZigLLVMBuildCall;654 pub const buildCall = LLVMBuildCall2;
655 extern fn LLVMBuildCall2(
656 *Builder,
657 *Type,
658 Fn: *Value,
659 Args: [*]const *Value,
660 NumArgs: c_uint,
661 Name: [*:0]const u8,
662 ) *Value;
663
664 pub const buildCallOld = ZigLLVMBuildCall;
646 extern fn ZigLLVMBuildCall(665 extern fn ZigLLVMBuildCall(
647 *Builder,666 *Builder,
648 *Type,667 *Type,
...@@ -1605,6 +1624,13 @@ pub const CallAttr = enum(c_int) {...@@ -1605,6 +1624,13 @@ pub const CallAttr = enum(c_int) {
1605 AlwaysInline,1624 AlwaysInline,
1606};1625};
16071626
1627pub const TailCallKind = enum(c_uint) {
1628 None,
1629 Tail,
1630 MustTail,
1631 NoTail,
1632};
1633
1608pub const DLLStorageClass = enum(c_uint) {1634pub const DLLStorageClass = enum(c_uint) {
1609 Default,1635 Default,
1610 DLLImport,1636 DLLImport,
src/zig_llvm.cpp+4-6
...@@ -453,6 +453,10 @@ LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,...@@ -453,6 +453,10 @@ LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
453 return wrap(call_inst);453 return wrap(call_inst);
454}454}
455455
456ZIG_EXTERN_C void ZigLLVMSetTailCallKind(LLVMValueRef Call, CallInst::TailCallKind TailCallKind) {
457 unwrap<CallInst>(Call)->setTailCallKind(TailCallKind);
458}
459
456void ZigLLVMAddAttributeAtIndex(LLVMValueRef Val, unsigned Idx, LLVMAttributeRef A) {460void ZigLLVMAddAttributeAtIndex(LLVMValueRef Val, unsigned Idx, LLVMAttributeRef A) {
457 if (isa<Function>(unwrap(Val))) {461 if (isa<Function>(unwrap(Val))) {
458 unwrap<Function>(Val)->addAttributeAtIndex(Idx, unwrap(A));462 unwrap<Function>(Val)->addAttributeAtIndex(Idx, unwrap(A));
...@@ -461,7 +465,6 @@ void ZigLLVMAddAttributeAtIndex(LLVMValueRef Val, unsigned Idx, LLVMAttributeRef...@@ -461,7 +465,6 @@ void ZigLLVMAddAttributeAtIndex(LLVMValueRef Val, unsigned Idx, LLVMAttributeRef
461 }465 }
462}466}
463467
464
465LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign,468LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign,
466 LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile)469 LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile)
467{470{
...@@ -1116,11 +1119,6 @@ void ZigLLVMAddFunctionAttr(LLVMValueRef fn_ref, const char *attr_name, const ch...@@ -1116,11 +1119,6 @@ void ZigLLVMAddFunctionAttr(LLVMValueRef fn_ref, const char *attr_name, const ch
1116 func->addFnAttr(attr_name, attr_value);1119 func->addFnAttr(attr_name, attr_value);
1117}1120}
11181121
1119void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn_ref) {
1120 Function *func = unwrap<Function>(fn_ref);
1121 func->addFnAttr(Attribute::Cold);
1122}
1123
1124void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv) {1122void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv) {
1125 cl::ParseCommandLineOptions(argc, argv);1123 cl::ParseCommandLineOptions(argc, argv);
1126}1124}
test/cases.zig+1
...@@ -4,5 +4,6 @@ const Cases = @import("src/Cases.zig");...@@ -4,5 +4,6 @@ const Cases = @import("src/Cases.zig");
4pub fn addCases(cases: *Cases) !void {4pub fn addCases(cases: *Cases) !void {
5 try @import("compile_errors.zig").addCases(cases);5 try @import("compile_errors.zig").addCases(cases);
6 try @import("cbe.zig").addCases(cases);6 try @import("cbe.zig").addCases(cases);
7 try @import("llvm_targets.zig").addCases(cases);
7 try @import("nvptx.zig").addCases(cases);8 try @import("nvptx.zig").addCases(cases);
8}9}
test/llvm_targets.zig created+117
...@@ -0,0 +1,117 @@
1const std = @import("std");
2const Cases = @import("src/Cases.zig");
3
4const targets = [_]std.zig.CrossTarget{
5 .{ .cpu_arch = .aarch64, .os_tag = .freestanding, .abi = .none },
6 .{ .cpu_arch = .aarch64, .os_tag = .linux, .abi = .none },
7 .{ .cpu_arch = .aarch64, .os_tag = .macos, .abi = .none },
8 .{ .cpu_arch = .aarch64, .os_tag = .uefi, .abi = .none },
9 .{ .cpu_arch = .aarch64, .os_tag = .windows, .abi = .gnu },
10 .{ .cpu_arch = .aarch64, .os_tag = .windows, .abi = .msvc },
11 .{ .cpu_arch = .aarch64_be, .os_tag = .freestanding, .abi = .none },
12 .{ .cpu_arch = .aarch64_be, .os_tag = .linux, .abi = .none },
13 .{ .cpu_arch = .aarch64_32, .os_tag = .freestanding, .abi = .none },
14 .{ .cpu_arch = .aarch64_32, .os_tag = .linux, .abi = .none },
15 .{ .cpu_arch = .amdgcn, .os_tag = .amdhsa, .abi = .none },
16 .{ .cpu_arch = .amdgcn, .os_tag = .amdpal, .abi = .none },
17 .{ .cpu_arch = .amdgcn, .os_tag = .linux, .abi = .none },
18 //.{ .cpu_arch = .amdgcn, .os_tag = .mesa3d, .abi = .none },
19 .{ .cpu_arch = .arm, .os_tag = .freestanding, .abi = .none },
20 .{ .cpu_arch = .arm, .os_tag = .linux, .abi = .none },
21 .{ .cpu_arch = .arm, .os_tag = .uefi, .abi = .none },
22 .{ .cpu_arch = .armeb, .os_tag = .freestanding, .abi = .none },
23 .{ .cpu_arch = .armeb, .os_tag = .linux, .abi = .none },
24 .{ .cpu_arch = .avr, .os_tag = .freebsd, .abi = .none },
25 .{ .cpu_arch = .avr, .os_tag = .freestanding, .abi = .none },
26 .{ .cpu_arch = .avr, .os_tag = .linux, .abi = .none },
27 .{ .cpu_arch = .bpfel, .os_tag = .linux, .abi = .gnu },
28 .{ .cpu_arch = .bpfel, .os_tag = .linux, .abi = .none },
29 .{ .cpu_arch = .bpfeb, .os_tag = .linux, .abi = .gnu },
30 .{ .cpu_arch = .bpfeb, .os_tag = .linux, .abi = .none },
31 .{ .cpu_arch = .hexagon, .os_tag = .linux, .abi = .none },
32 .{ .cpu_arch = .mips, .os_tag = .linux, .abi = .gnueabihf },
33 .{ .cpu_arch = .mips, .os_tag = .linux, .abi = .musl },
34 .{ .cpu_arch = .mips, .os_tag = .linux, .abi = .none },
35 .{ .cpu_arch = .mipsel, .os_tag = .linux, .abi = .gnueabihf },
36 .{ .cpu_arch = .mipsel, .os_tag = .linux, .abi = .musl },
37 .{ .cpu_arch = .mipsel, .os_tag = .linux, .abi = .none },
38 .{ .cpu_arch = .mips64, .os_tag = .linux, .abi = .none },
39 .{ .cpu_arch = .mips64el, .os_tag = .linux, .abi = .none },
40 .{ .cpu_arch = .msp430, .os_tag = .freebsd, .abi = .none },
41 .{ .cpu_arch = .msp430, .os_tag = .freestanding, .abi = .none },
42 .{ .cpu_arch = .msp430, .os_tag = .linux, .abi = .none },
43 //.{ .cpu_arch = .nvptx, .os_tag = .cuda, .abi = .none },
44 //.{ .cpu_arch = .nvptx64, .os_tag = .cuda, .abi = .none },
45 .{ .cpu_arch = .powerpc, .os_tag = .freebsd, .abi = .none },
46 .{ .cpu_arch = .powerpc, .os_tag = .freestanding, .abi = .none },
47 .{ .cpu_arch = .powerpc, .os_tag = .linux, .abi = .gnueabihf },
48 .{ .cpu_arch = .powerpc, .os_tag = .linux, .abi = .musl },
49 .{ .cpu_arch = .powerpc, .os_tag = .linux, .abi = .none },
50 .{ .cpu_arch = .powerpcle, .os_tag = .freebsd, .abi = .none },
51 .{ .cpu_arch = .powerpcle, .os_tag = .freestanding, .abi = .none },
52 .{ .cpu_arch = .powerpcle, .os_tag = .linux, .abi = .gnu },
53 .{ .cpu_arch = .powerpcle, .os_tag = .linux, .abi = .musl },
54 .{ .cpu_arch = .powerpcle, .os_tag = .linux, .abi = .none },
55 .{ .cpu_arch = .powerpc64, .os_tag = .freebsd, .abi = .none },
56 .{ .cpu_arch = .powerpc64, .os_tag = .freestanding, .abi = .none },
57 .{ .cpu_arch = .powerpc64, .os_tag = .linux, .abi = .gnu },
58 .{ .cpu_arch = .powerpc64, .os_tag = .linux, .abi = .musl },
59 .{ .cpu_arch = .powerpc64, .os_tag = .linux, .abi = .none },
60 .{ .cpu_arch = .powerpc64le, .os_tag = .freebsd, .abi = .none },
61 .{ .cpu_arch = .powerpc64le, .os_tag = .freestanding, .abi = .none },
62 .{ .cpu_arch = .powerpc64le, .os_tag = .linux, .abi = .gnu },
63 .{ .cpu_arch = .powerpc64le, .os_tag = .linux, .abi = .musl },
64 .{ .cpu_arch = .powerpc64le, .os_tag = .linux, .abi = .none },
65 //.{ .cpu_arch = .r600, .os_tag = .mesa3d, .abi = .none },
66 .{ .cpu_arch = .riscv32, .os_tag = .freestanding, .abi = .none },
67 .{ .cpu_arch = .riscv32, .os_tag = .linux, .abi = .none },
68 .{ .cpu_arch = .riscv64, .os_tag = .freestanding, .abi = .none },
69 .{ .cpu_arch = .riscv64, .os_tag = .linux, .abi = .gnu },
70 .{ .cpu_arch = .riscv64, .os_tag = .linux, .abi = .musl },
71 .{ .cpu_arch = .riscv64, .os_tag = .linux, .abi = .none },
72 .{ .cpu_arch = .s390x, .os_tag = .freestanding, .abi = .none },
73 .{ .cpu_arch = .s390x, .os_tag = .linux, .abi = .gnu },
74 .{ .cpu_arch = .sparc, .os_tag = .freestanding, .abi = .none },
75 .{ .cpu_arch = .sparc, .os_tag = .linux, .abi = .gnu },
76 .{ .cpu_arch = .sparc, .os_tag = .linux, .abi = .none },
77 .{ .cpu_arch = .sparcel, .os_tag = .freestanding, .abi = .none },
78 .{ .cpu_arch = .sparcel, .os_tag = .linux, .abi = .gnu },
79 .{ .cpu_arch = .sparc64, .os_tag = .freestanding, .abi = .none },
80 .{ .cpu_arch = .sparc64, .os_tag = .linux, .abi = .gnu },
81 //.{ .cpu_arch = .spirv32, .os_tag = .opencl, .abi = .none },
82 //.{ .cpu_arch = .spirv32, .os_tag = .glsl450, .abi = .none },
83 //.{ .cpu_arch = .spirv32, .os_tag = .vulkan, .abi = .none },
84 //.{ .cpu_arch = .spirv64, .os_tag = .opencl, .abi = .none },
85 //.{ .cpu_arch = .spirv64, .os_tag = .glsl450, .abi = .none },
86 //.{ .cpu_arch = .spirv64, .os_tag = .vulkan, .abi = .none },
87 .{ .cpu_arch = .thumb, .os_tag = .freestanding, .abi = .none },
88 .{ .cpu_arch = .thumbeb, .os_tag = .freestanding, .abi = .none },
89 .{ .cpu_arch = .ve, .os_tag = .linux, .abi = .none },
90 .{ .cpu_arch = .wasm32, .os_tag = .emscripten, .abi = .none },
91 .{ .cpu_arch = .wasm32, .os_tag = .freestanding, .abi = .none },
92 .{ .cpu_arch = .wasm32, .os_tag = .linux, .abi = .none },
93 .{ .cpu_arch = .wasm32, .os_tag = .wasi, .abi = .none },
94 .{ .cpu_arch = .wasm64, .os_tag = .emscripten, .abi = .none },
95 .{ .cpu_arch = .wasm64, .os_tag = .freestanding, .abi = .none },
96 .{ .cpu_arch = .wasm64, .os_tag = .linux, .abi = .none },
97 .{ .cpu_arch = .wasm64, .os_tag = .wasi, .abi = .none },
98 .{ .cpu_arch = .x86, .os_tag = .freestanding, .abi = .none },
99 .{ .cpu_arch = .x86, .os_tag = .linux, .abi = .none },
100 .{ .cpu_arch = .x86, .os_tag = .uefi, .abi = .none },
101 .{ .cpu_arch = .x86, .os_tag = .windows, .abi = .gnu },
102 .{ .cpu_arch = .x86, .os_tag = .windows, .abi = .msvc },
103 .{ .cpu_arch = .x86_64, .os_tag = .freebsd, .abi = .none },
104 .{ .cpu_arch = .x86_64, .os_tag = .freestanding, .abi = .none },
105 .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .none },
106 .{ .cpu_arch = .x86_64, .os_tag = .macos, .abi = .none },
107 .{ .cpu_arch = .x86_64, .os_tag = .uefi, .abi = .none },
108 .{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu },
109 .{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .msvc },
110};
111
112pub fn addCases(ctx: *Cases) !void {
113 for (targets) |target| {
114 var case = ctx.noEmitUsingLlvmBackend("llvm_targets", target);
115 case.addCompile("");
116 }
117}
test/src/Cases.zig+16
...@@ -76,6 +76,7 @@ pub const Case = struct {...@@ -76,6 +76,7 @@ pub const Case = struct {
76 output_mode: std.builtin.OutputMode,76 output_mode: std.builtin.OutputMode,
77 optimize_mode: std.builtin.Mode = .Debug,77 optimize_mode: std.builtin.Mode = .Debug,
78 updates: std.ArrayList(Update),78 updates: std.ArrayList(Update),
79 emit_bin: bool = true,
79 emit_h: bool = false,80 emit_h: bool = false,
80 is_test: bool = false,81 is_test: bool = false,
81 expect_exact: bool = false,82 expect_exact: bool = false,
...@@ -176,6 +177,19 @@ pub fn exeFromCompiledC(ctx: *Cases, name: []const u8, target: CrossTarget) *Cas...@@ -176,6 +177,19 @@ pub fn exeFromCompiledC(ctx: *Cases, name: []const u8, target: CrossTarget) *Cas
176 return &ctx.cases.items[ctx.cases.items.len - 1];177 return &ctx.cases.items[ctx.cases.items.len - 1];
177}178}
178179
180pub fn noEmitUsingLlvmBackend(ctx: *Cases, name: []const u8, target: CrossTarget) *Case {
181 ctx.cases.append(Case{
182 .name = name,
183 .target = target,
184 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
185 .output_mode = .Obj,
186 .emit_bin = false,
187 .deps = std.ArrayList(DepModule).init(ctx.arena),
188 .backend = .llvm,
189 }) catch @panic("out of memory");
190 return &ctx.cases.items[ctx.cases.items.len - 1];
191}
192
179/// Adds a test case that uses the LLVM backend to emit an executable.193/// Adds a test case that uses the LLVM backend to emit an executable.
180/// Currently this implies linking libc, because only then we can generate a testable executable.194/// Currently this implies linking libc, because only then we can generate a testable executable.
181pub fn exeUsingLlvmBackend(ctx: *Cases, name: []const u8, target: CrossTarget) *Case {195pub fn exeUsingLlvmBackend(ctx: *Cases, name: []const u8, target: CrossTarget) *Case {
...@@ -537,6 +551,8 @@ pub fn lowerToBuildSteps(...@@ -537,6 +551,8 @@ pub fn lowerToBuildSteps(
537 }),551 }),
538 };552 };
539553
554 artifact.emit_bin = if (case.emit_bin) .default else .no_emit;
555
540 if (case.link_libc) artifact.linkLibC();556 if (case.link_libc) artifact.linkLibC();
541557
542 switch (case.backend) {558 switch (case.backend) {