| author | |
| committer | |
| log | d21d1d4ba25701410b9ae99921326f8bfc8a44dd |
| tree | c56738ededf5966ce448e57be393996f76976426 |
| parent | 98c7aec4e4ae7deac5e802a8c592c2d91b6b77af |
| parent | 3fc2e36de2d125b2de255b03abc24bea30899caf |
| signature |
llvm: incremental Builder improvements12 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 | } |
| 425 | 425 | ||
| 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 | } |
| 1999 | 1999 | ||
| 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).?; | ||
| 2009 | 2008 | ||
| 2010 | // Update generated files | 2009 | // 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; |
| 2013 | 2014 | ||
| 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 { |
| 148 | 148 | ||
| 149 | const output_path = try step.evalZigProcess(argv_list.items, prog_node); | 149 | const output_path = try step.evalZigProcess(argv_list.items, prog_node); |
| 150 | 150 | ||
| 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.?).?; |
| 153 | 153 | ||
| 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 usual | 362 | .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 and | 408 | if (!info.force_in_data_layout and matches_default and |
| 410 | self.target.cpu.arch != .riscv64 and !is_aarch64_windows and | 409 | 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 or | 518 | 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)) or | 628 | } 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 or | 672 | .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 | "", // flags | 812 | "", // flags |
| 800 | 0, // runtime version | 813 | 0, // runtime version |
| ... | @@ -830,7 +843,7 @@ pub const Object = struct { | ... | @@ -830,7 +843,7 @@ pub const Object = struct { |
| 830 | 843 | ||
| 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 { |
| 963 | 976 | ||
| 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 | } |
| 969 | 982 | ||
| ... | @@ -1021,15 +1034,11 @@ pub const Object = struct { | ... | @@ -1021,15 +1034,11 @@ pub const Object = struct { |
| 1021 | 1034 | ||
| 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 | } |
| 1034 | 1043 | ||
| 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; |
| 1228 | 1238 | ||
| ... | @@ -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); |
| 1239 | 1249 | ||
| 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 | } |
| 1245 | 1260 | ||
| 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 | } |
| 1252 | 1270 | ||
| 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 | } |
| 1258 | 1278 | ||
| 1259 | // TODO: disable this if safety is off for the function scope | 1279 | // 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 { |
| 1267 | 1292 | ||
| 1268 | // TODO: disable this if safety is off for the function scope | 1293 | // 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 | } |
| 1274 | 1307 | ||
| ... | @@ -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; |
| 1287 | 1320 | ||
| 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; | ||
| 1297 | 1328 | ||
| 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 | }; |
| 1302 | 1339 | ||
| 1303 | const err_return_tracing = fn_info.return_type.toType().isError(mod) and | 1340 | 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 arg | 1349 | // 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 necessarily | 1350 | // 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); |
| 1317 | 1355 | ||
| ... | @@ -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); |
| 1339 | 1377 | ||
| 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)); |
| 1349 | 1387 | ||
| 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; |
| 1352 | 1390 | ||
| 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)); |
| 1364 | 1402 | ||
| 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; |
| 1367 | 1406 | ||
| 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 { |
| 1398 | 1437 | ||
| 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() orelse | 1452 | 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; | ||
| 1416 | 1462 | ||
| 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 | } |
| 1484 | 1530 | ||
| 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; |
| 1487 | 1535 | ||
| ... | @@ -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))); |
| 2817 | 2865 | ||
| 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)); |
| 2820 | 2868 | ||
| 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 | }; |
| 2828 | 2876 | ||
| 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 | } |
| 2845 | 2904 | ||
| 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 0 | 2907 | // 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"); | ||
| 2849 | 2912 | ||
| 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 | } |
| 2853 | 2919 | ||
| 2854 | const err_return_tracing = fn_info.return_type.toType().isError(mod) and | 2920 | 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; |
| 2856 | 2922 | ||
| 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 | } |
| 2860 | 2928 | ||
| 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 | } |
| 2876 | 2948 | ||
| ... | @@ -2880,9 +2952,10 @@ pub const Object = struct { | ... | @@ -2880,9 +2952,10 @@ pub const Object = struct { |
| 2880 | } | 2952 | } |
| 2881 | 2953 | ||
| 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); |
| 2884 | 2956 | ||
| 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 | } |
| 2888 | 2961 | ||
| ... | @@ -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 | } |
| 2926 | 3000 | ||
| 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 | } |
| 2932 | 3008 | ||
| 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; |
| 2935 | 3015 | ||
| 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 or | 3039 | 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 the | 3044 | // 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 stack | 3045 | // 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 | ); |
| 3008 | 3115 | ||
| ... | @@ -4403,47 +4510,114 @@ pub const Object = struct { | ... | @@ -4403,47 +4510,114 @@ pub const Object = struct { |
| 4403 | 4510 | ||
| 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() orelse | 4586 | 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 | } |
| 4434 | 4603 | ||
| 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), |
| 4843 | 5017 | ||
| 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), |
| 4848 | 5022 | ||
| 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 | } |
| 4955 | 5129 | ||
| 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); |
| 4974 | 5156 | ||
| 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(); |
| 4977 | 5159 | ||
| 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 | }; |
| 4985 | 5178 | ||
| ... | @@ -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 | } |
| 4992 | 5185 | ||
| 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 allocate | 5243 | // 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); |
| 5111 | 5304 | ||
| 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 | }; |
| 5133 | 5326 | ||
| 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 { |
| 5186 | 5363 | ||
| 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() orelse | 5375 | 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 | } |
| 5204 | 5383 | ||
| 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 | } |
| 5208 | 5402 | ||
| ... | @@ -5211,9 +5405,7 @@ pub const FuncGen = struct { | ... | @@ -5211,9 +5405,7 @@ pub const FuncGen = struct { |
| 5211 | } | 5405 | } |
| 5212 | 5406 | ||
| 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 trace | 5461 | // 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 | } |
| 5293 | 5484 | ||
| ... | @@ -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)); |
| 5396 | 5587 | ||
| 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)); |
| 5423 | 5614 | ||
| 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)); |
| 5450 | 5641 | ||
| 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 | } |
| 5509 | 5699 | ||
| 5510 | fn cmp( | 5700 | fn cmp( |
| ... | @@ -5953,16 +6143,15 @@ pub const FuncGen = struct { | ... | @@ -5953,16 +6143,15 @@ pub const FuncGen = struct { |
| 5953 | } | 6143 | } |
| 5954 | 6144 | ||
| 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 | } |
| 5967 | 6156 | ||
| 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 { |
| 6013 | 6202 | ||
| 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 | ); |
| 6026 | 6214 | ||
| 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 { |
| 6588 | 6776 | ||
| 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 and | 6780 | // 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('*'); |
| 6630 | 6818 | ||
| 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 | } |
| 6845 | 7033 | ||
| 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 | } | ||
| 6878 | 7054 | ||
| 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); |
| 7820 | 7996 | ||
| 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); |
| 7828 | 8001 | ||
| 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 | }; |
| 7862 | 8032 | ||
| 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)); |
| 7865 | 8035 | ||
| 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 | } |
| 7944 | 8114 | ||
| 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 | } |
| 7961 | 8126 | ||
| ... | @@ -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 | }); |
| 8313 | 8478 | ||
| 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 | } |
| 8327 | 8491 | ||
| ... | @@ -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 | }); |
| 8348 | 8512 | ||
| 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 | } |
| 8362 | 8525 | ||
| ... | @@ -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 { |
| 9283 | 9446 | ||
| 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 { |
| 9331 | 9494 | ||
| 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); |
| 9390 | 9553 | ||
| 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 | } |
| 9403 | 9565 | ||
| 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 | }); |
| 9418 | 9580 | ||
| 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); |
| 9426 | 9591 | ||
| 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); |
| 9471 | 9638 | ||
| 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 | } |
| 9488 | 9650 | ||
| ... | @@ -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)}); |
| 9501 | 9663 | ||
| 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); |
| 9504 | 9669 | ||
| 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); |
| 9512 | 9677 | ||
| 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 { |
| 9561 | 9728 | ||
| 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 | }); |
| 9566 | 9733 | ||
| 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) bool | 9757 | // Function signature: fn (anyerror) bool |
| 9591 | 9758 | ||
| 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); | ||
| 9594 | 9764 | ||
| 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); |
| 9598 | 9768 | ||
| 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 | }; |
| 9607 | 9779 | ||
| 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); |
| 9748 | 9916 | ||
| ... | @@ -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 { |
| 10222 | 10390 | ||
| 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); |
| 10254 | 10422 | ||
| 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#L2913 | 10427 | // 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); |
| 10270 | 10444 | ||
| 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 space | 10472 | const undef_init = try o.builder.undefConst(.ptr); // TODO: Address space |
| 10299 | 10473 | ||
| 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 | ); |
| 10752 | 10926 | ||
| 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 | } |
| 10993 | 11167 | ||
| 10994 | fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.CallConv { | 11168 | fn 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, |
| 4 | 4 | ||
| 5 | llvm: if (build_options.have_llvm) struct { | 5 | llvm: 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, |
| 15 | 17 | ||
| 16 | source_filename: String, | 18 | source_filename: String, |
| 17 | data_layout: String, | 19 | data_layout: String, |
| 18 | target_triple: String, | 20 | target_triple: String, |
| 21 | module_asm: std.ArrayListUnmanaged(u8), | ||
| 19 | 22 | ||
| 20 | string_map: std.AutoArrayHashMapUnmanaged(void, void), | 23 | string_map: std.AutoArrayHashMapUnmanaged(void, void), |
| 21 | string_bytes: std.ArrayListUnmanaged(u8), | ||
| 22 | string_indices: std.ArrayListUnmanaged(u32), | 24 | string_indices: std.ArrayListUnmanaged(u32), |
| 25 | string_bytes: std.ArrayListUnmanaged(u8), | ||
| 23 | 26 | ||
| 24 | types: std.AutoArrayHashMapUnmanaged(String, Type), | 27 | types: std.AutoArrayHashMapUnmanaged(String, Type), |
| 25 | next_unnamed_type: String, | 28 | next_unnamed_type: String, |
| ... | @@ -28,6 +31,11 @@ type_map: std.AutoArrayHashMapUnmanaged(void, void), | ... | @@ -28,6 +31,11 @@ type_map: std.AutoArrayHashMapUnmanaged(void, void), |
| 28 | type_items: std.ArrayListUnmanaged(Type.Item), | 31 | type_items: std.ArrayListUnmanaged(Type.Item), |
| 29 | type_extra: std.ArrayListUnmanaged(u32), | 32 | type_extra: std.ArrayListUnmanaged(u32), |
| 30 | 33 | ||
| 34 | attributes: std.AutoArrayHashMapUnmanaged(Attribute.Storage, void), | ||
| 35 | attributes_map: std.AutoArrayHashMapUnmanaged(void, void), | ||
| 36 | attributes_indices: std.ArrayListUnmanaged(u32), | ||
| 37 | attributes_extra: std.ArrayListUnmanaged(u32), | ||
| 38 | |||
| 31 | globals: std.AutoArrayHashMapUnmanaged(String, Global), | 39 | globals: std.AutoArrayHashMapUnmanaged(String, Global), |
| 32 | next_unnamed_global: String, | 40 | next_unnamed_global: String, |
| 33 | next_replaced_global: String, | 41 | next_replaced_global: String, |
| ... | @@ -41,6 +49,7 @@ constant_items: std.MultiArrayList(Constant.Item), | ... | @@ -41,6 +49,7 @@ constant_items: std.MultiArrayList(Constant.Item), |
| 41 | constant_extra: std.ArrayListUnmanaged(u32), | 49 | constant_extra: std.ArrayListUnmanaged(u32), |
| 42 | constant_limbs: std.ArrayListUnmanaged(std.math.big.Limb), | 50 | constant_limbs: std.ArrayListUnmanaged(std.math.big.Limb), |
| 43 | 51 | ||
| 52 | pub const expected_args_len = 16; | ||
| 44 | pub const expected_fields_len = 32; | 53 | pub const expected_fields_len = 32; |
| 45 | pub const expected_gep_indices_len = 8; | 54 | pub const expected_gep_indices_len = 8; |
| 46 | pub const expected_cases_len = 8; | 55 | pub 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 | } |
| 67 | 76 | ||
| 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) orelse | 97 | 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) or | 102 | .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 | } |
| 292 | 296 | ||
| 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 | }; |
| 825 | 840 | ||
| 841 | pub 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 | |||
| 1485 | pub 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 | |||
| 1515 | pub 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 | |||
| 826 | pub const Linkage = enum { | 1684 | pub 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 | }; |
| 1055 | 1913 | ||
| 1914 | pub 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 | |||
| 1056 | pub const Global = struct { | 2035 | pub 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 | } |
| 1176 | 2155 | ||
| ... | @@ -1301,6 +2280,8 @@ pub const Variable = struct { | ... | @@ -1301,6 +2280,8 @@ pub const Variable = struct { |
| 1301 | 2280 | ||
| 1302 | pub const Function = struct { | 2281 | pub 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 | else | 2976 | else |
| 1958 | wip.names.items[@intFromEnum(self)].toSlice(wip.builder).?; | 2977 | wip.names.items[@intFromEnum(self)].slice(wip.builder).?; |
| 1959 | } | 2978 | } |
| 1960 | }; | 2979 | }; |
| 1961 | 2980 | ||
| ... | @@ -2063,6 +3082,30 @@ pub const Function = struct { | ... | @@ -2063,6 +3082,30 @@ pub const Function = struct { |
| 2063 | rhs: Value, | 3082 | rhs: Value, |
| 2064 | }; | 3083 | }; |
| 2065 | 3084 | ||
| 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 | } |
| 3164 | 4216 | ||
| 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 | } |
| 3257 | 4414 | ||
| 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 | } |
| 3264 | 4422 | ||
| 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) { |
| 4092 | 5288 | ||
| 4093 | const first_global: Constant = @enumFromInt(1 << 30); | 5289 | const first_global: Constant = @enumFromInt(1 << 30); |
| 4094 | 5290 | ||
| 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 | }; |
| 4156 | 5368 | ||
| 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 | }; |
| 4249 | 5461 | ||
| 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 = .{}, | ||
| 4822 | 6089 | ||
| 4823 | .string_map = .{}, | 6090 | .string_map = .{}, |
| 4824 | .string_bytes = .{}, | ||
| 4825 | .string_indices = .{}, | 6091 | .string_indices = .{}, |
| 6092 | .string_bytes = .{}, | ||
| 4826 | 6093 | ||
| 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 = .{}, |
| 4833 | 6100 | ||
| 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(); |
| 4849 | 6132 | ||
| 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 | ); |
| 4859 | 6142 | ||
| ... | @@ -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); |
| 4872 | 6155 | ||
| 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 | } |
| 4883 | 6166 | ||
| ... | @@ -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 | } |
| 4904 | 6187 | ||
| 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 | } |
| 4911 | 6204 | ||
| 4912 | pub fn deinit(self: *Builder) void { | 6205 | pub 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); | ||
| 4916 | 6211 | ||
| 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); |
| 4922 | 6217 | ||
| 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 | } |
| 5138 | 6440 | ||
| 6441 | pub fn setModuleAsm(self: *Builder) std.ArrayListUnmanaged(u8).Writer { | ||
| 6442 | self.module_asm.clearRetainingCapacity(); | ||
| 6443 | return self.appendModuleAsm(); | ||
| 6444 | } | ||
| 6445 | |||
| 6446 | pub fn appendModuleAsm(self: *Builder) std.ArrayListUnmanaged(u8).Writer { | ||
| 6447 | return self.module_asm.writer(self.gpa); | ||
| 6448 | } | ||
| 6449 | |||
| 6450 | pub 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 | |||
| 5139 | pub fn string(self: *Builder, bytes: []const u8) Allocator.Error!String { | 6457 | pub 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( |
| 5230 | 6548 | ||
| 5231 | pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type { | 6549 | pub 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 | } |
| 5270 | 6588 | ||
| 6589 | pub 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 | |||
| 6661 | pub 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 | |||
| 6673 | pub 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 | |||
| 5271 | pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index { | 6682 | pub 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 |
| 5295 | 6706 | ||
| 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 | } |
| 5723 | 7135 | ||
| 7136 | pub 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 | |||
| 7147 | pub 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 | |||
| 5724 | pub fn dump(self: *Builder) void { | 7157 | pub 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 | } |
| 6222 | 7802 | ||
| ... | @@ -6227,7 +7807,7 @@ pub inline fn useLibLlvm(self: *const Builder) bool { | ... | @@ -6227,7 +7807,7 @@ pub inline fn useLibLlvm(self: *const Builder) bool { |
| 6227 | const NoExtra = struct {}; | 7807 | const NoExtra = struct {}; |
| 6228 | 7808 | ||
| 6229 | fn isValidIdentifier(id: []const u8) bool { | 7809 | fn 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 | } |
| 6237 | 7817 | ||
| 7818 | const QuoteBehavior = enum { always_quote, quote_unless_valid_identifier }; | ||
| 7819 | fn 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 | |||
| 6238 | fn ensureUnusedGlobalCapacity(self: *Builder, name: String) Allocator.Error!void { | 7837 | fn 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 | } |
| 6535 | 8134 | ||
| 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 | } |
| 6638 | 8237 | ||
| 8238 | fn 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 | |||
| 6639 | fn bigIntConstAssumeCapacity( | 8262 | fn 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 | } |
| 7074 | 8697 | ||
| 7075 | fn stringConstAssumeCapacity(self: *Builder, val: String) Constant { | 8698 | fn 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 | } |
| 7087 | 8710 | ||
| 7088 | fn stringNullConstAssumeCapacity(self: *Builder, val: String) Constant { | 8711 | fn 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 | } |
| 7780 | 9403 | ||
| 9404 | fn 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 | |||
| 7781 | fn ensureUnusedConstantCapacity( | 9461 | fn 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; |
| 27 | 27 | ||
| 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; | ||
| 30 | 33 | ||
| 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; |
| 33 | 36 | ||
| 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; |
| 311 | 314 | ||
| 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; |
| 317 | 317 | ||
| 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; |
| 320 | 329 | ||
| ... | @@ -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; |
| 533 | 542 | ||
| 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; |
| 536 | 545 | ||
| 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; |
| 644 | 653 | ||
| 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 | }; |
| 1607 | 1626 | ||
| 1627 | pub const TailCallKind = enum(c_uint) { | ||
| 1628 | None, | ||
| 1629 | Tail, | ||
| 1630 | MustTail, | ||
| 1631 | NoTail, | ||
| 1632 | }; | ||
| 1633 | |||
| 1608 | pub const DLLStorageClass = enum(c_uint) { | 1634 | pub 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 | } |
| 455 | 455 | ||
| 456 | ZIG_EXTERN_C void ZigLLVMSetTailCallKind(LLVMValueRef Call, CallInst::TailCallKind TailCallKind) { | ||
| 457 | unwrap<CallInst>(Call)->setTailCallKind(TailCallKind); | ||
| 458 | } | ||
| 459 | |||
| 456 | void ZigLLVMAddAttributeAtIndex(LLVMValueRef Val, unsigned Idx, LLVMAttributeRef A) { | 460 | void 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 | } |
| 463 | 467 | ||
| 464 | |||
| 465 | LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign, | 468 | LLVMValueRef 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 | } |
| 1118 | 1121 | ||
| 1119 | void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn_ref) { | ||
| 1120 | Function *func = unwrap<Function>(fn_ref); | ||
| 1121 | func->addFnAttr(Attribute::Cold); | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv) { | 1122 | void 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"); |
| 4 | pub fn addCases(cases: *Cases) !void { | 4 | pub 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 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const Cases = @import("src/Cases.zig"); | ||
| 3 | |||
| 4 | const 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 | |||
| 112 | pub 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 | } |
| 178 | 179 | ||
| 180 | pub 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. |
| 181 | pub fn exeUsingLlvmBackend(ctx: *Cases, name: []const u8, target: CrossTarget) *Case { | 195 | pub 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 | }; |
| 539 | 553 | ||
| 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(); |
| 541 | 557 | ||
| 542 | switch (case.backend) { | 558 | switch (case.backend) { |