代码生成属性

以下 属性 用于控制代码生成。

优化提示

coldinline 属性 提供生成代码的建议,可能比没有这些提示时生成得更快。这些属性仅为提示,可能会被忽略。

这两个属性都可以用于 函数。当应用于 trait 中的函数时,它们仅在该函数用作 trait 实现的默认函数时生效,而不是应用于所有 trait 实现。这些属性对没有函数体的 trait 函数没有影响。

inline 属性

inline 属性 建议将带有该属性的函数副本放置在调用者处,而不是生成代码去调用函数定义位置的代码。

注意

rustc 编译器会根据内部启发式算法自动内联函数。不正确地内联函数可能会使程序变慢,因此应谨慎使用此属性。

使用 inline 属性有三种方式

  • #[inline] 建议 执行内联扩展。
  • #[inline(always)] 建议 始终执行内联扩展。
  • #[inline(never)] 建议 永远不要执行内联扩展。

注意

任何形式的 #[inline] 都只是一个提示,语言对将带属性的函数副本放置在调用者处没有 强制要求

cold 属性

cold 属性 建议带属性的函数不太可能被调用。

no_builtins 属性

no_builtins 属性 可以应用于 crate 级别,以禁用将某些代码模式优化为调用假定存在的库函数。

target_feature 属性

target_feature 属性 可应用于函数,以针对特定的平台架构特性启用该函数的代码生成。它使用 MetaListNameValueStr 语法,其中只有一个键 enable,其值是逗号分隔的要启用的特性名称字符串。

#![allow(unused)]
fn main() {
#[cfg(target_feature = "avx2")]
#[target_feature(enable = "avx2")]
fn foo_avx2() {}
}

每个 目标架构 都有一组可以启用的特性。为 crate 未编译的目标架构指定特性是错误的。

在带有 target_feature 注解的函数中定义的闭包会继承包含函数的属性。

调用一个使用当前代码运行平台不支持的特性编译的函数是 未定义行为除非 平台明确说明这是安全的。

除非下述平台规则另有规定,否则以下限制适用

  • 安全的 #[target_feature] 函数(以及继承该属性的闭包)只能在启用了被调用方所有 target_feature 特性的调用方中安全地调用。此限制不适用于 unsafe 上下文。
  • 安全的 #[target_feature] 函数(以及继承该属性的闭包)只能在启用了被强制转换方所有 target_feature 特性的上下文中被强制转换为 安全的 函数指针。此限制不适用于 unsafe 函数指针。

隐式启用的特性也包含在此规则中。例如,一个 sse2 函数可以调用标记有 sse 的函数。

#![allow(unused)]
fn main() {
#[cfg(target_feature = "sse2")] {
#[target_feature(enable = "sse")]
fn foo_sse() {}

fn bar() {
    // Calling `foo_sse` here is unsafe, as we must ensure that SSE is
    // available first, even if `sse` is enabled by default on the target
    // platform or manually enabled as compiler flags.
    unsafe {
        foo_sse();
    }
}

#[target_feature(enable = "sse")]
fn bar_sse() {
    // Calling `foo_sse` here is safe.
    foo_sse();
    || foo_sse();
}

#[target_feature(enable = "sse2")]
fn bar_sse2() {
    // Calling `foo_sse` here is safe because `sse2` implies `sse`.
    foo_sse();
}
}
}

带有 #[target_feature] 属性的函数 永远不会 实现 Fn 系列 trait,尽管从包含函数继承特性的闭包会实现。

#[target_feature] 属性不允许用于以下位置

标记有 target_feature 的函数不会被内联到不支持指定特性的上下文中。#[inline(always)] 属性不能与 target_feature 属性一起使用。

可用特性

以下是可用特性名称的列表。

x86x86_64

在此平台上执行使用不支持特性编译的代码是未定义行为。因此,在此平台上使用 #[target_feature] 函数需遵循上述限制

