How to use if cfg!(target_feature = "adx")?

On my VSCode, the function carry_add_adx gets dark, indicating that it's not active in the current machine.

#[inline(always)]
#[cfg(target_feature = "adx")]
pub fn carry_add_adx<T: Into<u64>, S: Into<u64>>(
    a: T,
    b: S,
    c: u8,
) -> (u64, u8) {
    unimplemented!()
}

#[inline(always)]
pub fn carry_add<T: Into<u64>, S: Into<u64>>(
    a: T,
    b: S,
    c: u8,
) -> (u64, u8) {
    if cfg!(target_feature = "adx") {
        carry_add_adx(a, b, c)
    } else {
        unimplemented!();
    }
}

it shouldn't also be used for if cfg!(target_feature = "adx") { but it looks like it tries to use it. Why? I get:

error[E0425]: cannot find function `carry_add_adx` in this scope
  --> src/lib.rs:18:9
   |
18 |         carry_add_adx(a, b, c)
   |         ^^^^^^^^^^^^^ not found in this scope

Here's the documentation for static vs. dynamic feature detection:
https://doc.rust-lang.org/core/arch/index.html#cpu-feature-detection

The default x86_64 target does not have "adx" enabled. You can enable that with -Ctarget-feature or a newer -Ctarget-cpu, which will satisfy the static detection above, or you can use dynamic detection to detect features in the running cpu.

You get this error because #[cfg(false)] makes the following item disappear from your code if the condition is not met, but things inside cfg!(false) don't, so the function still has to exist.

You could do something like:

#[inline(always)]
pub fn carry_add<T: Into<u64>, S: Into<u64>>(
    a: T,
    b: S,
    c: u8,
) -> (u64, u8) {
     #[cfg(target_feature = "adx")]
     {
         carry_add_adx(a, b, c)
     }
     #[cfg(not(target_feature = "adx"))]
     {
         // default impl
     }     
}

or

#[inline(always)]
#[cfg(target_feature = "adx")]
pub fn carry_add<T: Into<u64>, S: Into<u64>>(
    a: T,
    b: S,
    c: u8,
) -> (u64, u8) {
    // adx impl...
}

#[inline(always)]
#[cfg(not(target_feature = "adx"))]
pub fn carry_add<T: Into<u64>, S: Into<u64>>(
    a: T,
    b: S,
    c: u8,
) -> (u64, u8) {
     // default impl
}

Technically it won't be used, but the call to carry_add_adx() will still be emitted.

When you compile without the target_feature = "adx", cfg!() will expand to :

#[inline(always)]
pub fn carry_add<T: Into<u64>, S: Into<u64>>(
    a: T,
    b: S,
    c: u8,
) -> (u64, u8) {
    if false {
        carry_add_adx(a, b, c)
    } else {
        unimplemented!();
    }
}

The cfg!() macro just evaluates to a boolean, so anything hidden behind a cfg!(...) still needs to be valid code. It just won't be executed at runtime and in release mode the unused code will be compiled out.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.