代码生成属性

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

优化提示

coldinline 属性 提供了生成代码的建议,这种方式可能比没有提示时更快。这些属性只是提示,可能会被忽略。

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

inline 属性

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

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

有三种使用 inline 属性的方法

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

注意#[inline] 的所有形式都是提示,语言对在调用者中放置带有属性的函数的副本没有*要求*。

cold 属性

cold 属性 建议不太可能调用具有该属性的函数。

no_builtins 属性

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

target_feature 属性

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

#![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 单精度浮点矩阵乘法指令
f64mmsveFEAT_F64MM — SVE 双精度浮点矩阵乘法指令
fcmaneonFEAT_FCMA — 浮点复数支持
fhmfp16FEAT_FHM — 半精度浮点 FMLAL 指令
flagmFEAT_FlagM — 条件标志操作
fp16neonFEAT_FP16 — 半精度浮点数据处理
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, 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] 可以与安全和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 内的代码获取导致 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 是一个提示,因此实现可能会提前停止其在堆栈上的遍历。有关重要注意事项,请参阅限制

示例

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