特性隐式启用描述
adxADX — 多精度带进位加法指令扩展
aessse2AES — 高级加密标准指令集
avxsse4.2AVX — 高级向量扩展
avx2avxAVX2 — 高级向量扩展 2
bmi1BMI1 — 位操作指令集
bmi2BMI2 — 位操作指令集 2
cmpxchg16bcmpxchg16b — 原子比较并交换 16 字节(128 位)数据
f16cavxF16C — 16 位浮点转换指令
fmaavxFMA3 — 三操作数融合乘加
fxsrfxsavefxrstor — 保存和恢复 x87 FPU、MMX 技术和 SSE 状态
lzcntlzcnt — 前导零计数
movbemovbe — 交换字节后移动数据
pclmulqdqsse2pclmulqdq — 打包的无进位乘法四字
popcntpopcnt — 置为 1 的位数计数
rdrandrdrand — 读取随机数
rdseedrdseed — 读取随机种子
shasse2SHA — 安全哈希算法扩展
sseSSE — 流式 SIMD 扩展
sse2sseSSE2 — 流式 SIMD 扩展 2
sse3sse2SSE3 — 流式 SIMD 扩展 3
sse4.1ssse3SSE4.1 — 流式 SIMD 扩展 4.1
sse4.2sse4.1SSE4.2 — 流式 SIMD 扩展 4.2
ssse3sse3SSSE3 — 补充流式 SIMD 扩展 3
xsavexsave — 保存处理器扩展状态
xsavecxsavec — 保存处理器扩展状态(带压缩)
xsaveoptxsaveopt — 保存处理器优化扩展状态
xsavesxsaves — 保存处理器扩展状态(supervisor 模式)

aarch64

在此平台上,#[target_feature] 函数的使用遵循上述限制

有关这些特性的更多文档可在 ARM 架构参考手册developer.arm.com 的其他位置找到。

注意

如果使用以下成对特性,它们应同时被标记为启用或禁用

  • pacapacg,LLVM 目前将其实现为一个特性。
特性隐式启用特性名称
aesneonFEAT_AES & FEAT_PMULL — 高级 SIMD AES & PMULL 指令
bf16FEAT_BF16 — BFloat16 指令
btiFEAT_BTI — 分支目标识别
crcFEAT_CRC — CRC32 校验和指令
ditFEAT_DIT — 数据独立时序指令
dotprodFEAT_DotProd — 高级 SIMD Int8 点积指令
dpbFEAT_DPB — 将数据缓存清除至持久点
dpb2FEAT_DPB2 — 将数据缓存清除至深度持久点
f32mmsveFEAT_F32MM — SVE 单精度 FP 矩阵乘法指令
f64mmsveFEAT_F64MM — SVE 双精度 FP 矩阵乘法指令
fcmaneonFEAT_FCMA — 浮点复数支持
fhmfp16FEAT_FHM — 半精度 FP FMLAL 指令
flagmFEAT_FlagM — 条件标志操作
fp16neonFEAT_FP16 — 半精度 FP 数据处理
frinttsFEAT_FRINTTS — 浮点转整数辅助指令
i8mmFEAT_I8MM — Int8 矩阵乘法
jsconvneonFEAT_JSCVT — JavaScript 转换指令
lseFEAT_LSE — 大型系统扩展
lorFEAT_LOR — 有限排序区域扩展
mteFEAT_MTE & FEAT_MTE2 — 内存标记扩展
neonFEAT_FP & FEAT_AdvSIMD — 浮点和高级 SIMD 扩展
panFEAT_PAN — 特权访问禁止扩展
pacaFEAT_PAuth — 指针认证(地址认证)
pacgFEAT_PAuth — 指针认证(通用认证)
pmuv3FEAT_PMUv3 — 性能监视器扩展 (v3)
randFEAT_RNG — 随机数生成器
rasFEAT_RAS & FEAT_RASv1p1 — 可靠性、可用性和可维护性扩展
rcpcFEAT_LRCPC — Release consistent Processor Consistent
rcpc2rcpcFEAT_LRCPC2 — 带立即偏移的 RcPc
rdmFEAT_RDM — 舍入双精度乘加
sbFEAT_SB — 推测屏障
sha2neonFEAT_SHA1 & FEAT_SHA256 — 高级 SIMD SHA 指令
sha3sha2FEAT_SHA512 & FEAT_SHA3 — 高级 SIMD SHA 指令
sm4neonFEAT_SM3 & FEAT_SM4 — 高级 SIMD SM3/4 指令
speFEAT_SPE — 统计分析扩展
ssbsFEAT_SSBS & FEAT_SSBS2 — 推测存储旁路安全
svefp16FEAT_SVE — 可伸缩向量扩展
sve2sveFEAT_SVE2 — 可伸缩向量扩展 2
sve2-aessve2, aesFEAT_SVE_AES — SVE AES 指令
sve2-sm4sve2, sm4FEAT_SVE_SM4 — SVE SM4 指令
sve2-sha3sve2, sha3FEAT_SVE_SHA3 — SVE SHA3 指令
sve2-bitpermsve2FEAT_SVE_BitPerm — SVE 位排列
tmeFEAT_TME — 事务内存扩展
vhFEAT_VHE — 虚拟化宿主扩展

