| author | |
| committer | |
| log | b7799ef322103c8e449c45494c29fb4a8c9867df |
| tree | f1f1a5fe4c52a7ce335a6e1ae75e939bcb07c86d |
| parent | 62381011e0dd692ec6bb30d14e0d5e2f6ec4d5d5 |
This should not be a public API, and the x86 backend does not support
the value 16.7 files changed, 145 insertions(+), 111 deletions(-)
lib/compiler/aro/aro/Type.zig+1-1| ... | ... | @@ -1116,7 +1116,7 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 { |
| 1116 | 1116 | |
| 1117 | 1117 | .bit_int => @min( |
| 1118 | 1118 | std.math.ceilPowerOfTwoPromote(u16, (ty.data.int.bits + 7) / 8), |
| 1119 | comp.target.maxIntAlignment(), | |
| 1119 | 16, // comp.target.maxIntAlignment(), please use your own logic for this value as it is implementation-defined | |
| 1120 | 1120 | ), |
| 1121 | 1121 | |
| 1122 | 1122 | .float => comp.target.c_type_alignment(.float), |
lib/std/Target.zig-91| ... | ... | @@ -1862,97 +1862,6 @@ pub fn standardDynamicLinkerPath(target: Target) DynamicLinker { |
| 1862 | 1862 | return DynamicLinker.standard(target.cpu, target.os.tag, target.abi); |
| 1863 | 1863 | } |
| 1864 | 1864 | |
| 1865 | pub fn maxIntAlignment(target: Target) u16 { | |
| 1866 | return switch (target.cpu.arch) { | |
| 1867 | .avr => 1, | |
| 1868 | .msp430 => 2, | |
| 1869 | .xcore => 4, | |
| 1870 | ||
| 1871 | .arm, | |
| 1872 | .armeb, | |
| 1873 | .thumb, | |
| 1874 | .thumbeb, | |
| 1875 | .hexagon, | |
| 1876 | .mips, | |
| 1877 | .mipsel, | |
| 1878 | .powerpc, | |
| 1879 | .powerpcle, | |
| 1880 | .r600, | |
| 1881 | .amdgcn, | |
| 1882 | .riscv32, | |
| 1883 | .sparc, | |
| 1884 | .sparcel, | |
| 1885 | .s390x, | |
| 1886 | .lanai, | |
| 1887 | .wasm32, | |
| 1888 | .wasm64, | |
| 1889 | => 8, | |
| 1890 | ||
| 1891 | .x86 => if (target.ofmt == .c) 16 else return switch (target.os.tag) { | |
| 1892 | .windows, .uefi => 8, | |
| 1893 | else => 4, | |
| 1894 | }, | |
| 1895 | ||
| 1896 | // For these, LLVMABIAlignmentOfType(i128) reports 8. Note that 16 | |
| 1897 | // is a relevant number in three cases: | |
| 1898 | // 1. Different machine code instruction when loading into SIMD register. | |
| 1899 | // 2. The C ABI wants 16 for extern structs. | |
| 1900 | // 3. 16-byte cmpxchg needs 16-byte alignment. | |
| 1901 | // Same logic for powerpc64, mips64, sparc64. | |
| 1902 | .powerpc64, | |
| 1903 | .powerpc64le, | |
| 1904 | .mips64, | |
| 1905 | .mips64el, | |
| 1906 | .sparc64, | |
| 1907 | => return switch (target.ofmt) { | |
| 1908 | .c => 16, | |
| 1909 | else => 8, | |
| 1910 | }, | |
| 1911 | ||
| 1912 | // Even LLVMABIAlignmentOfType(i128) agrees on these targets. | |
| 1913 | .x86_64, | |
| 1914 | .aarch64, | |
| 1915 | .aarch64_be, | |
| 1916 | .aarch64_32, | |
| 1917 | .riscv64, | |
| 1918 | .bpfel, | |
| 1919 | .bpfeb, | |
| 1920 | .nvptx, | |
| 1921 | .nvptx64, | |
| 1922 | => 16, | |
| 1923 | ||
| 1924 | // Below this comment are unverified but based on the fact that C requires | |
| 1925 | // int128_t to be 16 bytes aligned, it's a safe default. | |
| 1926 | .spu_2, | |
| 1927 | .csky, | |
| 1928 | .arc, | |
| 1929 | .m68k, | |
| 1930 | .tce, | |
| 1931 | .tcele, | |
| 1932 | .le32, | |
| 1933 | .amdil, | |
| 1934 | .hsail, | |
| 1935 | .spir, | |
| 1936 | .kalimba, | |
| 1937 | .renderscript32, | |
| 1938 | .spirv, | |
| 1939 | .spirv32, | |
| 1940 | .shave, | |
| 1941 | .le64, | |
| 1942 | .amdil64, | |
| 1943 | .hsail64, | |
| 1944 | .spir64, | |
| 1945 | .renderscript64, | |
| 1946 | .ve, | |
| 1947 | .spirv64, | |
| 1948 | .dxil, | |
| 1949 | .loongarch32, | |
| 1950 | .loongarch64, | |
| 1951 | .xtensa, | |
| 1952 | => 16, | |
| 1953 | }; | |
| 1954 | } | |
| 1955 | ||
| 1956 | 1865 | pub fn ptrBitWidth_cpu_abi(cpu: Cpu, abi: Abi) u16 { |
| 1957 | 1866 | switch (abi) { |
| 1958 | 1867 | .gnux32, .muslx32, .gnuabin32, .gnuilp32 => return 32, |
src/codegen/c/Type.zig+5-5| ... | ... | @@ -1312,10 +1312,10 @@ pub const Pool = struct { |
| 1312 | 1312 | }, |
| 1313 | 1313 | else => { |
| 1314 | 1314 | const target = &mod.resolved_target.result; |
| 1315 | const abi_align = Type.intAbiAlignment(int_info.bits, target.*); | |
| 1315 | const abi_align = Type.intAbiAlignment(int_info.bits, target.*, false); | |
| 1316 | 1316 | const abi_align_bytes = abi_align.toByteUnits().?; |
| 1317 | 1317 | const array_ctype = try pool.getArray(allocator, .{ |
| 1318 | .len = @divExact(Type.intAbiSize(int_info.bits, target.*), abi_align_bytes), | |
| 1318 | .len = @divExact(Type.intAbiSize(int_info.bits, target.*, false), abi_align_bytes), | |
| 1319 | 1319 | .elem_ctype = try pool.fromIntInfo(allocator, .{ |
| 1320 | 1320 | .signedness = .unsigned, |
| 1321 | 1321 | .bits = @intCast(abi_align_bytes * 8), |
| ... | ... | @@ -1443,7 +1443,7 @@ pub const Pool = struct { |
| 1443 | 1443 | .name = .{ .index = .len }, |
| 1444 | 1444 | .ctype = CType.usize, |
| 1445 | 1445 | .alignas = AlignAs.fromAbiAlignment( |
| 1446 | Type.intAbiAlignment(target.ptrBitWidth(), target.*), | |
| 1446 | Type.intAbiAlignment(target.ptrBitWidth(), target.*, false), | |
| 1447 | 1447 | ), |
| 1448 | 1448 | }, |
| 1449 | 1449 | }; |
| ... | ... | @@ -1545,7 +1545,7 @@ pub const Pool = struct { |
| 1545 | 1545 | .name = .{ .index = .len }, |
| 1546 | 1546 | .ctype = CType.usize, |
| 1547 | 1547 | .alignas = AlignAs.fromAbiAlignment( |
| 1548 | Type.intAbiAlignment(target.ptrBitWidth(), target.*), | |
| 1548 | Type.intAbiAlignment(target.ptrBitWidth(), target.*, false), | |
| 1549 | 1549 | ), |
| 1550 | 1550 | }, |
| 1551 | 1551 | }; |
| ... | ... | @@ -1665,7 +1665,7 @@ pub const Pool = struct { |
| 1665 | 1665 | .name = .{ .index = .@"error" }, |
| 1666 | 1666 | .ctype = error_set_ctype, |
| 1667 | 1667 | .alignas = AlignAs.fromAbiAlignment( |
| 1668 | Type.intAbiAlignment(error_set_bits, target.*), | |
| 1668 | Type.intAbiAlignment(error_set_bits, target.*, false), | |
| 1669 | 1669 | ), |
| 1670 | 1670 | }, |
| 1671 | 1671 | .{ |
src/codegen/llvm.zig+1-1| ... | ... | @@ -609,7 +609,7 @@ const DataLayoutBuilder = struct { |
| 609 | 609 | switch (kind) { |
| 610 | 610 | .integer => { |
| 611 | 611 | if (self.target.ptrBitWidth() <= 16 and size >= 128) return; |
| 612 | abi = @min(abi, self.target.maxIntAlignment() * 8); | |
| 612 | abi = @min(abi, Type.maxIntAlignment(self.target, true) * 8); | |
| 613 | 613 | switch (self.target.cpu.arch) { |
| 614 | 614 | .aarch64, |
| 615 | 615 | .aarch64_be, |
src/link/C.zig+3-1| ... | ... | @@ -383,7 +383,9 @@ fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) { |
| 383 | 383 | .msvc => try writer.writeAll("#define ZIG_TARGET_ABI_MSVC\n"), |
| 384 | 384 | else => {}, |
| 385 | 385 | } |
| 386 | try writer.print("#define ZIG_TARGET_MAX_INT_ALIGNMENT {d}\n", .{target.maxIntAlignment()}); | |
| 386 | try writer.print("#define ZIG_TARGET_MAX_INT_ALIGNMENT {d}\n", .{ | |
| 387 | Type.maxIntAlignment(target, false), | |
| 388 | }); | |
| 387 | 389 | return defines; |
| 388 | 390 | } |
| 389 | 391 |
src/type.zig+108-11| ... | ... | @@ -883,6 +883,7 @@ pub const Type = struct { |
| 883 | 883 | strat: AbiAlignmentAdvancedStrat, |
| 884 | 884 | ) Module.CompileError!AbiAlignmentAdvanced { |
| 885 | 885 | const target = mod.getTarget(); |
| 886 | const use_llvm = mod.comp.config.use_llvm; | |
| 886 | 887 | const ip = &mod.intern_pool; |
| 887 | 888 | |
| 888 | 889 | const opt_sema = switch (strat) { |
| ... | ... | @@ -895,7 +896,7 @@ pub const Type = struct { |
| 895 | 896 | else => switch (ip.indexToKey(ty.toIntern())) { |
| 896 | 897 | .int_type => |int_type| { |
| 897 | 898 | if (int_type.bits == 0) return AbiAlignmentAdvanced{ .scalar = .@"1" }; |
| 898 | return .{ .scalar = intAbiAlignment(int_type.bits, target) }; | |
| 899 | return .{ .scalar = intAbiAlignment(int_type.bits, target, use_llvm) }; | |
| 899 | 900 | }, |
| 900 | 901 | .ptr_type, .anyframe_type => { |
| 901 | 902 | return .{ .scalar = ptrAbiAlignment(target) }; |
| ... | ... | @@ -941,7 +942,7 @@ pub const Type = struct { |
| 941 | 942 | .error_set_type, .inferred_error_set_type => { |
| 942 | 943 | const bits = mod.errorSetBits(); |
| 943 | 944 | if (bits == 0) return AbiAlignmentAdvanced{ .scalar = .@"1" }; |
| 944 | return .{ .scalar = intAbiAlignment(bits, target) }; | |
| 945 | return .{ .scalar = intAbiAlignment(bits, target, use_llvm) }; | |
| 945 | 946 | }, |
| 946 | 947 | |
| 947 | 948 | // represents machine code; not a pointer |
| ... | ... | @@ -962,7 +963,7 @@ pub const Type = struct { |
| 962 | 963 | |
| 963 | 964 | .usize, |
| 964 | 965 | .isize, |
| 965 | => return .{ .scalar = intAbiAlignment(target.ptrBitWidth(), target) }, | |
| 966 | => return .{ .scalar = intAbiAlignment(target.ptrBitWidth(), target, use_llvm) }, | |
| 966 | 967 | |
| 967 | 968 | .export_options, |
| 968 | 969 | .extern_options, |
| ... | ... | @@ -1001,7 +1002,7 @@ pub const Type = struct { |
| 1001 | 1002 | .anyerror, .adhoc_inferred_error_set => { |
| 1002 | 1003 | const bits = mod.errorSetBits(); |
| 1003 | 1004 | if (bits == 0) return AbiAlignmentAdvanced{ .scalar = .@"1" }; |
| 1004 | return .{ .scalar = intAbiAlignment(bits, target) }; | |
| 1005 | return .{ .scalar = intAbiAlignment(bits, target, use_llvm) }; | |
| 1005 | 1006 | }, |
| 1006 | 1007 | |
| 1007 | 1008 | .void, |
| ... | ... | @@ -1216,6 +1217,7 @@ pub const Type = struct { |
| 1216 | 1217 | strat: AbiAlignmentAdvancedStrat, |
| 1217 | 1218 | ) Module.CompileError!AbiSizeAdvanced { |
| 1218 | 1219 | const target = mod.getTarget(); |
| 1220 | const use_llvm = mod.comp.config.use_llvm; | |
| 1219 | 1221 | const ip = &mod.intern_pool; |
| 1220 | 1222 | |
| 1221 | 1223 | switch (ty.toIntern()) { |
| ... | ... | @@ -1224,7 +1226,7 @@ pub const Type = struct { |
| 1224 | 1226 | else => switch (ip.indexToKey(ty.toIntern())) { |
| 1225 | 1227 | .int_type => |int_type| { |
| 1226 | 1228 | if (int_type.bits == 0) return AbiSizeAdvanced{ .scalar = 0 }; |
| 1227 | return AbiSizeAdvanced{ .scalar = intAbiSize(int_type.bits, target) }; | |
| 1229 | return AbiSizeAdvanced{ .scalar = intAbiSize(int_type.bits, target, use_llvm) }; | |
| 1228 | 1230 | }, |
| 1229 | 1231 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { |
| 1230 | 1232 | .Slice => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) * 2 }, |
| ... | ... | @@ -1286,7 +1288,7 @@ pub const Type = struct { |
| 1286 | 1288 | .error_set_type, .inferred_error_set_type => { |
| 1287 | 1289 | const bits = mod.errorSetBits(); |
| 1288 | 1290 | if (bits == 0) return AbiSizeAdvanced{ .scalar = 0 }; |
| 1289 | return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target) }; | |
| 1291 | return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target, use_llvm) }; | |
| 1290 | 1292 | }, |
| 1291 | 1293 | |
| 1292 | 1294 | .error_union_type => |error_union_type| { |
| ... | ... | @@ -1384,7 +1386,7 @@ pub const Type = struct { |
| 1384 | 1386 | .anyerror, .adhoc_inferred_error_set => { |
| 1385 | 1387 | const bits = mod.errorSetBits(); |
| 1386 | 1388 | if (bits == 0) return AbiSizeAdvanced{ .scalar = 0 }; |
| 1387 | return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target) }; | |
| 1389 | return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target, use_llvm) }; | |
| 1388 | 1390 | }, |
| 1389 | 1391 | |
| 1390 | 1392 | .prefetch_options => unreachable, // missing call to resolveTypeFields |
| ... | ... | @@ -1533,17 +1535,112 @@ pub const Type = struct { |
| 1533 | 1535 | return Alignment.fromNonzeroByteUnits(@divExact(target.ptrBitWidth(), 8)); |
| 1534 | 1536 | } |
| 1535 | 1537 | |
| 1536 | pub fn intAbiSize(bits: u16, target: Target) u64 { | |
| 1537 | return intAbiAlignment(bits, target).forward(@as(u16, @intCast((@as(u17, bits) + 7) / 8))); | |
| 1538 | pub fn intAbiSize(bits: u16, target: Target, use_llvm: bool) u64 { | |
| 1539 | return intAbiAlignment(bits, target, use_llvm).forward(@as(u16, @intCast((@as(u17, bits) + 7) / 8))); | |
| 1538 | 1540 | } |
| 1539 | 1541 | |
| 1540 | pub fn intAbiAlignment(bits: u16, target: Target) Alignment { | |
| 1542 | pub fn intAbiAlignment(bits: u16, target: Target, use_llvm: bool) Alignment { | |
| 1541 | 1543 | return Alignment.fromByteUnits(@min( |
| 1542 | 1544 | std.math.ceilPowerOfTwoPromote(u16, @as(u16, @intCast((@as(u17, bits) + 7) / 8))), |
| 1543 | target.maxIntAlignment(), | |
| 1545 | maxIntAlignment(target, use_llvm), | |
| 1544 | 1546 | )); |
| 1545 | 1547 | } |
| 1546 | 1548 | |
| 1549 | pub fn maxIntAlignment(target: std.Target, use_llvm: bool) u16 { | |
| 1550 | return switch (target.cpu.arch) { | |
| 1551 | .avr => 1, | |
| 1552 | .msp430 => 2, | |
| 1553 | .xcore => 4, | |
| 1554 | ||
| 1555 | .arm, | |
| 1556 | .armeb, | |
| 1557 | .thumb, | |
| 1558 | .thumbeb, | |
| 1559 | .hexagon, | |
| 1560 | .mips, | |
| 1561 | .mipsel, | |
| 1562 | .powerpc, | |
| 1563 | .powerpcle, | |
| 1564 | .r600, | |
| 1565 | .amdgcn, | |
| 1566 | .riscv32, | |
| 1567 | .sparc, | |
| 1568 | .sparcel, | |
| 1569 | .s390x, | |
| 1570 | .lanai, | |
| 1571 | .wasm32, | |
| 1572 | .wasm64, | |
| 1573 | => 8, | |
| 1574 | ||
| 1575 | .x86 => if (target.ofmt == .c) 16 else return switch (target.os.tag) { | |
| 1576 | .windows, .uefi => 8, | |
| 1577 | else => 4, | |
| 1578 | }, | |
| 1579 | ||
| 1580 | // For these, LLVMABIAlignmentOfType(i128) reports 8. Note that 16 | |
| 1581 | // is a relevant number in three cases: | |
| 1582 | // 1. Different machine code instruction when loading into SIMD register. | |
| 1583 | // 2. The C ABI wants 16 for extern structs. | |
| 1584 | // 3. 16-byte cmpxchg needs 16-byte alignment. | |
| 1585 | // Same logic for powerpc64, mips64, sparc64. | |
| 1586 | .powerpc64, | |
| 1587 | .powerpc64le, | |
| 1588 | .mips64, | |
| 1589 | .mips64el, | |
| 1590 | .sparc64, | |
| 1591 | => switch (target.ofmt) { | |
| 1592 | .c => 16, | |
| 1593 | else => 8, | |
| 1594 | }, | |
| 1595 | ||
| 1596 | .x86_64 => switch (target_util.zigBackend(target, use_llvm)) { | |
| 1597 | .stage2_x86_64 => 8, | |
| 1598 | else => 16, | |
| 1599 | }, | |
| 1600 | ||
| 1601 | // Even LLVMABIAlignmentOfType(i128) agrees on these targets. | |
| 1602 | .aarch64, | |
| 1603 | .aarch64_be, | |
| 1604 | .aarch64_32, | |
| 1605 | .riscv64, | |
| 1606 | .bpfel, | |
| 1607 | .bpfeb, | |
| 1608 | .nvptx, | |
| 1609 | .nvptx64, | |
| 1610 | => 16, | |
| 1611 | ||
| 1612 | // Below this comment are unverified but based on the fact that C requires | |
| 1613 | // int128_t to be 16 bytes aligned, it's a safe default. | |
| 1614 | .spu_2, | |
| 1615 | .csky, | |
| 1616 | .arc, | |
| 1617 | .m68k, | |
| 1618 | .tce, | |
| 1619 | .tcele, | |
| 1620 | .le32, | |
| 1621 | .amdil, | |
| 1622 | .hsail, | |
| 1623 | .spir, | |
| 1624 | .kalimba, | |
| 1625 | .renderscript32, | |
| 1626 | .spirv, | |
| 1627 | .spirv32, | |
| 1628 | .shave, | |
| 1629 | .le64, | |
| 1630 | .amdil64, | |
| 1631 | .hsail64, | |
| 1632 | .spir64, | |
| 1633 | .renderscript64, | |
| 1634 | .ve, | |
| 1635 | .spirv64, | |
| 1636 | .dxil, | |
| 1637 | .loongarch32, | |
| 1638 | .loongarch64, | |
| 1639 | .xtensa, | |
| 1640 | => 16, | |
| 1641 | }; | |
| 1642 | } | |
| 1643 | ||
| 1547 | 1644 | pub fn bitSize(ty: Type, mod: *Module) u64 { |
| 1548 | 1645 | return bitSizeAdvanced(ty, mod, null) catch unreachable; |
| 1549 | 1646 | } |
test/behavior/align.zig+27-1| ... | ... | @@ -184,6 +184,33 @@ test "alignment and size of structs with 128-bit fields" { |
| 184 | 184 | }, |
| 185 | 185 | }, |
| 186 | 186 | |
| 187 | .x86_64 => switch (builtin.zig_backend) { | |
| 188 | .stage2_x86_64 => .{ | |
| 189 | .a_align = 8, | |
| 190 | .a_size = 16, | |
| 191 | ||
| 192 | .b_align = 16, | |
| 193 | .b_size = 32, | |
| 194 | ||
| 195 | .u128_align = 8, | |
| 196 | .u128_size = 16, | |
| 197 | .u129_align = 8, | |
| 198 | .u129_size = 24, | |
| 199 | }, | |
| 200 | else => .{ | |
| 201 | .a_align = 16, | |
| 202 | .a_size = 16, | |
| 203 | ||
| 204 | .b_align = 16, | |
| 205 | .b_size = 32, | |
| 206 | ||
| 207 | .u128_align = 16, | |
| 208 | .u128_size = 16, | |
| 209 | .u129_align = 16, | |
| 210 | .u129_size = 32, | |
| 211 | }, | |
| 212 | }, | |
| 213 | ||
| 187 | 214 | .aarch64, |
| 188 | 215 | .aarch64_be, |
| 189 | 216 | .aarch64_32, |
| ... | ... | @@ -192,7 +219,6 @@ test "alignment and size of structs with 128-bit fields" { |
| 192 | 219 | .bpfeb, |
| 193 | 220 | .nvptx, |
| 194 | 221 | .nvptx64, |
| 195 | .x86_64, | |
| 196 | 222 | => .{ |
| 197 | 223 | .a_align = 16, |
| 198 | 224 | .a_size = 16, |