Skip to content

Commit d1b9074

Browse files
committed
Add the cpuid target feature
- Make `cpuid` and friends safe with `#[target_feature(enable = "cpuid")]` - Update documentation
1 parent 52618eb commit d1b9074

File tree

13 files changed

+118
-40
lines changed

13 files changed

+118
-40
lines changed

compiler/rustc_codegen_gcc/src/gcc_util.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ pub fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]>
8282
("x86", "avx512vbmi2") => smallvec!["avx512vbmi2", "avx512bw"],
8383
// NOTE: seems like GCC requires 'avx512bw' for 'avx512bitalg'.
8484
("x86", "avx512bitalg") => smallvec!["avx512bitalg", "avx512bw"],
85+
("x86", "cpuid") => smallvec![],
8586
("aarch64", "rcpc2") => smallvec!["rcpc-immo"],
8687
("aarch64", "dpb") => smallvec!["ccpp"],
8788
("aarch64", "dpb2") => smallvec!["ccdp"],

compiler/rustc_codegen_llvm/src/llvm_util.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,8 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
325325
TargetFeatureFoldStrength::Both("zu"),
326326
],
327327
)),
328+
// This is supposed to be detection-only, has no effect on codegen
329+
("x86", "cpuid") => None,
328330
(_, s) => Some(LLVMFeature::new(s)),
329331
}
330332
}

compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,8 @@ declare_features! (
455455
/// Allows function attribute `#[coverage(on/off)]`, to control coverage
456456
/// instrumentation of that function.
457457
(unstable, coverage_attribute, "1.74.0", Some(84605)),
458+
/// Allows using the `cpuid` target feature
459+
(unstable, cpuid_target_feature, "CURRENT_RUSTC_VERSION", Some(146558)),
458460
/// Allows non-builtin attributes in inner attribute position.
459461
(unstable, custom_inner_attributes, "1.30.0", Some(54726)),
460462
/// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`.

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,7 @@ symbols! {
780780
count,
781781
coverage,
782782
coverage_attribute,
783+
cpuid_target_feature,
783784
cr,
784785
crate_in_paths,
785786
crate_local,

compiler/rustc_target/src/target_features.rs

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ const AARCH64_TIED_FEATURES: &[&[&str]] = &[
375375

376376
static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
377377
// tidy-alphabetical-start
378-
("adx", Stable, &[]),
378+
("adx", Stable, &["cpuid"]),
379379
("aes", Stable, &["sse2"]),
380380
("amx-avx512", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
381381
("amx-bf16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
@@ -385,9 +385,9 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
385385
("amx-int8", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
386386
("amx-movrs", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
387387
("amx-tf32", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
388-
("amx-tile", Unstable(sym::x86_amx_intrinsics), &[]),
388+
("amx-tile", Unstable(sym::x86_amx_intrinsics), &["cpuid"]),
389389
("amx-transpose", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
390-
("apxf", Unstable(sym::apx_target_feature), &[]),
390+
("apxf", Unstable(sym::apx_target_feature), &["cpuid"]),
391391
("avx", Stable, &["sse4.2"]),
392392
("avx2", Stable, &["avx"]),
393393
(
@@ -429,24 +429,25 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
429429
("avxvnni", Stable, &["avx2"]),
430430
("avxvnniint8", Stable, &["avx2"]),
431431
("avxvnniint16", Stable, &["avx2"]),
432-
("bmi1", Stable, &[]),
433-
("bmi2", Stable, &[]),
434-
("cmpxchg16b", Stable, &[]),
435-
("ermsb", Unstable(sym::ermsb_target_feature), &[]),
432+
("bmi1", Stable, &["cpuid"]),
433+
("bmi2", Stable, &["cpuid"]),
434+
("cmpxchg16b", Stable, &["cpuid"]),
435+
("cpuid", Unstable(sym::cpuid_target_feature), &[]),
436+
("ermsb", Unstable(sym::ermsb_target_feature), &["cpuid"]),
436437
("f16c", Stable, &["avx"]),
437438
("fma", Stable, &["avx"]),
438-
("fxsr", Stable, &[]),
439+
("fxsr", Stable, &["cpuid"]),
439440
("gfni", Stable, &["sse2"]),
440441
("kl", Stable, &["sse2"]),
441-
("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]),
442-
("lzcnt", Stable, &[]),
443-
("movbe", Stable, &[]),
444-
("movrs", Unstable(sym::movrs_target_feature), &[]),
442+
("lahfsahf", Unstable(sym::lahfsahf_target_feature), &["cpuid"]),
443+
("lzcnt", Stable, &["cpuid"]),
444+
("movbe", Stable, &["cpuid"]),
445+
("movrs", Unstable(sym::movrs_target_feature), &["cpuid"]),
445446
("pclmulqdq", Stable, &["sse2"]),
446-
("popcnt", Stable, &[]),
447-
("prfchw", Unstable(sym::prfchw_target_feature), &[]),
448-
("rdrand", Stable, &[]),
449-
("rdseed", Stable, &[]),
447+
("popcnt", Stable, &["cpuid"]),
448+
("prfchw", Unstable(sym::prfchw_target_feature), &["cpuid"]),
449+
("rdrand", Stable, &["cpuid"]),
450+
("rdseed", Stable, &["cpuid"]),
450451
(
451452
"retpoline-external-thunk",
452453
Stability::Forbidden { reason: "use `-Zretpoline-external-thunk` compiler flag instead" },
@@ -462,28 +463,28 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
462463
Stability::Forbidden { reason: "use `-Zretpoline` compiler flag instead" },
463464
&[],
464465
),
465-
("rtm", Unstable(sym::rtm_target_feature), &[]),
466+
("rtm", Unstable(sym::rtm_target_feature), &["cpuid"]),
466467
("sha", Stable, &["sse2"]),
467468
("sha512", Stable, &["avx2"]),
468469
("sm3", Stable, &["avx"]),
469470
("sm4", Stable, &["avx2"]),
470471
// This cannot actually be toggled, the ABI always fixes it, so it'd make little sense to
471472
// stabilize. It must be in this list for the ABI check to be able to use it.
472473
("soft-float", Stability::Unstable(sym::x87_target_feature), &[]),
473-
("sse", Stable, &[]),
474+
("sse", Stable, &["cpuid"]),
474475
("sse2", Stable, &["sse"]),
475476
("sse3", Stable, &["sse2"]),
476477
("sse4.1", Stable, &["ssse3"]),
477478
("sse4.2", Stable, &["sse4.1"]),
478479
("sse4a", Stable, &["sse3"]),
479480
("ssse3", Stable, &["sse3"]),
480-
("tbm", Stable, &[]),
481+
("tbm", Stable, &["cpuid"]),
481482
("vaes", Stable, &["avx2", "aes"]),
482483
("vpclmulqdq", Stable, &["avx", "pclmulqdq"]),
483484
("widekl", Stable, &["kl"]),
484-
("x87", Unstable(sym::x87_target_feature), &[]),
485+
("x87", Unstable(sym::x87_target_feature), &["cpuid"]),
485486
("xop", Unstable(sym::xop_target_feature), &[/*"fma4", */ "avx", "sse4a"]),
486-
("xsave", Stable, &[]),
487+
("xsave", Stable, &["cpuid"]),
487488
("xsavec", Stable, &["xsave"]),
488489
("xsaveopt", Stable, &["xsave"]),
489490
("xsaves", Stable, &["xsave"]),

library/core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@
194194
// tidy-alphabetical-start
195195
#![feature(aarch64_unstable_target_feature)]
196196
#![feature(arm_target_feature)]
197+
#![feature(cpuid_target_feature)]
197198
#![feature(hexagon_target_feature)]
198199
#![feature(loongarch_target_feature)]
199200
#![feature(mips_target_feature)]

library/std_detect/src/detect/arch/x86.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,4 +281,6 @@ features! {
281281
/// ERMSB, Enhanced REP MOVSB and STOSB
282282
@FEATURE: #[unstable(feature = "xop_target_feature", issue = "127208")] xop: "xop";
283283
/// XOP: eXtended Operations (AMD)
284+
@FEATURE: #[unstable(feature = "cpuid_target_feature", issue = "146558")] cpuid: "cpuid";
285+
/// CPUID
284286
}

library/std_detect/src/detect/os/x86.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ pub(crate) fn detect_features() -> cache::Initializer {
3232
return value;
3333
}
3434

35+
value.set(Feature::cpuid as u32);
36+
3537
// Calling `__cpuid`/`__cpuid_count` from here on is safe because the CPU
3638
// has `cpuid` support.
3739

library/stdarch/crates/core_arch/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
x86_amx_intrinsics,
3434
f16,
3535
aarch64_unstable_target_feature,
36-
bigint_helper_methods
36+
bigint_helper_methods,
37+
cpuid_target_feature
3738
)]
3839
#![cfg_attr(test, feature(test, abi_vectorcall, stdarch_internal))]
3940
#![deny(clippy::missing_inline_in_public_items)]

library/stdarch/crates/core_arch/src/x86/cpuid.rs

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,20 @@ pub struct CpuidResult {
2727

2828
/// Returns the result of the `cpuid` instruction for a given `leaf` (`EAX`)
2929
/// and `sub_leaf` (`ECX`).
30-
///
31-
/// The highest-supported leaf value is returned by the first tuple argument of
32-
/// [`__get_cpuid_max(0)`](fn.__get_cpuid_max.html). For leaves containing
33-
/// sub-leaves, the second tuple argument returns the highest-supported
34-
/// sub-leaf value.
30+
///
31+
/// There are 2 types of information leafs - basic leafs (with `leaf < 0x8000000`)
32+
/// and extended leafs (with `leaf >= 0x80000000`). The highest supported basic and
33+
/// extended leafs can be obtained by calling CPUID with `0` and `0x80000000`,
34+
/// respectively, and reading the value in the `EAX` register. If the leaf supports
35+
/// more than one sub-leafs, then the procedure of obtaining the highest supported
36+
/// sub-leaf, as well as the behavior if a invalid sub-leaf value is passed, depends
37+
/// on the specific leaf.
38+
///
39+
/// If the `leaf` value is higher than the maximum supported basic or extended leaf
40+
/// for the processor, this returns the information for the highest supported basic
41+
/// information leaf (with the passed `sub_leaf` value). If the `leaf` value is less
42+
/// than or equal to the highest basic or extended leaf value, but the leaf is not
43+
/// supported on the processor, all zeros are returned.
3544
///
3645
/// The [CPUID Wikipedia page][wiki_cpuid] contains how to query which
3746
/// information using the `EAX` and `ECX` registers, and the interpretation of
@@ -48,8 +57,9 @@ pub struct CpuidResult {
4857
/// [amd64_ref]: http://support.amd.com/TechDocs/24594.pdf
4958
#[inline]
5059
#[cfg_attr(test, assert_instr(cpuid))]
60+
#[target_feature(enable = "cpuid")]
5161
#[stable(feature = "simd_x86", since = "1.27.0")]
52-
pub unsafe fn __cpuid_count(leaf: u32, sub_leaf: u32) -> CpuidResult {
62+
pub fn __cpuid_count(leaf: u32, sub_leaf: u32) -> CpuidResult {
5363
let eax;
5464
let ebx;
5565
let ecx;
@@ -58,7 +68,7 @@ pub unsafe fn __cpuid_count(leaf: u32, sub_leaf: u32) -> CpuidResult {
5868
// LLVM sometimes reserves `ebx` for its internal use, we so we need to use
5969
// a scratch register for it instead.
6070
#[cfg(target_arch = "x86")]
61-
{
71+
unsafe {
6272
asm!(
6373
"mov {0}, ebx",
6474
"cpuid",
@@ -67,11 +77,11 @@ pub unsafe fn __cpuid_count(leaf: u32, sub_leaf: u32) -> CpuidResult {
6777
inout("eax") leaf => eax,
6878
inout("ecx") sub_leaf => ecx,
6979
out("edx") edx,
70-
options(nostack, preserves_flags),
80+
options(pure, nomem, nostack, preserves_flags),
7181
);
7282
}
7383
#[cfg(target_arch = "x86_64")]
74-
{
84+
unsafe {
7585
asm!(
7686
"mov {0:r}, rbx",
7787
"cpuid",
@@ -80,33 +90,34 @@ pub unsafe fn __cpuid_count(leaf: u32, sub_leaf: u32) -> CpuidResult {
8090
inout("eax") leaf => eax,
8191
inout("ecx") sub_leaf => ecx,
8292
out("edx") edx,
83-
options(nostack, preserves_flags),
93+
options(pure, nomem, nostack, preserves_flags),
8494
);
8595
}
8696
CpuidResult { eax, ebx, ecx, edx }
8797
}
8898

99+
/// Calls CPUID with the provided `leaf` value, with `sub_leaf` set to 0.
89100
/// See [`__cpuid_count`](fn.__cpuid_count.html).
90101
#[inline]
91102
#[cfg_attr(test, assert_instr(cpuid))]
103+
#[target_feature(enable = "cpuid")]
92104
#[stable(feature = "simd_x86", since = "1.27.0")]
93-
pub unsafe fn __cpuid(leaf: u32) -> CpuidResult {
105+
pub fn __cpuid(leaf: u32) -> CpuidResult {
94106
__cpuid_count(leaf, 0)
95107
}
96108

97-
/// Returns the highest-supported `leaf` (`EAX`) and sub-leaf (`ECX`) `cpuid`
98-
/// values.
109+
/// Returns the EAX and EBX register after calling CPUID with the provided `leaf`,
110+
/// with `sub_leaf` set to 0.
99111
///
100-
/// If `cpuid` is supported, and `leaf` is zero, then the first tuple argument
101-
/// contains the highest `leaf` value that `cpuid` supports. For `leaf`s
102-
/// containing sub-leafs, the second tuple argument contains the
103-
/// highest-supported sub-leaf value.
112+
/// If `leaf` if 0 or `0x80000000`, the first tuple argument contains the maximum
113+
/// supported basic or extended leaf, respectively.
104114
///
105115
/// See also [`__cpuid`](fn.__cpuid.html) and
106116
/// [`__cpuid_count`](fn.__cpuid_count.html).
107117
#[inline]
118+
#[target_feature(enable = "cpuid")]
108119
#[stable(feature = "simd_x86", since = "1.27.0")]
109-
pub unsafe fn __get_cpuid_max(leaf: u32) -> (u32, u32) {
120+
pub fn __get_cpuid_max(leaf: u32) -> (u32, u32) {
110121
let CpuidResult { eax, ebx, .. } = __cpuid(leaf);
111122
(eax, ebx)
112123
}

0 commit comments

Comments
 (0)