LLVM似乎忽略了core::intrinsics::assume(..)个呼叫.它们最终会生成字节码,但不会更改生成的机器码.例如,以以下(无意义的)代码为例:

pub fn one(xs: &mut Vec<i32>) {
    if let Some(x) = xs.pop() {
        xs.push(x);
    }
}

这将编译成大量的程序集:

example::one:
        push    rbp
        push    r15
        push    r14
        push    r12
        push    rbx
        mov     rbx, qword ptr [rdi + 16]
        test    rbx, rbx
        je      .LBB0_9
        mov     r14, rdi
        lea     rsi, [rbx - 1]
        mov     qword ptr [rdi + 16], rsi
        mov     rdi, qword ptr [rdi]
        mov     ebp, dword ptr [rdi + 4*rbx - 4]
        cmp     rsi, qword ptr [r14 + 8]
        jne     .LBB0_8
        lea     rax, [rsi + rsi]
        cmp     rax, rbx
        cmova   rbx, rax
        mov     ecx, 4
        xor     r15d, r15d
        mov     rax, rbx
        mul     rcx
        mov     r12, rax
        setno   al
        jo      .LBB0_11
        mov     r15b, al
        shl     r15, 2
        test    rsi, rsi
        je      .LBB0_4
        shl     rsi, 2
        mov     edx, 4
        mov     rcx, r12
        call    qword ptr [rip + __rust_realloc@GOTPCREL]
        mov     rdi, rax
        test    rax, rax
        je      .LBB0_10
.LBB0_7:
        mov     qword ptr [r14], rdi
        mov     qword ptr [r14 + 8], rbx
        mov     rsi, qword ptr [r14 + 16]
.LBB0_8:
        or      ebp, 1
        mov     dword ptr [rdi + 4*rsi], ebp
        add     qword ptr [r14 + 16], 1
.LBB0_9:
        pop     rbx
        pop     r12
        pop     r14
        pop     r15
        pop     rbp
        ret
.LBB0_4:
        mov     rdi, r12
        mov     rsi, r15
        call    qword ptr [rip + __rust_alloc@GOTPCREL]
        mov     rdi, rax
        test    rax, rax
        jne     .LBB0_7
.LBB0_10:
        mov     rdi, r12
        mov     rsi, r15
        call    qword ptr [rip + alloc::alloc::handle_alloc_error@GOTPCREL]
        ud2
.LBB0_11:
        call    qword ptr [rip + alloc::raw_vec::capacity_overflow@GOTPCREL]
        ud2

现在,我们可以引入一个假设,即xs之后不是满的(容量)

#![feature(core_intrinsics)]

pub fn one(xs: &mut Vec<i32>) {
    if let Some(x) = xs.pop() {
        unsafe {
            core::intrinsics::assume(xs.len() < xs.capacity());
        }
        xs.push(x);
    }
}

然而,尽管LLVM字节码中出现了assume个字节码,但程序集是

pub fn one(xs: &mut Vec<i32>) {
    if let Some(x) = xs.pop() {
        if xs.len() >= xs.capacity() {
            unsafe { core::hint::unreachable_unchecked() }
        }
        xs.push(x);
    }
}

我们得到以下信息:

example::one:
        mov     rax, qword ptr [rdi + 16]
        test    rax, rax
        je      .LBB0_2
        mov     qword ptr [rdi + 16], rax
.LBB0_2:
        ret

这基本上是一个无操作,但也不太糟糕.当然,我们可以通过以下方式保留价值:

pub fn one(xs: &mut Vec<i32>) {
    xs.last_mut().map(|_e| ());
}

总结出我们的预期:

example::one:
        ret

为什么LLVM似乎忽略了assume个内在变量?

推荐答案

由于rustc和LLVM的改进,这now compiles to just a ret个版本将在最新版本的rustc上运行.LLVM忽略了内在特性,因为它以前无法对其进行优化,但现在它有能力更好地优化它.

Rust相关问答推荐

使用元组执行条件分支的正确方法

如果A == B,则将Rc A下推到Rc B

为什么铁 rust S似乎有内在的易变性?

如何删除Mac Tauri上的停靠图标?

为什么我们需要std::thread::scope,如果我们可以使用thread.join()在函数的生命周期内删除引用?

如何修复数组中NewType导致的运行时开销

用于判断整数块是否连续的SIMD算法.

返回Result<;(),框<;dyn错误>>;工作

考虑到Rust不允许多个可变引用,类似PyTorch的自动区分如何在Rust中工作?

根据掩码将 simd 通道设置为 0 的惯用方法?

Rust 1.70 中未找到 Trait 实现

如何使用 Bincode 在 Rust 中序列化 Enum,同时保留 Enum 判别式而不是索引?

如何获取模块树?

pyO3 和 Panics

为什么 for_each 在释放模式(cargo run -r)下比 for 循环快得多?

如何使返回 XMLError 的方法与 anyhow::Error 兼容?

返回引用字符串的future

如何在 nom 中构建负前瞻解析器?

Rust - 在线程之间不安全地共享没有互斥量的可变数据

TinyVec 如何与 Vec 大小相同?