authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-08-18 20:34:36-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-08-18 20:34:36-07:00
logcee82c7ce4fb8beb39042f9dba16a1a391803fa4
treeea2a12b10b3742acc3f343a36bf14a8c34246776
parentb975f7a56fec9e0e7aca9832282bc772c743d731

improved ABI alignment/size for >= 128-bit integers

* riscv64: adjust alignment and size of 128-bit integers. * take ofmt=c into account for ABI alignment of 128-bit integers and structs. * Type: make packed struct support intInfo * fix f80 alignment for i386-windows-msvc

4 files changed, 69 insertions(+), 32 deletions(-)

lib/std/target.zig+6-3
......@@ -1808,20 +1808,23 @@ pub const Target = struct {
18081808 // 1. Different machine code instruction when loading into SIMD register.
18091809 // 2. The C ABI wants 16 for extern structs.
18101810 // 3. 16-byte cmpxchg needs 16-byte alignment.
1811 // Same logic for riscv64, powerpc64, mips64, sparc64.
1811 // Same logic for powerpc64, mips64, sparc64.
18121812 .x86_64,
1813 .riscv64,
18141813 .powerpc64,
18151814 .powerpc64le,
18161815 .mips64,
18171816 .mips64el,
18181817 .sparc64,
1819 => 8,
1818 => return switch (target.ofmt) {
1819 .c => 16,
1820 else => 8,
1821 },
18201822
18211823 // Even LLVMABIAlignmentOfType(i128) agrees on these targets.
18221824 .aarch64,
18231825 .aarch64_be,
18241826 .aarch64_32,
1827 .riscv64,
18251828 .bpfel,
18261829 .bpfeb,
18271830 .nvptx,
src/Module.zig+19-11
......@@ -948,20 +948,28 @@ pub const Struct = struct {
948948
949949 switch (layout) {
950950 .Packed => return 0,
951 .Auto => return field.ty.abiAlignment(target),
952 .Extern => {
953 // This logic is duplicated in Type.abiAlignmentAdvanced.
954 const ty_abi_align = field.ty.abiAlignment(target);
955
956 if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) {
957 // The C ABI requires 128 bit integer fields of structs
958 // to be 16-bytes aligned.
959 return @maximum(ty_abi_align, 16);
951 .Auto => {
952 if (target.ofmt == .c) {
953 return alignmentExtern(field, target);
954 } else {
955 return field.ty.abiAlignment(target);
960956 }
961
962 return ty_abi_align;
963957 },
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);
964970 }
971
972 return ty_abi_align;
965973 }
966974 };
967975
src/type.zig+14-2
......@@ -3019,7 +3019,7 @@ pub const Type = extern union {
30193019 big_align = @maximum(big_align, field_align);
30203020
30213021 // This logic is duplicated in Module.Struct.Field.alignment.
3022 if (struct_obj.layout == .Extern) {
3022 if (struct_obj.layout == .Extern or target.ofmt == .c) {
30233023 if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) {
30243024 // The C ABI requires 128 bit integer fields of structs
30253025 // to be 16-bytes aligned.
......@@ -3348,7 +3348,13 @@ pub const Type = extern union {
33483348 .f128 => return AbiSizeAdvanced{ .scalar = 16 },
33493349
33503350 .f80 => switch (target.cpu.arch) {
3351 .i386 => return AbiSizeAdvanced{ .scalar = 12 },
3351 .i386 => switch (target.os.tag) {
3352 .windows => switch (target.abi) {
3353 .msvc => return AbiSizeAdvanced{ .scalar = 16 },
3354 else => return AbiSizeAdvanced{ .scalar = 12 },
3355 },
3356 else => return AbiSizeAdvanced{ .scalar = 12 },
3357 },
33523358 .x86_64 => return AbiSizeAdvanced{ .scalar = 16 },
33533359 else => {
33543360 var payload: Payload.Bits = .{
......@@ -4559,6 +4565,12 @@ pub const Type = extern union {
45594565
45604566 .vector => ty = ty.castTag(.vector).?.data.elem_type,
45614567
4568 .@"struct" => {
4569 const struct_obj = ty.castTag(.@"struct").?.data;
4570 assert(struct_obj.layout == .Packed);
4571 ty = struct_obj.backing_int_ty;
4572 },
4573
45624574 else => unreachable,
45634575 };
45644576 }
test/behavior/align.zig+30-16
......@@ -100,8 +100,8 @@ test "alignment and size of structs with 128-bit fields" {
100100 .a_align = 8,
101101 .a_size = 16,
102102
103 .b_align = 8,
104 .b_size = 24,
103 .b_align = 16,
104 .b_size = 32,
105105
106106 .u128_align = 8,
107107 .u128_size = 16,
......@@ -114,8 +114,8 @@ test "alignment and size of structs with 128-bit fields" {
114114 .a_align = 8,
115115 .a_size = 16,
116116
117 .b_align = 8,
118 .b_size = 24,
117 .b_align = 16,
118 .b_size = 32,
119119
120120 .u128_align = 8,
121121 .u128_size = 16,
......@@ -126,8 +126,8 @@ test "alignment and size of structs with 128-bit fields" {
126126 .a_align = 4,
127127 .a_size = 16,
128128
129 .b_align = 4,
130 .b_size = 20,
129 .b_align = 16,
130 .b_size = 32,
131131
132132 .u128_align = 4,
133133 .u128_size = 16,
......@@ -140,25 +140,39 @@ test "alignment and size of structs with 128-bit fields" {
140140 .mips64el,
141141 .powerpc64,
142142 .powerpc64le,
143 .riscv64,
144143 .sparc64,
145144 .x86_64,
146 => .{
147 .a_align = 8,
148 .a_size = 16,
145 => switch (builtin.object_format) {
146 .c => .{
147 .a_align = 16,
148 .a_size = 16,
149149
150 .b_align = 16,
151 .b_size = 32,
150 .b_align = 16,
151 .b_size = 32,
152152
153 .u128_align = 8,
154 .u128_size = 16,
155 .u129_align = 8,
156 .u129_size = 24,
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 },
157170 },
158171
159172 .aarch64,
160173 .aarch64_be,
161174 .aarch64_32,
175 .riscv64,
162176 .bpfel,
163177 .bpfeb,
164178 .nvptx,