| ... | @@ -2,11 +2,30 @@ const std = @import("std"); | ... | @@ -2,11 +2,30 @@ const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const Target = std.Target; | 3 | const Target = std.Target; |
| 4 | | 4 | |
| 5 | const XCR0_XMM = 0x02; | 5 | /// Only covers EAX for now. |
| 6 | const XCR0_YMM = 0x04; | 6 | const Xcr0 = packed struct(u32) { |
| 7 | const XCR0_MASKREG = 0x20; | 7 | x87: bool, |
| 8 | const XCR0_ZMM0_15 = 0x40; | 8 | sse: bool, |
| 9 | const XCR0_ZMM16_31 = 0x80; | 9 | avx: bool, |
| | 10 | bndreg: bool, |
| | 11 | bndcsr: bool, |
| | 12 | opmask: bool, |
| | 13 | zmm_hi256: bool, |
| | 14 | hi16_zmm: bool, |
| | 15 | pt: bool, |
| | 16 | pkru: bool, |
| | 17 | pasid: bool, |
| | 18 | cet_u: bool, |
| | 19 | cet_s: bool, |
| | 20 | hdc: bool, |
| | 21 | uintr: bool, |
| | 22 | lbr: bool, |
| | 23 | hwp: bool, |
| | 24 | xtilecfg: bool, |
| | 25 | xtiledata: bool, |
| | 26 | apx: bool, |
| | 27 | _reserved: u12, |
| | 28 | }; |
| 10 | | 29 | |
| 11 | fn setFeature(cpu: *Target.Cpu, feature: Target.x86.Feature, enabled: bool) void { | 30 | fn setFeature(cpu: *Target.Cpu, feature: Target.x86.Feature, enabled: bool) void { |
| 12 | const idx = @as(Target.Cpu.Feature.Set.Index, @intFromEnum(feature)); | 31 | const idx = @as(Target.Cpu.Feature.Set.Index, @intFromEnum(feature)); |
| ... | @@ -339,12 +358,6 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { | ... | @@ -339,12 +358,6 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { |
| 339 | | 358 | |
| 340 | leaf = cpuid(1, 0); | 359 | leaf = cpuid(1, 0); |
| 341 | | 360 | |
| 342 | setFeature(cpu, .cx8, bit(leaf.edx, 8)); | | |
| 343 | setFeature(cpu, .cmov, bit(leaf.edx, 15)); | | |
| 344 | setFeature(cpu, .mmx, bit(leaf.edx, 23)); | | |
| 345 | setFeature(cpu, .fxsr, bit(leaf.edx, 24)); | | |
| 346 | setFeature(cpu, .sse, bit(leaf.edx, 25)); | | |
| 347 | setFeature(cpu, .sse2, bit(leaf.edx, 26)); | | |
| 348 | setFeature(cpu, .sse3, bit(leaf.ecx, 0)); | 361 | setFeature(cpu, .sse3, bit(leaf.ecx, 0)); |
| 349 | setFeature(cpu, .pclmul, bit(leaf.ecx, 1)); | 362 | setFeature(cpu, .pclmul, bit(leaf.ecx, 1)); |
| 350 | setFeature(cpu, .ssse3, bit(leaf.ecx, 9)); | 363 | setFeature(cpu, .ssse3, bit(leaf.ecx, 9)); |
| ... | @@ -356,13 +369,20 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { | ... | @@ -356,13 +369,20 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { |
| 356 | setFeature(cpu, .aes, bit(leaf.ecx, 25)); | 369 | setFeature(cpu, .aes, bit(leaf.ecx, 25)); |
| 357 | setFeature(cpu, .rdrnd, bit(leaf.ecx, 30)); | 370 | setFeature(cpu, .rdrnd, bit(leaf.ecx, 30)); |
| 358 | | 371 | |
| | 372 | setFeature(cpu, .cx8, bit(leaf.edx, 8)); |
| | 373 | setFeature(cpu, .cmov, bit(leaf.edx, 15)); |
| | 374 | setFeature(cpu, .mmx, bit(leaf.edx, 23)); |
| | 375 | setFeature(cpu, .fxsr, bit(leaf.edx, 24)); |
| | 376 | setFeature(cpu, .sse, bit(leaf.edx, 25)); |
| | 377 | setFeature(cpu, .sse2, bit(leaf.edx, 26)); |
| | 378 | |
| 359 | const has_xsave = bit(leaf.ecx, 27); | 379 | const has_xsave = bit(leaf.ecx, 27); |
| 360 | const has_avx = bit(leaf.ecx, 28); | 380 | const has_avx = bit(leaf.ecx, 28); |
| 361 | | 381 | |
| 362 | // Make sure not to call xgetbv if xsave is not supported | 382 | // Make sure not to call xgetbv if xsave is not supported |
| 363 | const xcr0_eax = if (has_xsave and has_avx) getXCR0() else 0; | 383 | const xcr0: Xcr0 = if (has_xsave and has_avx) @bitCast(getXCR0()) else @bitCast(@as(u32, 0)); |
| 364 | | 384 | |
| 365 | const has_avx_save = hasMask(xcr0_eax, XCR0_XMM | XCR0_YMM); | 385 | const has_avx_save = xcr0.sse and xcr0.avx; |
| 366 | | 386 | |
| 367 | // LLVM approaches avx512_save by hardcoding it to true on Darwin, | 387 | // LLVM approaches avx512_save by hardcoding it to true on Darwin, |
| 368 | // because the kernel saves the context even if the bit is not set. | 388 | // because the kernel saves the context even if the bit is not set. |
| ... | @@ -384,22 +404,26 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { | ... | @@ -384,22 +404,26 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { |
| 384 | // Darwin lazily saves the AVX512 context on first use: trust that the OS will | 404 | // Darwin lazily saves the AVX512 context on first use: trust that the OS will |
| 385 | // save the AVX512 context if we use AVX512 instructions, even if the bit is not | 405 | // save the AVX512 context if we use AVX512 instructions, even if the bit is not |
| 386 | // set right now. | 406 | // set right now. |
| 387 | const has_avx512_save = switch (os_tag.isDarwin()) { | 407 | const has_avx512_save = if (os_tag.isDarwin()) |
| 388 | true => true, | 408 | true |
| 389 | false => hasMask(xcr0_eax, XCR0_MASKREG | XCR0_ZMM0_15 | XCR0_ZMM16_31), | 409 | else |
| 390 | }; | 410 | xcr0.zmm_hi256 and xcr0.hi16_zmm; |
| | 411 | |
| | 412 | // AMX requires additional context to be saved by the OS. |
| | 413 | const has_amx_save = xcr0.xtilecfg and xcr0.xtiledata; |
| 391 | | 414 | |
| 392 | setFeature(cpu, .avx, has_avx_save); | 415 | setFeature(cpu, .avx, has_avx_save); |
| 393 | setFeature(cpu, .fma, has_avx_save and bit(leaf.ecx, 12)); | 416 | setFeature(cpu, .fma, bit(leaf.ecx, 12) and has_avx_save); |
| 394 | // Only enable XSAVE if OS has enabled support for saving YMM state. | 417 | // Only enable XSAVE if OS has enabled support for saving YMM state. |
| 395 | setFeature(cpu, .xsave, has_avx_save and bit(leaf.ecx, 26)); | 418 | setFeature(cpu, .xsave, bit(leaf.ecx, 26) and has_avx_save); |
| 396 | setFeature(cpu, .f16c, has_avx_save and bit(leaf.ecx, 29)); | 419 | setFeature(cpu, .f16c, bit(leaf.ecx, 29) and has_avx_save); |
| 397 | | 420 | |
| 398 | leaf = cpuid(0x80000000, 0); | 421 | leaf = cpuid(0x80000000, 0); |
| 399 | const max_ext_level = leaf.eax; | 422 | const max_ext_level = leaf.eax; |
| 400 | | 423 | |
| 401 | if (max_ext_level >= 0x80000001) { | 424 | if (max_ext_level >= 0x80000001) { |
| 402 | leaf = cpuid(0x80000001, 0); | 425 | leaf = cpuid(0x80000001, 0); |
| | 426 | |
| 403 | setFeature(cpu, .sahf, bit(leaf.ecx, 0)); | 427 | setFeature(cpu, .sahf, bit(leaf.ecx, 0)); |
| 404 | setFeature(cpu, .lzcnt, bit(leaf.ecx, 5)); | 428 | setFeature(cpu, .lzcnt, bit(leaf.ecx, 5)); |
| 405 | setFeature(cpu, .sse4a, bit(leaf.ecx, 6)); | 429 | setFeature(cpu, .sse4a, bit(leaf.ecx, 6)); |
| ... | @@ -409,11 +433,21 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { | ... | @@ -409,11 +433,21 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { |
| 409 | setFeature(cpu, .fma4, bit(leaf.ecx, 16) and has_avx_save); | 433 | setFeature(cpu, .fma4, bit(leaf.ecx, 16) and has_avx_save); |
| 410 | setFeature(cpu, .tbm, bit(leaf.ecx, 21)); | 434 | setFeature(cpu, .tbm, bit(leaf.ecx, 21)); |
| 411 | setFeature(cpu, .mwaitx, bit(leaf.ecx, 29)); | 435 | setFeature(cpu, .mwaitx, bit(leaf.ecx, 29)); |
| | 436 | |
| 412 | setFeature(cpu, .@"64bit", bit(leaf.edx, 29)); | 437 | setFeature(cpu, .@"64bit", bit(leaf.edx, 29)); |
| 413 | } else { | 438 | } else { |
| 414 | for ([_]Target.x86.Feature{ | 439 | for ([_]Target.x86.Feature{ |
| 415 | .sahf, .lzcnt, .sse4a, .prfchw, .xop, | 440 | .sahf, |
| 416 | .lwp, .fma4, .tbm, .mwaitx, .@"64bit", | 441 | .lzcnt, |
| | 442 | .sse4a, |
| | 443 | .prfchw, |
| | 444 | .xop, |
| | 445 | .lwp, |
| | 446 | .fma4, |
| | 447 | .tbm, |
| | 448 | .mwaitx, |
| | 449 | |
| | 450 | .@"64bit", |
| 417 | }) |feat| { | 451 | }) |feat| { |
| 418 | setFeature(cpu, feat, false); | 452 | setFeature(cpu, feat, false); |
| 419 | } | 453 | } |
| ... | @@ -422,10 +456,16 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { | ... | @@ -422,10 +456,16 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { |
| 422 | // Misc. memory-related features. | 456 | // Misc. memory-related features. |
| 423 | if (max_ext_level >= 0x80000008) { | 457 | if (max_ext_level >= 0x80000008) { |
| 424 | leaf = cpuid(0x80000008, 0); | 458 | leaf = cpuid(0x80000008, 0); |
| | 459 | |
| 425 | setFeature(cpu, .clzero, bit(leaf.ebx, 0)); | 460 | setFeature(cpu, .clzero, bit(leaf.ebx, 0)); |
| | 461 | setFeature(cpu, .rdpru, bit(leaf.ebx, 4)); |
| 426 | setFeature(cpu, .wbnoinvd, bit(leaf.ebx, 9)); | 462 | setFeature(cpu, .wbnoinvd, bit(leaf.ebx, 9)); |
| 427 | } else { | 463 | } else { |
| 428 | for ([_]Target.x86.Feature{ .clzero, .wbnoinvd }) |feat| { | 464 | for ([_]Target.x86.Feature{ |
| | 465 | .clzero, |
| | 466 | .rdpru, |
| | 467 | .wbnoinvd, |
| | 468 | }) |feat| { |
| 429 | setFeature(cpu, feat, false); | 469 | setFeature(cpu, feat, false); |
| 430 | } | 470 | } |
| 431 | } | 471 | } |
| ... | @@ -444,6 +484,7 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { | ... | @@ -444,6 +484,7 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { |
| 444 | setFeature(cpu, .rtm, bit(leaf.ebx, 11)); | 484 | setFeature(cpu, .rtm, bit(leaf.ebx, 11)); |
| 445 | // AVX512 is only supported if the OS supports the context save for it. | 485 | // AVX512 is only supported if the OS supports the context save for it. |
| 446 | setFeature(cpu, .avx512f, bit(leaf.ebx, 16) and has_avx512_save); | 486 | setFeature(cpu, .avx512f, bit(leaf.ebx, 16) and has_avx512_save); |
| | 487 | setFeature(cpu, .evex512, bit(leaf.ebx, 16) and has_avx512_save); |
| 447 | setFeature(cpu, .avx512dq, bit(leaf.ebx, 17) and has_avx512_save); | 488 | setFeature(cpu, .avx512dq, bit(leaf.ebx, 17) and has_avx512_save); |
| 448 | setFeature(cpu, .rdseed, bit(leaf.ebx, 18)); | 489 | setFeature(cpu, .rdseed, bit(leaf.ebx, 18)); |
| 449 | setFeature(cpu, .adx, bit(leaf.ebx, 19)); | 490 | setFeature(cpu, .adx, bit(leaf.ebx, 19)); |
| ... | @@ -470,8 +511,8 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { | ... | @@ -470,8 +511,8 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { |
| 470 | setFeature(cpu, .avx512vnni, bit(leaf.ecx, 11) and has_avx512_save); | 511 | setFeature(cpu, .avx512vnni, bit(leaf.ecx, 11) and has_avx512_save); |
| 471 | setFeature(cpu, .avx512bitalg, bit(leaf.ecx, 12) and has_avx512_save); | 512 | setFeature(cpu, .avx512bitalg, bit(leaf.ecx, 12) and has_avx512_save); |
| 472 | setFeature(cpu, .avx512vpopcntdq, bit(leaf.ecx, 14) and has_avx512_save); | 513 | setFeature(cpu, .avx512vpopcntdq, bit(leaf.ecx, 14) and has_avx512_save); |
| 473 | setFeature(cpu, .avx512vp2intersect, bit(leaf.edx, 8) and has_avx512_save); | | |
| 474 | setFeature(cpu, .rdpid, bit(leaf.ecx, 22)); | 514 | setFeature(cpu, .rdpid, bit(leaf.ecx, 22)); |
| | 515 | setFeature(cpu, .kl, bit(leaf.ecx, 23)); |
| 475 | setFeature(cpu, .cldemote, bit(leaf.ecx, 25)); | 516 | setFeature(cpu, .cldemote, bit(leaf.ecx, 25)); |
| 476 | setFeature(cpu, .movdiri, bit(leaf.ecx, 27)); | 517 | setFeature(cpu, .movdiri, bit(leaf.ecx, 27)); |
| 477 | setFeature(cpu, .movdir64b, bit(leaf.ecx, 28)); | 518 | setFeature(cpu, .movdir64b, bit(leaf.ecx, 28)); |
| ... | @@ -487,32 +528,153 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { | ... | @@ -487,32 +528,153 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { |
| 487 | // leaves using cpuid, since that information is ignored while | 528 | // leaves using cpuid, since that information is ignored while |
| 488 | // detecting features using the "-march=native" flag. | 529 | // detecting features using the "-march=native" flag. |
| 489 | // For more info, see X86 ISA docs. | 530 | // For more info, see X86 ISA docs. |
| 490 | setFeature(cpu, .pconfig, bit(leaf.edx, 18)); | | |
| 491 | setFeature(cpu, .uintr, bit(leaf.edx, 5)); | 531 | setFeature(cpu, .uintr, bit(leaf.edx, 5)); |
| | 532 | setFeature(cpu, .avx512vp2intersect, bit(leaf.edx, 8) and has_avx512_save); |
| | 533 | setFeature(cpu, .serialize, bit(leaf.edx, 14)); |
| | 534 | setFeature(cpu, .tsxldtrk, bit(leaf.edx, 16)); |
| | 535 | setFeature(cpu, .pconfig, bit(leaf.edx, 18)); |
| | 536 | setFeature(cpu, .amx_bf16, bit(leaf.edx, 22) and has_amx_save); |
| | 537 | setFeature(cpu, .avx512fp16, bit(leaf.edx, 23) and has_avx512_save); |
| | 538 | setFeature(cpu, .amx_tile, bit(leaf.edx, 24) and has_amx_save); |
| | 539 | setFeature(cpu, .amx_int8, bit(leaf.edx, 25) and has_amx_save); |
| 492 | | 540 | |
| 493 | // TODO I feel unsure about this check. | 541 | if (leaf.eax >= 1) { |
| 494 | // It doesn't really seem to check for 7.1, just for 7. | | |
| 495 | // Is this a sound assumption to make? | | |
| 496 | // Note that this is what other implementations do, so I kind of trust it. | | |
| 497 | const has_leaf_7_1 = max_level >= 7; | | |
| 498 | if (has_leaf_7_1) { | | |
| 499 | leaf = cpuid(0x7, 0x1); | 542 | leaf = cpuid(0x7, 0x1); |
| | 543 | |
| | 544 | setFeature(cpu, .sha512, bit(leaf.eax, 0)); |
| | 545 | setFeature(cpu, .sm3, bit(leaf.eax, 1)); |
| | 546 | setFeature(cpu, .sm4, bit(leaf.eax, 2)); |
| | 547 | setFeature(cpu, .raoint, bit(leaf.eax, 3)); |
| | 548 | setFeature(cpu, .avxvnni, bit(leaf.eax, 4) and has_avx_save); |
| 500 | setFeature(cpu, .avx512bf16, bit(leaf.eax, 5) and has_avx512_save); | 549 | setFeature(cpu, .avx512bf16, bit(leaf.eax, 5) and has_avx512_save); |
| | 550 | setFeature(cpu, .cmpccxadd, bit(leaf.eax, 7)); |
| | 551 | setFeature(cpu, .amx_fp16, bit(leaf.eax, 21) and has_amx_save); |
| | 552 | setFeature(cpu, .hreset, bit(leaf.eax, 22)); |
| | 553 | setFeature(cpu, .avxifma, bit(leaf.eax, 23) and has_avx_save); |
| | 554 | |
| | 555 | setFeature(cpu, .avxvnniint8, bit(leaf.edx, 4) and has_avx_save); |
| | 556 | setFeature(cpu, .avxneconvert, bit(leaf.edx, 5) and has_avx_save); |
| | 557 | setFeature(cpu, .amx_complex, bit(leaf.edx, 8) and has_amx_save); |
| | 558 | setFeature(cpu, .avxvnniint16, bit(leaf.edx, 10) and has_avx_save); |
| | 559 | setFeature(cpu, .prefetchi, bit(leaf.edx, 14)); |
| | 560 | setFeature(cpu, .usermsr, bit(leaf.edx, 15)); |
| | 561 | setFeature(cpu, .avx10_1_256, bit(leaf.edx, 19)); |
| | 562 | // APX |
| | 563 | setFeature(cpu, .egpr, bit(leaf.edx, 21)); |
| | 564 | setFeature(cpu, .push2pop2, bit(leaf.edx, 21)); |
| | 565 | setFeature(cpu, .ppx, bit(leaf.edx, 21)); |
| | 566 | setFeature(cpu, .ndd, bit(leaf.edx, 21)); |
| | 567 | setFeature(cpu, .ccmp, bit(leaf.edx, 21)); |
| | 568 | setFeature(cpu, .cf, bit(leaf.edx, 21)); |
| 501 | } else { | 569 | } else { |
| 502 | setFeature(cpu, .avx512bf16, false); | 570 | for ([_]Target.x86.Feature{ |
| | 571 | .sha512, |
| | 572 | .sm3, |
| | 573 | .sm4, |
| | 574 | .raoint, |
| | 575 | .avxvnni, |
| | 576 | .avx512bf16, |
| | 577 | .cmpccxadd, |
| | 578 | .amx_fp16, |
| | 579 | .hreset, |
| | 580 | .avxifma, |
| | 581 | |
| | 582 | .avxvnniint8, |
| | 583 | .avxneconvert, |
| | 584 | .amx_complex, |
| | 585 | .avxvnniint16, |
| | 586 | .prefetchi, |
| | 587 | .usermsr, |
| | 588 | .avx10_1_256, |
| | 589 | .egpr, |
| | 590 | .push2pop2, |
| | 591 | .ppx, |
| | 592 | .ndd, |
| | 593 | .ccmp, |
| | 594 | .cf, |
| | 595 | }) |feat| { |
| | 596 | setFeature(cpu, feat, false); |
| | 597 | } |
| 503 | } | 598 | } |
| 504 | } else { | 599 | } else { |
| 505 | for ([_]Target.x86.Feature{ | 600 | for ([_]Target.x86.Feature{ |
| 506 | .fsgsbase, .sgx, .bmi, .avx2, | 601 | .fsgsbase, |
| 507 | .bmi2, .invpcid, .rtm, .avx512f, | 602 | .sgx, |
| 508 | .avx512dq, .rdseed, .adx, .avx512ifma, | 603 | .bmi, |
| 509 | .clflushopt, .clwb, .avx512pf, .avx512er, | 604 | .avx2, |
| 510 | .avx512cd, .sha, .avx512bw, .avx512vl, | 605 | .smep, |
| 511 | .prefetchwt1, .avx512vbmi, .pku, .waitpkg, | 606 | .bmi2, |
| 512 | .avx512vbmi2, .shstk, .gfni, .vaes, | 607 | .invpcid, |
| 513 | .vpclmulqdq, .avx512vnni, .avx512bitalg, .avx512vpopcntdq, | 608 | .rtm, |
| 514 | .avx512vp2intersect, .rdpid, .cldemote, .movdiri, | 609 | .avx512f, |
| 515 | .movdir64b, .enqcmd, .pconfig, .avx512bf16, | 610 | .evex512, |
| | 611 | .avx512dq, |
| | 612 | .rdseed, |
| | 613 | .adx, |
| | 614 | .smap, |
| | 615 | .avx512ifma, |
| | 616 | .clflushopt, |
| | 617 | .clwb, |
| | 618 | .avx512pf, |
| | 619 | .avx512er, |
| | 620 | .avx512cd, |
| | 621 | .sha, |
| | 622 | .avx512bw, |
| | 623 | .avx512vl, |
| | 624 | |
| | 625 | .prefetchwt1, |
| | 626 | .avx512vbmi, |
| | 627 | .pku, |
| | 628 | .waitpkg, |
| | 629 | .avx512vbmi2, |
| | 630 | .shstk, |
| | 631 | .gfni, |
| | 632 | .vaes, |
| | 633 | .vpclmulqdq, |
| | 634 | .avx512vnni, |
| | 635 | .avx512bitalg, |
| | 636 | .avx512vpopcntdq, |
| | 637 | .rdpid, |
| | 638 | .kl, |
| | 639 | .cldemote, |
| | 640 | .movdiri, |
| | 641 | .movdir64b, |
| | 642 | .enqcmd, |
| | 643 | |
| | 644 | .uintr, |
| | 645 | .avx512vp2intersect, |
| | 646 | .serialize, |
| | 647 | .tsxldtrk, |
| | 648 | .pconfig, |
| | 649 | .amx_bf16, |
| | 650 | .avx512fp16, |
| | 651 | .amx_tile, |
| | 652 | .amx_int8, |
| | 653 | |
| | 654 | .sha512, |
| | 655 | .sm3, |
| | 656 | .sm4, |
| | 657 | .raoint, |
| | 658 | .avxvnni, |
| | 659 | .avx512bf16, |
| | 660 | .cmpccxadd, |
| | 661 | .amx_fp16, |
| | 662 | .hreset, |
| | 663 | .avxifma, |
| | 664 | |
| | 665 | .avxvnniint8, |
| | 666 | .avxneconvert, |
| | 667 | .amx_complex, |
| | 668 | .avxvnniint16, |
| | 669 | .prefetchi, |
| | 670 | .usermsr, |
| | 671 | .avx10_1_256, |
| | 672 | .egpr, |
| | 673 | .push2pop2, |
| | 674 | .ppx, |
| | 675 | .ndd, |
| | 676 | .ccmp, |
| | 677 | .cf, |
| 516 | }) |feat| { | 678 | }) |feat| { |
| 517 | setFeature(cpu, feat, false); | 679 | setFeature(cpu, feat, false); |
| 518 | } | 680 | } |
| ... | @@ -520,21 +682,55 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { | ... | @@ -520,21 +682,55 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { |
| 520 | | 682 | |
| 521 | if (max_level >= 0xD and has_avx_save) { | 683 | if (max_level >= 0xD and has_avx_save) { |
| 522 | leaf = cpuid(0xD, 0x1); | 684 | leaf = cpuid(0xD, 0x1); |
| | 685 | |
| 523 | // Only enable XSAVE if OS has enabled support for saving YMM state. | 686 | // Only enable XSAVE if OS has enabled support for saving YMM state. |
| 524 | setFeature(cpu, .xsaveopt, bit(leaf.eax, 0)); | 687 | setFeature(cpu, .xsaveopt, bit(leaf.eax, 0)); |
| 525 | setFeature(cpu, .xsavec, bit(leaf.eax, 1)); | 688 | setFeature(cpu, .xsavec, bit(leaf.eax, 1)); |
| 526 | setFeature(cpu, .xsaves, bit(leaf.eax, 3)); | 689 | setFeature(cpu, .xsaves, bit(leaf.eax, 3)); |
| 527 | } else { | 690 | } else { |
| 528 | for ([_]Target.x86.Feature{ .xsaveopt, .xsavec, .xsaves }) |feat| { | 691 | for ([_]Target.x86.Feature{ |
| | 692 | .xsaveopt, |
| | 693 | .xsavec, |
| | 694 | .xsaves, |
| | 695 | }) |feat| { |
| 529 | setFeature(cpu, feat, false); | 696 | setFeature(cpu, feat, false); |
| 530 | } | 697 | } |
| 531 | } | 698 | } |
| 532 | | 699 | |
| 533 | if (max_level >= 0x14) { | 700 | if (max_level >= 0x14) { |
| 534 | leaf = cpuid(0x14, 0); | 701 | leaf = cpuid(0x14, 0); |
| | 702 | |
| 535 | setFeature(cpu, .ptwrite, bit(leaf.ebx, 4)); | 703 | setFeature(cpu, .ptwrite, bit(leaf.ebx, 4)); |
| 536 | } else { | 704 | } else { |
| 537 | setFeature(cpu, .ptwrite, false); | 705 | for ([_]Target.x86.Feature{ |
| | 706 | .ptwrite, |
| | 707 | }) |feat| { |
| | 708 | setFeature(cpu, feat, false); |
| | 709 | } |
| | 710 | } |
| | 711 | |
| | 712 | if (max_level >= 0x19) { |
| | 713 | leaf = cpuid(0x19, 0); |
| | 714 | |
| | 715 | setFeature(cpu, .widekl, bit(leaf.ebx, 2)); |
| | 716 | } else { |
| | 717 | for ([_]Target.x86.Feature{ |
| | 718 | .widekl, |
| | 719 | }) |feat| { |
| | 720 | setFeature(cpu, feat, false); |
| | 721 | } |
| | 722 | } |
| | 723 | |
| | 724 | if (max_level >= 0x24) { |
| | 725 | leaf = cpuid(0x24, 0); |
| | 726 | |
| | 727 | setFeature(cpu, .avx10_1_512, bit(leaf.ebx, 18)); |
| | 728 | } else { |
| | 729 | for ([_]Target.x86.Feature{ |
| | 730 | .avx10_1_512, |
| | 731 | }) |feat| { |
| | 732 | setFeature(cpu, feat, false); |
| | 733 | } |
| 538 | } | 734 | } |
| 539 | } | 735 | } |
| 540 | | 736 | |