authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-04-21 19:12:59-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-04-23 17:16:03-07:00
log9deea9b1d8a393fc6a3a5ecc9f112009ee6dc3b2
tree9f7023ae326ff2c872d057d5937a8161fedab15f
parent8e0a802ea1bb34a3f82ff4d2f7e2d40fc57726f2

x86_64: fix C abi for unions

Closes #19721

9 files changed, 386 insertions(+), 385 deletions(-)

src/InternPool.zig+32-32
...@@ -1921,7 +1921,7 @@ pub const LoadedUnionType = struct {...@@ -1921,7 +1921,7 @@ pub const LoadedUnionType = struct {
1921 return self.flagsPtr(ip).layout;1921 return self.flagsPtr(ip).layout;
1922 }1922 }
19231923
1924 pub fn fieldAlign(self: LoadedUnionType, ip: *const InternPool, field_index: u32) Alignment {1924 pub fn fieldAlign(self: LoadedUnionType, ip: *const InternPool, field_index: usize) Alignment {
1925 if (self.field_aligns.len == 0) return .none;1925 if (self.field_aligns.len == 0) return .none;
1926 return self.field_aligns.get(ip)[field_index];1926 return self.field_aligns.get(ip)[field_index];
1927 }1927 }
...@@ -2087,41 +2087,41 @@ pub const LoadedStructType = struct {...@@ -2087,41 +2087,41 @@ pub const LoadedStructType = struct {
20872087
2088 /// Returns the already-existing field with the same name, if any.2088 /// Returns the already-existing field with the same name, if any.
2089 pub fn addFieldName(2089 pub fn addFieldName(
2090 self: @This(),2090 self: LoadedStructType,
2091 ip: *InternPool,2091 ip: *InternPool,
2092 name: NullTerminatedString,2092 name: NullTerminatedString,
2093 ) ?u32 {2093 ) ?u32 {
2094 return ip.addFieldName(self.names_map.unwrap().?, self.field_names.start, name);2094 return ip.addFieldName(self.names_map.unwrap().?, self.field_names.start, name);
2095 }2095 }
20962096
2097 pub fn fieldAlign(s: @This(), ip: *const InternPool, i: usize) Alignment {2097 pub fn fieldAlign(s: LoadedStructType, ip: *const InternPool, i: usize) Alignment {
2098 if (s.field_aligns.len == 0) return .none;2098 if (s.field_aligns.len == 0) return .none;
2099 return s.field_aligns.get(ip)[i];2099 return s.field_aligns.get(ip)[i];
2100 }2100 }
21012101
2102 pub fn fieldInit(s: @This(), ip: *const InternPool, i: usize) Index {2102 pub fn fieldInit(s: LoadedStructType, ip: *const InternPool, i: usize) Index {
2103 if (s.field_inits.len == 0) return .none;2103 if (s.field_inits.len == 0) return .none;
2104 assert(s.haveFieldInits(ip));2104 assert(s.haveFieldInits(ip));
2105 return s.field_inits.get(ip)[i];2105 return s.field_inits.get(ip)[i];
2106 }2106 }
21072107
2108 /// Returns `none` in the case the struct is a tuple.2108 /// Returns `none` in the case the struct is a tuple.
2109 pub fn fieldName(s: @This(), ip: *const InternPool, i: usize) OptionalNullTerminatedString {2109 pub fn fieldName(s: LoadedStructType, ip: *const InternPool, i: usize) OptionalNullTerminatedString {
2110 if (s.field_names.len == 0) return .none;2110 if (s.field_names.len == 0) return .none;
2111 return s.field_names.get(ip)[i].toOptional();2111 return s.field_names.get(ip)[i].toOptional();
2112 }2112 }
21132113
2114 pub fn fieldIsComptime(s: @This(), ip: *const InternPool, i: usize) bool {2114 pub fn fieldIsComptime(s: LoadedStructType, ip: *const InternPool, i: usize) bool {
2115 return s.comptime_bits.getBit(ip, i);2115 return s.comptime_bits.getBit(ip, i);
2116 }2116 }
21172117
2118 pub fn setFieldComptime(s: @This(), ip: *InternPool, i: usize) void {2118 pub fn setFieldComptime(s: LoadedStructType, ip: *InternPool, i: usize) void {
2119 s.comptime_bits.setBit(ip, i);2119 s.comptime_bits.setBit(ip, i);
2120 }2120 }
21212121
2122 /// Reads the non-opv flag calculated during AstGen. Used to short-circuit more2122 /// Reads the non-opv flag calculated during AstGen. Used to short-circuit more
2123 /// complicated logic.2123 /// complicated logic.
2124 pub fn knownNonOpv(s: @This(), ip: *InternPool) bool {2124 pub fn knownNonOpv(s: LoadedStructType, ip: *InternPool) bool {
2125 return switch (s.layout) {2125 return switch (s.layout) {
2126 .@"packed" => false,2126 .@"packed" => false,
2127 .auto, .@"extern" => s.flagsPtr(ip).known_non_opv,2127 .auto, .@"extern" => s.flagsPtr(ip).known_non_opv,
...@@ -2130,7 +2130,7 @@ pub const LoadedStructType = struct {...@@ -2130,7 +2130,7 @@ pub const LoadedStructType = struct {
21302130
2131 /// The returned pointer expires with any addition to the `InternPool`.2131 /// The returned pointer expires with any addition to the `InternPool`.
2132 /// Asserts the struct is not packed.2132 /// Asserts the struct is not packed.
2133 pub fn flagsPtr(self: @This(), ip: *const InternPool) *Tag.TypeStruct.Flags {2133 pub fn flagsPtr(self: LoadedStructType, ip: *const InternPool) *Tag.TypeStruct.Flags {
2134 assert(self.layout != .@"packed");2134 assert(self.layout != .@"packed");
2135 const flags_field_index = std.meta.fieldIndex(Tag.TypeStruct, "flags").?;2135 const flags_field_index = std.meta.fieldIndex(Tag.TypeStruct, "flags").?;
2136 return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]);2136 return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]);
...@@ -2138,13 +2138,13 @@ pub const LoadedStructType = struct {...@@ -2138,13 +2138,13 @@ pub const LoadedStructType = struct {
21382138
2139 /// The returned pointer expires with any addition to the `InternPool`.2139 /// The returned pointer expires with any addition to the `InternPool`.
2140 /// Asserts that the struct is packed.2140 /// Asserts that the struct is packed.
2141 pub fn packedFlagsPtr(self: @This(), ip: *const InternPool) *Tag.TypeStructPacked.Flags {2141 pub fn packedFlagsPtr(self: LoadedStructType, ip: *const InternPool) *Tag.TypeStructPacked.Flags {
2142 assert(self.layout == .@"packed");2142 assert(self.layout == .@"packed");
2143 const flags_field_index = std.meta.fieldIndex(Tag.TypeStructPacked, "flags").?;2143 const flags_field_index = std.meta.fieldIndex(Tag.TypeStructPacked, "flags").?;
2144 return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]);2144 return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]);
2145 }2145 }
21462146
2147 pub fn assumeRuntimeBitsIfFieldTypesWip(s: @This(), ip: *InternPool) bool {2147 pub fn assumeRuntimeBitsIfFieldTypesWip(s: LoadedStructType, ip: *InternPool) bool {
2148 if (s.layout == .@"packed") return false;2148 if (s.layout == .@"packed") return false;
2149 const flags_ptr = s.flagsPtr(ip);2149 const flags_ptr = s.flagsPtr(ip);
2150 if (flags_ptr.field_types_wip) {2150 if (flags_ptr.field_types_wip) {
...@@ -2154,7 +2154,7 @@ pub const LoadedStructType = struct {...@@ -2154,7 +2154,7 @@ pub const LoadedStructType = struct {
2154 return false;2154 return false;
2155 }2155 }
21562156
2157 pub fn setTypesWip(s: @This(), ip: *InternPool) bool {2157 pub fn setTypesWip(s: LoadedStructType, ip: *InternPool) bool {
2158 if (s.layout == .@"packed") return false;2158 if (s.layout == .@"packed") return false;
2159 const flags_ptr = s.flagsPtr(ip);2159 const flags_ptr = s.flagsPtr(ip);
2160 if (flags_ptr.field_types_wip) return true;2160 if (flags_ptr.field_types_wip) return true;
...@@ -2162,12 +2162,12 @@ pub const LoadedStructType = struct {...@@ -2162,12 +2162,12 @@ pub const LoadedStructType = struct {
2162 return false;2162 return false;
2163 }2163 }
21642164
2165 pub fn clearTypesWip(s: @This(), ip: *InternPool) void {2165 pub fn clearTypesWip(s: LoadedStructType, ip: *InternPool) void {
2166 if (s.layout == .@"packed") return;2166 if (s.layout == .@"packed") return;
2167 s.flagsPtr(ip).field_types_wip = false;2167 s.flagsPtr(ip).field_types_wip = false;
2168 }2168 }
21692169
2170 pub fn setLayoutWip(s: @This(), ip: *InternPool) bool {2170 pub fn setLayoutWip(s: LoadedStructType, ip: *InternPool) bool {
2171 if (s.layout == .@"packed") return false;2171 if (s.layout == .@"packed") return false;
2172 const flags_ptr = s.flagsPtr(ip);2172 const flags_ptr = s.flagsPtr(ip);
2173 if (flags_ptr.layout_wip) return true;2173 if (flags_ptr.layout_wip) return true;
...@@ -2175,12 +2175,12 @@ pub const LoadedStructType = struct {...@@ -2175,12 +2175,12 @@ pub const LoadedStructType = struct {
2175 return false;2175 return false;
2176 }2176 }
21772177
2178 pub fn clearLayoutWip(s: @This(), ip: *InternPool) void {2178 pub fn clearLayoutWip(s: LoadedStructType, ip: *InternPool) void {
2179 if (s.layout == .@"packed") return;2179 if (s.layout == .@"packed") return;
2180 s.flagsPtr(ip).layout_wip = false;2180 s.flagsPtr(ip).layout_wip = false;
2181 }2181 }
21822182
2183 pub fn setAlignmentWip(s: @This(), ip: *InternPool) bool {2183 pub fn setAlignmentWip(s: LoadedStructType, ip: *InternPool) bool {
2184 if (s.layout == .@"packed") return false;2184 if (s.layout == .@"packed") return false;
2185 const flags_ptr = s.flagsPtr(ip);2185 const flags_ptr = s.flagsPtr(ip);
2186 if (flags_ptr.alignment_wip) return true;2186 if (flags_ptr.alignment_wip) return true;
...@@ -2188,12 +2188,12 @@ pub const LoadedStructType = struct {...@@ -2188,12 +2188,12 @@ pub const LoadedStructType = struct {
2188 return false;2188 return false;
2189 }2189 }
21902190
2191 pub fn clearAlignmentWip(s: @This(), ip: *InternPool) void {2191 pub fn clearAlignmentWip(s: LoadedStructType, ip: *InternPool) void {
2192 if (s.layout == .@"packed") return;2192 if (s.layout == .@"packed") return;
2193 s.flagsPtr(ip).alignment_wip = false;2193 s.flagsPtr(ip).alignment_wip = false;
2194 }2194 }
21952195
2196 pub fn setInitsWip(s: @This(), ip: *InternPool) bool {2196 pub fn setInitsWip(s: LoadedStructType, ip: *InternPool) bool {
2197 switch (s.layout) {2197 switch (s.layout) {
2198 .@"packed" => {2198 .@"packed" => {
2199 const flag = &s.packedFlagsPtr(ip).field_inits_wip;2199 const flag = &s.packedFlagsPtr(ip).field_inits_wip;
...@@ -2210,14 +2210,14 @@ pub const LoadedStructType = struct {...@@ -2210,14 +2210,14 @@ pub const LoadedStructType = struct {
2210 }2210 }
2211 }2211 }
22122212
2213 pub fn clearInitsWip(s: @This(), ip: *InternPool) void {2213 pub fn clearInitsWip(s: LoadedStructType, ip: *InternPool) void {
2214 switch (s.layout) {2214 switch (s.layout) {
2215 .@"packed" => s.packedFlagsPtr(ip).field_inits_wip = false,2215 .@"packed" => s.packedFlagsPtr(ip).field_inits_wip = false,
2216 .auto, .@"extern" => s.flagsPtr(ip).field_inits_wip = false,2216 .auto, .@"extern" => s.flagsPtr(ip).field_inits_wip = false,
2217 }2217 }
2218 }2218 }
22192219
2220 pub fn setFullyResolved(s: @This(), ip: *InternPool) bool {2220 pub fn setFullyResolved(s: LoadedStructType, ip: *InternPool) bool {
2221 if (s.layout == .@"packed") return true;2221 if (s.layout == .@"packed") return true;
2222 const flags_ptr = s.flagsPtr(ip);2222 const flags_ptr = s.flagsPtr(ip);
2223 if (flags_ptr.fully_resolved) return true;2223 if (flags_ptr.fully_resolved) return true;
...@@ -2225,13 +2225,13 @@ pub const LoadedStructType = struct {...@@ -2225,13 +2225,13 @@ pub const LoadedStructType = struct {
2225 return false;2225 return false;
2226 }2226 }
22272227
2228 pub fn clearFullyResolved(s: @This(), ip: *InternPool) void {2228 pub fn clearFullyResolved(s: LoadedStructType, ip: *InternPool) void {
2229 s.flagsPtr(ip).fully_resolved = false;2229 s.flagsPtr(ip).fully_resolved = false;
2230 }2230 }
22312231
2232 /// The returned pointer expires with any addition to the `InternPool`.2232 /// The returned pointer expires with any addition to the `InternPool`.
2233 /// Asserts the struct is not packed.2233 /// Asserts the struct is not packed.
2234 pub fn size(self: @This(), ip: *InternPool) *u32 {2234 pub fn size(self: LoadedStructType, ip: *InternPool) *u32 {
2235 assert(self.layout != .@"packed");2235 assert(self.layout != .@"packed");
2236 const size_field_index = std.meta.fieldIndex(Tag.TypeStruct, "size").?;2236 const size_field_index = std.meta.fieldIndex(Tag.TypeStruct, "size").?;
2237 return @ptrCast(&ip.extra.items[self.extra_index + size_field_index]);2237 return @ptrCast(&ip.extra.items[self.extra_index + size_field_index]);
...@@ -2241,50 +2241,50 @@ pub const LoadedStructType = struct {...@@ -2241,50 +2241,50 @@ pub const LoadedStructType = struct {
2241 /// this type or the user specifies it, it is stored here. This will be2241 /// this type or the user specifies it, it is stored here. This will be
2242 /// set to `none` until the layout is resolved.2242 /// set to `none` until the layout is resolved.
2243 /// Asserts the struct is packed.2243 /// Asserts the struct is packed.
2244 pub fn backingIntType(s: @This(), ip: *const InternPool) *Index {2244 pub fn backingIntType(s: LoadedStructType, ip: *const InternPool) *Index {
2245 assert(s.layout == .@"packed");2245 assert(s.layout == .@"packed");
2246 const field_index = std.meta.fieldIndex(Tag.TypeStructPacked, "backing_int_ty").?;2246 const field_index = std.meta.fieldIndex(Tag.TypeStructPacked, "backing_int_ty").?;
2247 return @ptrCast(&ip.extra.items[s.extra_index + field_index]);2247 return @ptrCast(&ip.extra.items[s.extra_index + field_index]);
2248 }2248 }
22492249
2250 /// Asserts the struct is not packed.2250 /// Asserts the struct is not packed.
2251 pub fn setZirIndex(s: @This(), ip: *InternPool, new_zir_index: TrackedInst.Index.Optional) void {2251 pub fn setZirIndex(s: LoadedStructType, ip: *InternPool, new_zir_index: TrackedInst.Index.Optional) void {
2252 assert(s.layout != .@"packed");2252 assert(s.layout != .@"packed");
2253 const field_index = std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?;2253 const field_index = std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?;
2254 ip.extra.items[s.extra_index + field_index] = @intFromEnum(new_zir_index);2254 ip.extra.items[s.extra_index + field_index] = @intFromEnum(new_zir_index);
2255 }2255 }
22562256
2257 pub fn haveFieldTypes(s: @This(), ip: *const InternPool) bool {2257 pub fn haveFieldTypes(s: LoadedStructType, ip: *const InternPool) bool {
2258 const types = s.field_types.get(ip);2258 const types = s.field_types.get(ip);
2259 return types.len == 0 or types[0] != .none;2259 return types.len == 0 or types[0] != .none;
2260 }2260 }
22612261
2262 pub fn haveFieldInits(s: @This(), ip: *const InternPool) bool {2262 pub fn haveFieldInits(s: LoadedStructType, ip: *const InternPool) bool {
2263 return switch (s.layout) {2263 return switch (s.layout) {
2264 .@"packed" => s.packedFlagsPtr(ip).inits_resolved,2264 .@"packed" => s.packedFlagsPtr(ip).inits_resolved,
2265 .auto, .@"extern" => s.flagsPtr(ip).inits_resolved,2265 .auto, .@"extern" => s.flagsPtr(ip).inits_resolved,
2266 };2266 };
2267 }2267 }
22682268
2269 pub fn setHaveFieldInits(s: @This(), ip: *InternPool) void {2269 pub fn setHaveFieldInits(s: LoadedStructType, ip: *InternPool) void {
2270 switch (s.layout) {2270 switch (s.layout) {
2271 .@"packed" => s.packedFlagsPtr(ip).inits_resolved = true,2271 .@"packed" => s.packedFlagsPtr(ip).inits_resolved = true,
2272 .auto, .@"extern" => s.flagsPtr(ip).inits_resolved = true,2272 .auto, .@"extern" => s.flagsPtr(ip).inits_resolved = true,
2273 }2273 }
2274 }2274 }
22752275
2276 pub fn haveLayout(s: @This(), ip: *InternPool) bool {2276 pub fn haveLayout(s: LoadedStructType, ip: *InternPool) bool {
2277 return switch (s.layout) {2277 return switch (s.layout) {
2278 .@"packed" => s.backingIntType(ip).* != .none,2278 .@"packed" => s.backingIntType(ip).* != .none,
2279 .auto, .@"extern" => s.flagsPtr(ip).layout_resolved,2279 .auto, .@"extern" => s.flagsPtr(ip).layout_resolved,
2280 };2280 };
2281 }2281 }
22822282
2283 pub fn isTuple(s: @This(), ip: *InternPool) bool {2283 pub fn isTuple(s: LoadedStructType, ip: *InternPool) bool {
2284 return s.layout != .@"packed" and s.flagsPtr(ip).is_tuple;2284 return s.layout != .@"packed" and s.flagsPtr(ip).is_tuple;
2285 }2285 }
22862286
2287 pub fn hasReorderedFields(s: @This()) bool {2287 pub fn hasReorderedFields(s: LoadedStructType) bool {
2288 return s.layout == .auto;2288 return s.layout == .auto;
2289 }2289 }
22902290
...@@ -2318,7 +2318,7 @@ pub const LoadedStructType = struct {...@@ -2318,7 +2318,7 @@ pub const LoadedStructType = struct {
2318 /// Iterates over non-comptime fields in the order they are laid out in memory at runtime.2318 /// Iterates over non-comptime fields in the order they are laid out in memory at runtime.
2319 /// May or may not include zero-bit fields.2319 /// May or may not include zero-bit fields.
2320 /// Asserts the struct is not packed.2320 /// Asserts the struct is not packed.
2321 pub fn iterateRuntimeOrder(s: @This(), ip: *InternPool) RuntimeOrderIterator {2321 pub fn iterateRuntimeOrder(s: LoadedStructType, ip: *InternPool) RuntimeOrderIterator {
2322 assert(s.layout != .@"packed");2322 assert(s.layout != .@"packed");
2323 return .{2323 return .{
2324 .ip = ip,2324 .ip = ip,
...@@ -2358,7 +2358,7 @@ pub const LoadedStructType = struct {...@@ -2358,7 +2358,7 @@ pub const LoadedStructType = struct {
2358 }2358 }
2359 };2359 };
23602360
2361 pub fn iterateRuntimeOrderReverse(s: @This(), ip: *InternPool) ReverseRuntimeOrderIterator {2361 pub fn iterateRuntimeOrderReverse(s: LoadedStructType, ip: *InternPool) ReverseRuntimeOrderIterator {
2362 assert(s.layout != .@"packed");2362 assert(s.layout != .@"packed");
2363 return .{2363 return .{
2364 .ip = ip,2364 .ip = ip,
src/Module.zig+25-25
...@@ -6140,18 +6140,18 @@ pub const UnionLayout = struct {...@@ -6140,18 +6140,18 @@ pub const UnionLayout = struct {
6140 padding: u32,6140 padding: u32,
6141};6141};
61426142
6143pub fn getUnionLayout(mod: *Module, u: InternPool.LoadedUnionType) UnionLayout {6143pub fn getUnionLayout(mod: *Module, loaded_union: InternPool.LoadedUnionType) UnionLayout {
6144 const ip = &mod.intern_pool;6144 const ip = &mod.intern_pool;
6145 assert(u.haveLayout(ip));6145 assert(loaded_union.haveLayout(ip));
6146 var most_aligned_field: u32 = undefined;6146 var most_aligned_field: u32 = undefined;
6147 var most_aligned_field_size: u64 = undefined;6147 var most_aligned_field_size: u64 = undefined;
6148 var biggest_field: u32 = undefined;6148 var biggest_field: u32 = undefined;
6149 var payload_size: u64 = 0;6149 var payload_size: u64 = 0;
6150 var payload_align: Alignment = .@"1";6150 var payload_align: Alignment = .@"1";
6151 for (u.field_types.get(ip), 0..) |field_ty, i| {6151 for (loaded_union.field_types.get(ip), 0..) |field_ty, field_index| {
6152 if (!Type.fromInterned(field_ty).hasRuntimeBitsIgnoreComptime(mod)) continue;6152 if (!Type.fromInterned(field_ty).hasRuntimeBitsIgnoreComptime(mod)) continue;
61536153
6154 const explicit_align = u.fieldAlign(ip, @intCast(i));6154 const explicit_align = loaded_union.fieldAlign(ip, field_index);
6155 const field_align = if (explicit_align != .none)6155 const field_align = if (explicit_align != .none)
6156 explicit_align6156 explicit_align
6157 else6157 else
...@@ -6159,16 +6159,16 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.LoadedUnionType) UnionLayout {...@@ -6159,16 +6159,16 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.LoadedUnionType) UnionLayout {
6159 const field_size = Type.fromInterned(field_ty).abiSize(mod);6159 const field_size = Type.fromInterned(field_ty).abiSize(mod);
6160 if (field_size > payload_size) {6160 if (field_size > payload_size) {
6161 payload_size = field_size;6161 payload_size = field_size;
6162 biggest_field = @intCast(i);6162 biggest_field = @intCast(field_index);
6163 }6163 }
6164 if (field_align.compare(.gte, payload_align)) {6164 if (field_align.compare(.gte, payload_align)) {
6165 payload_align = field_align;6165 payload_align = field_align;
6166 most_aligned_field = @intCast(i);6166 most_aligned_field = @intCast(field_index);
6167 most_aligned_field_size = field_size;6167 most_aligned_field_size = field_size;
6168 }6168 }
6169 }6169 }
6170 const have_tag = u.flagsPtr(ip).runtime_tag.hasTag();6170 const have_tag = loaded_union.flagsPtr(ip).runtime_tag.hasTag();
6171 if (!have_tag or !Type.fromInterned(u.enum_tag_ty).hasRuntimeBits(mod)) {6171 if (!have_tag or !Type.fromInterned(loaded_union.enum_tag_ty).hasRuntimeBits(mod)) {
6172 return .{6172 return .{
6173 .abi_size = payload_align.forward(payload_size),6173 .abi_size = payload_align.forward(payload_size),
6174 .abi_align = payload_align,6174 .abi_align = payload_align,
...@@ -6183,10 +6183,10 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.LoadedUnionType) UnionLayout {...@@ -6183,10 +6183,10 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.LoadedUnionType) UnionLayout {
6183 };6183 };
6184 }6184 }
61856185
6186 const tag_size = Type.fromInterned(u.enum_tag_ty).abiSize(mod);6186 const tag_size = Type.fromInterned(loaded_union.enum_tag_ty).abiSize(mod);
6187 const tag_align = Type.fromInterned(u.enum_tag_ty).abiAlignment(mod).max(.@"1");6187 const tag_align = Type.fromInterned(loaded_union.enum_tag_ty).abiAlignment(mod).max(.@"1");
6188 return .{6188 return .{
6189 .abi_size = u.size(ip).*,6189 .abi_size = loaded_union.size(ip).*,
6190 .abi_align = tag_align.max(payload_align),6190 .abi_align = tag_align.max(payload_align),
6191 .most_aligned_field = most_aligned_field,6191 .most_aligned_field = most_aligned_field,
6192 .most_aligned_field_size = most_aligned_field_size,6192 .most_aligned_field_size = most_aligned_field_size,
...@@ -6195,24 +6195,24 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.LoadedUnionType) UnionLayout {...@@ -6195,24 +6195,24 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.LoadedUnionType) UnionLayout {
6195 .payload_align = payload_align,6195 .payload_align = payload_align,
6196 .tag_align = tag_align,6196 .tag_align = tag_align,
6197 .tag_size = tag_size,6197 .tag_size = tag_size,
6198 .padding = u.padding(ip).*,6198 .padding = loaded_union.padding(ip).*,
6199 };6199 };
6200}6200}
62016201
6202pub fn unionAbiSize(mod: *Module, u: InternPool.LoadedUnionType) u64 {6202pub fn unionAbiSize(mod: *Module, loaded_union: InternPool.LoadedUnionType) u64 {
6203 return mod.getUnionLayout(u).abi_size;6203 return mod.getUnionLayout(loaded_union).abi_size;
6204}6204}
62056205
6206/// Returns 0 if the union is represented with 0 bits at runtime.6206/// Returns 0 if the union is represented with 0 bits at runtime.
6207pub fn unionAbiAlignment(mod: *Module, u: InternPool.LoadedUnionType) Alignment {6207pub fn unionAbiAlignment(mod: *Module, loaded_union: InternPool.LoadedUnionType) Alignment {
6208 const ip = &mod.intern_pool;6208 const ip = &mod.intern_pool;
6209 const have_tag = u.flagsPtr(ip).runtime_tag.hasTag();6209 const have_tag = loaded_union.flagsPtr(ip).runtime_tag.hasTag();
6210 var max_align: Alignment = .none;6210 var max_align: Alignment = .none;
6211 if (have_tag) max_align = Type.fromInterned(u.enum_tag_ty).abiAlignment(mod);6211 if (have_tag) max_align = Type.fromInterned(loaded_union.enum_tag_ty).abiAlignment(mod);
6212 for (u.field_types.get(ip), 0..) |field_ty, field_index| {6212 for (loaded_union.field_types.get(ip), 0..) |field_ty, field_index| {
6213 if (!Type.fromInterned(field_ty).hasRuntimeBits(mod)) continue;6213 if (!Type.fromInterned(field_ty).hasRuntimeBits(mod)) continue;
62146214
6215 const field_align = mod.unionFieldNormalAlignment(u, @intCast(field_index));6215 const field_align = mod.unionFieldNormalAlignment(loaded_union, @intCast(field_index));
6216 max_align = max_align.max(field_align);6216 max_align = max_align.max(field_align);
6217 }6217 }
6218 return max_align;6218 return max_align;
...@@ -6221,20 +6221,20 @@ pub fn unionAbiAlignment(mod: *Module, u: InternPool.LoadedUnionType) Alignment...@@ -6221,20 +6221,20 @@ pub fn unionAbiAlignment(mod: *Module, u: InternPool.LoadedUnionType) Alignment
6221/// Returns the field alignment, assuming the union is not packed.6221/// Returns the field alignment, assuming the union is not packed.
6222/// Keep implementation in sync with `Sema.unionFieldAlignment`.6222/// Keep implementation in sync with `Sema.unionFieldAlignment`.
6223/// Prefer to call that function instead of this one during Sema.6223/// Prefer to call that function instead of this one during Sema.
6224pub fn unionFieldNormalAlignment(mod: *Module, u: InternPool.LoadedUnionType, field_index: u32) Alignment {6224pub fn unionFieldNormalAlignment(mod: *Module, loaded_union: InternPool.LoadedUnionType, field_index: u32) Alignment {
6225 const ip = &mod.intern_pool;6225 const ip = &mod.intern_pool;
6226 const field_align = u.fieldAlign(ip, field_index);6226 const field_align = loaded_union.fieldAlign(ip, field_index);
6227 if (field_align != .none) return field_align;6227 if (field_align != .none) return field_align;
6228 const field_ty = Type.fromInterned(u.field_types.get(ip)[field_index]);6228 const field_ty = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
6229 return field_ty.abiAlignment(mod);6229 return field_ty.abiAlignment(mod);
6230}6230}
62316231
6232/// Returns the index of the active field, given the current tag value6232/// Returns the index of the active field, given the current tag value
6233pub fn unionTagFieldIndex(mod: *Module, u: InternPool.LoadedUnionType, enum_tag: Value) ?u32 {6233pub fn unionTagFieldIndex(mod: *Module, loaded_union: InternPool.LoadedUnionType, enum_tag: Value) ?u32 {
6234 const ip = &mod.intern_pool;6234 const ip = &mod.intern_pool;
6235 if (enum_tag.toIntern() == .none) return null;6235 if (enum_tag.toIntern() == .none) return null;
6236 assert(ip.typeOf(enum_tag.toIntern()) == u.enum_tag_ty);6236 assert(ip.typeOf(enum_tag.toIntern()) == loaded_union.enum_tag_ty);
6237 return u.loadTagType(ip).tagValueIndex(ip, enum_tag.toIntern());6237 return loaded_union.loadTagType(ip).tagValueIndex(ip, enum_tag.toIntern());
6238}6238}
62396239
6240/// Returns the field alignment of a non-packed struct in byte units.6240/// Returns the field alignment of a non-packed struct in byte units.
src/Sema.zig+2-2
...@@ -35405,7 +35405,7 @@ pub fn resolveUnionAlignment(...@@ -35405,7 +35405,7 @@ pub fn resolveUnionAlignment(
35405 const field_ty = Type.fromInterned(union_type.field_types.get(ip)[field_index]);35405 const field_ty = Type.fromInterned(union_type.field_types.get(ip)[field_index]);
35406 if (!(try sema.typeHasRuntimeBits(field_ty))) continue;35406 if (!(try sema.typeHasRuntimeBits(field_ty))) continue;
3540735407
35408 const explicit_align = union_type.fieldAlign(ip, @intCast(field_index));35408 const explicit_align = union_type.fieldAlign(ip, field_index);
35409 const field_align = if (explicit_align != .none)35409 const field_align = if (explicit_align != .none)
35410 explicit_align35410 explicit_align
35411 else35411 else
...@@ -35465,7 +35465,7 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {...@@ -35465,7 +35465,7 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
35465 else => return err,35465 else => return err,
35466 });35466 });
3546735467
35468 const explicit_align = union_type.fieldAlign(ip, @intCast(field_index));35468 const explicit_align = union_type.fieldAlign(ip, field_index);
35469 const field_align = if (explicit_align != .none)35469 const field_align = if (explicit_align != .none)
35470 explicit_align35470 explicit_align
35471 else35471 else
src/arch/x86_64/CodeGen.zig+5-5
...@@ -14316,7 +14316,7 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo...@@ -14316,7 +14316,7 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo
14316 .mmx => {},14316 .mmx => {},
14317 .sse => switch (ty.zigTypeTag(mod)) {14317 .sse => switch (ty.zigTypeTag(mod)) {
14318 else => {14318 else => {
14319 const classes = mem.sliceTo(&abi.classifySystemV(ty, mod, .other), .none);14319 const classes = mem.sliceTo(&abi.classifySystemV(ty, mod, self.target.*, .other), .none);
14320 assert(std.mem.indexOfNone(abi.Class, classes, &.{14320 assert(std.mem.indexOfNone(abi.Class, classes, &.{
14321 .integer, .sse, .memory, .float, .float_combine,14321 .integer, .sse, .memory, .float, .float_combine,
14322 }) == null);14322 }) == null);
...@@ -18450,7 +18450,7 @@ fn airVaArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -18450,7 +18450,7 @@ fn airVaArg(self: *Self, inst: Air.Inst.Index) !void {
18450 const overflow_arg_area: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 8 } };18450 const overflow_arg_area: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 8 } };
18451 const reg_save_area: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 16 } };18451 const reg_save_area: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 16 } };
1845218452
18453 const classes = mem.sliceTo(&abi.classifySystemV(promote_ty, mod, .arg), .none);18453 const classes = mem.sliceTo(&abi.classifySystemV(promote_ty, mod, self.target.*, .arg), .none);
18454 switch (classes[0]) {18454 switch (classes[0]) {
18455 .integer => {18455 .integer => {
18456 assert(classes.len == 1);18456 assert(classes.len == 1);
...@@ -18800,7 +18800,7 @@ fn resolveCallingConventionValues(...@@ -18800,7 +18800,7 @@ fn resolveCallingConventionValues(
18800 var ret_tracking_i: usize = 0;18800 var ret_tracking_i: usize = 0;
1880118801
18802 const classes = switch (resolved_cc) {18802 const classes = switch (resolved_cc) {
18803 .SysV => mem.sliceTo(&abi.classifySystemV(ret_ty, mod, .ret), .none),18803 .SysV => mem.sliceTo(&abi.classifySystemV(ret_ty, mod, self.target.*, .ret), .none),
18804 .Win64 => &.{abi.classifyWindows(ret_ty, mod)},18804 .Win64 => &.{abi.classifyWindows(ret_ty, mod)},
18805 else => unreachable,18805 else => unreachable,
18806 };18806 };
...@@ -18875,7 +18875,7 @@ fn resolveCallingConventionValues(...@@ -18875,7 +18875,7 @@ fn resolveCallingConventionValues(
18875 var arg_mcv_i: usize = 0;18875 var arg_mcv_i: usize = 0;
1887618876
18877 const classes = switch (resolved_cc) {18877 const classes = switch (resolved_cc) {
18878 .SysV => mem.sliceTo(&abi.classifySystemV(ty, mod, .arg), .none),18878 .SysV => mem.sliceTo(&abi.classifySystemV(ty, mod, self.target.*, .arg), .none),
18879 .Win64 => &.{abi.classifyWindows(ty, mod)},18879 .Win64 => &.{abi.classifyWindows(ty, mod)},
18880 else => unreachable,18880 else => unreachable,
18881 };18881 };
...@@ -19090,7 +19090,7 @@ fn memSize(self: *Self, ty: Type) Memory.Size {...@@ -19090,7 +19090,7 @@ fn memSize(self: *Self, ty: Type) Memory.Size {
1909019090
19091fn splitType(self: *Self, ty: Type) ![2]Type {19091fn splitType(self: *Self, ty: Type) ![2]Type {
19092 const mod = self.bin_file.comp.module.?;19092 const mod = self.bin_file.comp.module.?;
19093 const classes = mem.sliceTo(&abi.classifySystemV(ty, mod, .other), .none);19093 const classes = mem.sliceTo(&abi.classifySystemV(ty, mod, self.target.*, .other), .none);
19094 var parts: [2]Type = undefined;19094 var parts: [2]Type = undefined;
19095 if (classes.len == 2) for (&parts, classes, 0..) |*part, class, part_i| {19095 if (classes.len == 2) for (&parts, classes, 0..) |*part, class, part_i| {
19096 part.* = switch (class) {19096 part.* = switch (class) {
src/arch/x86_64/abi.zig+108-163
...@@ -11,6 +11,37 @@ pub const Class = enum {...@@ -11,6 +11,37 @@ pub const Class = enum {
11 float,11 float,
12 float_combine,12 float_combine,
13 integer_per_element,13 integer_per_element,
14
15 fn isX87(class: Class) bool {
16 return switch (class) {
17 .x87, .x87up, .complex_x87 => true,
18 else => false,
19 };
20 }
21
22 /// Combine a field class with the prev one.
23 fn combineSystemV(prev_class: Class, next_class: Class) Class {
24 // "If both classes are equal, this is the resulting class."
25 if (prev_class == next_class)
26 return if (prev_class == .float) .float_combine else prev_class;
27
28 // "If one of the classes is NO_CLASS, the resulting class
29 // is the other class."
30 if (prev_class == .none) return next_class;
31
32 // "If one of the classes is MEMORY, the result is the MEMORY class."
33 if (prev_class == .memory or next_class == .memory) return .memory;
34
35 // "If one of the classes is INTEGER, the result is the INTEGER."
36 if (prev_class == .integer or next_class == .integer) return .integer;
37
38 // "If one of the classes is X87, X87UP, COMPLEX_X87 class,
39 // MEMORY is used as class."
40 if (prev_class.isX87() or next_class.isX87()) return .memory;
41
42 // "Otherwise class SSE is used."
43 return .sse;
44 }
14};45};
1546
16pub fn classifyWindows(ty: Type, zcu: *Zcu) Class {47pub fn classifyWindows(ty: Type, zcu: *Zcu) Class {
...@@ -69,9 +100,7 @@ pub const Context = enum { ret, arg, field, other };...@@ -69,9 +100,7 @@ pub const Context = enum { ret, arg, field, other };
69100
70/// There are a maximum of 8 possible return slots. Returned values are in101/// There are a maximum of 8 possible return slots. Returned values are in
71/// the beginning of the array; unused slots are filled with .none.102/// the beginning of the array; unused slots are filled with .none.
72pub fn classifySystemV(ty: Type, zcu: *Zcu, ctx: Context) [8]Class {103pub fn classifySystemV(ty: Type, zcu: *Zcu, target: std.Target, ctx: Context) [8]Class {
73 const ip = &zcu.intern_pool;
74 const target = zcu.getTarget();
75 const memory_class = [_]Class{104 const memory_class = [_]Class{
76 .memory, .none, .none, .none,105 .memory, .none, .none, .none,
77 .none, .none, .none, .none,106 .none, .none, .none, .none,
...@@ -231,121 +260,30 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, ctx: Context) [8]Class {...@@ -231,121 +260,30 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, ctx: Context) [8]Class {
231 }260 }
232 return memory_class;261 return memory_class;
233 },262 },
234 .Struct => {263 .Struct, .Union => {
235 // "If the size of an object is larger than eight eightbytes, or264 // "If the size of an object is larger than eight eightbytes, or
236 // it contains unaligned fields, it has class MEMORY"265 // it contains unaligned fields, it has class MEMORY"
237 // "If the size of the aggregate exceeds a single eightbyte, each is classified266 // "If the size of the aggregate exceeds a single eightbyte, each is classified
238 // separately.".267 // separately.".
239 const loaded_struct = ip.loadStructType(ty.toIntern());
240 const ty_size = ty.abiSize(zcu);268 const ty_size = ty.abiSize(zcu);
241 if (loaded_struct.layout == .@"packed") {269 switch (ty.containerLayout(zcu)) {
242 assert(ty_size <= 16);270 .auto, .@"extern" => {},
243 result[0] = .integer;271 .@"packed" => {
244 if (ty_size > 8) result[1] = .integer;272 assert(ty_size <= 16);
245 return result;273 result[0] = .integer;
246 }274 if (ty_size > 8) result[1] = .integer;
247 if (ty_size > 64)275 return result;
248 return memory_class;276 },
249
250 var byte_offset: u64 = 0;
251 classifySystemVStruct(&result, &byte_offset, loaded_struct, zcu);
252
253 // Post-merger cleanup
254
255 // "If one of the classes is MEMORY, the whole argument is passed in memory"
256 // "If X87UP is not preceded by X87, the whole argument is passed in memory."
257 var found_sseup = false;
258 for (result, 0..) |item, i| switch (item) {
259 .memory => return memory_class,
260 .x87up => if (i == 0 or result[i - 1] != .x87) return memory_class,
261 .sseup => found_sseup = true,
262 else => continue,
263 };
264 // "If the size of the aggregate exceeds two eightbytes and the first eight-
265 // byte isn’t SSE or any other eightbyte isn’t SSEUP, the whole argument
266 // is passed in memory."
267 if (ty_size > 16 and (result[0] != .sse or !found_sseup)) return memory_class;
268
269 // "If SSEUP is not preceded by SSE or SSEUP, it is converted to SSE."
270 for (&result, 0..) |*item, i| {
271 if (item.* == .sseup) switch (result[i - 1]) {
272 .sse, .sseup => continue,
273 else => item.* = .sse,
274 };
275 }
276 return result;
277 },
278 .Union => {
279 // "If the size of an object is larger than eight eightbytes, or
280 // it contains unaligned fields, it has class MEMORY"
281 // "If the size of the aggregate exceeds a single eightbyte, each is classified
282 // separately.".
283 const union_obj = zcu.typeToUnion(ty).?;
284 const ty_size = zcu.unionAbiSize(union_obj);
285 if (union_obj.getLayout(ip) == .@"packed") {
286 assert(ty_size <= 16);
287 result[0] = .integer;
288 if (ty_size > 8) result[1] = .integer;
289 return result;
290 }277 }
291 if (ty_size > 64)278 if (ty_size > 64)
292 return memory_class;279 return memory_class;
293280
294 for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| {281 _ = if (zcu.typeToStruct(ty)) |loaded_struct|
295 const field_align = union_obj.fieldAlign(ip, @intCast(field_index));282 classifySystemVStruct(&result, 0, loaded_struct, zcu, target)
296 if (field_align != .none and283 else if (zcu.typeToUnion(ty)) |loaded_union|
297 field_align.compare(.lt, Type.fromInterned(field_ty).abiAlignment(zcu)))284 classifySystemVUnion(&result, 0, loaded_union, zcu, target)
298 {285 else
299 return memory_class;286 unreachable;
300 }
301 // Combine this field with the previous one.
302 const field_class = classifySystemV(Type.fromInterned(field_ty), zcu, .field);
303 for (&result, 0..) |*result_item, i| {
304 const field_item = field_class[i];
305 // "If both classes are equal, this is the resulting class."
306 if (result_item.* == field_item) {
307 continue;
308 }
309
310 // "If one of the classes is NO_CLASS, the resulting class
311 // is the other class."
312 if (result_item.* == .none) {
313 result_item.* = field_item;
314 continue;
315 }
316 if (field_item == .none) {
317 continue;
318 }
319
320 // "If one of the classes is MEMORY, the result is the MEMORY class."
321 if (result_item.* == .memory or field_item == .memory) {
322 result_item.* = .memory;
323 continue;
324 }
325
326 // "If one of the classes is INTEGER, the result is the INTEGER."
327 if (result_item.* == .integer or field_item == .integer) {
328 result_item.* = .integer;
329 continue;
330 }
331
332 // "If one of the classes is X87, X87UP, COMPLEX_X87 class,
333 // MEMORY is used as class."
334 if (result_item.* == .x87 or
335 result_item.* == .x87up or
336 result_item.* == .complex_x87 or
337 field_item == .x87 or
338 field_item == .x87up or
339 field_item == .complex_x87)
340 {
341 result_item.* = .memory;
342 continue;
343 }
344
345 // "Otherwise class SSE is used."
346 result_item.* = .sse;
347 }
348 }
349287
350 // Post-merger cleanup288 // Post-merger cleanup
351289
...@@ -391,78 +329,85 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, ctx: Context) [8]Class {...@@ -391,78 +329,85 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, ctx: Context) [8]Class {
391329
392fn classifySystemVStruct(330fn classifySystemVStruct(
393 result: *[8]Class,331 result: *[8]Class,
394 byte_offset: *u64,332 starting_byte_offset: u64,
395 loaded_struct: InternPool.LoadedStructType,333 loaded_struct: InternPool.LoadedStructType,
396 zcu: *Zcu,334 zcu: *Zcu,
397) void {335 target: std.Target,
336) u64 {
398 const ip = &zcu.intern_pool;337 const ip = &zcu.intern_pool;
338 var byte_offset = starting_byte_offset;
399 var field_it = loaded_struct.iterateRuntimeOrder(ip);339 var field_it = loaded_struct.iterateRuntimeOrder(ip);
400 while (field_it.next()) |field_index| {340 while (field_it.next()) |field_index| {
401 const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);341 const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
402 const field_align = loaded_struct.fieldAlign(ip, field_index);342 const field_align = loaded_struct.fieldAlign(ip, field_index);
403 byte_offset.* = std.mem.alignForward(343 byte_offset = std.mem.alignForward(
404 u64,344 u64,
405 byte_offset.*,345 byte_offset,
406 field_align.toByteUnits() orelse field_ty.abiAlignment(zcu).toByteUnits().?,346 field_align.toByteUnits() orelse field_ty.abiAlignment(zcu).toByteUnits().?,
407 );347 );
408 if (zcu.typeToStruct(field_ty)) |field_loaded_struct| {348 if (zcu.typeToStruct(field_ty)) |field_loaded_struct| {
409 if (field_loaded_struct.layout != .@"packed") {349 switch (field_loaded_struct.layout) {
410 classifySystemVStruct(result, byte_offset, field_loaded_struct, zcu);350 .auto, .@"extern" => {
411 continue;351 byte_offset = classifySystemVStruct(result, byte_offset, field_loaded_struct, zcu, target);
412 }352 continue;
413 }353 },
414 const field_class = std.mem.sliceTo(&classifySystemV(field_ty, zcu, .field), .none);354 .@"packed" => {},
415 const field_size = field_ty.abiSize(zcu);
416 combine: {
417 // Combine this field with the previous one.
418 const result_class = &result[@intCast(byte_offset.* / 8)];
419 // "If both classes are equal, this is the resulting class."
420 if (result_class.* == field_class[0]) {
421 if (result_class.* == .float) {
422 result_class.* = .float_combine;
423 }
424 break :combine;
425 }
426
427 // "If one of the classes is NO_CLASS, the resulting class
428 // is the other class."
429 if (result_class.* == .none) {
430 result_class.* = field_class[0];
431 break :combine;
432 }355 }
433 assert(field_class[0] != .none);356 } else if (zcu.typeToUnion(field_ty)) |field_loaded_union| {
434357 switch (field_loaded_union.getLayout(ip)) {
435 // "If one of the classes is MEMORY, the result is the MEMORY class."358 .auto, .@"extern" => {
436 if (result_class.* == .memory or field_class[0] == .memory) {359 byte_offset = classifySystemVUnion(result, byte_offset, field_loaded_union, zcu, target);
437 result_class.* = .memory;360 continue;
438 break :combine;361 },
362 .@"packed" => {},
439 }363 }
364 }
365 const field_classes = std.mem.sliceTo(&classifySystemV(field_ty, zcu, target, .field), .none);
366 for (result[@intCast(byte_offset / 8)..][0..field_classes.len], field_classes) |*result_class, field_class|
367 result_class.* = result_class.combineSystemV(field_class);
368 byte_offset += field_ty.abiSize(zcu);
369 }
370 const final_byte_offset = starting_byte_offset + loaded_struct.size(ip).*;
371 std.debug.assert(final_byte_offset == std.mem.alignForward(
372 u64,
373 byte_offset,
374 loaded_struct.flagsPtr(ip).alignment.toByteUnits().?,
375 ));
376 return final_byte_offset;
377}
440378
441 // "If one of the classes is INTEGER, the result is the INTEGER."379fn classifySystemVUnion(
442 if (result_class.* == .integer or field_class[0] == .integer) {380 result: *[8]Class,
443 result_class.* = .integer;381 starting_byte_offset: u64,
444 break :combine;382 loaded_union: InternPool.LoadedUnionType,
383 zcu: *Zcu,
384 target: std.Target,
385) u64 {
386 const ip = &zcu.intern_pool;
387 for (0..loaded_union.field_types.len) |field_index| {
388 const field_ty = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
389 if (zcu.typeToStruct(field_ty)) |field_loaded_struct| {
390 switch (field_loaded_struct.layout) {
391 .auto, .@"extern" => {
392 _ = classifySystemVStruct(result, starting_byte_offset, field_loaded_struct, zcu, target);
393 continue;
394 },
395 .@"packed" => {},
445 }396 }
446397 } else if (zcu.typeToUnion(field_ty)) |field_loaded_union| {
447 // "If one of the classes is X87, X87UP, COMPLEX_X87 class,398 switch (field_loaded_union.getLayout(ip)) {
448 // MEMORY is used as class."399 .auto, .@"extern" => {
449 if (result_class.* == .x87 or400 _ = classifySystemVUnion(result, starting_byte_offset, field_loaded_union, zcu, target);
450 result_class.* == .x87up or401 continue;
451 result_class.* == .complex_x87 or402 },
452 field_class[0] == .x87 or403 .@"packed" => {},
453 field_class[0] == .x87up or
454 field_class[0] == .complex_x87)
455 {
456 result_class.* = .memory;
457 break :combine;
458 }404 }
459
460 // "Otherwise class SSE is used."
461 result_class.* = .sse;
462 }405 }
463 @memcpy(result[@intCast(byte_offset.* / 8 + 1)..][0 .. field_class.len - 1], field_class[1..]);406 const field_classes = std.mem.sliceTo(&classifySystemV(field_ty, zcu, target, .field), .none);
464 byte_offset.* += field_size;407 for (result[@intCast(starting_byte_offset / 8)..][0..field_classes.len], field_classes) |*result_class, field_class|
408 result_class.* = result_class.combineSystemV(field_class);
465 }409 }
410 return starting_byte_offset + loaded_union.size(ip).*;
466}411}
467412
468pub const SysV = struct {413pub const SysV = struct {
src/codegen/c/Type.zig+1-1
...@@ -1858,7 +1858,7 @@ pub const Pool = struct {...@@ -1858,7 +1858,7 @@ pub const Pool = struct {
1858 loaded_tag.names.get(ip)[field_index].toSlice(ip),1858 loaded_tag.names.get(ip)[field_index].toSlice(ip),
1859 );1859 );
1860 const field_alignas = AlignAs.fromAlignment(.{1860 const field_alignas = AlignAs.fromAlignment(.{
1861 .@"align" = loaded_union.fieldAlign(ip, @intCast(field_index)),1861 .@"align" = loaded_union.fieldAlign(ip, field_index),
1862 .abi = field_type.abiAlignment(zcu),1862 .abi = field_type.abiAlignment(zcu),
1863 });1863 });
1864 pool.addHashedExtraAssumeCapacityTo(scratch, &hasher, Field, .{1864 pool.addHashedExtraAssumeCapacityTo(scratch, &hasher, Field, .{
src/codegen/llvm.zig+128-127
...@@ -1384,7 +1384,7 @@ pub const Object = struct {...@@ -1384,7 +1384,7 @@ pub const Object = struct {
1384 const namespace = zcu.namespacePtr(decl.src_namespace);1384 const namespace = zcu.namespacePtr(decl.src_namespace);
1385 const owner_mod = namespace.file_scope.mod;1385 const owner_mod = namespace.file_scope.mod;
1386 const fn_info = zcu.typeToFunc(decl.typeOf(zcu)).?;1386 const fn_info = zcu.typeToFunc(decl.typeOf(zcu)).?;
1387 const target = zcu.getTarget();1387 const target = owner_mod.resolved_target.result;
1388 const ip = &zcu.intern_pool;1388 const ip = &zcu.intern_pool;
13891389
1390 var dg: DeclGen = .{1390 var dg: DeclGen = .{
...@@ -1456,7 +1456,7 @@ pub const Object = struct {...@@ -1456,7 +1456,7 @@ pub const Object = struct {
1456 var llvm_arg_i: u32 = 0;1456 var llvm_arg_i: u32 = 0;
14571457
1458 // This gets the LLVM values from the function and stores them in `dg.args`.1458 // This gets the LLVM values from the function and stores them in `dg.args`.
1459 const sret = firstParamSRet(fn_info, zcu);1459 const sret = firstParamSRet(fn_info, zcu, target);
1460 const ret_ptr: Builder.Value = if (sret) param: {1460 const ret_ptr: Builder.Value = if (sret) param: {
1461 const param = wip.arg(llvm_arg_i);1461 const param = wip.arg(llvm_arg_i);
1462 llvm_arg_i += 1;1462 llvm_arg_i += 1;
...@@ -2755,7 +2755,7 @@ pub const Object = struct {...@@ -2755,7 +2755,7 @@ pub const Object = struct {
27552755
2756 // Return type goes first.2756 // Return type goes first.
2757 if (Type.fromInterned(fn_info.return_type).hasRuntimeBitsIgnoreComptime(mod)) {2757 if (Type.fromInterned(fn_info.return_type).hasRuntimeBitsIgnoreComptime(mod)) {
2758 const sret = firstParamSRet(fn_info, mod);2758 const sret = firstParamSRet(fn_info, mod, target);
2759 const ret_ty = if (sret) Type.void else Type.fromInterned(fn_info.return_type);2759 const ret_ty = if (sret) Type.void else Type.fromInterned(fn_info.return_type);
2760 debug_param_types.appendAssumeCapacity(try o.lowerDebugType(ret_ty));2760 debug_param_types.appendAssumeCapacity(try o.lowerDebugType(ret_ty));
27612761
...@@ -2881,7 +2881,7 @@ pub const Object = struct {...@@ -2881,7 +2881,7 @@ pub const Object = struct {
2881 assert(decl.has_tv);2881 assert(decl.has_tv);
2882 const fn_info = zcu.typeToFunc(zig_fn_type).?;2882 const fn_info = zcu.typeToFunc(zig_fn_type).?;
2883 const target = owner_mod.resolved_target.result;2883 const target = owner_mod.resolved_target.result;
2884 const sret = firstParamSRet(fn_info, zcu);2884 const sret = firstParamSRet(fn_info, zcu, target);
28852885
2886 const is_extern = decl.isExtern(zcu);2886 const is_extern = decl.isExtern(zcu);
2887 const function_index = try o.builder.addFunction(2887 const function_index = try o.builder.addFunction(
...@@ -3604,7 +3604,7 @@ pub const Object = struct {...@@ -3604,7 +3604,7 @@ pub const Object = struct {
3604 var llvm_params = std.ArrayListUnmanaged(Builder.Type){};3604 var llvm_params = std.ArrayListUnmanaged(Builder.Type){};
3605 defer llvm_params.deinit(o.gpa);3605 defer llvm_params.deinit(o.gpa);
36063606
3607 if (firstParamSRet(fn_info, mod)) {3607 if (firstParamSRet(fn_info, mod, target)) {
3608 try llvm_params.append(o.gpa, .ptr);3608 try llvm_params.append(o.gpa, .ptr);
3609 }3609 }
36103610
...@@ -5130,7 +5130,7 @@ pub const FuncGen = struct {...@@ -5130,7 +5130,7 @@ pub const FuncGen = struct {
5130 const return_type = Type.fromInterned(fn_info.return_type);5130 const return_type = Type.fromInterned(fn_info.return_type);
5131 const llvm_fn = try self.resolveInst(pl_op.operand);5131 const llvm_fn = try self.resolveInst(pl_op.operand);
5132 const target = mod.getTarget();5132 const target = mod.getTarget();
5133 const sret = firstParamSRet(fn_info, mod);5133 const sret = firstParamSRet(fn_info, mod, target);
51345134
5135 var llvm_args = std.ArrayList(Builder.Value).init(self.gpa);5135 var llvm_args = std.ArrayList(Builder.Value).init(self.gpa);
5136 defer llvm_args.deinit();5136 defer llvm_args.deinit();
...@@ -10865,38 +10865,38 @@ fn toLlvmGlobalAddressSpace(wanted_address_space: std.builtin.AddressSpace, targ...@@ -10865,38 +10865,38 @@ fn toLlvmGlobalAddressSpace(wanted_address_space: std.builtin.AddressSpace, targ
10865 };10865 };
10866}10866}
1086710867
10868fn firstParamSRet(fn_info: InternPool.Key.FuncType, mod: *Module) bool {10868fn firstParamSRet(fn_info: InternPool.Key.FuncType, zcu: *Zcu, target: std.Target) bool {
10869 const return_type = Type.fromInterned(fn_info.return_type);10869 const return_type = Type.fromInterned(fn_info.return_type);
10870 if (!return_type.hasRuntimeBitsIgnoreComptime(mod)) return false;10870 if (!return_type.hasRuntimeBitsIgnoreComptime(zcu)) return false;
1087110871
10872 const target = mod.getTarget();10872 return switch (fn_info.cc) {
10873 switch (fn_info.cc) {10873 .Unspecified, .Inline => isByRef(return_type, zcu),
10874 .Unspecified, .Inline => return isByRef(return_type, mod),
10875 .C => switch (target.cpu.arch) {10874 .C => switch (target.cpu.arch) {
10876 .mips, .mipsel => return false,10875 .mips, .mipsel => false,
10876 .x86 => isByRef(return_type, zcu),
10877 .x86_64 => switch (target.os.tag) {10877 .x86_64 => switch (target.os.tag) {
10878 .windows => return x86_64_abi.classifyWindows(return_type, mod) == .memory,10878 .windows => x86_64_abi.classifyWindows(return_type, zcu) == .memory,
10879 else => return firstParamSRetSystemV(return_type, mod),10879 else => firstParamSRetSystemV(return_type, zcu, target),
10880 },10880 },
10881 .wasm32 => return wasm_c_abi.classifyType(return_type, mod)[0] == .indirect,10881 .wasm32 => wasm_c_abi.classifyType(return_type, zcu)[0] == .indirect,
10882 .aarch64, .aarch64_be => return aarch64_c_abi.classifyType(return_type, mod) == .memory,10882 .aarch64, .aarch64_be => aarch64_c_abi.classifyType(return_type, zcu) == .memory,
10883 .arm, .armeb => switch (arm_c_abi.classifyType(return_type, mod, .ret)) {10883 .arm, .armeb => switch (arm_c_abi.classifyType(return_type, zcu, .ret)) {
10884 .memory, .i64_array => return true,10884 .memory, .i64_array => true,
10885 .i32_array => |size| return size != 1,10885 .i32_array => |size| size != 1,
10886 .byval => return false,10886 .byval => false,
10887 },10887 },
10888 .riscv32, .riscv64 => return riscv_c_abi.classifyType(return_type, mod) == .memory,10888 .riscv32, .riscv64 => riscv_c_abi.classifyType(return_type, zcu) == .memory,
10889 else => return false, // TODO investigate C ABI for other architectures10889 else => false, // TODO investigate C ABI for other architectures
10890 },10890 },
10891 .SysV => return firstParamSRetSystemV(return_type, mod),10891 .SysV => firstParamSRetSystemV(return_type, zcu, target),
10892 .Win64 => return x86_64_abi.classifyWindows(return_type, mod) == .memory,10892 .Win64 => x86_64_abi.classifyWindows(return_type, zcu) == .memory,
10893 .Stdcall => return !isScalar(mod, return_type),10893 .Stdcall => !isScalar(zcu, return_type),
10894 else => return false,10894 else => false,
10895 }10895 };
10896}10896}
1089710897
10898fn firstParamSRetSystemV(ty: Type, mod: *Module) bool {10898fn firstParamSRetSystemV(ty: Type, zcu: *Zcu, target: std.Target) bool {
10899 const class = x86_64_abi.classifySystemV(ty, mod, .ret);10899 const class = x86_64_abi.classifySystemV(ty, zcu, target, .ret);
10900 if (class[0] == .memory) return true;10900 if (class[0] == .memory) return true;
10901 if (class[0] == .x87 and class[2] != .none) return true;10901 if (class[0] == .x87 and class[2] != .none) return true;
10902 return false;10902 return false;
...@@ -10922,6 +10922,7 @@ fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Bu...@@ -10922,6 +10922,7 @@ fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Bu
10922 .C => {10922 .C => {
10923 switch (target.cpu.arch) {10923 switch (target.cpu.arch) {
10924 .mips, .mipsel => return o.lowerType(return_type),10924 .mips, .mipsel => return o.lowerType(return_type),
10925 .x86 => return if (isByRef(return_type, mod)) .void else o.lowerType(return_type),
10925 .x86_64 => switch (target.os.tag) {10926 .x86_64 => switch (target.os.tag) {
10926 .windows => return lowerWin64FnRetTy(o, fn_info),10927 .windows => return lowerWin64FnRetTy(o, fn_info),
10927 else => return lowerSystemVFnRetTy(o, fn_info),10928 else => return lowerSystemVFnRetTy(o, fn_info),
...@@ -11014,7 +11015,8 @@ fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.E...@@ -11014,7 +11015,8 @@ fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.E
11014 if (isScalar(mod, return_type)) {11015 if (isScalar(mod, return_type)) {
11015 return o.lowerType(return_type);11016 return o.lowerType(return_type);
11016 }11017 }
11017 const classes = x86_64_abi.classifySystemV(return_type, mod, .ret);11018 const target = mod.getTarget();
11019 const classes = x86_64_abi.classifySystemV(return_type, mod, target, .ret);
11018 if (classes[0] == .memory) return .void;11020 if (classes[0] == .memory) return .void;
11019 var types_index: u32 = 0;11021 var types_index: u32 = 0;
11020 var types_buffer: [8]Builder.Type = undefined;11022 var types_buffer: [8]Builder.Type = undefined;
...@@ -11098,8 +11100,8 @@ const ParamTypeIterator = struct {...@@ -11098,8 +11100,8 @@ const ParamTypeIterator = struct {
1109811100
11099 pub fn next(it: *ParamTypeIterator) Allocator.Error!?Lowering {11101 pub fn next(it: *ParamTypeIterator) Allocator.Error!?Lowering {
11100 if (it.zig_index >= it.fn_info.param_types.len) return null;11102 if (it.zig_index >= it.fn_info.param_types.len) return null;
11101 const mod = it.object.module;11103 const zcu = it.object.module;
11102 const ip = &mod.intern_pool;11104 const ip = &zcu.intern_pool;
11103 const ty = it.fn_info.param_types.get(ip)[it.zig_index];11105 const ty = it.fn_info.param_types.get(ip)[it.zig_index];
11104 it.byval_attr = false;11106 it.byval_attr = false;
11105 return nextInner(it, Type.fromInterned(ty));11107 return nextInner(it, Type.fromInterned(ty));
...@@ -11107,8 +11109,8 @@ const ParamTypeIterator = struct {...@@ -11107,8 +11109,8 @@ const ParamTypeIterator = struct {
1110711109
11108 /// `airCall` uses this instead of `next` so that it can take into account variadic functions.11110 /// `airCall` uses this instead of `next` so that it can take into account variadic functions.
11109 pub fn nextCall(it: *ParamTypeIterator, fg: *FuncGen, args: []const Air.Inst.Ref) Allocator.Error!?Lowering {11111 pub fn nextCall(it: *ParamTypeIterator, fg: *FuncGen, args: []const Air.Inst.Ref) Allocator.Error!?Lowering {
11110 const mod = it.object.module;11112 const zcu = it.object.module;
11111 const ip = &mod.intern_pool;11113 const ip = &zcu.intern_pool;
11112 if (it.zig_index >= it.fn_info.param_types.len) {11114 if (it.zig_index >= it.fn_info.param_types.len) {
11113 if (it.zig_index >= args.len) {11115 if (it.zig_index >= args.len) {
11114 return null;11116 return null;
...@@ -11121,10 +11123,10 @@ const ParamTypeIterator = struct {...@@ -11121,10 +11123,10 @@ const ParamTypeIterator = struct {
11121 }11123 }
1112211124
11123 fn nextInner(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering {11125 fn nextInner(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering {
11124 const mod = it.object.module;11126 const zcu = it.object.module;
11125 const target = mod.getTarget();11127 const target = zcu.getTarget();
1112611128
11127 if (!ty.hasRuntimeBitsIgnoreComptime(mod)) {11129 if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) {
11128 it.zig_index += 1;11130 it.zig_index += 1;
11129 return .no_bits;11131 return .no_bits;
11130 }11132 }
...@@ -11132,12 +11134,12 @@ const ParamTypeIterator = struct {...@@ -11132,12 +11134,12 @@ const ParamTypeIterator = struct {
11132 .Unspecified, .Inline => {11134 .Unspecified, .Inline => {
11133 it.zig_index += 1;11135 it.zig_index += 1;
11134 it.llvm_index += 1;11136 it.llvm_index += 1;
11135 if (ty.isSlice(mod) or11137 if (ty.isSlice(zcu) or
11136 (ty.zigTypeTag(mod) == .Optional and ty.optionalChild(mod).isSlice(mod) and !ty.ptrAllowsZero(mod)))11138 (ty.zigTypeTag(zcu) == .Optional and ty.optionalChild(zcu).isSlice(zcu) and !ty.ptrAllowsZero(zcu)))
11137 {11139 {
11138 it.llvm_index += 1;11140 it.llvm_index += 1;
11139 return .slice;11141 return .slice;
11140 } else if (isByRef(ty, mod)) {11142 } else if (isByRef(ty, zcu)) {
11141 return .byref;11143 return .byref;
11142 } else {11144 } else {
11143 return .byval;11145 return .byval;
...@@ -11146,87 +11148,85 @@ const ParamTypeIterator = struct {...@@ -11146,87 +11148,85 @@ const ParamTypeIterator = struct {
11146 .Async => {11148 .Async => {
11147 @panic("TODO implement async function lowering in the LLVM backend");11149 @panic("TODO implement async function lowering in the LLVM backend");
11148 },11150 },
11149 .C => {11151 .C => switch (target.cpu.arch) {
11150 switch (target.cpu.arch) {11152 .mips, .mipsel => {
11151 .mips, .mipsel => {11153 it.zig_index += 1;
11152 it.zig_index += 1;11154 it.llvm_index += 1;
11153 it.llvm_index += 1;11155 return .byval;
11156 },
11157 .x86_64 => switch (target.os.tag) {
11158 .windows => return it.nextWin64(ty),
11159 else => return it.nextSystemV(ty),
11160 },
11161 .wasm32 => {
11162 it.zig_index += 1;
11163 it.llvm_index += 1;
11164 if (isScalar(zcu, ty)) {
11154 return .byval;11165 return .byval;
11155 },11166 }
11156 .x86_64 => switch (target.os.tag) {11167 const classes = wasm_c_abi.classifyType(ty, zcu);
11157 .windows => return it.nextWin64(ty),11168 if (classes[0] == .indirect) {
11158 else => return it.nextSystemV(ty),11169 return .byref;
11159 },11170 }
11160 .wasm32 => {11171 return .abi_sized_int;
11161 it.zig_index += 1;11172 },
11162 it.llvm_index += 1;11173 .aarch64, .aarch64_be => {
11163 if (isScalar(mod, ty)) {11174 it.zig_index += 1;
11164 return .byval;11175 it.llvm_index += 1;
11165 }11176 switch (aarch64_c_abi.classifyType(ty, zcu)) {
11166 const classes = wasm_c_abi.classifyType(ty, mod);11177 .memory => return .byref_mut,
11167 if (classes[0] == .indirect) {11178 .float_array => |len| return Lowering{ .float_array = len },
11179 .byval => return .byval,
11180 .integer => {
11181 it.types_len = 1;
11182 it.types_buffer[0] = .i64;
11183 return .multiple_llvm_types;
11184 },
11185 .double_integer => return Lowering{ .i64_array = 2 },
11186 }
11187 },
11188 .arm, .armeb => {
11189 it.zig_index += 1;
11190 it.llvm_index += 1;
11191 switch (arm_c_abi.classifyType(ty, zcu, .arg)) {
11192 .memory => {
11193 it.byval_attr = true;
11168 return .byref;11194 return .byref;
11169 }11195 },
11170 return .abi_sized_int;11196 .byval => return .byval,
11171 },11197 .i32_array => |size| return Lowering{ .i32_array = size },
11172 .aarch64, .aarch64_be => {11198 .i64_array => |size| return Lowering{ .i64_array = size },
11173 it.zig_index += 1;11199 }
11174 it.llvm_index += 1;11200 },
11175 switch (aarch64_c_abi.classifyType(ty, mod)) {11201 .riscv32, .riscv64 => {
11176 .memory => return .byref_mut,11202 it.zig_index += 1;
11177 .float_array => |len| return Lowering{ .float_array = len },11203 it.llvm_index += 1;
11178 .byval => return .byval,11204 if (ty.toIntern() == .f16_type and
11179 .integer => {11205 !std.Target.riscv.featureSetHas(target.cpu.features, .d)) return .as_u16;
11180 it.types_len = 1;11206 switch (riscv_c_abi.classifyType(ty, zcu)) {
11181 it.types_buffer[0] = .i64;11207 .memory => return .byref_mut,
11182 return .multiple_llvm_types;11208 .byval => return .byval,
11183 },11209 .integer => return .abi_sized_int,
11184 .double_integer => return Lowering{ .i64_array = 2 },11210 .double_integer => return Lowering{ .i64_array = 2 },
11185 }11211 .fields => {
11186 },11212 it.types_len = 0;
11187 .arm, .armeb => {11213 for (0..ty.structFieldCount(zcu)) |field_index| {
11188 it.zig_index += 1;11214 const field_ty = ty.structFieldType(field_index, zcu);
11189 it.llvm_index += 1;11215 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
11190 switch (arm_c_abi.classifyType(ty, mod, .arg)) {11216 it.types_buffer[it.types_len] = try it.object.lowerType(field_ty);
11191 .memory => {11217 it.types_len += 1;
11192 it.byval_attr = true;11218 }
11193 return .byref;11219 it.llvm_index += it.types_len - 1;
11194 },11220 return .multiple_llvm_types;
11195 .byval => return .byval,11221 },
11196 .i32_array => |size| return Lowering{ .i32_array = size },11222 }
11197 .i64_array => |size| return Lowering{ .i64_array = size },11223 },
11198 }11224 // TODO investigate C ABI for other architectures
11199 },11225 else => {
11200 .riscv32, .riscv64 => {11226 it.zig_index += 1;
11201 it.zig_index += 1;11227 it.llvm_index += 1;
11202 it.llvm_index += 1;11228 return .byval;
11203 if (ty.toIntern() == .f16_type and11229 },
11204 !std.Target.riscv.featureSetHas(target.cpu.features, .d)) return .as_u16;
11205 switch (riscv_c_abi.classifyType(ty, mod)) {
11206 .memory => return .byref_mut,
11207 .byval => return .byval,
11208 .integer => return .abi_sized_int,
11209 .double_integer => return Lowering{ .i64_array = 2 },
11210 .fields => {
11211 it.types_len = 0;
11212 for (0..ty.structFieldCount(mod)) |field_index| {
11213 const field_ty = ty.structFieldType(field_index, mod);
11214 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
11215 it.types_buffer[it.types_len] = try it.object.lowerType(field_ty);
11216 it.types_len += 1;
11217 }
11218 it.llvm_index += it.types_len - 1;
11219 return .multiple_llvm_types;
11220 },
11221 }
11222 },
11223 // TODO investigate C ABI for other architectures
11224 else => {
11225 it.zig_index += 1;
11226 it.llvm_index += 1;
11227 return .byval;
11228 },
11229 }
11230 },11230 },
11231 .Win64 => return it.nextWin64(ty),11231 .Win64 => return it.nextWin64(ty),
11232 .SysV => return it.nextSystemV(ty),11232 .SysV => return it.nextSystemV(ty),
...@@ -11234,7 +11234,7 @@ const ParamTypeIterator = struct {...@@ -11234,7 +11234,7 @@ const ParamTypeIterator = struct {
11234 it.zig_index += 1;11234 it.zig_index += 1;
11235 it.llvm_index += 1;11235 it.llvm_index += 1;
1123611236
11237 if (isScalar(mod, ty)) {11237 if (isScalar(zcu, ty)) {
11238 return .byval;11238 return .byval;
11239 } else {11239 } else {
11240 it.byval_attr = true;11240 it.byval_attr = true;
...@@ -11250,10 +11250,10 @@ const ParamTypeIterator = struct {...@@ -11250,10 +11250,10 @@ const ParamTypeIterator = struct {
11250 }11250 }
1125111251
11252 fn nextWin64(it: *ParamTypeIterator, ty: Type) ?Lowering {11252 fn nextWin64(it: *ParamTypeIterator, ty: Type) ?Lowering {
11253 const mod = it.object.module;11253 const zcu = it.object.module;
11254 switch (x86_64_abi.classifyWindows(ty, mod)) {11254 switch (x86_64_abi.classifyWindows(ty, zcu)) {
11255 .integer => {11255 .integer => {
11256 if (isScalar(mod, ty)) {11256 if (isScalar(zcu, ty)) {
11257 it.zig_index += 1;11257 it.zig_index += 1;
11258 it.llvm_index += 1;11258 it.llvm_index += 1;
11259 return .byval;11259 return .byval;
...@@ -11283,16 +11283,17 @@ const ParamTypeIterator = struct {...@@ -11283,16 +11283,17 @@ const ParamTypeIterator = struct {
11283 }11283 }
1128411284
11285 fn nextSystemV(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering {11285 fn nextSystemV(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering {
11286 const mod = it.object.module;11286 const zcu = it.object.module;
11287 const ip = &mod.intern_pool;11287 const ip = &zcu.intern_pool;
11288 const classes = x86_64_abi.classifySystemV(ty, mod, .arg);11288 const target = zcu.getTarget();
11289 const classes = x86_64_abi.classifySystemV(ty, zcu, target, .arg);
11289 if (classes[0] == .memory) {11290 if (classes[0] == .memory) {
11290 it.zig_index += 1;11291 it.zig_index += 1;
11291 it.llvm_index += 1;11292 it.llvm_index += 1;
11292 it.byval_attr = true;11293 it.byval_attr = true;
11293 return .byref;11294 return .byref;
11294 }11295 }
11295 if (isScalar(mod, ty)) {11296 if (isScalar(zcu, ty)) {
11296 it.zig_index += 1;11297 it.zig_index += 1;
11297 it.llvm_index += 1;11298 it.llvm_index += 1;
11298 return .byval;11299 return .byval;
test/c_abi/cfuncs.c+38-1
...@@ -269,6 +269,33 @@ void c_struct_f32_f32f32(struct Struct_f32_f32f32 s) {...@@ -269,6 +269,33 @@ void c_struct_f32_f32f32(struct Struct_f32_f32f32 s) {
269 assert_or_panic(s.b.d == 3.0f);269 assert_or_panic(s.b.d == 3.0f);
270}270}
271271
272struct Struct_u32_Union_u32_u32u32 {
273 uint32_t a;
274 union {
275 struct {
276 uint32_t d, e;
277 } c;
278 } b;
279};
280
281struct Struct_u32_Union_u32_u32u32 zig_ret_struct_u32_union_u32_u32u32(void);
282
283void zig_struct_u32_union_u32_u32u32(struct Struct_u32_Union_u32_u32u32);
284
285struct Struct_u32_Union_u32_u32u32 c_ret_struct_u32_union_u32_u32u32(void) {
286 struct Struct_u32_Union_u32_u32u32 s;
287 s.a = 1;
288 s.b.c.d = 2;
289 s.b.c.e = 3;
290 return s;
291}
292
293void c_struct_u32_union_u32_u32u32(struct Struct_u32_Union_u32_u32u32 s) {
294 assert_or_panic(s.a == 1);
295 assert_or_panic(s.b.c.d == 2);
296 assert_or_panic(s.b.c.e == 3);
297}
298
272struct BigStruct {299struct BigStruct {
273 uint64_t a;300 uint64_t a;
274 uint64_t b;301 uint64_t b;
...@@ -2664,6 +2691,16 @@ void run_c_tests(void) {...@@ -2664,6 +2691,16 @@ void run_c_tests(void) {
2664 }2691 }
2665#endif2692#endif
26662693
2694#if !defined(__powerpc__)
2695 {
2696 struct Struct_u32_Union_u32_u32u32 s = zig_ret_struct_u32_union_u32_u32u32();
2697 assert_or_panic(s.a == 1);
2698 assert_or_panic(s.b.c.d == 2);
2699 assert_or_panic(s.b.c.e == 3);
2700 zig_struct_u32_union_u32_u32u32(s);
2701 }
2702#endif
2703
2667 {2704 {
2668 struct BigStruct s = {1, 2, 3, 4, 5};2705 struct BigStruct s = {1, 2, 3, 4, 5};
2669 zig_big_struct(s);2706 zig_big_struct(s);
...@@ -2678,7 +2715,7 @@ void run_c_tests(void) {...@@ -2678,7 +2715,7 @@ void run_c_tests(void) {
2678 }2715 }
2679#endif2716#endif
26802717
2681#if !defined __i386__ && !defined __arm__ && !defined __aarch64__ && \2718#if !defined __arm__ && !defined __aarch64__ && \
2682 !defined __mips__ && !defined __powerpc__ && !defined ZIG_RISCV642719 !defined __mips__ && !defined __powerpc__ && !defined ZIG_RISCV64
2683 {2720 {
2684 struct MedStructInts s = {1, 2, 3};2721 struct MedStructInts s = {1, 2, 3};
test/c_abi/main.zig+47-29
...@@ -10,11 +10,11 @@ const builtin = @import("builtin");...@@ -10,11 +10,11 @@ const builtin = @import("builtin");
10const print = std.debug.print;10const print = std.debug.print;
11const expect = std.testing.expect;11const expect = std.testing.expect;
12const expectEqual = std.testing.expectEqual;12const expectEqual = std.testing.expectEqual;
13const has_i128 = builtin.cpu.arch != .x86 and !builtin.cpu.arch.isARM() and13const have_i128 = builtin.cpu.arch != .x86 and !builtin.cpu.arch.isARM() and
14 !builtin.cpu.arch.isMIPS() and !builtin.cpu.arch.isPPC();14 !builtin.cpu.arch.isMIPS() and !builtin.cpu.arch.isPPC();
1515
16const has_f128 = builtin.cpu.arch.isX86() and !builtin.os.tag.isDarwin();16const have_f128 = builtin.cpu.arch.isX86() and !builtin.os.tag.isDarwin();
17const has_f80 = builtin.cpu.arch.isX86();17const have_f80 = builtin.cpu.arch.isX86();
1818
19extern fn run_c_tests() void;19extern fn run_c_tests() void;
2020
...@@ -53,13 +53,13 @@ test "C ABI integers" {...@@ -53,13 +53,13 @@ test "C ABI integers" {
53 c_u16(0xfffe);53 c_u16(0xfffe);
54 c_u32(0xfffffffd);54 c_u32(0xfffffffd);
55 c_u64(0xfffffffffffffffc);55 c_u64(0xfffffffffffffffc);
56 if (has_i128) c_struct_u128(.{ .value = 0xfffffffffffffffc });56 if (have_i128) c_struct_u128(.{ .value = 0xfffffffffffffffc });
5757
58 c_i8(-1);58 c_i8(-1);
59 c_i16(-2);59 c_i16(-2);
60 c_i32(-3);60 c_i32(-3);
61 c_i64(-4);61 c_i64(-4);
62 if (has_i128) c_struct_i128(.{ .value = -6 });62 if (have_i128) c_struct_i128(.{ .value = -6 });
63 c_five_integers(12, 34, 56, 78, 90);63 c_five_integers(12, 34, 56, 78, 90);
64}64}
6565
...@@ -186,7 +186,6 @@ const complex_abi_compatible = builtin.cpu.arch != .x86 and !builtin.cpu.arch.is...@@ -186,7 +186,6 @@ const complex_abi_compatible = builtin.cpu.arch != .x86 and !builtin.cpu.arch.is
186186
187test "C ABI complex float" {187test "C ABI complex float" {
188 if (!complex_abi_compatible) return error.SkipZigTest;188 if (!complex_abi_compatible) return error.SkipZigTest;
189 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) return error.SkipZigTest; // See https://github.com/ziglang/zig/issues/8465
190189
191 const a = ComplexFloat{ .real = 1.25, .imag = 2.6 };190 const a = ComplexFloat{ .real = 1.25, .imag = 2.6 };
192 const b = ComplexFloat{ .real = 11.3, .imag = -1.5 };191 const b = ComplexFloat{ .real = 11.3, .imag = -1.5 };
...@@ -401,6 +400,42 @@ test "C ABI struct f32 {f32,f32}" {...@@ -401,6 +400,42 @@ test "C ABI struct f32 {f32,f32}" {
401 c_struct_f32_f32f32(.{ .a = 1.0, .b = .{ .c = 2.0, .d = 3.0 } });400 c_struct_f32_f32f32(.{ .a = 1.0, .b = .{ .c = 2.0, .d = 3.0 } });
402}401}
403402
403const Struct_u32_Union_u32_u32u32 = extern struct {
404 a: u32,
405 b: extern union {
406 c: extern struct {
407 d: u32,
408 e: u32,
409 },
410 },
411};
412
413export fn zig_ret_struct_u32_union_u32_u32u32() Struct_u32_Union_u32_u32u32 {
414 return .{ .a = 1, .b = .{ .c = .{ .d = 2, .e = 3 } } };
415}
416
417export fn zig_struct_u32_union_u32_u32u32(s: Struct_u32_Union_u32_u32u32) void {
418 expect(s.a == 1) catch @panic("test failure");
419 expect(s.b.c.d == 2) catch @panic("test failure");
420 expect(s.b.c.e == 3) catch @panic("test failure");
421}
422
423extern fn c_ret_struct_u32_union_u32_u32u32() Struct_u32_Union_u32_u32u32;
424
425extern fn c_struct_u32_union_u32_u32u32(Struct_u32_Union_u32_u32u32) void;
426
427test "C ABI struct{u32,union{u32,struct{u32,u32}}}" {
428 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
429 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;
430 if (builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
431
432 const s = c_ret_struct_u32_union_u32_u32u32();
433 try expect(s.a == 1);
434 try expect(s.b.c.d == 2);
435 try expect(s.b.c.e == 3);
436 c_struct_u32_union_u32_u32u32(.{ .a = 1, .b = .{ .c = .{ .d = 2, .e = 3 } } });
437}
438
404const BigStruct = extern struct {439const BigStruct = extern struct {
405 a: u64,440 a: u64,
406 b: u64,441 b: u64,
...@@ -470,7 +505,6 @@ extern fn c_med_struct_mixed(MedStructMixed) void;...@@ -470,7 +505,6 @@ extern fn c_med_struct_mixed(MedStructMixed) void;
470extern fn c_ret_med_struct_mixed() MedStructMixed;505extern fn c_ret_med_struct_mixed() MedStructMixed;
471506
472test "C ABI medium struct of ints and floats" {507test "C ABI medium struct of ints and floats" {
473 if (builtin.cpu.arch == .x86) return error.SkipZigTest;
474 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;508 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
475 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;509 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;
476 if (builtin.cpu.arch.isPPC64()) return error.SkipZigTest;510 if (builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
...@@ -538,7 +572,6 @@ extern fn c_med_struct_ints(MedStructInts) void;...@@ -538,7 +572,6 @@ extern fn c_med_struct_ints(MedStructInts) void;
538extern fn c_ret_med_struct_ints() MedStructInts;572extern fn c_ret_med_struct_ints() MedStructInts;
539573
540test "C ABI medium struct of ints" {574test "C ABI medium struct of ints" {
541 if (builtin.cpu.arch == .x86) return error.SkipZigTest;
542 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;575 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
543 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;576 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;
544 if (builtin.cpu.arch.isPPC64()) return error.SkipZigTest;577 if (builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
...@@ -600,7 +633,7 @@ export fn zig_big_packed_struct(x: BigPackedStruct) void {...@@ -600,7 +633,7 @@ export fn zig_big_packed_struct(x: BigPackedStruct) void {
600}633}
601634
602test "C ABI big packed struct" {635test "C ABI big packed struct" {
603 if (!has_i128) return error.SkipZigTest;636 if (!have_i128) return error.SkipZigTest;
604637
605 const s = BigPackedStruct{ .a = 1, .b = 2 };638 const s = BigPackedStruct{ .a = 1, .b = 2 };
606 c_big_packed_struct(s);639 c_big_packed_struct(s);
...@@ -943,7 +976,6 @@ extern fn c_float_array_struct(FloatArrayStruct) void;...@@ -943,7 +976,6 @@ extern fn c_float_array_struct(FloatArrayStruct) void;
943extern fn c_ret_float_array_struct() FloatArrayStruct;976extern fn c_ret_float_array_struct() FloatArrayStruct;
944977
945test "Float array like struct" {978test "Float array like struct" {
946 if (builtin.cpu.arch == .x86 and builtin.mode != .Debug) return error.SkipZigTest;
947 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;979 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
948 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;980 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;
949981
...@@ -5318,7 +5350,6 @@ extern fn c_ptr_size_float_struct(Vector2) void;...@@ -5318,7 +5350,6 @@ extern fn c_ptr_size_float_struct(Vector2) void;
5318extern fn c_ret_ptr_size_float_struct() Vector2;5350extern fn c_ret_ptr_size_float_struct() Vector2;
53195351
5320test "C ABI pointer sized float struct" {5352test "C ABI pointer sized float struct" {
5321 if (builtin.cpu.arch == .x86) return error.SkipZigTest;
5322 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;5353 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
5323 if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest;5354 if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
5324 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;5355 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;
...@@ -5348,7 +5379,6 @@ test "DC: Zig passes to C" {...@@ -5348,7 +5379,6 @@ test "DC: Zig passes to C" {
5348 try expectOk(c_assert_DC(.{ .v1 = -0.25, .v2 = 15 }));5379 try expectOk(c_assert_DC(.{ .v1 = -0.25, .v2 = 15 }));
5349}5380}
5350test "DC: Zig returns to C" {5381test "DC: Zig returns to C" {
5351 if (builtin.cpu.arch == .x86 and builtin.mode != .Debug) return error.SkipZigTest;
5352 if (builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest;5382 if (builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest;
5353 if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest;5383 if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
5354 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;5384 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;
...@@ -5363,7 +5393,6 @@ test "DC: C passes to Zig" {...@@ -5363,7 +5393,6 @@ test "DC: C passes to Zig" {
5363 try expectOk(c_send_DC());5393 try expectOk(c_send_DC());
5364}5394}
5365test "DC: C returns to Zig" {5395test "DC: C returns to Zig" {
5366 if (builtin.cpu.arch == .x86 and builtin.mode != .Debug) return error.SkipZigTest;
5367 if (builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest;5396 if (builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest;
5368 if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest;5397 if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
5369 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;5398 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;
...@@ -5397,7 +5426,6 @@ test "CFF: Zig passes to C" {...@@ -5397,7 +5426,6 @@ test "CFF: Zig passes to C" {
5397 try expectOk(c_assert_CFF(.{ .v1 = 39, .v2 = 0.875, .v3 = 1.0 }));5426 try expectOk(c_assert_CFF(.{ .v1 = 39, .v2 = 0.875, .v3 = 1.0 }));
5398}5427}
5399test "CFF: Zig returns to C" {5428test "CFF: Zig returns to C" {
5400 if (builtin.cpu.arch == .x86 and builtin.mode != .Debug) return error.SkipZigTest;
5401 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;5429 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
5402 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;5430 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;
5403 if (builtin.cpu.arch.isPPC64()) return error.SkipZigTest;5431 if (builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
...@@ -5414,7 +5442,6 @@ test "CFF: C passes to Zig" {...@@ -5414,7 +5442,6 @@ test "CFF: C passes to Zig" {
5414 try expectOk(c_send_CFF());5442 try expectOk(c_send_CFF());
5415}5443}
5416test "CFF: C returns to Zig" {5444test "CFF: C returns to Zig" {
5417 if (builtin.cpu.arch == .x86 and builtin.mode != .Debug) return error.SkipZigTest;
5418 if (builtin.cpu.arch == .aarch64 and builtin.mode != .Debug) return error.SkipZigTest;5445 if (builtin.cpu.arch == .aarch64 and builtin.mode != .Debug) return error.SkipZigTest;
5419 if (builtin.cpu.arch.isRISCV() and builtin.mode != .Debug) return error.SkipZigTest;5446 if (builtin.cpu.arch.isRISCV() and builtin.mode != .Debug) return error.SkipZigTest;
5420 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;5447 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
...@@ -5442,28 +5469,24 @@ pub export fn zig_ret_CFF() CFF {...@@ -5442,28 +5469,24 @@ pub export fn zig_ret_CFF() CFF {
5442const PD = extern struct { v1: ?*anyopaque, v2: f64 };5469const PD = extern struct { v1: ?*anyopaque, v2: f64 };
54435470
5444test "PD: Zig passes to C" {5471test "PD: Zig passes to C" {
5445 if (builtin.target.cpu.arch == .x86) return error.SkipZigTest;
5446 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;5472 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
5447 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;5473 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;
5448 if (builtin.cpu.arch.isPPC64()) return error.SkipZigTest;5474 if (builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
5449 try expectOk(c_assert_PD(.{ .v1 = null, .v2 = 0.5 }));5475 try expectOk(c_assert_PD(.{ .v1 = null, .v2 = 0.5 }));
5450}5476}
5451test "PD: Zig returns to C" {5477test "PD: Zig returns to C" {
5452 if (builtin.target.cpu.arch == .x86) return error.SkipZigTest;
5453 if (builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest;5478 if (builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest;
5454 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;5479 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;
5455 if (builtin.cpu.arch.isPPC64()) return error.SkipZigTest;5480 if (builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
5456 try expectOk(c_assert_ret_PD());5481 try expectOk(c_assert_ret_PD());
5457}5482}
5458test "PD: C passes to Zig" {5483test "PD: C passes to Zig" {
5459 if (builtin.target.cpu.arch == .x86) return error.SkipZigTest;
5460 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;5484 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
5461 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;5485 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;
5462 if (builtin.cpu.arch.isPPC64()) return error.SkipZigTest;5486 if (builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
5463 try expectOk(c_send_PD());5487 try expectOk(c_send_PD());
5464}5488}
5465test "PD: C returns to Zig" {5489test "PD: C returns to Zig" {
5466 if (builtin.target.cpu.arch == .x86) return error.SkipZigTest;
5467 if (builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest;5490 if (builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest;
5468 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;5491 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;
5469 if (builtin.cpu.arch.isPPC64()) return error.SkipZigTest;5492 if (builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
...@@ -5519,7 +5542,6 @@ const ByVal = extern struct {...@@ -5519,7 +5542,6 @@ const ByVal = extern struct {
55195542
5520extern fn c_func_ptr_byval(*anyopaque, *anyopaque, ByVal, c_ulong, *anyopaque, c_ulong) void;5543extern fn c_func_ptr_byval(*anyopaque, *anyopaque, ByVal, c_ulong, *anyopaque, c_ulong) void;
5521test "C function that takes byval struct called via function pointer" {5544test "C function that takes byval struct called via function pointer" {
5522 if (builtin.cpu.arch == .x86 and builtin.mode != .Debug) return error.SkipZigTest;
5523 if (builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest;5545 if (builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest;
5524 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;5546 if (builtin.cpu.arch.isPPC()) return error.SkipZigTest;
55255547
...@@ -5551,7 +5573,6 @@ const f16_struct = extern struct {...@@ -5551,7 +5573,6 @@ const f16_struct = extern struct {
5551};5573};
5552extern fn c_f16_struct(f16_struct) f16_struct;5574extern fn c_f16_struct(f16_struct) f16_struct;
5553test "f16 struct" {5575test "f16 struct" {
5554 if (builtin.target.cpu.arch == .x86) return error.SkipZigTest;
5555 if (builtin.target.cpu.arch.isMIPS()) return error.SkipZigTest;5576 if (builtin.target.cpu.arch.isMIPS()) return error.SkipZigTest;
5556 if (builtin.target.cpu.arch.isPPC()) return error.SkipZigTest;5577 if (builtin.target.cpu.arch.isPPC()) return error.SkipZigTest;
5557 if (builtin.target.cpu.arch.isPPC()) return error.SkipZigTest;5578 if (builtin.target.cpu.arch.isPPC()) return error.SkipZigTest;
...@@ -5563,7 +5584,7 @@ test "f16 struct" {...@@ -5563,7 +5584,7 @@ test "f16 struct" {
55635584
5564extern fn c_f80(f80) f80;5585extern fn c_f80(f80) f80;
5565test "f80 bare" {5586test "f80 bare" {
5566 if (!has_f80) return error.SkipZigTest;5587 if (!have_f80) return error.SkipZigTest;
55675588
5568 const a = c_f80(12.34);5589 const a = c_f80(12.34);
5569 try expect(@as(f64, @floatCast(a)) == 56.78);5590 try expect(@as(f64, @floatCast(a)) == 56.78);
...@@ -5574,9 +5595,7 @@ const f80_struct = extern struct {...@@ -5574,9 +5595,7 @@ const f80_struct = extern struct {
5574};5595};
5575extern fn c_f80_struct(f80_struct) f80_struct;5596extern fn c_f80_struct(f80_struct) f80_struct;
5576test "f80 struct" {5597test "f80 struct" {
5577 if (!has_f80) return error.SkipZigTest;5598 if (!have_f80) return error.SkipZigTest;
5578 if (builtin.target.cpu.arch == .x86) return error.SkipZigTest;
5579 if (builtin.zig_backend == .stage2_llvm and builtin.mode != .Debug) return error.SkipZigTest;
55805599
5581 const a = c_f80_struct(.{ .a = 12.34 });5600 const a = c_f80_struct(.{ .a = 12.34 });
5582 try expect(@as(f64, @floatCast(a.a)) == 56.78);5601 try expect(@as(f64, @floatCast(a.a)) == 56.78);
...@@ -5588,8 +5607,7 @@ const f80_extra_struct = extern struct {...@@ -5588,8 +5607,7 @@ const f80_extra_struct = extern struct {
5588};5607};
5589extern fn c_f80_extra_struct(f80_extra_struct) f80_extra_struct;5608extern fn c_f80_extra_struct(f80_extra_struct) f80_extra_struct;
5590test "f80 extra struct" {5609test "f80 extra struct" {
5591 if (!has_f80) return error.SkipZigTest;5610 if (!have_f80) return error.SkipZigTest;
5592 if (builtin.target.cpu.arch == .x86) return error.SkipZigTest;
55935611
5594 const a = c_f80_extra_struct(.{ .a = 12.34, .b = 42 });5612 const a = c_f80_extra_struct(.{ .a = 12.34, .b = 42 });
5595 try expect(@as(f64, @floatCast(a.a)) == 56.78);5613 try expect(@as(f64, @floatCast(a.a)) == 56.78);
...@@ -5598,7 +5616,7 @@ test "f80 extra struct" {...@@ -5598,7 +5616,7 @@ test "f80 extra struct" {
55985616
5599extern fn c_f128(f128) f128;5617extern fn c_f128(f128) f128;
5600test "f128 bare" {5618test "f128 bare" {
5601 if (!has_f128) return error.SkipZigTest;5619 if (!have_f128) return error.SkipZigTest;
56025620
5603 const a = c_f128(12.34);5621 const a = c_f128(12.34);
5604 try expect(@as(f64, @floatCast(a)) == 56.78);5622 try expect(@as(f64, @floatCast(a)) == 56.78);
...@@ -5609,7 +5627,7 @@ const f128_struct = extern struct {...@@ -5609,7 +5627,7 @@ const f128_struct = extern struct {
5609};5627};
5610extern fn c_f128_struct(f128_struct) f128_struct;5628extern fn c_f128_struct(f128_struct) f128_struct;
5611test "f128 struct" {5629test "f128 struct" {
5612 if (!has_f128) return error.SkipZigTest;5630 if (!have_f128) return error.SkipZigTest;
56135631
5614 const a = c_f128_struct(.{ .a = 12.34 });5632 const a = c_f128_struct(.{ .a = 12.34 });
5615 try expect(@as(f64, @floatCast(a.a)) == 56.78);5633 try expect(@as(f64, @floatCast(a.a)) == 56.78);