代码生成属性

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

优化提示

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

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

inline 属性

inline 属性 建议在调用方放置一份被标记函数的副本,而不是生成调用函数定义位置的代码。

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

使用 inline 属性有三种方法

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

注意#[inline] 的所有形式都是提示,语言对在调用方放置被标记函数的副本没有要求

cold 属性

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

no_builtins 属性

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

target_feature 属性

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

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

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

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

标记为 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, 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

#[target_feature] 可与 Wasm 平台上的安全函数和 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 除外。当应用于特征声明中的函数和方法时,该属性适用于所有实现。如果特征提供了具有该属性的默认实现,则该属性也适用于覆盖实现。

当应用于 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 似乎是在标记函数的定义位置调用的,从而在虚拟调用中丢失了实际的调用者信息。这种强制转换的一个常见示例是创建其方法已标记的特征对象。

注意:上述函数指针的 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)。
  • 函数中的任何内联汇编都必须使用指定的指令集而不是目标默认指令集。