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
7272 }
7373
7474 // Now we detect the model.
75 switch (vendor) {
76 0x756e6547 => {
77 detectIntelProcessor(&cpu, family, model, brand_id);
78 },
79 0x68747541 => {
80 if (detectAMDProcessor(cpu, family, model)) |m| cpu.model = m;
81 },
82 else => {},
75 if (switch (vendor) {
76 0x756e6547 => detectIntelProcessor(&cpu, family, model, brand_id),
77 0x68747541 => detectAmdProcessor(&cpu, family, model),
78 else => null,
79 }) |m| b: {
80 // Some hypervisors are evil liars and will operate in long mode while identifying as a
81 // CPU model that never had long mode in reality. We've seen this in practice with
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;
8387 }
8488 }
8589
......@@ -93,239 +97,85 @@ pub fn detectNativeCpuAndFeatures(arch: Target.Cpu.Arch, os: Target.Os, query: T
9397 return cpu;
9498}
9599
96fn detectIntelProcessor(cpu: *Target.Cpu, family: u32, model: u32, brand_id: u32) void {
97 if (brand_id != 0) {
98 return;
99 }
100 switch (family) {
101 3 => {
102 cpu.model = &Target.x86.cpu.i386;
103 return;
104 },
105 4 => {
106 cpu.model = &Target.x86.cpu.i486;
107 return;
108 },
109 5 => {
110 if (cpu.has(.x86, .mmx)) {
111 cpu.model = &Target.x86.cpu.pentium_mmx;
112 return;
113 }
114 cpu.model = &Target.x86.cpu.pentium;
115 return;
116 },
117 6 => {
118 switch (model) {
119 0x01 => {
120 cpu.model = &Target.x86.cpu.pentiumpro;
121 return;
122 },
123 0x03, 0x05, 0x06 => {
124 cpu.model = &Target.x86.cpu.pentium2;
125 return;
126 },
127 0x07, 0x08, 0x0a, 0x0b => {
128 cpu.model = &Target.x86.cpu.pentium3;
129 return;
130 },
131 0x09, 0x0d, 0x15 => {
132 cpu.model = &Target.x86.cpu.pentium_m;
133 return;
134 },
135 0x0e => {
136 cpu.model = &Target.x86.cpu.yonah;
137 return;
138 },
139 0x0f, 0x16 => {
140 cpu.model = &Target.x86.cpu.core2;
141 return;
142 },
143 0x17, 0x1d => {
144 cpu.model = &Target.x86.cpu.penryn;
145 return;
146 },
147 0x1a, 0x1e, 0x1f, 0x2e => {
148 cpu.model = &Target.x86.cpu.nehalem;
149 return;
150 },
151 0x25, 0x2c, 0x2f => {
152 cpu.model = &Target.x86.cpu.westmere;
153 return;
154 },
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;
100fn detectIntelProcessor(cpu: *const Target.Cpu, family: u32, model: u32, brand_id: u32) ?*const Target.Cpu.Model {
101 if (brand_id != 0) return null;
102
103 return switch (family) {
104 3 => &Target.x86.cpu.i386,
105 4 => &Target.x86.cpu.i486,
106 5 => if (cpu.has(.x86, .mmx))
107 &Target.x86.cpu.pentium_mmx
108 else
109 &Target.x86.cpu.pentium,
110 6 => switch (model) {
111 0x01 => &Target.x86.cpu.pentiumpro,
112 0x03, 0x05, 0x06 => &Target.x86.cpu.pentium2,
113 0x07, 0x08, 0x0a, 0x0b => &Target.x86.cpu.pentium3,
114 0x09, 0x0d, 0x15 => &Target.x86.cpu.pentium_m,
115 0x0e => &Target.x86.cpu.yonah,
116 0x0f, 0x16 => &Target.x86.cpu.core2,
117 0x17, 0x1d => &Target.x86.cpu.penryn,
118 0x1a, 0x1e, 0x1f, 0x2e => &Target.x86.cpu.nehalem,
119 0x25, 0x2c, 0x2f => &Target.x86.cpu.westmere,
120 0x2a, 0x2d => &Target.x86.cpu.sandybridge,
121 0x3a, 0x3e => &Target.x86.cpu.ivybridge,
122 0x3c, 0x3f, 0x45, 0x46 => &Target.x86.cpu.haswell,
123 0x3d, 0x47, 0x4f, 0x56 => &Target.x86.cpu.broadwell,
124 0x4e, 0x5e, 0x8e, 0x9e, 0xa5, 0xa6 => &Target.x86.cpu.skylake,
125 0xa7 => &Target.x86.cpu.rocketlake,
126 0x55 => if (cpu.has(.x86, .avx512bf16))
127 &Target.x86.cpu.cooperlake
128 else if (cpu.has(.x86, .avx512vnni))
129 &Target.x86.cpu.cascadelake
130 else
131 &Target.x86.cpu.skylake_avx512,
132 0x66 => &Target.x86.cpu.cannonlake,
133 0x7d, 0x7e => &Target.x86.cpu.icelake_client,
134 0x6a, 0x6c => &Target.x86.cpu.icelake_server,
135 0x8c, 0x8d => &Target.x86.cpu.tigerlake,
136 0x97, 0x9a => &Target.x86.cpu.alderlake,
137 0xbe => &Target.x86.cpu.gracemont,
138 0xb7, 0xba, 0xbf => &Target.x86.cpu.raptorlake,
139 0xaa, 0xac => &Target.x86.cpu.meteorlake,
140 0xc5, 0xb5 => &Target.x86.cpu.arrowlake,
141 0xc6 => &Target.x86.cpu.arrowlake_s,
142 0xbd => &Target.x86.cpu.lunarlake,
143 0xcc, 0xd5 => &Target.x86.cpu.pantherlake,
144 0xad => &Target.x86.cpu.graniterapids,
145 0xae => &Target.x86.cpu.graniterapids_d,
146 0xcf => &Target.x86.cpu.emeraldrapids,
147 0x8f => &Target.x86.cpu.sapphirerapids,
148 0x1c, 0x26, 0x27, 0x35, 0x36 => &Target.x86.cpu.bonnell,
149 0x37, 0x4a, 0x4d, 0x5a, 0x5d, 0x4c => &Target.x86.cpu.silvermont,
150 0x5c, 0x5f => &Target.x86.cpu.goldmont,
151 0x7a => &Target.x86.cpu.goldmont_plus,
152 0x86, 0x8a, 0x96, 0x9c => &Target.x86.cpu.tremont,
153 0xaf => &Target.x86.cpu.sierraforest,
154 0xb6 => &Target.x86.cpu.grandridge,
155 0xdd => &Target.x86.cpu.clearwaterforest,
156 0x57 => &Target.x86.cpu.knl,
157 0x85 => &Target.x86.cpu.knm,
158 else => null,
309159 },
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,
310166 18 => switch (model) {
311 0x01, 0x03 => {
312 cpu.model = &Target.x86.cpu.novalake;
313 return;
314 },
315 else => return, // Unknown CPU Model
167 0x01, 0x03 => &Target.x86.cpu.novalake,
168 else => null,
316169 },
317170 19 => switch (model) {
318 0x01 => {
319 cpu.model = &Target.x86.cpu.diamondrapids;
320 return;
321 },
322 else => return, // Unknown CPU Model
171 0x01 => &Target.x86.cpu.diamondrapids,
172 else => null,
323173 },
324 else => return, // Unknown CPU Model
325 }
174 else => null,
175 };
326176}
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 {
329179 return switch (family) {
330180 4 => &Target.x86.cpu.i486,
331181 5 => switch (model) {