| author | |
| committer | |
| log | 2ccaa5414b904edb2f4af293291f5401d106f277 |
| tree | d587757486c1ae205629c48540b66858ec6fb62a |
| parent | 7d674d5fb664b6e2d4d3d5b85751ed464dc4c4b9 |
| parent | 150786e83c705a34e16f031b7848a440946b2ef9 |
| signature |
More ABI size and alignment fixes22 files changed, 266 insertions(+), 156 deletions(-)
lib/std/target.zig+24-23| ... | @@ -9,6 +9,7 @@ pub const Target = struct { | ... | @@ -9,6 +9,7 @@ pub const Target = struct { |
| 9 | cpu: Cpu, | 9 | cpu: Cpu, |
| 10 | os: Os, | 10 | os: Os, |
| 11 | abi: Abi, | 11 | abi: Abi, |
| 12 | ofmt: ObjectFormat, | ||
| 12 | 13 | ||
| 13 | pub const Os = struct { | 14 | pub const Os = struct { |
| 14 | tag: Tag, | 15 | tag: Tag, |
| ... | @@ -594,6 +595,20 @@ pub const Target = struct { | ... | @@ -594,6 +595,20 @@ pub const Target = struct { |
| 594 | .nvptx => ".ptx", | 595 | .nvptx => ".ptx", |
| 595 | }; | 596 | }; |
| 596 | } | 597 | } |
| 598 | |||
| 599 | pub fn default(os_tag: Os.Tag, cpu_arch: Cpu.Arch) ObjectFormat { | ||
| 600 | return switch (os_tag) { | ||
| 601 | .windows, .uefi => .coff, | ||
| 602 | .ios, .macos, .watchos, .tvos => .macho, | ||
| 603 | .plan9 => .plan9, | ||
| 604 | else => return switch (cpu_arch) { | ||
| 605 | .wasm32, .wasm64 => .wasm, | ||
| 606 | .spirv32, .spirv64 => .spirv, | ||
| 607 | .nvptx, .nvptx64 => .nvptx, | ||
| 608 | else => .elf, | ||
| 609 | }, | ||
| 610 | }; | ||
| 611 | } | ||
| 597 | }; | 612 | }; |
| 598 | 613 | ||
| 599 | pub const SubSystem = enum { | 614 | pub const SubSystem = enum { |
| ... | @@ -1381,24 +1396,6 @@ pub const Target = struct { | ... | @@ -1381,24 +1396,6 @@ pub const Target = struct { |
| 1381 | return libPrefix_os_abi(self.os.tag, self.abi); | 1396 | return libPrefix_os_abi(self.os.tag, self.abi); |
| 1382 | } | 1397 | } |
| 1383 | 1398 | ||
| 1384 | pub fn getObjectFormatSimple(os_tag: Os.Tag, cpu_arch: Cpu.Arch) ObjectFormat { | ||
| 1385 | return switch (os_tag) { | ||
| 1386 | .windows, .uefi => .coff, | ||
| 1387 | .ios, .macos, .watchos, .tvos => .macho, | ||
| 1388 | .plan9 => .plan9, | ||
| 1389 | else => return switch (cpu_arch) { | ||
| 1390 | .wasm32, .wasm64 => .wasm, | ||
| 1391 | .spirv32, .spirv64 => .spirv, | ||
| 1392 | .nvptx, .nvptx64 => .nvptx, | ||
| 1393 | else => .elf, | ||
| 1394 | }, | ||
| 1395 | }; | ||
| 1396 | } | ||
| 1397 | |||
| 1398 | pub fn getObjectFormat(self: Target) ObjectFormat { | ||
| 1399 | return getObjectFormatSimple(self.os.tag, self.cpu.arch); | ||
| 1400 | } | ||
| 1401 | |||
| 1402 | pub fn isMinGW(self: Target) bool { | 1399 | pub fn isMinGW(self: Target) bool { |
| 1403 | return self.os.tag == .windows and self.isGnu(); | 1400 | return self.os.tag == .windows and self.isGnu(); |
| 1404 | } | 1401 | } |
| ... | @@ -1806,24 +1803,28 @@ pub const Target = struct { | ... | @@ -1806,24 +1803,28 @@ pub const Target = struct { |
| 1806 | else => 4, | 1803 | else => 4, |
| 1807 | }, | 1804 | }, |
| 1808 | 1805 | ||
| 1809 | // For x86_64, LLVMABIAlignmentOfType(i128) reports 8. However I think 16 | 1806 | // For these, LLVMABIAlignmentOfType(i128) reports 8. Note that 16 |
| 1810 | // is a better number for two reasons: | 1807 | // is a relevant number in three cases: |
| 1811 | // 1. Better machine code when loading into SIMD register. | 1808 | // 1. Different machine code instruction when loading into SIMD register. |
| 1812 | // 2. The C ABI wants 16 for extern structs. | 1809 | // 2. The C ABI wants 16 for extern structs. |
| 1813 | // 3. 16-byte cmpxchg needs 16-byte alignment. | 1810 | // 3. 16-byte cmpxchg needs 16-byte alignment. |
| 1814 | // Same logic for riscv64, powerpc64, mips64, sparc64. | 1811 | // Same logic for powerpc64, mips64, sparc64. |
| 1815 | .x86_64, | 1812 | .x86_64, |
| 1816 | .riscv64, | ||
| 1817 | .powerpc64, | 1813 | .powerpc64, |
| 1818 | .powerpc64le, | 1814 | .powerpc64le, |
| 1819 | .mips64, | 1815 | .mips64, |
| 1820 | .mips64el, | 1816 | .mips64el, |
| 1821 | .sparc64, | 1817 | .sparc64, |
| 1818 | => return switch (target.ofmt) { | ||
| 1819 | .c => 16, | ||
| 1820 | else => 8, | ||
| 1821 | }, | ||
| 1822 | 1822 | ||
| 1823 | // Even LLVMABIAlignmentOfType(i128) agrees on these targets. | 1823 | // Even LLVMABIAlignmentOfType(i128) agrees on these targets. |
| 1824 | .aarch64, | 1824 | .aarch64, |
| 1825 | .aarch64_be, | 1825 | .aarch64_be, |
| 1826 | .aarch64_32, | 1826 | .aarch64_32, |
| 1827 | .riscv64, | ||
| 1827 | .bpfel, | 1828 | .bpfel, |
| 1828 | .bpfeb, | 1829 | .bpfeb, |
| 1829 | .nvptx, | 1830 | .nvptx, |
lib/std/zig.zig+7-5| ... | @@ -103,7 +103,6 @@ pub const BinNameOptions = struct { | ... | @@ -103,7 +103,6 @@ pub const BinNameOptions = struct { |
| 103 | target: std.Target, | 103 | target: std.Target, |
| 104 | output_mode: std.builtin.OutputMode, | 104 | output_mode: std.builtin.OutputMode, |
| 105 | link_mode: ?std.builtin.LinkMode = null, | 105 | link_mode: ?std.builtin.LinkMode = null, |
| 106 | object_format: ?std.Target.ObjectFormat = null, | ||
| 107 | version: ?std.builtin.Version = null, | 106 | version: ?std.builtin.Version = null, |
| 108 | }; | 107 | }; |
| 109 | 108 | ||
| ... | @@ -111,8 +110,7 @@ pub const BinNameOptions = struct { | ... | @@ -111,8 +110,7 @@ pub const BinNameOptions = struct { |
| 111 | pub fn binNameAlloc(allocator: std.mem.Allocator, options: BinNameOptions) error{OutOfMemory}![]u8 { | 110 | pub fn binNameAlloc(allocator: std.mem.Allocator, options: BinNameOptions) error{OutOfMemory}![]u8 { |
| 112 | const root_name = options.root_name; | 111 | const root_name = options.root_name; |
| 113 | const target = options.target; | 112 | const target = options.target; |
| 114 | const ofmt = options.object_format orelse target.getObjectFormat(); | 113 | switch (target.ofmt) { |
| 115 | switch (ofmt) { | ||
| 116 | .coff => switch (options.output_mode) { | 114 | .coff => switch (options.output_mode) { |
| 117 | .Exe => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.exeFileExt() }), | 115 | .Exe => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.exeFileExt() }), |
| 118 | .Lib => { | 116 | .Lib => { |
| ... | @@ -186,8 +184,12 @@ pub fn binNameAlloc(allocator: std.mem.Allocator, options: BinNameOptions) error | ... | @@ -186,8 +184,12 @@ pub fn binNameAlloc(allocator: std.mem.Allocator, options: BinNameOptions) error |
| 186 | .raw => return std.fmt.allocPrint(allocator, "{s}.bin", .{root_name}), | 184 | .raw => return std.fmt.allocPrint(allocator, "{s}.bin", .{root_name}), |
| 187 | .plan9 => switch (options.output_mode) { | 185 | .plan9 => switch (options.output_mode) { |
| 188 | .Exe => return allocator.dupe(u8, root_name), | 186 | .Exe => return allocator.dupe(u8, root_name), |
| 189 | .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, ofmt.fileExt(target.cpu.arch) }), | 187 | .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ |
| 190 | .Lib => return std.fmt.allocPrint(allocator, "{s}{s}.a", .{ target.libPrefix(), root_name }), | 188 | root_name, target.ofmt.fileExt(target.cpu.arch), |
| 189 | }), | ||
| 190 | .Lib => return std.fmt.allocPrint(allocator, "{s}{s}.a", .{ | ||
| 191 | target.libPrefix(), root_name, | ||
| 192 | }), | ||
| 191 | }, | 193 | }, |
| 192 | .nvptx => return std.fmt.allocPrint(allocator, "{s}", .{root_name}), | 194 | .nvptx => return std.fmt.allocPrint(allocator, "{s}", .{root_name}), |
| 193 | } | 195 | } |
lib/std/zig/CrossTarget.zig+12-1| ... | @@ -42,6 +42,9 @@ abi: ?Target.Abi = null, | ... | @@ -42,6 +42,9 @@ abi: ?Target.Abi = null, |
| 42 | /// based on the `os_tag`. | 42 | /// based on the `os_tag`. |
| 43 | dynamic_linker: DynamicLinker = DynamicLinker{}, | 43 | dynamic_linker: DynamicLinker = DynamicLinker{}, |
| 44 | 44 | ||
| 45 | /// `null` means default for the cpu/arch/os combo. | ||
| 46 | ofmt: ?Target.ObjectFormat = null, | ||
| 47 | |||
| 45 | pub const CpuModel = union(enum) { | 48 | pub const CpuModel = union(enum) { |
| 46 | /// Always native | 49 | /// Always native |
| 47 | native, | 50 | native, |
| ... | @@ -168,6 +171,7 @@ pub fn toTarget(self: CrossTarget) Target { | ... | @@ -168,6 +171,7 @@ pub fn toTarget(self: CrossTarget) Target { |
| 168 | .cpu = self.getCpu(), | 171 | .cpu = self.getCpu(), |
| 169 | .os = self.getOs(), | 172 | .os = self.getOs(), |
| 170 | .abi = self.getAbi(), | 173 | .abi = self.getAbi(), |
| 174 | .ofmt = self.getObjectFormat(), | ||
| 171 | }; | 175 | }; |
| 172 | } | 176 | } |
| 173 | 177 | ||
| ... | @@ -197,6 +201,8 @@ pub const ParseOptions = struct { | ... | @@ -197,6 +201,8 @@ pub const ParseOptions = struct { |
| 197 | /// detected path, or a standard path. | 201 | /// detected path, or a standard path. |
| 198 | dynamic_linker: ?[]const u8 = null, | 202 | dynamic_linker: ?[]const u8 = null, |
| 199 | 203 | ||
| 204 | object_format: ?[]const u8 = null, | ||
| 205 | |||
| 200 | /// If this is provided, the function will populate some information about parsing failures, | 206 | /// If this is provided, the function will populate some information about parsing failures, |
| 201 | /// so that user-friendly error messages can be delivered. | 207 | /// so that user-friendly error messages can be delivered. |
| 202 | diagnostics: ?*Diagnostics = null, | 208 | diagnostics: ?*Diagnostics = null, |
| ... | @@ -321,6 +327,11 @@ pub fn parse(args: ParseOptions) !CrossTarget { | ... | @@ -321,6 +327,11 @@ pub fn parse(args: ParseOptions) !CrossTarget { |
| 321 | } | 327 | } |
| 322 | } | 328 | } |
| 323 | 329 | ||
| 330 | if (args.object_format) |ofmt_name| { | ||
| 331 | result.ofmt = std.meta.stringToEnum(Target.ObjectFormat, ofmt_name) orelse | ||
| 332 | return error.UnknownObjectFormat; | ||
| 333 | } | ||
| 334 | |||
| 324 | return result; | 335 | return result; |
| 325 | } | 336 | } |
| 326 | 337 | ||
| ... | @@ -620,7 +631,7 @@ pub fn setGnuLibCVersion(self: *CrossTarget, major: u32, minor: u32, patch: u32) | ... | @@ -620,7 +631,7 @@ pub fn setGnuLibCVersion(self: *CrossTarget, major: u32, minor: u32, patch: u32) |
| 620 | } | 631 | } |
| 621 | 632 | ||
| 622 | pub fn getObjectFormat(self: CrossTarget) Target.ObjectFormat { | 633 | pub fn getObjectFormat(self: CrossTarget) Target.ObjectFormat { |
| 623 | return Target.getObjectFormatSimple(self.getOsTag(), self.getCpuArch()); | 634 | return self.ofmt orelse Target.ObjectFormat.default(self.getOsTag(), self.getCpuArch()); |
| 624 | } | 635 | } |
| 625 | 636 | ||
| 626 | pub fn updateCpuFeatures(self: CrossTarget, set: *Target.Cpu.Feature.Set) void { | 637 | pub fn updateCpuFeatures(self: CrossTarget, set: *Target.Cpu.Feature.Set) void { |
lib/std/zig/system/NativeTargetInfo.zig+5| ... | @@ -276,6 +276,7 @@ fn detectAbiAndDynamicLinker( | ... | @@ -276,6 +276,7 @@ fn detectAbiAndDynamicLinker( |
| 276 | }; | 276 | }; |
| 277 | var ld_info_list_buffer: [all_abis.len]LdInfo = undefined; | 277 | var ld_info_list_buffer: [all_abis.len]LdInfo = undefined; |
| 278 | var ld_info_list_len: usize = 0; | 278 | var ld_info_list_len: usize = 0; |
| 279 | const ofmt = cross_target.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch); | ||
| 279 | 280 | ||
| 280 | for (all_abis) |abi| { | 281 | for (all_abis) |abi| { |
| 281 | // This may be a nonsensical parameter. We detect this with error.UnknownDynamicLinkerPath and | 282 | // This may be a nonsensical parameter. We detect this with error.UnknownDynamicLinkerPath and |
| ... | @@ -284,6 +285,7 @@ fn detectAbiAndDynamicLinker( | ... | @@ -284,6 +285,7 @@ fn detectAbiAndDynamicLinker( |
| 284 | .cpu = cpu, | 285 | .cpu = cpu, |
| 285 | .os = os, | 286 | .os = os, |
| 286 | .abi = abi, | 287 | .abi = abi, |
| 288 | .ofmt = ofmt, | ||
| 287 | }; | 289 | }; |
| 288 | const ld = target.standardDynamicLinkerPath(); | 290 | const ld = target.standardDynamicLinkerPath(); |
| 289 | if (ld.get() == null) continue; | 291 | if (ld.get() == null) continue; |
| ... | @@ -346,6 +348,7 @@ fn detectAbiAndDynamicLinker( | ... | @@ -346,6 +348,7 @@ fn detectAbiAndDynamicLinker( |
| 346 | .cpu = cpu, | 348 | .cpu = cpu, |
| 347 | .os = os_adjusted, | 349 | .os = os_adjusted, |
| 348 | .abi = cross_target.abi orelse found_ld_info.abi, | 350 | .abi = cross_target.abi orelse found_ld_info.abi, |
| 351 | .ofmt = cross_target.ofmt orelse Target.ObjectFormat.default(os_adjusted.tag, cpu.arch), | ||
| 349 | }, | 352 | }, |
| 350 | .dynamic_linker = if (cross_target.dynamic_linker.get() == null) | 353 | .dynamic_linker = if (cross_target.dynamic_linker.get() == null) |
| 351 | DynamicLinker.init(found_ld_path) | 354 | DynamicLinker.init(found_ld_path) |
| ... | @@ -539,6 +542,7 @@ pub fn abiAndDynamicLinkerFromFile( | ... | @@ -539,6 +542,7 @@ pub fn abiAndDynamicLinkerFromFile( |
| 539 | .cpu = cpu, | 542 | .cpu = cpu, |
| 540 | .os = os, | 543 | .os = os, |
| 541 | .abi = cross_target.abi orelse Target.Abi.default(cpu.arch, os), | 544 | .abi = cross_target.abi orelse Target.Abi.default(cpu.arch, os), |
| 545 | .ofmt = cross_target.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch), | ||
| 542 | }, | 546 | }, |
| 543 | .dynamic_linker = cross_target.dynamic_linker, | 547 | .dynamic_linker = cross_target.dynamic_linker, |
| 544 | }; | 548 | }; |
| ... | @@ -829,6 +833,7 @@ fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, cross_target: Cros | ... | @@ -829,6 +833,7 @@ fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, cross_target: Cros |
| 829 | .cpu = cpu, | 833 | .cpu = cpu, |
| 830 | .os = os, | 834 | .os = os, |
| 831 | .abi = cross_target.abi orelse Target.Abi.default(cpu.arch, os), | 835 | .abi = cross_target.abi orelse Target.Abi.default(cpu.arch, os), |
| 836 | .ofmt = cross_target.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch), | ||
| 832 | }; | 837 | }; |
| 833 | return NativeTargetInfo{ | 838 | return NativeTargetInfo{ |
| 834 | .target = target, | 839 | .target = target, |
src/Compilation.zig+15-15| ... | @@ -810,7 +810,6 @@ pub const InitOptions = struct { | ... | @@ -810,7 +810,6 @@ pub const InitOptions = struct { |
| 810 | /// this flag would be set to disable this machinery to avoid false positives. | 810 | /// this flag would be set to disable this machinery to avoid false positives. |
| 811 | disable_lld_caching: bool = false, | 811 | disable_lld_caching: bool = false, |
| 812 | cache_mode: CacheMode = .incremental, | 812 | cache_mode: CacheMode = .incremental, |
| 813 | object_format: ?std.Target.ObjectFormat = null, | ||
| 814 | optimize_mode: std.builtin.Mode = .Debug, | 813 | optimize_mode: std.builtin.Mode = .Debug, |
| 815 | keep_source_files_loaded: bool = false, | 814 | keep_source_files_loaded: bool = false, |
| 816 | clang_argv: []const []const u8 = &[0][]const u8{}, | 815 | clang_argv: []const []const u8 = &[0][]const u8{}, |
| ... | @@ -1027,8 +1026,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { | ... | @@ -1027,8 +1026,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1027 | const comp = try arena.create(Compilation); | 1026 | const comp = try arena.create(Compilation); |
| 1028 | const root_name = try arena.dupeZ(u8, options.root_name); | 1027 | const root_name = try arena.dupeZ(u8, options.root_name); |
| 1029 | 1028 | ||
| 1030 | const ofmt = options.object_format orelse options.target.getObjectFormat(); | ||
| 1031 | |||
| 1032 | const use_stage1 = options.use_stage1 orelse blk: { | 1029 | const use_stage1 = options.use_stage1 orelse blk: { |
| 1033 | // Even though we may have no Zig code to compile (depending on `options.main_pkg`), | 1030 | // Even though we may have no Zig code to compile (depending on `options.main_pkg`), |
| 1034 | // we may need to use stage1 for building compiler-rt and other dependencies. | 1031 | // we may need to use stage1 for building compiler-rt and other dependencies. |
| ... | @@ -1042,7 +1039,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { | ... | @@ -1042,7 +1039,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1042 | } | 1039 | } |
| 1043 | 1040 | ||
| 1044 | // If LLVM does not support the target, then we can't use it. | 1041 | // If LLVM does not support the target, then we can't use it. |
| 1045 | if (!target_util.hasLlvmSupport(options.target, ofmt)) | 1042 | if (!target_util.hasLlvmSupport(options.target, options.target.ofmt)) |
| 1046 | break :blk false; | 1043 | break :blk false; |
| 1047 | 1044 | ||
| 1048 | break :blk build_options.is_stage1; | 1045 | break :blk build_options.is_stage1; |
| ... | @@ -1072,7 +1069,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { | ... | @@ -1072,7 +1069,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1072 | break :blk true; | 1069 | break :blk true; |
| 1073 | 1070 | ||
| 1074 | // If LLVM does not support the target, then we can't use it. | 1071 | // If LLVM does not support the target, then we can't use it. |
| 1075 | if (!target_util.hasLlvmSupport(options.target, ofmt)) | 1072 | if (!target_util.hasLlvmSupport(options.target, options.target.ofmt)) |
| 1076 | break :blk false; | 1073 | break :blk false; |
| 1077 | 1074 | ||
| 1078 | // Prefer LLVM for release builds. | 1075 | // Prefer LLVM for release builds. |
| ... | @@ -1115,7 +1112,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { | ... | @@ -1115,7 +1112,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1115 | if (!build_options.have_llvm) | 1112 | if (!build_options.have_llvm) |
| 1116 | break :blk false; | 1113 | break :blk false; |
| 1117 | 1114 | ||
| 1118 | if (ofmt == .c) | 1115 | if (options.target.ofmt == .c) |
| 1119 | break :blk false; | 1116 | break :blk false; |
| 1120 | 1117 | ||
| 1121 | if (options.want_lto) |lto| { | 1118 | if (options.want_lto) |lto| { |
| ... | @@ -1374,7 +1371,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { | ... | @@ -1374,7 +1371,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1374 | cache.hash.add(options.target.os.getVersionRange()); | 1371 | cache.hash.add(options.target.os.getVersionRange()); |
| 1375 | cache.hash.add(options.is_native_os); | 1372 | cache.hash.add(options.is_native_os); |
| 1376 | cache.hash.add(options.target.abi); | 1373 | cache.hash.add(options.target.abi); |
| 1377 | cache.hash.add(ofmt); | 1374 | cache.hash.add(options.target.ofmt); |
| 1378 | cache.hash.add(pic); | 1375 | cache.hash.add(pic); |
| 1379 | cache.hash.add(pie); | 1376 | cache.hash.add(pie); |
| 1380 | cache.hash.add(lto); | 1377 | cache.hash.add(lto); |
| ... | @@ -1682,7 +1679,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { | ... | @@ -1682,7 +1679,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1682 | .sysroot = sysroot, | 1679 | .sysroot = sysroot, |
| 1683 | .output_mode = options.output_mode, | 1680 | .output_mode = options.output_mode, |
| 1684 | .link_mode = link_mode, | 1681 | .link_mode = link_mode, |
| 1685 | .object_format = ofmt, | ||
| 1686 | .optimize_mode = options.optimize_mode, | 1682 | .optimize_mode = options.optimize_mode, |
| 1687 | .use_lld = use_lld, | 1683 | .use_lld = use_lld, |
| 1688 | .use_llvm = use_llvm, | 1684 | .use_llvm = use_llvm, |
| ... | @@ -1841,7 +1837,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { | ... | @@ -1841,7 +1837,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1841 | 1837 | ||
| 1842 | const have_bin_emit = comp.bin_file.options.emit != null or comp.whole_bin_sub_path != null; | 1838 | const have_bin_emit = comp.bin_file.options.emit != null or comp.whole_bin_sub_path != null; |
| 1843 | 1839 | ||
| 1844 | if (have_bin_emit and !comp.bin_file.options.skip_linker_dependencies) { | 1840 | if (have_bin_emit and !comp.bin_file.options.skip_linker_dependencies and |
| 1841 | options.target.ofmt != .c) | ||
| 1842 | { | ||
| 1845 | if (comp.getTarget().isDarwin()) { | 1843 | if (comp.getTarget().isDarwin()) { |
| 1846 | switch (comp.getTarget().abi) { | 1844 | switch (comp.getTarget().abi) { |
| 1847 | .none, | 1845 | .none, |
| ... | @@ -3739,7 +3737,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P | ... | @@ -3739,7 +3737,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P |
| 3739 | else | 3737 | else |
| 3740 | c_source_basename[0 .. c_source_basename.len - std.fs.path.extension(c_source_basename).len]; | 3738 | c_source_basename[0 .. c_source_basename.len - std.fs.path.extension(c_source_basename).len]; |
| 3741 | 3739 | ||
| 3742 | const o_ext = comp.bin_file.options.object_format.fileExt(comp.bin_file.options.target.cpu.arch); | 3740 | const target = comp.getTarget(); |
| 3741 | const o_ext = target.ofmt.fileExt(target.cpu.arch); | ||
| 3743 | const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: { | 3742 | const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: { |
| 3744 | var argv = std.ArrayList([]const u8).init(comp.gpa); | 3743 | var argv = std.ArrayList([]const u8).init(comp.gpa); |
| 3745 | defer argv.deinit(); | 3744 | defer argv.deinit(); |
| ... | @@ -4092,7 +4091,7 @@ pub fn addCCArgs( | ... | @@ -4092,7 +4091,7 @@ pub fn addCCArgs( |
| 4092 | 4091 | ||
| 4093 | if (!comp.bin_file.options.strip) { | 4092 | if (!comp.bin_file.options.strip) { |
| 4094 | try argv.append("-g"); | 4093 | try argv.append("-g"); |
| 4095 | switch (comp.bin_file.options.object_format) { | 4094 | switch (target.ofmt) { |
| 4096 | .coff => try argv.append("-gcodeview"), | 4095 | .coff => try argv.append("-gcodeview"), |
| 4097 | else => {}, | 4096 | else => {}, |
| 4098 | } | 4097 | } |
| ... | @@ -4660,7 +4659,7 @@ fn wantBuildLibCFromSource(comp: Compilation) bool { | ... | @@ -4660,7 +4659,7 @@ fn wantBuildLibCFromSource(comp: Compilation) bool { |
| 4660 | }; | 4659 | }; |
| 4661 | return comp.bin_file.options.link_libc and is_exe_or_dyn_lib and | 4660 | return comp.bin_file.options.link_libc and is_exe_or_dyn_lib and |
| 4662 | comp.bin_file.options.libc_installation == null and | 4661 | comp.bin_file.options.libc_installation == null and |
| 4663 | comp.bin_file.options.object_format != .c; | 4662 | comp.bin_file.options.target.ofmt != .c; |
| 4664 | } | 4663 | } |
| 4665 | 4664 | ||
| 4666 | fn wantBuildGLibCFromSource(comp: Compilation) bool { | 4665 | fn wantBuildGLibCFromSource(comp: Compilation) bool { |
| ... | @@ -4688,7 +4687,7 @@ fn wantBuildLibUnwindFromSource(comp: *Compilation) bool { | ... | @@ -4688,7 +4687,7 @@ fn wantBuildLibUnwindFromSource(comp: *Compilation) bool { |
| 4688 | .Exe => true, | 4687 | .Exe => true, |
| 4689 | }; | 4688 | }; |
| 4690 | return is_exe_or_dyn_lib and comp.bin_file.options.link_libunwind and | 4689 | return is_exe_or_dyn_lib and comp.bin_file.options.link_libunwind and |
| 4691 | comp.bin_file.options.object_format != .c; | 4690 | comp.bin_file.options.target.ofmt != .c; |
| 4692 | } | 4691 | } |
| 4693 | 4692 | ||
| 4694 | fn setAllocFailure(comp: *Compilation) void { | 4693 | fn setAllocFailure(comp: *Compilation) void { |
| ... | @@ -4747,7 +4746,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca | ... | @@ -4747,7 +4746,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca |
| 4747 | const zig_backend: std.builtin.CompilerBackend = blk: { | 4746 | const zig_backend: std.builtin.CompilerBackend = blk: { |
| 4748 | if (use_stage1) break :blk .stage1; | 4747 | if (use_stage1) break :blk .stage1; |
| 4749 | if (build_options.have_llvm and comp.bin_file.options.use_llvm) break :blk .stage2_llvm; | 4748 | if (build_options.have_llvm and comp.bin_file.options.use_llvm) break :blk .stage2_llvm; |
| 4750 | if (comp.bin_file.options.object_format == .c) break :blk .stage2_c; | 4749 | if (target.ofmt == .c) break :blk .stage2_c; |
| 4751 | break :blk switch (target.cpu.arch) { | 4750 | break :blk switch (target.cpu.arch) { |
| 4752 | .wasm32, .wasm64 => std.builtin.CompilerBackend.stage2_wasm, | 4751 | .wasm32, .wasm64 => std.builtin.CompilerBackend.stage2_wasm, |
| 4753 | .arm, .armeb, .thumb, .thumbeb => .stage2_arm, | 4752 | .arm, .armeb, .thumb, .thumbeb => .stage2_arm, |
| ... | @@ -4895,6 +4894,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca | ... | @@ -4895,6 +4894,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca |
| 4895 | \\ .cpu = cpu, | 4894 | \\ .cpu = cpu, |
| 4896 | \\ .os = os, | 4895 | \\ .os = os, |
| 4897 | \\ .abi = abi, | 4896 | \\ .abi = abi, |
| 4897 | \\ .ofmt = object_format, | ||
| 4898 | \\}}; | 4898 | \\}}; |
| 4899 | \\pub const object_format = std.Target.ObjectFormat.{}; | 4899 | \\pub const object_format = std.Target.ObjectFormat.{}; |
| 4900 | \\pub const mode = std.builtin.Mode.{}; | 4900 | \\pub const mode = std.builtin.Mode.{}; |
| ... | @@ -4909,7 +4909,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca | ... | @@ -4909,7 +4909,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca |
| 4909 | \\pub const code_model = std.builtin.CodeModel.{}; | 4909 | \\pub const code_model = std.builtin.CodeModel.{}; |
| 4910 | \\ | 4910 | \\ |
| 4911 | , .{ | 4911 | , .{ |
| 4912 | std.zig.fmtId(@tagName(comp.bin_file.options.object_format)), | 4912 | std.zig.fmtId(@tagName(target.ofmt)), |
| 4913 | std.zig.fmtId(@tagName(comp.bin_file.options.optimize_mode)), | 4913 | std.zig.fmtId(@tagName(comp.bin_file.options.optimize_mode)), |
| 4914 | link_libc, | 4914 | link_libc, |
| 4915 | comp.bin_file.options.link_libcpp, | 4915 | comp.bin_file.options.link_libcpp, |
src/Module.zig+33-5| ... | @@ -935,13 +935,41 @@ pub const Struct = struct { | ... | @@ -935,13 +935,41 @@ pub const Struct = struct { |
| 935 | /// If true then `default_val` is the comptime field value. | 935 | /// If true then `default_val` is the comptime field value. |
| 936 | is_comptime: bool, | 936 | is_comptime: bool, |
| 937 | 937 | ||
| 938 | /// Returns the field alignment, assuming the struct is not packed. | 938 | /// Returns the field alignment. If the struct is packed, returns 0. |
| 939 | pub fn normalAlignment(field: Field, target: Target) u32 { | 939 | pub fn alignment( |
| 940 | if (field.abi_align == 0) { | 940 | field: Field, |
| 941 | return field.ty.abiAlignment(target); | 941 | target: Target, |
| 942 | } else { | 942 | layout: std.builtin.Type.ContainerLayout, |
| 943 | ) u32 { | ||
| 944 | if (field.abi_align != 0) { | ||
| 945 | assert(layout != .Packed); | ||
| 943 | return field.abi_align; | 946 | return field.abi_align; |
| 944 | } | 947 | } |
| 948 | |||
| 949 | switch (layout) { | ||
| 950 | .Packed => return 0, | ||
| 951 | .Auto => { | ||
| 952 | if (target.ofmt == .c) { | ||
| 953 | return alignmentExtern(field, target); | ||
| 954 | } else { | ||
| 955 | return field.ty.abiAlignment(target); | ||
| 956 | } | ||
| 957 | }, | ||
| 958 | .Extern => return alignmentExtern(field, target), | ||
| 959 | } | ||
| 960 | } | ||
| 961 | |||
| 962 | pub fn alignmentExtern(field: Field, target: Target) u32 { | ||
| 963 | // This logic is duplicated in Type.abiAlignmentAdvanced. | ||
| 964 | const ty_abi_align = field.ty.abiAlignment(target); | ||
| 965 | |||
| 966 | if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) { | ||
| 967 | // The C ABI requires 128 bit integer fields of structs | ||
| 968 | // to be 16-bytes aligned. | ||
| 969 | return @maximum(ty_abi_align, 16); | ||
| 970 | } | ||
| 971 | |||
| 972 | return ty_abi_align; | ||
| 945 | } | 973 | } |
| 946 | }; | 974 | }; |
| 947 | 975 |
src/Sema.zig+2-5| ... | @@ -14380,10 +14380,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -14380,10 +14380,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14380 | else | 14380 | else |
| 14381 | field.default_val; | 14381 | field.default_val; |
| 14382 | const default_val_ptr = try sema.optRefValue(block, src, field.ty, opt_default_val); | 14382 | const default_val_ptr = try sema.optRefValue(block, src, field.ty, opt_default_val); |
| 14383 | const alignment = switch (layout) { | 14383 | const alignment = field.alignment(target, layout); |
| 14384 | .Auto, .Extern => field.normalAlignment(target), | ||
| 14385 | .Packed => 0, | ||
| 14386 | }; | ||
| 14387 | 14384 | ||
| 14388 | struct_field_fields.* = .{ | 14385 | struct_field_fields.* = .{ |
| 14389 | // name: []const u8, | 14386 | // name: []const u8, |
| ... | @@ -20657,7 +20654,7 @@ fn panicWithMsg( | ... | @@ -20657,7 +20654,7 @@ fn panicWithMsg( |
| 20657 | const arena = sema.arena; | 20654 | const arena = sema.arena; |
| 20658 | 20655 | ||
| 20659 | const this_feature_is_implemented_in_the_backend = | 20656 | const this_feature_is_implemented_in_the_backend = |
| 20660 | mod.comp.bin_file.options.object_format == .c or | 20657 | mod.comp.bin_file.options.target.ofmt == .c or |
| 20661 | mod.comp.bin_file.options.use_llvm; | 20658 | mod.comp.bin_file.options.use_llvm; |
| 20662 | if (!this_feature_is_implemented_in_the_backend) { | 20659 | if (!this_feature_is_implemented_in_the_backend) { |
| 20663 | // TODO implement this feature in all the backends and then delete this branch | 20660 | // TODO implement this feature in all the backends and then delete this branch |
src/codegen/llvm.zig+8-6| ... | @@ -273,7 +273,7 @@ pub const Object = struct { | ... | @@ -273,7 +273,7 @@ pub const Object = struct { |
| 273 | var di_compile_unit: ?*llvm.DICompileUnit = null; | 273 | var di_compile_unit: ?*llvm.DICompileUnit = null; |
| 274 | 274 | ||
| 275 | if (!options.strip) { | 275 | if (!options.strip) { |
| 276 | switch (options.object_format) { | 276 | switch (options.target.ofmt) { |
| 277 | .coff => llvm_module.addModuleCodeViewFlag(), | 277 | .coff => llvm_module.addModuleCodeViewFlag(), |
| 278 | else => llvm_module.addModuleDebugInfoFlag(), | 278 | else => llvm_module.addModuleDebugInfoFlag(), |
| 279 | } | 279 | } |
| ... | @@ -1841,6 +1841,7 @@ pub const Object = struct { | ... | @@ -1841,6 +1841,7 @@ pub const Object = struct { |
| 1841 | } | 1841 | } |
| 1842 | 1842 | ||
| 1843 | const fields = ty.structFields(); | 1843 | const fields = ty.structFields(); |
| 1844 | const layout = ty.containerLayout(); | ||
| 1844 | 1845 | ||
| 1845 | var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{}; | 1846 | var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{}; |
| 1846 | defer di_fields.deinit(gpa); | 1847 | defer di_fields.deinit(gpa); |
| ... | @@ -1854,7 +1855,7 @@ pub const Object = struct { | ... | @@ -1854,7 +1855,7 @@ pub const Object = struct { |
| 1854 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; | 1855 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 1855 | 1856 | ||
| 1856 | const field_size = field.ty.abiSize(target); | 1857 | const field_size = field.ty.abiSize(target); |
| 1857 | const field_align = field.normalAlignment(target); | 1858 | const field_align = field.alignment(target, layout); |
| 1858 | const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align); | 1859 | const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 1859 | offset = field_offset + field_size; | 1860 | offset = field_offset + field_size; |
| 1860 | 1861 | ||
| ... | @@ -2757,7 +2758,7 @@ pub const DeclGen = struct { | ... | @@ -2757,7 +2758,7 @@ pub const DeclGen = struct { |
| 2757 | for (struct_obj.fields.values()) |field| { | 2758 | for (struct_obj.fields.values()) |field| { |
| 2758 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; | 2759 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 2759 | 2760 | ||
| 2760 | const field_align = field.normalAlignment(target); | 2761 | const field_align = field.alignment(target, struct_obj.layout); |
| 2761 | const field_ty_align = field.ty.abiAlignment(target); | 2762 | const field_ty_align = field.ty.abiAlignment(target); |
| 2762 | any_underaligned_fields = any_underaligned_fields or | 2763 | any_underaligned_fields = any_underaligned_fields or |
| 2763 | field_align < field_ty_align; | 2764 | field_align < field_ty_align; |
| ... | @@ -3433,7 +3434,7 @@ pub const DeclGen = struct { | ... | @@ -3433,7 +3434,7 @@ pub const DeclGen = struct { |
| 3433 | for (struct_obj.fields.values()) |field, i| { | 3434 | for (struct_obj.fields.values()) |field, i| { |
| 3434 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; | 3435 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 3435 | 3436 | ||
| 3436 | const field_align = field.normalAlignment(target); | 3437 | const field_align = field.alignment(target, struct_obj.layout); |
| 3437 | big_align = @maximum(big_align, field_align); | 3438 | big_align = @maximum(big_align, field_align); |
| 3438 | const prev_offset = offset; | 3439 | const prev_offset = offset; |
| 3439 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | 3440 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| ... | @@ -9376,13 +9377,14 @@ fn llvmFieldIndex( | ... | @@ -9376,13 +9377,14 @@ fn llvmFieldIndex( |
| 9376 | } | 9377 | } |
| 9377 | return null; | 9378 | return null; |
| 9378 | } | 9379 | } |
| 9379 | assert(ty.containerLayout() != .Packed); | 9380 | const layout = ty.containerLayout(); |
| 9381 | assert(layout != .Packed); | ||
| 9380 | 9382 | ||
| 9381 | var llvm_field_index: c_uint = 0; | 9383 | var llvm_field_index: c_uint = 0; |
| 9382 | for (ty.structFields().values()) |field, i| { | 9384 | for (ty.structFields().values()) |field, i| { |
| 9383 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; | 9385 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 9384 | 9386 | ||
| 9385 | const field_align = field.normalAlignment(target); | 9387 | const field_align = field.alignment(target, layout); |
| 9386 | big_align = @maximum(big_align, field_align); | 9388 | big_align = @maximum(big_align, field_align); |
| 9387 | const prev_offset = offset; | 9389 | const prev_offset = offset; |
| 9388 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | 9390 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
src/link.zig+5-6| ... | @@ -72,7 +72,6 @@ pub const Options = struct { | ... | @@ -72,7 +72,6 @@ pub const Options = struct { |
| 72 | target: std.Target, | 72 | target: std.Target, |
| 73 | output_mode: std.builtin.OutputMode, | 73 | output_mode: std.builtin.OutputMode, |
| 74 | link_mode: std.builtin.LinkMode, | 74 | link_mode: std.builtin.LinkMode, |
| 75 | object_format: std.Target.ObjectFormat, | ||
| 76 | optimize_mode: std.builtin.Mode, | 75 | optimize_mode: std.builtin.Mode, |
| 77 | machine_code_model: std.builtin.CodeModel, | 76 | machine_code_model: std.builtin.CodeModel, |
| 78 | root_name: [:0]const u8, | 77 | root_name: [:0]const u8, |
| ... | @@ -273,13 +272,13 @@ pub const File = struct { | ... | @@ -273,13 +272,13 @@ pub const File = struct { |
| 273 | /// rewriting it. A malicious file is detected as incremental link failure | 272 | /// rewriting it. A malicious file is detected as incremental link failure |
| 274 | /// and does not cause Illegal Behavior. This operation is not atomic. | 273 | /// and does not cause Illegal Behavior. This operation is not atomic. |
| 275 | pub fn openPath(allocator: Allocator, options: Options) !*File { | 274 | pub fn openPath(allocator: Allocator, options: Options) !*File { |
| 276 | if (options.object_format == .macho) { | 275 | if (options.target.ofmt == .macho) { |
| 277 | return &(try MachO.openPath(allocator, options)).base; | 276 | return &(try MachO.openPath(allocator, options)).base; |
| 278 | } | 277 | } |
| 279 | 278 | ||
| 280 | const use_stage1 = build_options.is_stage1 and options.use_stage1; | 279 | const use_stage1 = build_options.is_stage1 and options.use_stage1; |
| 281 | if (use_stage1 or options.emit == null) { | 280 | if (use_stage1 or options.emit == null) { |
| 282 | return switch (options.object_format) { | 281 | return switch (options.target.ofmt) { |
| 283 | .coff => &(try Coff.createEmpty(allocator, options)).base, | 282 | .coff => &(try Coff.createEmpty(allocator, options)).base, |
| 284 | .elf => &(try Elf.createEmpty(allocator, options)).base, | 283 | .elf => &(try Elf.createEmpty(allocator, options)).base, |
| 285 | .macho => unreachable, | 284 | .macho => unreachable, |
| ... | @@ -298,7 +297,7 @@ pub const File = struct { | ... | @@ -298,7 +297,7 @@ pub const File = struct { |
| 298 | if (options.module == null) { | 297 | if (options.module == null) { |
| 299 | // No point in opening a file, we would not write anything to it. | 298 | // No point in opening a file, we would not write anything to it. |
| 300 | // Initialize with empty. | 299 | // Initialize with empty. |
| 301 | return switch (options.object_format) { | 300 | return switch (options.target.ofmt) { |
| 302 | .coff => &(try Coff.createEmpty(allocator, options)).base, | 301 | .coff => &(try Coff.createEmpty(allocator, options)).base, |
| 303 | .elf => &(try Elf.createEmpty(allocator, options)).base, | 302 | .elf => &(try Elf.createEmpty(allocator, options)).base, |
| 304 | .macho => unreachable, | 303 | .macho => unreachable, |
| ... | @@ -314,12 +313,12 @@ pub const File = struct { | ... | @@ -314,12 +313,12 @@ pub const File = struct { |
| 314 | // Open a temporary object file, not the final output file because we | 313 | // Open a temporary object file, not the final output file because we |
| 315 | // want to link with LLD. | 314 | // want to link with LLD. |
| 316 | break :blk try std.fmt.allocPrint(allocator, "{s}{s}", .{ | 315 | break :blk try std.fmt.allocPrint(allocator, "{s}{s}", .{ |
| 317 | emit.sub_path, options.object_format.fileExt(options.target.cpu.arch), | 316 | emit.sub_path, options.target.ofmt.fileExt(options.target.cpu.arch), |
| 318 | }); | 317 | }); |
| 319 | } else emit.sub_path; | 318 | } else emit.sub_path; |
| 320 | errdefer if (use_lld) allocator.free(sub_path); | 319 | errdefer if (use_lld) allocator.free(sub_path); |
| 321 | 320 | ||
| 322 | const file: *File = switch (options.object_format) { | 321 | const file: *File = switch (options.target.ofmt) { |
| 323 | .coff => &(try Coff.openPath(allocator, sub_path, options)).base, | 322 | .coff => &(try Coff.openPath(allocator, sub_path, options)).base, |
| 324 | .elf => &(try Elf.openPath(allocator, sub_path, options)).base, | 323 | .elf => &(try Elf.openPath(allocator, sub_path, options)).base, |
| 325 | .macho => unreachable, | 324 | .macho => unreachable, |
src/link/C.zig+1-1| ... | @@ -48,7 +48,7 @@ const DeclBlock = struct { | ... | @@ -48,7 +48,7 @@ const DeclBlock = struct { |
| 48 | }; | 48 | }; |
| 49 | 49 | ||
| 50 | pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C { | 50 | pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C { |
| 51 | assert(options.object_format == .c); | 51 | assert(options.target.ofmt == .c); |
| 52 | 52 | ||
| 53 | if (options.use_llvm) return error.LLVMHasNoCBackend; | 53 | if (options.use_llvm) return error.LLVMHasNoCBackend; |
| 54 | if (options.use_lld) return error.LLDHasNoCBackend; | 54 | if (options.use_lld) return error.LLDHasNoCBackend; |
src/link/Coff.zig+1-1| ... | @@ -128,7 +128,7 @@ pub const TextBlock = struct { | ... | @@ -128,7 +128,7 @@ pub const TextBlock = struct { |
| 128 | pub const SrcFn = void; | 128 | pub const SrcFn = void; |
| 129 | 129 | ||
| 130 | pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Coff { | 130 | pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Coff { |
| 131 | assert(options.object_format == .coff); | 131 | assert(options.target.ofmt == .coff); |
| 132 | 132 | ||
| 133 | if (build_options.have_llvm and options.use_llvm) { | 133 | if (build_options.have_llvm and options.use_llvm) { |
| 134 | return createEmpty(allocator, options); | 134 | return createEmpty(allocator, options); |
src/link/Elf.zig+1-1| ... | @@ -249,7 +249,7 @@ pub const Export = struct { | ... | @@ -249,7 +249,7 @@ pub const Export = struct { |
| 249 | }; | 249 | }; |
| 250 | 250 | ||
| 251 | pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Elf { | 251 | pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Elf { |
| 252 | assert(options.object_format == .elf); | 252 | assert(options.target.ofmt == .elf); |
| 253 | 253 | ||
| 254 | if (build_options.have_llvm and options.use_llvm) { | 254 | if (build_options.have_llvm and options.use_llvm) { |
| 255 | return createEmpty(allocator, options); | 255 | return createEmpty(allocator, options); |
src/link/MachO.zig+2-2| ... | @@ -270,7 +270,7 @@ pub const Export = struct { | ... | @@ -270,7 +270,7 @@ pub const Export = struct { |
| 270 | }; | 270 | }; |
| 271 | 271 | ||
| 272 | pub fn openPath(allocator: Allocator, options: link.Options) !*MachO { | 272 | pub fn openPath(allocator: Allocator, options: link.Options) !*MachO { |
| 273 | assert(options.object_format == .macho); | 273 | assert(options.target.ofmt == .macho); |
| 274 | 274 | ||
| 275 | const use_stage1 = build_options.is_stage1 and options.use_stage1; | 275 | const use_stage1 = build_options.is_stage1 and options.use_stage1; |
| 276 | if (use_stage1 or options.emit == null) { | 276 | if (use_stage1 or options.emit == null) { |
| ... | @@ -289,7 +289,7 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO { | ... | @@ -289,7 +289,7 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO { |
| 289 | // we also want to put the intermediary object file in the cache while the | 289 | // we also want to put the intermediary object file in the cache while the |
| 290 | // main emit directory is the cwd. | 290 | // main emit directory is the cwd. |
| 291 | self.base.intermediary_basename = try std.fmt.allocPrint(allocator, "{s}{s}", .{ | 291 | self.base.intermediary_basename = try std.fmt.allocPrint(allocator, "{s}{s}", .{ |
| 292 | emit.sub_path, options.object_format.fileExt(options.target.cpu.arch), | 292 | emit.sub_path, options.target.ofmt.fileExt(options.target.cpu.arch), |
| 293 | }); | 293 | }); |
| 294 | } | 294 | } |
| 295 | 295 |
src/link/NvPtx.zig+1-1| ... | @@ -57,7 +57,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*NvPtx { | ... | @@ -57,7 +57,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*NvPtx { |
| 57 | pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*NvPtx { | 57 | pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*NvPtx { |
| 58 | if (!build_options.have_llvm) @panic("nvptx target requires a zig compiler with llvm enabled."); | 58 | if (!build_options.have_llvm) @panic("nvptx target requires a zig compiler with llvm enabled."); |
| 59 | if (!options.use_llvm) return error.PtxArchNotSupported; | 59 | if (!options.use_llvm) return error.PtxArchNotSupported; |
| 60 | assert(options.object_format == .nvptx); | 60 | assert(options.target.ofmt == .nvptx); |
| 61 | 61 | ||
| 62 | const nvptx = try createEmpty(allocator, options); | 62 | const nvptx = try createEmpty(allocator, options); |
| 63 | log.info("Opening .ptx target file {s}", .{sub_path}); | 63 | log.info("Opening .ptx target file {s}", .{sub_path}); |
src/link/Plan9.zig+1-1| ... | @@ -657,7 +657,7 @@ pub const base_tag = .plan9; | ... | @@ -657,7 +657,7 @@ pub const base_tag = .plan9; |
| 657 | pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Plan9 { | 657 | pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Plan9 { |
| 658 | if (options.use_llvm) | 658 | if (options.use_llvm) |
| 659 | return error.LLVMBackendDoesNotSupportPlan9; | 659 | return error.LLVMBackendDoesNotSupportPlan9; |
| 660 | assert(options.object_format == .plan9); | 660 | assert(options.target.ofmt == .plan9); |
| 661 | 661 | ||
| 662 | const self = try createEmpty(allocator, options); | 662 | const self = try createEmpty(allocator, options); |
| 663 | errdefer self.base.destroy(); | 663 | errdefer self.base.destroy(); |
src/link/SpirV.zig+1-1| ... | @@ -99,7 +99,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*SpirV { | ... | @@ -99,7 +99,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*SpirV { |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*SpirV { | 101 | pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*SpirV { |
| 102 | assert(options.object_format == .spirv); | 102 | assert(options.target.ofmt == .spirv); |
| 103 | 103 | ||
| 104 | if (options.use_llvm) return error.LLVM_BackendIsTODO_ForSpirV; // TODO: LLVM Doesn't support SpirV at all. | 104 | if (options.use_llvm) return error.LLVM_BackendIsTODO_ForSpirV; // TODO: LLVM Doesn't support SpirV at all. |
| 105 | if (options.use_lld) return error.LLD_LinkingIsTODO_ForSpirV; // TODO: LLD Doesn't support SpirV at all. | 105 | if (options.use_lld) return error.LLD_LinkingIsTODO_ForSpirV; // TODO: LLD Doesn't support SpirV at all. |
src/link/Wasm.zig+1-1| ... | @@ -282,7 +282,7 @@ pub const StringTable = struct { | ... | @@ -282,7 +282,7 @@ pub const StringTable = struct { |
| 282 | }; | 282 | }; |
| 283 | 283 | ||
| 284 | pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Wasm { | 284 | pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Wasm { |
| 285 | assert(options.object_format == .wasm); | 285 | assert(options.target.ofmt == .wasm); |
| 286 | 286 | ||
| 287 | if (build_options.have_llvm and options.use_llvm) { | 287 | if (build_options.have_llvm and options.use_llvm) { |
| 288 | return createEmpty(allocator, options); | 288 | return createEmpty(allocator, options); |
src/main.zig+22-29| ... | @@ -2192,6 +2192,7 @@ fn buildOutputType( | ... | @@ -2192,6 +2192,7 @@ fn buildOutputType( |
| 2192 | .arch_os_abi = target_arch_os_abi, | 2192 | .arch_os_abi = target_arch_os_abi, |
| 2193 | .cpu_features = target_mcpu, | 2193 | .cpu_features = target_mcpu, |
| 2194 | .dynamic_linker = target_dynamic_linker, | 2194 | .dynamic_linker = target_dynamic_linker, |
| 2195 | .object_format = target_ofmt, | ||
| 2195 | }; | 2196 | }; |
| 2196 | 2197 | ||
| 2197 | // Before passing the mcpu string in for parsing, we convert any -m flags that were | 2198 | // Before passing the mcpu string in for parsing, we convert any -m flags that were |
| ... | @@ -2494,28 +2495,7 @@ fn buildOutputType( | ... | @@ -2494,28 +2495,7 @@ fn buildOutputType( |
| 2494 | } | 2495 | } |
| 2495 | } | 2496 | } |
| 2496 | 2497 | ||
| 2497 | const object_format: std.Target.ObjectFormat = blk: { | 2498 | const object_format = target_info.target.ofmt; |
| 2498 | const ofmt = target_ofmt orelse break :blk target_info.target.getObjectFormat(); | ||
| 2499 | if (mem.eql(u8, ofmt, "elf")) { | ||
| 2500 | break :blk .elf; | ||
| 2501 | } else if (mem.eql(u8, ofmt, "c")) { | ||
| 2502 | break :blk .c; | ||
| 2503 | } else if (mem.eql(u8, ofmt, "coff")) { | ||
| 2504 | break :blk .coff; | ||
| 2505 | } else if (mem.eql(u8, ofmt, "macho")) { | ||
| 2506 | break :blk .macho; | ||
| 2507 | } else if (mem.eql(u8, ofmt, "wasm")) { | ||
| 2508 | break :blk .wasm; | ||
| 2509 | } else if (mem.eql(u8, ofmt, "hex")) { | ||
| 2510 | break :blk .hex; | ||
| 2511 | } else if (mem.eql(u8, ofmt, "raw")) { | ||
| 2512 | break :blk .raw; | ||
| 2513 | } else if (mem.eql(u8, ofmt, "spirv")) { | ||
| 2514 | break :blk .spirv; | ||
| 2515 | } else { | ||
| 2516 | fatal("unsupported object format: {s}", .{ofmt}); | ||
| 2517 | } | ||
| 2518 | }; | ||
| 2519 | 2499 | ||
| 2520 | if (output_mode == .Obj and (object_format == .coff or object_format == .macho)) { | 2500 | if (output_mode == .Obj and (object_format == .coff or object_format == .macho)) { |
| 2521 | const total_obj_count = c_source_files.items.len + | 2501 | const total_obj_count = c_source_files.items.len + |
| ... | @@ -2569,7 +2549,6 @@ fn buildOutputType( | ... | @@ -2569,7 +2549,6 @@ fn buildOutputType( |
| 2569 | .target = target_info.target, | 2549 | .target = target_info.target, |
| 2570 | .output_mode = output_mode, | 2550 | .output_mode = output_mode, |
| 2571 | .link_mode = link_mode, | 2551 | .link_mode = link_mode, |
| 2572 | .object_format = object_format, | ||
| 2573 | .version = optional_version, | 2552 | .version = optional_version, |
| 2574 | }), | 2553 | }), |
| 2575 | }, | 2554 | }, |
| ... | @@ -2859,7 +2838,6 @@ fn buildOutputType( | ... | @@ -2859,7 +2838,6 @@ fn buildOutputType( |
| 2859 | .emit_implib = emit_implib_resolved.data, | 2838 | .emit_implib = emit_implib_resolved.data, |
| 2860 | .link_mode = link_mode, | 2839 | .link_mode = link_mode, |
| 2861 | .dll_export_fns = dll_export_fns, | 2840 | .dll_export_fns = dll_export_fns, |
| 2862 | .object_format = object_format, | ||
| 2863 | .optimize_mode = optimize_mode, | 2841 | .optimize_mode = optimize_mode, |
| 2864 | .keep_source_files_loaded = false, | 2842 | .keep_source_files_loaded = false, |
| 2865 | .clang_argv = clang_argv.items, | 2843 | .clang_argv = clang_argv.items, |
| ... | @@ -3173,11 +3151,11 @@ fn parseCrossTargetOrReportFatalError( | ... | @@ -3173,11 +3151,11 @@ fn parseCrossTargetOrReportFatalError( |
| 3173 | for (diags.arch.?.allCpuModels()) |cpu| { | 3151 | for (diags.arch.?.allCpuModels()) |cpu| { |
| 3174 | help_text.writer().print(" {s}\n", .{cpu.name}) catch break :help; | 3152 | help_text.writer().print(" {s}\n", .{cpu.name}) catch break :help; |
| 3175 | } | 3153 | } |
| 3176 | std.log.info("Available CPUs for architecture '{s}':\n{s}", .{ | 3154 | std.log.info("available CPUs for architecture '{s}':\n{s}", .{ |
| 3177 | @tagName(diags.arch.?), help_text.items, | 3155 | @tagName(diags.arch.?), help_text.items, |
| 3178 | }); | 3156 | }); |
| 3179 | } | 3157 | } |
| 3180 | fatal("Unknown CPU: '{s}'", .{diags.cpu_name.?}); | 3158 | fatal("unknown CPU: '{s}'", .{diags.cpu_name.?}); |
| 3181 | }, | 3159 | }, |
| 3182 | error.UnknownCpuFeature => { | 3160 | error.UnknownCpuFeature => { |
| 3183 | help: { | 3161 | help: { |
| ... | @@ -3186,11 +3164,26 @@ fn parseCrossTargetOrReportFatalError( | ... | @@ -3186,11 +3164,26 @@ fn parseCrossTargetOrReportFatalError( |
| 3186 | for (diags.arch.?.allFeaturesList()) |feature| { | 3164 | for (diags.arch.?.allFeaturesList()) |feature| { |
| 3187 | help_text.writer().print(" {s}: {s}\n", .{ feature.name, feature.description }) catch break :help; | 3165 | help_text.writer().print(" {s}: {s}\n", .{ feature.name, feature.description }) catch break :help; |
| 3188 | } | 3166 | } |
| 3189 | std.log.info("Available CPU features for architecture '{s}':\n{s}", .{ | 3167 | std.log.info("available CPU features for architecture '{s}':\n{s}", .{ |
| 3190 | @tagName(diags.arch.?), help_text.items, | 3168 | @tagName(diags.arch.?), help_text.items, |
| 3191 | }); | 3169 | }); |
| 3192 | } | 3170 | } |
| 3193 | fatal("Unknown CPU feature: '{s}'", .{diags.unknown_feature_name.?}); | 3171 | fatal("unknown CPU feature: '{s}'", .{diags.unknown_feature_name.?}); |
| 3172 | }, | ||
| 3173 | error.UnknownObjectFormat => { | ||
| 3174 | { | ||
| 3175 | var help_text = std.ArrayList(u8).init(allocator); | ||
| 3176 | defer help_text.deinit(); | ||
| 3177 | inline for (@typeInfo(std.Target.ObjectFormat).Enum.fields) |field| { | ||
| 3178 | help_text.writer().print(" {s}\n", .{field.name}) catch | ||
| 3179 | // TODO change this back to `break :help` | ||
| 3180 | // this working around a stage1 bug. | ||
| 3181 | //break :help; | ||
| 3182 | @panic("out of memory"); | ||
| 3183 | } | ||
| 3184 | std.log.info("available object formats:\n{s}", .{help_text.items}); | ||
| 3185 | } | ||
| 3186 | fatal("unknown object format: '{s}'", .{opts.object_format.?}); | ||
| 3194 | }, | 3187 | }, |
| 3195 | else => |e| return e, | 3188 | else => |e| return e, |
| 3196 | }; | 3189 | }; |
| ... | @@ -3360,7 +3353,7 @@ fn updateModule(gpa: Allocator, comp: *Compilation, hook: AfterUpdateHook) !void | ... | @@ -3360,7 +3353,7 @@ fn updateModule(gpa: Allocator, comp: *Compilation, hook: AfterUpdateHook) !void |
| 3360 | 3353 | ||
| 3361 | // If a .pdb file is part of the expected output, we must also copy | 3354 | // If a .pdb file is part of the expected output, we must also copy |
| 3362 | // it into place here. | 3355 | // it into place here. |
| 3363 | const is_coff = comp.bin_file.options.object_format == .coff; | 3356 | const is_coff = comp.bin_file.options.target.ofmt == .coff; |
| 3364 | const have_pdb = is_coff and !comp.bin_file.options.strip; | 3357 | const have_pdb = is_coff and !comp.bin_file.options.strip; |
| 3365 | if (have_pdb) { | 3358 | if (have_pdb) { |
| 3366 | // Replace `.out` or `.exe` with `.pdb` on both the source and destination | 3359 | // Replace `.out` or `.exe` with `.pdb` on both the source and destination |
src/stage1/codegen.cpp+1| ... | @@ -10082,6 +10082,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { | ... | @@ -10082,6 +10082,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { |
| 10082 | " .cpu = cpu,\n" | 10082 | " .cpu = cpu,\n" |
| 10083 | " .os = os,\n" | 10083 | " .os = os,\n" |
| 10084 | " .abi = abi,\n" | 10084 | " .abi = abi,\n" |
| 10085 | " .ofmt = object_format,\n" | ||
| 10085 | "};\n" | 10086 | "};\n" |
| 10086 | ); | 10087 | ); |
| 10087 | 10088 |
src/test.zig+7-8| ... | @@ -606,7 +606,6 @@ pub const TestContext = struct { | ... | @@ -606,7 +606,6 @@ pub const TestContext = struct { |
| 606 | output_mode: std.builtin.OutputMode, | 606 | output_mode: std.builtin.OutputMode, |
| 607 | optimize_mode: std.builtin.Mode = .Debug, | 607 | optimize_mode: std.builtin.Mode = .Debug, |
| 608 | updates: std.ArrayList(Update), | 608 | updates: std.ArrayList(Update), |
| 609 | object_format: ?std.Target.ObjectFormat = null, | ||
| 610 | emit_h: bool = false, | 609 | emit_h: bool = false, |
| 611 | is_test: bool = false, | 610 | is_test: bool = false, |
| 612 | expect_exact: bool = false, | 611 | expect_exact: bool = false, |
| ... | @@ -782,12 +781,13 @@ pub const TestContext = struct { | ... | @@ -782,12 +781,13 @@ pub const TestContext = struct { |
| 782 | pub fn exeFromCompiledC(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case { | 781 | pub fn exeFromCompiledC(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case { |
| 783 | const prefixed_name = std.fmt.allocPrint(ctx.arena, "CBE: {s}", .{name}) catch | 782 | const prefixed_name = std.fmt.allocPrint(ctx.arena, "CBE: {s}", .{name}) catch |
| 784 | @panic("out of memory"); | 783 | @panic("out of memory"); |
| 784 | var target_adjusted = target; | ||
| 785 | target_adjusted.ofmt = std.Target.ObjectFormat.c; | ||
| 785 | ctx.cases.append(Case{ | 786 | ctx.cases.append(Case{ |
| 786 | .name = prefixed_name, | 787 | .name = prefixed_name, |
| 787 | .target = target, | 788 | .target = target_adjusted, |
| 788 | .updates = std.ArrayList(Update).init(ctx.cases.allocator), | 789 | .updates = std.ArrayList(Update).init(ctx.cases.allocator), |
| 789 | .output_mode = .Exe, | 790 | .output_mode = .Exe, |
| 790 | .object_format = .c, | ||
| 791 | .files = std.ArrayList(File).init(ctx.arena), | 791 | .files = std.ArrayList(File).init(ctx.arena), |
| 792 | }) catch @panic("out of memory"); | 792 | }) catch @panic("out of memory"); |
| 793 | return &ctx.cases.items[ctx.cases.items.len - 1]; | 793 | return &ctx.cases.items[ctx.cases.items.len - 1]; |
| ... | @@ -851,12 +851,13 @@ pub const TestContext = struct { | ... | @@ -851,12 +851,13 @@ pub const TestContext = struct { |
| 851 | 851 | ||
| 852 | /// Adds a test case for Zig or ZIR input, producing C code. | 852 | /// Adds a test case for Zig or ZIR input, producing C code. |
| 853 | pub fn addC(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case { | 853 | pub fn addC(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case { |
| 854 | var target_adjusted = target; | ||
| 855 | target_adjusted.ofmt = std.Target.ObjectFormat.c; | ||
| 854 | ctx.cases.append(Case{ | 856 | ctx.cases.append(Case{ |
| 855 | .name = name, | 857 | .name = name, |
| 856 | .target = target, | 858 | .target = target_adjusted, |
| 857 | .updates = std.ArrayList(Update).init(ctx.cases.allocator), | 859 | .updates = std.ArrayList(Update).init(ctx.cases.allocator), |
| 858 | .output_mode = .Obj, | 860 | .output_mode = .Obj, |
| 859 | .object_format = .c, | ||
| 860 | .files = std.ArrayList(File).init(ctx.arena), | 861 | .files = std.ArrayList(File).init(ctx.arena), |
| 861 | }) catch @panic("out of memory"); | 862 | }) catch @panic("out of memory"); |
| 862 | return &ctx.cases.items[ctx.cases.items.len - 1]; | 863 | return &ctx.cases.items[ctx.cases.items.len - 1]; |
| ... | @@ -1501,7 +1502,6 @@ pub const TestContext = struct { | ... | @@ -1501,7 +1502,6 @@ pub const TestContext = struct { |
| 1501 | .root_name = "test_case", | 1502 | .root_name = "test_case", |
| 1502 | .target = target, | 1503 | .target = target, |
| 1503 | .output_mode = case.output_mode, | 1504 | .output_mode = case.output_mode, |
| 1504 | .object_format = case.object_format, | ||
| 1505 | }); | 1505 | }); |
| 1506 | 1506 | ||
| 1507 | const emit_directory: Compilation.Directory = .{ | 1507 | const emit_directory: Compilation.Directory = .{ |
| ... | @@ -1537,7 +1537,6 @@ pub const TestContext = struct { | ... | @@ -1537,7 +1537,6 @@ pub const TestContext = struct { |
| 1537 | .emit_h = emit_h, | 1537 | .emit_h = emit_h, |
| 1538 | .main_pkg = &main_pkg, | 1538 | .main_pkg = &main_pkg, |
| 1539 | .keep_source_files_loaded = true, | 1539 | .keep_source_files_loaded = true, |
| 1540 | .object_format = case.object_format, | ||
| 1541 | .is_native_os = case.target.isNativeOs(), | 1540 | .is_native_os = case.target.isNativeOs(), |
| 1542 | .is_native_abi = case.target.isNativeAbi(), | 1541 | .is_native_abi = case.target.isNativeAbi(), |
| 1543 | .dynamic_linker = target_info.dynamic_linker.get(), | 1542 | .dynamic_linker = target_info.dynamic_linker.get(), |
| ... | @@ -1782,7 +1781,7 @@ pub const TestContext = struct { | ... | @@ -1782,7 +1781,7 @@ pub const TestContext = struct { |
| 1782 | ".." ++ ss ++ "{s}" ++ ss ++ "{s}", | 1781 | ".." ++ ss ++ "{s}" ++ ss ++ "{s}", |
| 1783 | .{ &tmp.sub_path, bin_name }, | 1782 | .{ &tmp.sub_path, bin_name }, |
| 1784 | ); | 1783 | ); |
| 1785 | if (case.object_format != null and case.object_format.? == .c) { | 1784 | if (case.target.ofmt != null and case.target.ofmt.? == .c) { |
| 1786 | if (host.getExternalExecutor(target_info, .{ .link_libc = true }) != .native) { | 1785 | if (host.getExternalExecutor(target_info, .{ .link_libc = true }) != .native) { |
| 1787 | // We wouldn't be able to run the compiled C code. | 1786 | // We wouldn't be able to run the compiled C code. |
| 1788 | continue :update; // Pass test. | 1787 | continue :update; // Pass test. |
src/type.zig+74-29| ... | @@ -2376,6 +2376,32 @@ pub const Type = extern union { | ... | @@ -2376,6 +2376,32 @@ pub const Type = extern union { |
| 2376 | .error_set_merged, | 2376 | .error_set_merged, |
| 2377 | => return true, | 2377 | => return true, |
| 2378 | 2378 | ||
| 2379 | // Pointers to zero-bit types still have a runtime address; however, pointers | ||
| 2380 | // to comptime-only types do not, with the exception of function pointers. | ||
| 2381 | .anyframe_T, | ||
| 2382 | .optional_single_mut_pointer, | ||
| 2383 | .optional_single_const_pointer, | ||
| 2384 | .single_const_pointer, | ||
| 2385 | .single_mut_pointer, | ||
| 2386 | .many_const_pointer, | ||
| 2387 | .many_mut_pointer, | ||
| 2388 | .c_const_pointer, | ||
| 2389 | .c_mut_pointer, | ||
| 2390 | .const_slice, | ||
| 2391 | .mut_slice, | ||
| 2392 | .pointer, | ||
| 2393 | => { | ||
| 2394 | if (ignore_comptime_only) { | ||
| 2395 | return true; | ||
| 2396 | } else if (ty.childType().zigTypeTag() == .Fn) { | ||
| 2397 | return true; | ||
| 2398 | } else if (sema_kit) |sk| { | ||
| 2399 | return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, ty)); | ||
| 2400 | } else { | ||
| 2401 | return !comptimeOnly(ty); | ||
| 2402 | } | ||
| 2403 | }, | ||
| 2404 | |||
| 2379 | // These are false because they are comptime-only types. | 2405 | // These are false because they are comptime-only types. |
| 2380 | .single_const_pointer_to_comptime_int, | 2406 | .single_const_pointer_to_comptime_int, |
| 2381 | .void, | 2407 | .void, |
| ... | @@ -2399,30 +2425,6 @@ pub const Type = extern union { | ... | @@ -2399,30 +2425,6 @@ pub const Type = extern union { |
| 2399 | .fn_ccc_void_no_args, | 2425 | .fn_ccc_void_no_args, |
| 2400 | => return false, | 2426 | => return false, |
| 2401 | 2427 | ||
| 2402 | // These types have more than one possible value, so the result is the same as | ||
| 2403 | // asking whether they are comptime-only types. | ||
| 2404 | .anyframe_T, | ||
| 2405 | .optional_single_mut_pointer, | ||
| 2406 | .optional_single_const_pointer, | ||
| 2407 | .single_const_pointer, | ||
| 2408 | .single_mut_pointer, | ||
| 2409 | .many_const_pointer, | ||
| 2410 | .many_mut_pointer, | ||
| 2411 | .c_const_pointer, | ||
| 2412 | .c_mut_pointer, | ||
| 2413 | .const_slice, | ||
| 2414 | .mut_slice, | ||
| 2415 | .pointer, | ||
| 2416 | => { | ||
| 2417 | if (ignore_comptime_only) { | ||
| 2418 | return true; | ||
| 2419 | } else if (sema_kit) |sk| { | ||
| 2420 | return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, ty)); | ||
| 2421 | } else { | ||
| 2422 | return !comptimeOnly(ty); | ||
| 2423 | } | ||
| 2424 | }, | ||
| 2425 | |||
| 2426 | .optional => { | 2428 | .optional => { |
| 2427 | var buf: Payload.ElemType = undefined; | 2429 | var buf: Payload.ElemType = undefined; |
| 2428 | const child_ty = ty.optionalChild(&buf); | 2430 | const child_ty = ty.optionalChild(&buf); |
| ... | @@ -3029,6 +3031,15 @@ pub const Type = extern union { | ... | @@ -3029,6 +3031,15 @@ pub const Type = extern union { |
| 3029 | }, | 3031 | }, |
| 3030 | }; | 3032 | }; |
| 3031 | big_align = @maximum(big_align, field_align); | 3033 | big_align = @maximum(big_align, field_align); |
| 3034 | |||
| 3035 | // This logic is duplicated in Module.Struct.Field.alignment. | ||
| 3036 | if (struct_obj.layout == .Extern or target.ofmt == .c) { | ||
| 3037 | if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) { | ||
| 3038 | // The C ABI requires 128 bit integer fields of structs | ||
| 3039 | // to be 16-bytes aligned. | ||
| 3040 | big_align = @maximum(big_align, 16); | ||
| 3041 | } | ||
| 3042 | } | ||
| 3032 | } | 3043 | } |
| 3033 | return AbiAlignmentAdvanced{ .scalar = big_align }; | 3044 | return AbiAlignmentAdvanced{ .scalar = big_align }; |
| 3034 | }, | 3045 | }, |
| ... | @@ -3263,8 +3274,8 @@ pub const Type = extern union { | ... | @@ -3263,8 +3274,8 @@ pub const Type = extern union { |
| 3263 | 3274 | ||
| 3264 | .array_u8 => return AbiSizeAdvanced{ .scalar = ty.castTag(.array_u8).?.data }, | 3275 | .array_u8 => return AbiSizeAdvanced{ .scalar = ty.castTag(.array_u8).?.data }, |
| 3265 | .array_u8_sentinel_0 => return AbiSizeAdvanced{ .scalar = ty.castTag(.array_u8_sentinel_0).?.data + 1 }, | 3276 | .array_u8_sentinel_0 => return AbiSizeAdvanced{ .scalar = ty.castTag(.array_u8_sentinel_0).?.data + 1 }, |
| 3266 | .array, .vector => { | 3277 | .array => { |
| 3267 | const payload = ty.cast(Payload.Array).?.data; | 3278 | const payload = ty.castTag(.array).?.data; |
| 3268 | switch (try payload.elem_type.abiSizeAdvanced(target, strat)) { | 3279 | switch (try payload.elem_type.abiSizeAdvanced(target, strat)) { |
| 3269 | .scalar => |elem_size| return AbiSizeAdvanced{ .scalar = payload.len * elem_size }, | 3280 | .scalar => |elem_size| return AbiSizeAdvanced{ .scalar = payload.len * elem_size }, |
| 3270 | .val => switch (strat) { | 3281 | .val => switch (strat) { |
| ... | @@ -3286,6 +3297,28 @@ pub const Type = extern union { | ... | @@ -3286,6 +3297,28 @@ pub const Type = extern union { |
| 3286 | } | 3297 | } |
| 3287 | }, | 3298 | }, |
| 3288 | 3299 | ||
| 3300 | .vector => { | ||
| 3301 | const payload = ty.castTag(.vector).?.data; | ||
| 3302 | const sema_kit = switch (strat) { | ||
| 3303 | .sema_kit => |sk| sk, | ||
| 3304 | .eager => null, | ||
| 3305 | .lazy => |arena| return AbiSizeAdvanced{ | ||
| 3306 | .val = try Value.Tag.lazy_size.create(arena, ty), | ||
| 3307 | }, | ||
| 3308 | }; | ||
| 3309 | const elem_bits = try payload.elem_type.bitSizeAdvanced(target, sema_kit); | ||
| 3310 | const total_bits = elem_bits * payload.len; | ||
| 3311 | const total_bytes = (total_bits + 7) / 8; | ||
| 3312 | const alignment = switch (try ty.abiAlignmentAdvanced(target, strat)) { | ||
| 3313 | .scalar => |x| x, | ||
| 3314 | .val => return AbiSizeAdvanced{ | ||
| 3315 | .val = try Value.Tag.lazy_size.create(strat.lazy, ty), | ||
| 3316 | }, | ||
| 3317 | }; | ||
| 3318 | const result = std.mem.alignForwardGeneric(u64, total_bytes, alignment); | ||
| 3319 | return AbiSizeAdvanced{ .scalar = result }; | ||
| 3320 | }, | ||
| 3321 | |||
| 3289 | .isize, | 3322 | .isize, |
| 3290 | .usize, | 3323 | .usize, |
| 3291 | .@"anyframe", | 3324 | .@"anyframe", |
| ... | @@ -3329,7 +3362,13 @@ pub const Type = extern union { | ... | @@ -3329,7 +3362,13 @@ pub const Type = extern union { |
| 3329 | .f128 => return AbiSizeAdvanced{ .scalar = 16 }, | 3362 | .f128 => return AbiSizeAdvanced{ .scalar = 16 }, |
| 3330 | 3363 | ||
| 3331 | .f80 => switch (target.cpu.arch) { | 3364 | .f80 => switch (target.cpu.arch) { |
| 3332 | .i386 => return AbiSizeAdvanced{ .scalar = 12 }, | 3365 | .i386 => switch (target.os.tag) { |
| 3366 | .windows => switch (target.abi) { | ||
| 3367 | .msvc => return AbiSizeAdvanced{ .scalar = 16 }, | ||
| 3368 | else => return AbiSizeAdvanced{ .scalar = 12 }, | ||
| 3369 | }, | ||
| 3370 | else => return AbiSizeAdvanced{ .scalar = 12 }, | ||
| 3371 | }, | ||
| 3333 | .x86_64 => return AbiSizeAdvanced{ .scalar = 16 }, | 3372 | .x86_64 => return AbiSizeAdvanced{ .scalar = 16 }, |
| 3334 | else => { | 3373 | else => { |
| 3335 | var payload: Payload.Bits = .{ | 3374 | var payload: Payload.Bits = .{ |
| ... | @@ -4540,6 +4579,12 @@ pub const Type = extern union { | ... | @@ -4540,6 +4579,12 @@ pub const Type = extern union { |
| 4540 | 4579 | ||
| 4541 | .vector => ty = ty.castTag(.vector).?.data.elem_type, | 4580 | .vector => ty = ty.castTag(.vector).?.data.elem_type, |
| 4542 | 4581 | ||
| 4582 | .@"struct" => { | ||
| 4583 | const struct_obj = ty.castTag(.@"struct").?.data; | ||
| 4584 | assert(struct_obj.layout == .Packed); | ||
| 4585 | ty = struct_obj.backing_int_ty; | ||
| 4586 | }, | ||
| 4587 | |||
| 4543 | else => unreachable, | 4588 | else => unreachable, |
| 4544 | }; | 4589 | }; |
| 4545 | } | 4590 | } |
| ... | @@ -5502,7 +5547,7 @@ pub const Type = extern union { | ... | @@ -5502,7 +5547,7 @@ pub const Type = extern union { |
| 5502 | .@"struct" => { | 5547 | .@"struct" => { |
| 5503 | const struct_obj = ty.castTag(.@"struct").?.data; | 5548 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 5504 | assert(struct_obj.layout != .Packed); | 5549 | assert(struct_obj.layout != .Packed); |
| 5505 | return struct_obj.fields.values()[index].normalAlignment(target); | 5550 | return struct_obj.fields.values()[index].alignment(target, struct_obj.layout); |
| 5506 | }, | 5551 | }, |
| 5507 | .@"union", .union_safety_tagged, .union_tagged => { | 5552 | .@"union", .union_safety_tagged, .union_tagged => { |
| 5508 | const union_obj = ty.cast(Payload.Union).?.data; | 5553 | const union_obj = ty.cast(Payload.Union).?.data; |
| ... | @@ -5609,7 +5654,7 @@ pub const Type = extern union { | ... | @@ -5609,7 +5654,7 @@ pub const Type = extern union { |
| 5609 | if (!field.ty.hasRuntimeBits() or field.is_comptime) | 5654 | if (!field.ty.hasRuntimeBits() or field.is_comptime) |
| 5610 | return FieldOffset{ .field = it.field, .offset = it.offset }; | 5655 | return FieldOffset{ .field = it.field, .offset = it.offset }; |
| 5611 | 5656 | ||
| 5612 | const field_align = field.normalAlignment(it.target); | 5657 | const field_align = field.alignment(it.target, it.struct_obj.layout); |
| 5613 | it.big_align = @maximum(it.big_align, field_align); | 5658 | it.big_align = @maximum(it.big_align, field_align); |
| 5614 | it.offset = std.mem.alignForwardGeneric(u64, it.offset, field_align); | 5659 | it.offset = std.mem.alignForwardGeneric(u64, it.offset, field_align); |
| 5615 | defer it.offset += field.ty.abiSize(it.target); | 5660 | defer it.offset += field.ty.abiSize(it.target); |
test/behavior/align.zig+42-15| ... | @@ -100,8 +100,8 @@ test "alignment and size of structs with 128-bit fields" { | ... | @@ -100,8 +100,8 @@ test "alignment and size of structs with 128-bit fields" { |
| 100 | .a_align = 8, | 100 | .a_align = 8, |
| 101 | .a_size = 16, | 101 | .a_size = 16, |
| 102 | 102 | ||
| 103 | .b_align = 8, | 103 | .b_align = 16, |
| 104 | .b_size = 24, | 104 | .b_size = 32, |
| 105 | 105 | ||
| 106 | .u128_align = 8, | 106 | .u128_align = 8, |
| 107 | .u128_size = 16, | 107 | .u128_size = 16, |
| ... | @@ -114,8 +114,8 @@ test "alignment and size of structs with 128-bit fields" { | ... | @@ -114,8 +114,8 @@ test "alignment and size of structs with 128-bit fields" { |
| 114 | .a_align = 8, | 114 | .a_align = 8, |
| 115 | .a_size = 16, | 115 | .a_size = 16, |
| 116 | 116 | ||
| 117 | .b_align = 8, | 117 | .b_align = 16, |
| 118 | .b_size = 24, | 118 | .b_size = 32, |
| 119 | 119 | ||
| 120 | .u128_align = 8, | 120 | .u128_align = 8, |
| 121 | .u128_size = 16, | 121 | .u128_size = 16, |
| ... | @@ -126,8 +126,8 @@ test "alignment and size of structs with 128-bit fields" { | ... | @@ -126,8 +126,8 @@ test "alignment and size of structs with 128-bit fields" { |
| 126 | .a_align = 4, | 126 | .a_align = 4, |
| 127 | .a_size = 16, | 127 | .a_size = 16, |
| 128 | 128 | ||
| 129 | .b_align = 4, | 129 | .b_align = 16, |
| 130 | .b_size = 20, | 130 | .b_size = 32, |
| 131 | 131 | ||
| 132 | .u128_align = 4, | 132 | .u128_align = 4, |
| 133 | .u128_size = 16, | 133 | .u128_size = 16, |
| ... | @@ -140,12 +140,39 @@ test "alignment and size of structs with 128-bit fields" { | ... | @@ -140,12 +140,39 @@ test "alignment and size of structs with 128-bit fields" { |
| 140 | .mips64el, | 140 | .mips64el, |
| 141 | .powerpc64, | 141 | .powerpc64, |
| 142 | .powerpc64le, | 142 | .powerpc64le, |
| 143 | .riscv64, | ||
| 144 | .sparc64, | 143 | .sparc64, |
| 145 | .x86_64, | 144 | .x86_64, |
| 145 | => switch (builtin.object_format) { | ||
| 146 | .c => .{ | ||
| 147 | .a_align = 16, | ||
| 148 | .a_size = 16, | ||
| 149 | |||
| 150 | .b_align = 16, | ||
| 151 | .b_size = 32, | ||
| 152 | |||
| 153 | .u128_align = 16, | ||
| 154 | .u128_size = 16, | ||
| 155 | .u129_align = 16, | ||
| 156 | .u129_size = 32, | ||
| 157 | }, | ||
| 158 | else => .{ | ||
| 159 | .a_align = 8, | ||
| 160 | .a_size = 16, | ||
| 161 | |||
| 162 | .b_align = 16, | ||
| 163 | .b_size = 32, | ||
| 164 | |||
| 165 | .u128_align = 8, | ||
| 166 | .u128_size = 16, | ||
| 167 | .u129_align = 8, | ||
| 168 | .u129_size = 24, | ||
| 169 | }, | ||
| 170 | }, | ||
| 171 | |||
| 146 | .aarch64, | 172 | .aarch64, |
| 147 | .aarch64_be, | 173 | .aarch64_be, |
| 148 | .aarch64_32, | 174 | .aarch64_32, |
| 175 | .riscv64, | ||
| 149 | .bpfel, | 176 | .bpfel, |
| 150 | .bpfeb, | 177 | .bpfeb, |
| 151 | .nvptx, | 178 | .nvptx, |
| ... | @@ -166,17 +193,17 @@ test "alignment and size of structs with 128-bit fields" { | ... | @@ -166,17 +193,17 @@ test "alignment and size of structs with 128-bit fields" { |
| 166 | else => return error.SkipZigTest, | 193 | else => return error.SkipZigTest, |
| 167 | }; | 194 | }; |
| 168 | comptime { | 195 | comptime { |
| 169 | std.debug.assert(@alignOf(A) == expected.a_align); | 196 | assert(@alignOf(A) == expected.a_align); |
| 170 | std.debug.assert(@sizeOf(A) == expected.a_size); | 197 | assert(@sizeOf(A) == expected.a_size); |
| 171 | 198 | ||
| 172 | std.debug.assert(@alignOf(B) == expected.b_align); | 199 | assert(@alignOf(B) == expected.b_align); |
| 173 | std.debug.assert(@sizeOf(B) == expected.b_size); | 200 | assert(@sizeOf(B) == expected.b_size); |
| 174 | 201 | ||
| 175 | std.debug.assert(@alignOf(u128) == expected.u128_align); | 202 | assert(@alignOf(u128) == expected.u128_align); |
| 176 | std.debug.assert(@sizeOf(u128) == expected.u128_size); | 203 | assert(@sizeOf(u128) == expected.u128_size); |
| 177 | 204 | ||
| 178 | std.debug.assert(@alignOf(u129) == expected.u129_align); | 205 | assert(@alignOf(u129) == expected.u129_align); |
| 179 | std.debug.assert(@sizeOf(u129) == expected.u129_size); | 206 | assert(@sizeOf(u129) == expected.u129_size); |
| 180 | } | 207 | } |
| 181 | } | 208 | } |
| 182 | 209 |