riscv32riscv64

在此平台上,#[target_feature] 函数的使用遵循上述限制

这些特性的更多文档可在其各自的规范中找到。许多规范在 RISC-V ISA 手册 或托管在 RISC-V GitHub 账户 上的其他手册中描述。

特性隐式启用描述
aA — 原子指令
cC — 压缩指令
mM — 整数乘法和除法指令
zbzba, zbc, zbsZb — 位操作指令
zbaZba — 地址生成指令
zbbZbb — 基本位操作
zbcZbc — 无进位乘法
zbkbZbkb — 密码学位操作指令
zbkcZbkc — 密码学无进位乘法
zbkxZbkx — 交叉开关排列
zbsZbs — 单一位指令
zkzkn, zkr, zks, zkt, zbkb, zbkc, zkbxZk — 标量密码学
zknzknd, zkne, zknh, zbkb, zbkc, zkbxZkn — NIST 算法套件扩展
zkndZknd — NIST 套件:AES 解密
zkneZkne — NIST 套件:AES 加密
zknhZknh — NIST 套件:哈希函数指令
zkrZkr — 熵源扩展
zkszksed, zksh, zbkb, zbkc, zkbxZks — 商密算法套件
zksedZksed — 商密套件:SM4 分组密码指令
zkshZksh — 商密套件:SM3 哈希函数指令
zktZkt — 数据独立执行延迟子集

wasm32wasm64

在 Wasm 平台上,安全的 #[target_feature] 函数始终可以在安全上下文中使用。通过 #[target_feature] 属性导致未定义行为是不可能的,因为尝试使用 Wasm 引擎不支持的指令会在加载时失败,不会出现与编译器预期不同的解释风险。

附加信息

关于根据编译时设置选择性地启用或禁用代码编译,请参阅 target_feature 条件编译选项。请注意,此选项不受 target_feature 属性的影响,仅由整个 crate 启用的特性驱动。

对于这些平台上的运行时特性检测,请参阅标准库中的 is_x86_feature_detectedis_aarch64_feature_detected 宏。

注意

rustc 为每个目标和 CPU 启用了一组默认特性。可以使用 -C target-cpu 标志选择 CPU。可以使用 -C target-feature 标志为整个 crate 启用或禁用单个特性。

track_caller 属性

除了入口点 fn main 外,track_caller 属性可以应用于任何具有 "Rust" ABI 的函数。

当应用于 trait 声明中的函数和方法时,该属性适用于所有实现。如果 trait 提供了带有该属性的默认实现,则该属性也适用于覆盖实现。

当应用于 extern 块中的函数时,该属性也必须应用于任何链接的实现,否则会导致未定义行为。当应用于可供 extern 块使用的函数时,extern 块中的声明也必须具有该属性,否则会导致未定义行为。

