代码生成属性

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

优化提示

coldinline 属性 提供建议,以某种可能比不使用提示更快的方式生成代码。这些属性只是提示,可能会被忽略。

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

inline 属性

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

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

有三种使用内联属性的方式

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

注意: 各种形式的 #[inline] 都是提示,语言不要求 将带属性的函数的副本放置在调用者中。

cold 属性

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

no_builtins 属性

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

target_feature 属性

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

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

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

调用使用当前平台不支持的功能编译的函数是 未定义行为除非 平台明确声明这是安全的。

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

可用功能

以下是可用功能名称的列表。

x86x86_64

在此平台上执行具有不支持的功能的代码是未定义行为。因此,此平台要求 #[target_feature] 仅应用于 unsafe 函数

功能隐式启用描述
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 — 保存处理器扩展状态(监管者)

aarch64

此平台要求 #[target_feature] 仅应用于 unsafe 函数

有关这些功能的更多文档,请参阅 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 — 发布一致性处理器一致性
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] 仅应用于 unsafe 函数

有关这些功能的更多文档,请在其各自的规范中查找。许多规范在 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, zbkxZk — 标量密码学
zknzknd, zkne, zknh, zbkb, zbkc, zkbxZkn — NIST 算法套件扩展
zkndZknd — NIST 套件:AES 解密
zkneZkne — NIST 套件:AES 加密
zknhZknh — NIST 套件:哈希函数指令
zkrZkr — 熵源扩展
zkszksed, zksh, zbkb, zbkc, zbkxZks — ShangMi 算法套件
zksedZksed — ShangMi 套件:SM4 块密码指令
zkshZksh — ShangMi 套件:SM3 哈希函数指令
zktZkt — 数据独立执行延迟子集

wasm32wasm64

在 Wasm 平台上,#[target_feature] 可以与 safe 和 unsafe 函数 一起使用。不可能通过 #[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 属性

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

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

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

行为

将该属性应用于函数 f 允许 f 中的代码获取 Location 的提示,该提示指示导致 f 调用的“最顶层”跟踪调用。在观察点,实现的行为就好像它从 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 intrinsic。

注意: 由于结果 Location 是一个提示,因此实现可能会提前停止其向上遍历堆栈的过程。请参阅 限制 以了解重要的注意事项。

示例

fcalls_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,该 shim 对观察者来说似乎是在带属性的函数的定义站点被调用的,从而在虚拟调用中丢失了实际的调用者信息。这种强制转换的一个常见示例是创建 trait 对象,其方法是带属性的。

注意: 函数指针的上述 shim 是必要的,因为 rustc 通过将隐式参数附加到函数 ABI 中来在代码生成上下文中实现 track_caller,但这对于间接调用来说是不健全的,因为该参数不是函数类型的一部分,并且给定的函数指针类型可能指向也可能不指向带有该属性的函数。shim 的创建向函数指针的调用者隐藏了隐式参数,从而保持了健全性。

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),具体取决于指令集。
  • 函数中的任何内联汇编都必须使用指定的指令集,而不是目标默认指令集。