authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-08-16 12:14:17+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-08-16 12:14:17+02:00
log99e540dc39ba45365eaa82db0459a0d7acc251eb
treecac5f0b91dbfa90cee9d1b9587d5d89292f84a0d
parent77bb7adc5cd5fa24cd515684418c20ed9270c2ad
parent5ee0c6422399b5219dbc06a3d7bb9f59f20cf7ef

Merge pull request '`std.zig.system.x86`: deal with lying hypervisors' (#36527) from alexrp/zig:x86-cpu-detect-nonsense into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36527

1 files changed, 84 insertions(+), 234 deletions(-)

lib/std/zig/system/x86.zig+84-234
...@@ -72,14 +72,18 @@ pub fn detectNativeCpuAndFeatures(arch: Target.Cpu.Arch, os: Target.Os, query: T...@@ -72,14 +72,18 @@ pub fn detectNativeCpuAndFeatures(arch: Target.Cpu.Arch, os: Target.Os, query: T
72 }72 }
7373
74 // Now we detect the model.74 // Now we detect the model.
75 switch (vendor) {75 if (switch (vendor) {
76 0x756e6547 => {76 0x756e6547 => detectIntelProcessor(&cpu, family, model, brand_id),
77 detectIntelProcessor(&cpu, family, model, brand_id);77 0x68747541 => detectAmdProcessor(&cpu, family, model),
78 },78 else => null,
79 0x68747541 => {79 }) |m| b: {
80 if (detectAMDProcessor(cpu, family, model)) |m| cpu.model = m;80 // Some hypervisors are evil liars and will operate in long mode while identifying as a
81 },81 // CPU model that never had long mode in reality. We've seen this in practice with
82 else => {},82 // athlon_xp (AMD K7). Catch this contradiction and fall back to using a generic CPU
83 // model with the features we detected earlier.
84 if (cpu.has(.x86, .@"64bit") and !Target.x86.featureSetHas(m.features, .@"64bit")) break :b;
85
86 cpu.model = m;
83 }87 }
84 }88 }
8589
...@@ -93,239 +97,85 @@ pub fn detectNativeCpuAndFeatures(arch: Target.Cpu.Arch, os: Target.Os, query: T...@@ -93,239 +97,85 @@ pub fn detectNativeCpuAndFeatures(arch: Target.Cpu.Arch, os: Target.Os, query: T
93 return cpu;97 return cpu;
94}98}
9599
96fn detectIntelProcessor(cpu: *Target.Cpu, family: u32, model: u32, brand_id: u32) void {100fn detectIntelProcessor(cpu: *const Target.Cpu, family: u32, model: u32, brand_id: u32) ?*const Target.Cpu.Model {
97 if (brand_id != 0) {101 if (brand_id != 0) return null;
98 return;102
99 }103 return switch (family) {
100 switch (family) {104 3 => &Target.x86.cpu.i386,
101 3 => {105 4 => &Target.x86.cpu.i486,
102 cpu.model = &Target.x86.cpu.i386;106 5 => if (cpu.has(.x86, .mmx))
103 return;107 &Target.x86.cpu.pentium_mmx
104 },108 else
105 4 => {109 &Target.x86.cpu.pentium,
106 cpu.model = &Target.x86.cpu.i486;110 6 => switch (model) {
107 return;111 0x01 => &Target.x86.cpu.pentiumpro,
108 },112 0x03, 0x05, 0x06 => &Target.x86.cpu.pentium2,
109 5 => {113 0x07, 0x08, 0x0a, 0x0b => &Target.x86.cpu.pentium3,
110 if (cpu.has(.x86, .mmx)) {114 0x09, 0x0d, 0x15 => &Target.x86.cpu.pentium_m,
111 cpu.model = &Target.x86.cpu.pentium_mmx;115 0x0e => &Target.x86.cpu.yonah,
112 return;116 0x0f, 0x16 => &Target.x86.cpu.core2,
113 }117 0x17, 0x1d => &Target.x86.cpu.penryn,
114 cpu.model = &Target.x86.cpu.pentium;118 0x1a, 0x1e, 0x1f, 0x2e => &Target.x86.cpu.nehalem,
115 return;119 0x25, 0x2c, 0x2f => &Target.x86.cpu.westmere,
116 },120 0x2a, 0x2d => &Target.x86.cpu.sandybridge,
117 6 => {121 0x3a, 0x3e => &Target.x86.cpu.ivybridge,
118 switch (model) {122 0x3c, 0x3f, 0x45, 0x46 => &Target.x86.cpu.haswell,
119 0x01 => {123 0x3d, 0x47, 0x4f, 0x56 => &Target.x86.cpu.broadwell,
120 cpu.model = &Target.x86.cpu.pentiumpro;124 0x4e, 0x5e, 0x8e, 0x9e, 0xa5, 0xa6 => &Target.x86.cpu.skylake,
121 return;125 0xa7 => &Target.x86.cpu.rocketlake,
122 },126 0x55 => if (cpu.has(.x86, .avx512bf16))
123 0x03, 0x05, 0x06 => {127 &Target.x86.cpu.cooperlake
124 cpu.model = &Target.x86.cpu.pentium2;128 else if (cpu.has(.x86, .avx512vnni))
125 return;129 &Target.x86.cpu.cascadelake
126 },130 else
127 0x07, 0x08, 0x0a, 0x0b => {131 &Target.x86.cpu.skylake_avx512,
128 cpu.model = &Target.x86.cpu.pentium3;132 0x66 => &Target.x86.cpu.cannonlake,
129 return;133 0x7d, 0x7e => &Target.x86.cpu.icelake_client,
130 },134 0x6a, 0x6c => &Target.x86.cpu.icelake_server,
131 0x09, 0x0d, 0x15 => {135 0x8c, 0x8d => &Target.x86.cpu.tigerlake,
132 cpu.model = &Target.x86.cpu.pentium_m;136 0x97, 0x9a => &Target.x86.cpu.alderlake,
133 return;137 0xbe => &Target.x86.cpu.gracemont,
134 },138 0xb7, 0xba, 0xbf => &Target.x86.cpu.raptorlake,
135 0x0e => {139 0xaa, 0xac => &Target.x86.cpu.meteorlake,
136 cpu.model = &Target.x86.cpu.yonah;140 0xc5, 0xb5 => &Target.x86.cpu.arrowlake,
137 return;141 0xc6 => &Target.x86.cpu.arrowlake_s,
138 },142 0xbd => &Target.x86.cpu.lunarlake,
139 0x0f, 0x16 => {143 0xcc, 0xd5 => &Target.x86.cpu.pantherlake,
140 cpu.model = &Target.x86.cpu.core2;144 0xad => &Target.x86.cpu.graniterapids,
141 return;145 0xae => &Target.x86.cpu.graniterapids_d,
142 },146 0xcf => &Target.x86.cpu.emeraldrapids,
143 0x17, 0x1d => {147 0x8f => &Target.x86.cpu.sapphirerapids,
144 cpu.model = &Target.x86.cpu.penryn;148 0x1c, 0x26, 0x27, 0x35, 0x36 => &Target.x86.cpu.bonnell,
145 return;149 0x37, 0x4a, 0x4d, 0x5a, 0x5d, 0x4c => &Target.x86.cpu.silvermont,
146 },150 0x5c, 0x5f => &Target.x86.cpu.goldmont,
147 0x1a, 0x1e, 0x1f, 0x2e => {151 0x7a => &Target.x86.cpu.goldmont_plus,
148 cpu.model = &Target.x86.cpu.nehalem;152 0x86, 0x8a, 0x96, 0x9c => &Target.x86.cpu.tremont,
149 return;153 0xaf => &Target.x86.cpu.sierraforest,
150 },154 0xb6 => &Target.x86.cpu.grandridge,
151 0x25, 0x2c, 0x2f => {155 0xdd => &Target.x86.cpu.clearwaterforest,
152 cpu.model = &Target.x86.cpu.westmere;156 0x57 => &Target.x86.cpu.knl,
153 return;157 0x85 => &Target.x86.cpu.knm,
154 },158 else => null,
155 0x2a, 0x2d => {
156 cpu.model = &Target.x86.cpu.sandybridge;
157 return;
158 },
159 0x3a, 0x3e => {
160 cpu.model = &Target.x86.cpu.ivybridge;
161 return;
162 },
163 0x3c, 0x3f, 0x45, 0x46 => {
164 cpu.model = &Target.x86.cpu.haswell;
165 return;
166 },
167 0x3d, 0x47, 0x4f, 0x56 => {
168 cpu.model = &Target.x86.cpu.broadwell;
169 return;
170 },
171 0x4e, 0x5e, 0x8e, 0x9e, 0xa5, 0xa6 => {
172 cpu.model = &Target.x86.cpu.skylake;
173 return;
174 },
175 0xa7 => {
176 cpu.model = &Target.x86.cpu.rocketlake;
177 return;
178 },
179 0x55 => {
180 if (cpu.has(.x86, .avx512bf16)) {
181 cpu.model = &Target.x86.cpu.cooperlake;
182 return;
183 } else if (cpu.has(.x86, .avx512vnni)) {
184 cpu.model = &Target.x86.cpu.cascadelake;
185 return;
186 } else {
187 cpu.model = &Target.x86.cpu.skylake_avx512;
188 return;
189 }
190 },
191 0x66 => {
192 cpu.model = &Target.x86.cpu.cannonlake;
193 return;
194 },
195 0x7d, 0x7e => {
196 cpu.model = &Target.x86.cpu.icelake_client;
197 return;
198 },
199 0x6a, 0x6c => {
200 cpu.model = &Target.x86.cpu.icelake_server;
201 return;
202 },
203 0x8c, 0x8d => {
204 cpu.model = &Target.x86.cpu.tigerlake;
205 return;
206 },
207 0x97, 0x9a => {
208 cpu.model = &Target.x86.cpu.alderlake;
209 return;
210 },
211 0xbe => {
212 cpu.model = &Target.x86.cpu.gracemont;
213 return;
214 },
215 0xb7, 0xba, 0xbf => {
216 cpu.model = &Target.x86.cpu.raptorlake;
217 return;
218 },
219 0xaa, 0xac => {
220 cpu.model = &Target.x86.cpu.meteorlake;
221 return;
222 },
223 0xc5, 0xb5 => {
224 cpu.model = &Target.x86.cpu.arrowlake;
225 return;
226 },
227 0xc6 => {
228 cpu.model = &Target.x86.cpu.arrowlake_s;
229 return;
230 },
231 0xbd => {
232 cpu.model = &Target.x86.cpu.lunarlake;
233 return;
234 },
235 0xcc, 0xd5 => {
236 cpu.model = &Target.x86.cpu.pantherlake;
237 return;
238 },
239 0xad => {
240 cpu.model = &Target.x86.cpu.graniterapids;
241 return;
242 },
243 0xae => {
244 cpu.model = &Target.x86.cpu.graniterapids_d;
245 return;
246 },
247 0xcf => {
248 cpu.model = &Target.x86.cpu.emeraldrapids;
249 return;
250 },
251 0x8f => {
252 cpu.model = &Target.x86.cpu.sapphirerapids;
253 return;
254 },
255 0x1c, 0x26, 0x27, 0x35, 0x36 => {
256 cpu.model = &Target.x86.cpu.bonnell;
257 return;
258 },
259 0x37, 0x4a, 0x4d, 0x5a, 0x5d, 0x4c => {
260 cpu.model = &Target.x86.cpu.silvermont;
261 return;
262 },
263 0x5c, 0x5f => {
264 cpu.model = &Target.x86.cpu.goldmont;
265 return;
266 },
267 0x7a => {
268 cpu.model = &Target.x86.cpu.goldmont_plus;
269 return;
270 },
271 0x86, 0x8a, 0x96, 0x9c => {
272 cpu.model = &Target.x86.cpu.tremont;
273 return;
274 },
275 0xaf => {
276 cpu.model = &Target.x86.cpu.sierraforest;
277 return;
278 },
279 0xb6 => {
280 cpu.model = &Target.x86.cpu.grandridge;
281 return;
282 },
283 0xdd => {
284 cpu.model = &Target.x86.cpu.clearwaterforest;
285 return;
286 },
287 0x57 => {
288 cpu.model = &Target.x86.cpu.knl;
289 return;
290 },
291 0x85 => {
292 cpu.model = &Target.x86.cpu.knm;
293 return;
294 },
295 else => return, // Unknown CPU Model
296 }
297 },
298 15 => {
299 if (cpu.has(.x86, .@"64bit")) {
300 cpu.model = &Target.x86.cpu.nocona;
301 return;
302 }
303 if (cpu.has(.x86, .sse3)) {
304 cpu.model = &Target.x86.cpu.prescott;
305 return;
306 }
307 cpu.model = &Target.x86.cpu.pentium4;
308 return;
309 },159 },
160 15 => if (cpu.has(.x86, .@"64bit"))
161 &Target.x86.cpu.nocona
162 else if (cpu.has(.x86, .sse3))
163 &Target.x86.cpu.prescott
164 else
165 &Target.x86.cpu.pentium4,
310 18 => switch (model) {166 18 => switch (model) {
311 0x01, 0x03 => {167 0x01, 0x03 => &Target.x86.cpu.novalake,
312 cpu.model = &Target.x86.cpu.novalake;168 else => null,
313 return;
314 },
315 else => return, // Unknown CPU Model
316 },169 },
317 19 => switch (model) {170 19 => switch (model) {
318 0x01 => {171 0x01 => &Target.x86.cpu.diamondrapids,
319 cpu.model = &Target.x86.cpu.diamondrapids;172 else => null,
320 return;
321 },
322 else => return, // Unknown CPU Model
323 },173 },
324 else => return, // Unknown CPU Model174 else => null,
325 }175 };
326}176}
327177
328fn detectAMDProcessor(cpu: Target.Cpu, family: u32, model: u32) ?*const Target.Cpu.Model {178fn detectAmdProcessor(cpu: *const Target.Cpu, family: u32, model: u32) ?*const Target.Cpu.Model {
329 return switch (family) {179 return switch (family) {
330 4 => &Target.x86.cpu.i486,180 4 => &Target.x86.cpu.i486,
331 5 => switch (model) {181 5 => switch (model) {