行为

将此属性应用于函数 f 允许 f 中的代码获取导致 f 被调用的“最顶层”被追踪调用的 Location 的提示。在观察点,实现的行为就像它从 f 的栈帧向上追溯,以找到最近的 未带属性 函数 outer 的栈帧,并返回 outer 中被追踪调用的 Location

#![allow(unused)]
fn main() {
#[track_caller]
fn f() {
    println!("{}", std::panic::Location::caller());
}
}

注意

core 提供了 core::panic::Location::caller 用于观察调用方位置。它封装了 rustc 实现的 core::intrinsics::caller_location 内建函数。

注意

因为结果 Location 是一个提示,实现可能会提前停止向上追溯栈。有关重要注意事项,请参阅限制

示例

f 直接由 calls_f 调用时,f 中的代码观察到其在 calls_f 中的调用点。

#![allow(unused)]
fn main() {
#[track_caller]
fn f() {
    println!("{}", std::panic::Location::caller());
}
fn calls_f() {
    f(); // <-- f() prints this location
}
}

f 由另一个带有属性的函数 g 调用,而 g 又由 calls_g 调用时,fg 中的代码都观察到 gcalls_g 中的调用点。

#![allow(unused)]
fn main() {
#[track_caller]
fn f() {
    println!("{}", std::panic::Location::caller());
}
#[track_caller]
fn g() {
    println!("{}", std::panic::Location::caller());
    f();
}

fn calls_g() {
    g(); // <-- g() prints this location twice, once itself and once from f()
}
}

g 由另一个带有属性的函数 h 调用,而 h 又由 calls_h 调用时,fgh 中的所有代码都观察到 hcalls_h 中的调用点。

#![allow(unused)]
fn main() {
#[track_caller]
fn f() {
    println!("{}", std::panic::Location::caller());
}
#[track_caller]
fn g() {
    println!("{}", std::panic::Location::caller());
    f();
}
#[track_caller]
fn h() {
    println!("{}", std::panic::Location::caller());
    g();
}

fn calls_h() {
    h(); // <-- prints this location three times, once itself, once from g(), once from f()
}
}

依此类推。

限制

此信息仅为提示,不要求实现保留它。

特别是,将带有 #[track_caller] 的函数强制转换为函数指针会创建一个垫片(shim),该垫片对于观察者来说看起来像是在带属性函数的定义处被调用,从而在虚拟调用中丢失了实际的调用方信息。这种强制转换的一个常见例子是创建其方法带有此属性的 trait 对象。

注意

上述针对函数指针的垫片是必需的,因为 rustc 在代码生成上下文中通过向函数 ABI 追加一个隐式参数来实现 track_caller,但这对于间接调用来说是不健全的,因为该参数不是函数类型的一部分,并且给定的函数指针类型可能引用带有或不带有该属性的函数。创建垫片将隐式参数对函数指针的调用者隐藏起来,从而保证了健全性。

instruction_set 属性

instruction_set 属性 可以应用于函数,以控制该函数将为其生成哪个指令集。

这允许在支持它的 CPU 架构上,在单个程序中混合使用多种指令集。

它使用 MetaListPath 语法,以及由架构家族名称和指令集名称组成的路径。

在不支持 instruction_set 属性的目标上使用它是编译错误。

在 ARM 平台

对于 ARMv4TARMv5te 架构,支持以下内容

  • arm::a32 — 将函数生成为 A32 “ARM” 代码。
  • arm::t32 — 将函数生成为 T32 “Thumb” 代码。
#[instruction_set(arm::a32)]
fn foo_arm_code() {}

#[instruction_set(arm::t32)]
fn bar_thumb_code() {}

使用 instruction_set 属性具有以下效果

  • 如果函数的地址被当作函数指针,地址的最低位将根据指令集设置为 0 (arm) 或 1 (thumb)。
  • 函数中的任何内联汇编必须使用指定的指令集,而不是目标的默认指令集。