代码生成属性

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

优化提示

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 属性 可以应用于函数,以启用为特定平台架构特性生成该函数的代码。 它使用带有单个 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 位) 数据
fmaavxFMA3 — 三操作数融合乘加
fxsrfxsavefxrstor — 保存和恢复 x87 FPU、MMX 技术和 SSE 状态
lzcntlzcnt — 前导零计数
movbemovbe - 字节交换后移动数据
pclmulqdqsse2pclmulqdq — 打包无进位乘法 quadword
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 - 高级 SIMD AES 指令
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 - 内存标记扩展
neonFEAT_FP 和 FEAT_AdvSIMD - 浮点数和高级 SIMD 扩展
panFEAT_PAN - 特权访问不允许扩展
pacaFEAT_PAuth - 指针认证(地址认证)
pacgFEAT_PAuth - 指针认证(通用认证)
pmuv3FEAT_PMUv3 - 性能监视器扩展(v3)
randFEAT_RNG - 随机数生成器
rasFEAT_RAS - 可靠性、可用性和服务性扩展
rcpcFEAT_LRCPC - 一致性处理器ARMv8.2 可以支持多种架构,其中一些可用特性如下所示:
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 - 推测存储旁路安全指令
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 - 虚拟化主机扩展指令

wasm32wasm64

#[target_feature] 可以在 Wasm 平台上用于安全函数和 非安全函数 。 在 Wasm 引擎不支持的指令下,尝试使用 #[target_feature] 属性将在加载时失败,不会有与编译器预期不同的解释风险,因此不可能引起未定义行为。

特性描述
simd128WebAssembly simd proposal

附加信息

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 只是一个提示,实现可能会在遍历堆栈时提前停止。请参阅 限制 以获取重要的注意事项。

示例

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 被另一个带有 track_caller 属性的函数 g 直接调用,而 g 又被 calls_g 调用时, fg 中的代码都可以观察到 calls_g 中调用 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 被另一个有 track_caller 属性的函数 h 直接或间接调用时 (例如 hcalls_h 调用) ,则 fgh 中的代码都会观察到 calls_hh 的调用位置。 也就是说,调用链中最深的有 track_caller 属性的函数的调用位置会传递到所有下层函数:

#![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] 的函数转换为函数指针会创建一个外壳函数,对于观察者来说,该外壳函数似乎是在函数定义的位置被调用的,从而在虚拟调用之间丢失了实际的调用者信息。 这种转换的常见例子是创建一个具有方法的 trait 对象,并将其进行标注。

注意: 函数指针的上述外壳函数是必要的,因为 rustc 在代码生成上实现 track_caller 通过将一个隐式参数附加到函数 ABI 上,但是这对于间接调用是非安全的, 因为该参数不是函数类型的一部分,给定的函数指针类型可能引用一个没有该属性的函数或具有该属性的函数。创建外壳函数隐藏了函数指针调用者的隐式参数,从而保持了安全性。

instruction_set 属性

可以将 instruction_set 属性应用于函数,以启用针对目标体系结构支持的特定指令集的代码生成。 它使用 MetaListPath 语法和一个由架构和指令集组成的路径,指定如何为在单个程序中使用多个指令集的体系结构生成代码。

对于 ARMv4ARMv5te 架构的目标,以下值可用:

  • arm::a32 - 使用 ARM 编码.
  • arm::t32 - 使用 Thumb 编码.
#[instruction_set(arm::a32)]
fn foo_arm_code() {}

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