| author | |
| committer | |
| log | 9deea9b1d8a393fc6a3a5ecc9f112009ee6dc3b2 |
| tree | 9f7023ae326ff2c872d057d5937a8161fedab15f |
| parent | 8e0a802ea1bb34a3f82ff4d2f7e2d40fc57726f2 |
Closes #197219 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 | } |
| 1923 | 1923 | ||
| 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 { |
| 2087 | 2087 | ||
| 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 | } |
| 2096 | 2096 | ||
| 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 | } |
| 2101 | 2101 | ||
| 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 | } |
| 2107 | 2107 | ||
| 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 | } |
| 2113 | 2113 | ||
| 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 | } |
| 2117 | 2117 | ||
| 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 | } |
| 2121 | 2121 | ||
| 2122 | /// Reads the non-opv flag calculated during AstGen. Used to short-circuit more | 2122 | /// 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 { |
| 2130 | 2130 | ||
| 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 { |
| 2138 | 2138 | ||
| 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 | } |
| 2146 | 2146 | ||
| 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 | } |
| 2156 | 2156 | ||
| 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 | } |
| 2164 | 2164 | ||
| 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 | } |
| 2169 | 2169 | ||
| 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 | } |
| 2177 | 2177 | ||
| 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 | } |
| 2182 | 2182 | ||
| 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 | } |
| 2190 | 2190 | ||
| 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 | } |
| 2195 | 2195 | ||
| 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 | } |
| 2212 | 2212 | ||
| 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 | } |
| 2219 | 2219 | ||
| 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 | } |
| 2227 | 2227 | ||
| 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 | } |
| 2231 | 2231 | ||
| 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 be | 2241 | /// 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 | } |
| 2249 | 2249 | ||
| 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 | } |
| 2256 | 2256 | ||
| 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 | } |
| 2261 | 2261 | ||
| 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 | } |
| 2268 | 2268 | ||
| 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 | } |
| 2275 | 2275 | ||
| 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 | } |
| 2282 | 2282 | ||
| 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 | } |
| 2286 | 2286 | ||
| 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 | } |
| 2290 | 2290 | ||
| ... | @@ -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 | }; |
| 2360 | 2360 | ||
| 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 | }; |
| 6142 | 6142 | ||
| 6143 | pub fn getUnionLayout(mod: *Module, u: InternPool.LoadedUnionType) UnionLayout { | 6143 | pub 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; |
| 6153 | 6153 | ||
| 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_align | 6156 | explicit_align |
| 6157 | else | 6157 | 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 | } |
| 6185 | 6185 | ||
| 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 | } |
| 6201 | 6201 | ||
| 6202 | pub fn unionAbiSize(mod: *Module, u: InternPool.LoadedUnionType) u64 { | 6202 | pub 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 | } |
| 6205 | 6205 | ||
| 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. |
| 6207 | pub fn unionAbiAlignment(mod: *Module, u: InternPool.LoadedUnionType) Alignment { | 6207 | pub 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; |
| 6214 | 6214 | ||
| 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. |
| 6224 | pub fn unionFieldNormalAlignment(mod: *Module, u: InternPool.LoadedUnionType, field_index: u32) Alignment { | 6224 | pub 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 | } |
| 6231 | 6231 | ||
| 6232 | /// Returns the index of the active field, given the current tag value | 6232 | /// Returns the index of the active field, given the current tag value |
| 6233 | pub fn unionTagFieldIndex(mod: *Module, u: InternPool.LoadedUnionType, enum_tag: Value) ?u32 { | 6233 | pub 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 | } |
| 6239 | 6239 | ||
| 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; |
| 35407 | 35407 | ||
| 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_align | 35410 | explicit_align |
| 35411 | else | 35411 | 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 | }); |
| 35467 | 35467 | ||
| 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_align | 35470 | explicit_align |
| 35471 | else | 35471 | 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 } }; |
| 18452 | 18452 | ||
| 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; |
| 18801 | 18801 | ||
| 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; |
| 18876 | 18876 | ||
| 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 { |
| 19090 | 19090 | ||
| 19091 | fn splitType(self: *Self, ty: Type) ![2]Type { | 19091 | fn 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 | }; |
| 15 | 46 | ||
| 16 | pub fn classifyWindows(ty: Type, zcu: *Zcu) Class { | 47 | pub 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 }; |
| 69 | 100 | ||
| 70 | /// There are a maximum of 8 possible return slots. Returned values are in | 101 | /// 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. |
| 72 | pub fn classifySystemV(ty: Type, zcu: *Zcu, ctx: Context) [8]Class { | 103 | pub 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, or | 264 | // "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 classified | 266 | // "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; |
| 293 | 280 | ||
| 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 and | 283 | 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 | } | ||
| 349 | 287 | ||
| 350 | // Post-merger cleanup | 288 | // Post-merger cleanup |
| 351 | 289 | ||
| ... | @@ -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 { |
| 391 | 329 | ||
| 392 | fn classifySystemVStruct( | 330 | fn 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| { |
| 434 | 357 | 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 | } | ||
| 440 | 378 | ||
| 441 | // "If one of the classes is INTEGER, the result is the INTEGER." | 379 | fn 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 | } |
| 446 | 397 | } 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 or | 400 | _ = classifySystemVUnion(result, starting_byte_offset, field_loaded_union, zcu, target); |
| 450 | result_class.* == .x87up or | 401 | continue; |
| 451 | result_class.* == .complex_x87 or | 402 | }, |
| 452 | field_class[0] == .x87 or | 403 | .@"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 | } |
| 467 | 412 | ||
| 468 | pub const SysV = struct { | 413 | pub 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; |
| 1389 | 1389 | ||
| 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; |
| 1457 | 1457 | ||
| 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 { |
| 2755 | 2755 | ||
| 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)); |
| 2761 | 2761 | ||
| ... | @@ -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); |
| 2885 | 2885 | ||
| 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); |
| 3606 | 3606 | ||
| 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 | } |
| 3610 | 3610 | ||
| ... | @@ -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); |
| 5134 | 5134 | ||
| 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 | } |
| 10867 | 10867 | ||
| 10868 | fn firstParamSRet(fn_info: InternPool.Key.FuncType, mod: *Module) bool { | 10868 | fn 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; |
| 10871 | 10871 | ||
| 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 architectures | 10889 | 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 | } |
| 10897 | 10897 | ||
| 10898 | fn firstParamSRetSystemV(ty: Type, mod: *Module) bool { | 10898 | fn 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 { |
| 11098 | 11100 | ||
| 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 { |
| 11107 | 11109 | ||
| 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 | } |
| 11122 | 11124 | ||
| 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(); |
| 11126 | 11128 | ||
| 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) or | 11137 | 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 and | 11229 | }, |
| 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; |
| 11236 | 11236 | ||
| 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 | } |
| 11251 | 11251 | ||
| 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 | } |
| 11284 | 11284 | ||
| 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 | } |
| 271 | 271 | ||
| 272 | struct Struct_u32_Union_u32_u32u32 { | ||
| 273 | uint32_t a; | ||
| 274 | union { | ||
| 275 | struct { | ||
| 276 | uint32_t d, e; | ||
| 277 | } c; | ||
| 278 | } b; | ||
| 279 | }; | ||
| 280 | |||
| 281 | struct Struct_u32_Union_u32_u32u32 zig_ret_struct_u32_union_u32_u32u32(void); | ||
| 282 | |||
| 283 | void zig_struct_u32_union_u32_u32u32(struct Struct_u32_Union_u32_u32u32); | ||
| 284 | |||
| 285 | struct 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 | |||
| 293 | void 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 | |||
| 272 | struct BigStruct { | 299 | struct 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 | #endif | 2692 | #endif |
| 2666 | 2693 | ||
| 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 | #endif | 2716 | #endif |
| 2680 | 2717 | ||
| 2681 | #if !defined __i386__ && !defined __arm__ && !defined __aarch64__ && \ | 2718 | #if !defined __arm__ && !defined __aarch64__ && \ |
| 2682 | !defined __mips__ && !defined __powerpc__ && !defined ZIG_RISCV64 | 2719 | !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"); |
| 10 | const print = std.debug.print; | 10 | const print = std.debug.print; |
| 11 | const expect = std.testing.expect; | 11 | const expect = std.testing.expect; |
| 12 | const expectEqual = std.testing.expectEqual; | 12 | const expectEqual = std.testing.expectEqual; |
| 13 | const has_i128 = builtin.cpu.arch != .x86 and !builtin.cpu.arch.isARM() and | 13 | const 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(); |
| 15 | 15 | ||
| 16 | const has_f128 = builtin.cpu.arch.isX86() and !builtin.os.tag.isDarwin(); | 16 | const have_f128 = builtin.cpu.arch.isX86() and !builtin.os.tag.isDarwin(); |
| 17 | const has_f80 = builtin.cpu.arch.isX86(); | 17 | const have_f80 = builtin.cpu.arch.isX86(); |
| 18 | 18 | ||
| 19 | extern fn run_c_tests() void; | 19 | extern fn run_c_tests() void; |
| 20 | 20 | ||
| ... | @@ -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 }); |
| 57 | 57 | ||
| 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 | } |
| 65 | 65 | ||
| ... | @@ -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 |
| 186 | 186 | ||
| 187 | test "C ABI complex float" { | 187 | test "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 | ||
| 190 | 189 | ||
| 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 | } |
| 403 | 402 | ||
| 403 | const 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 | |||
| 413 | export 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 | |||
| 417 | export 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 | |||
| 423 | extern fn c_ret_struct_u32_union_u32_u32u32() Struct_u32_Union_u32_u32u32; | ||
| 424 | |||
| 425 | extern fn c_struct_u32_union_u32_u32u32(Struct_u32_Union_u32_u32u32) void; | ||
| 426 | |||
| 427 | test "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 | |||
| 404 | const BigStruct = extern struct { | 439 | const 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; |
| 470 | extern fn c_ret_med_struct_mixed() MedStructMixed; | 505 | extern fn c_ret_med_struct_mixed() MedStructMixed; |
| 471 | 506 | ||
| 472 | test "C ABI medium struct of ints and floats" { | 507 | test "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; |
| 538 | extern fn c_ret_med_struct_ints() MedStructInts; | 572 | extern fn c_ret_med_struct_ints() MedStructInts; |
| 539 | 573 | ||
| 540 | test "C ABI medium struct of ints" { | 574 | test "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 | } |
| 601 | 634 | ||
| 602 | test "C ABI big packed struct" { | 635 | test "C ABI big packed struct" { |
| 603 | if (!has_i128) return error.SkipZigTest; | 636 | if (!have_i128) return error.SkipZigTest; |
| 604 | 637 | ||
| 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; |
| 943 | extern fn c_ret_float_array_struct() FloatArrayStruct; | 976 | extern fn c_ret_float_array_struct() FloatArrayStruct; |
| 944 | 977 | ||
| 945 | test "Float array like struct" { | 978 | test "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; |
| 949 | 981 | ||
| ... | @@ -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; |
| 5318 | extern fn c_ret_ptr_size_float_struct() Vector2; | 5350 | extern fn c_ret_ptr_size_float_struct() Vector2; |
| 5319 | 5351 | ||
| 5320 | test "C ABI pointer sized float struct" { | 5352 | test "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 | } |
| 5350 | test "DC: Zig returns to C" { | 5381 | test "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 | } |
| 5365 | test "DC: C returns to Zig" { | 5395 | test "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 | } |
| 5399 | test "CFF: Zig returns to C" { | 5428 | test "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 | } |
| 5416 | test "CFF: C returns to Zig" { | 5444 | test "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 { |
| 5442 | const PD = extern struct { v1: ?*anyopaque, v2: f64 }; | 5469 | const PD = extern struct { v1: ?*anyopaque, v2: f64 }; |
| 5443 | 5470 | ||
| 5444 | test "PD: Zig passes to C" { | 5471 | test "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 | } |
| 5451 | test "PD: Zig returns to C" { | 5477 | test "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 | } |
| 5458 | test "PD: C passes to Zig" { | 5483 | test "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 | } |
| 5465 | test "PD: C returns to Zig" { | 5489 | test "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 { |
| 5519 | 5542 | ||
| 5520 | extern fn c_func_ptr_byval(*anyopaque, *anyopaque, ByVal, c_ulong, *anyopaque, c_ulong) void; | 5543 | extern fn c_func_ptr_byval(*anyopaque, *anyopaque, ByVal, c_ulong, *anyopaque, c_ulong) void; |
| 5521 | test "C function that takes byval struct called via function pointer" { | 5544 | test "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; |
| 5525 | 5547 | ||
| ... | @@ -5551,7 +5573,6 @@ const f16_struct = extern struct { | ... | @@ -5551,7 +5573,6 @@ const f16_struct = extern struct { |
| 5551 | }; | 5573 | }; |
| 5552 | extern fn c_f16_struct(f16_struct) f16_struct; | 5574 | extern fn c_f16_struct(f16_struct) f16_struct; |
| 5553 | test "f16 struct" { | 5575 | test "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" { |
| 5563 | 5584 | ||
| 5564 | extern fn c_f80(f80) f80; | 5585 | extern fn c_f80(f80) f80; |
| 5565 | test "f80 bare" { | 5586 | test "f80 bare" { |
| 5566 | if (!has_f80) return error.SkipZigTest; | 5587 | if (!have_f80) return error.SkipZigTest; |
| 5567 | 5588 | ||
| 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 | }; |
| 5575 | extern fn c_f80_struct(f80_struct) f80_struct; | 5596 | extern fn c_f80_struct(f80_struct) f80_struct; |
| 5576 | test "f80 struct" { | 5597 | test "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; | ||
| 5580 | 5599 | ||
| 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 | }; |
| 5589 | extern fn c_f80_extra_struct(f80_extra_struct) f80_extra_struct; | 5608 | extern fn c_f80_extra_struct(f80_extra_struct) f80_extra_struct; |
| 5590 | test "f80 extra struct" { | 5609 | test "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; | ||
| 5593 | 5611 | ||
| 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" { |
| 5598 | 5616 | ||
| 5599 | extern fn c_f128(f128) f128; | 5617 | extern fn c_f128(f128) f128; |
| 5600 | test "f128 bare" { | 5618 | test "f128 bare" { |
| 5601 | if (!has_f128) return error.SkipZigTest; | 5619 | if (!have_f128) return error.SkipZigTest; |
| 5602 | 5620 | ||
| 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 | }; |
| 5610 | extern fn c_f128_struct(f128_struct) f128_struct; | 5628 | extern fn c_f128_struct(f128_struct) f128_struct; |
| 5611 | test "f128 struct" { | 5629 | test "f128 struct" { |
| 5612 | if (!has_f128) return error.SkipZigTest; | 5630 | if (!have_f128) return error.SkipZigTest; |
| 5613 | 5631 | ||
| 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); |