首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么铁锈编译器不能优化掉Box::downcast的错误臂?

为什么铁锈编译器不能优化掉Box::downcast的错误臂?
EN

Stack Overflow用户
提问于 2018-09-13 22:33:25
回答 1查看 488关注 0票数 10

我有一个Box<dyn Any>,我知道底层类型,所以我想优化Box::downcast() (来源)中的测试。

首先我试着用std::hint::unreachable_unchecked()

代码语言:javascript
复制
pub unsafe fn downcast() -> Box<i32> {
    let value = any();
    if let Ok(value) = value.downcast() {
        value
    } else {
        std::hint::unreachable_unchecked()
    }
}

代码语言:javascript
复制
pub unsafe fn downcast() -> Box<i32> {
    any().downcast().map_err(|_| std::hint::unreachable_unchecked()).unwrap()
}

对于rustc -C opt-level=3,两者都会产生这样的结果(省略40行):

代码语言:javascript
复制
example::downcast:
        push    rbx
        sub     rsp, 16
        call    any@PLT
        mov     rbx, rax
        mov     qword ptr [rsp], rax
        mov     qword ptr [rsp + 8], rdx
        mov     rdi, rax
        call    qword ptr [rdx + 24]
        mov     rax, rbx
        add     rsp, 16
        pop     rbx
        ret
        mov     rbx, rax
        mov     rdi, rsp
        call    core::ptr::drop_in_place
        mov     rdi, rbx
        call    _Unwind_Resume@PLT
        ud2

因为这不是我想要的优化,所以我尝试了

代码语言:javascript
复制
pub unsafe fn downcast() -> Box<i32> {
    let value = any();
    std::intrinsics::assume(value.is::<i32>());
    value.downcast().unwrap()
}

但情况更糟了(省略了118行):

代码语言:javascript
复制
example::downcast:
        push    r15
        push    r14
        push    rbx
        sub     rsp, 32
        call    any@PLT
        mov     rbx, rax
        mov     r14, rdx
        mov     qword ptr [rsp], rax
        mov     qword ptr [rsp + 8], rdx
        mov     r15, qword ptr [rdx + 24]
        mov     rdi, rax
        call    r15
        mov     qword ptr [rsp + 16], rbx
        mov     qword ptr [rsp + 24], r14
        mov     rdi, rbx
        call    r15
        movabs  rcx, -5015437470765251660     ;TypeId::of::<i32>()
        cmp     rax, rcx
        jne     .LBB5_7
        mov     rax, rbx
        add     rsp, 32
        pop     rbx
        pop     r14
        pop     r15
        ret
.LBB5_7:
        mov     rdi, rbx
        mov     rsi, r14
        call    core::result::unwrap_failed
        ud2
        mov     rbx, rax
        lea     rdi, [rsp + 16]
        call    core::ptr::drop_in_place
        mov     rdi, rbx
        call    _Unwind_Resume@PLT
        ud2
        mov     rbx, rax
        mov     rdi, rsp
        call    core::ptr::drop_in_place
        mov     rdi, rbx
        call    _Unwind_Resume@PLT
        ud2

我希望生成这样的代码,这是来自Box::downcastBox::downcast arm

代码语言:javascript
复制
pub unsafe fn downcast() -> Box<i32> {
    let value = any();
    let raw: *mut dyn Any = Box::into_raw(value);
    Box::from_raw(raw as *mut i32)
}

其结果是(行省略):

代码语言:javascript
复制
example::downcast:
        push    rax
        call    any@PLT
        pop     rcx
        ret

为什么编译器不能这样优化代码呢?

全装配戈德波特

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-01-18 19:07:23

让我们尽可能地手工优化您的代码。如果手动内联downcast(),就会得到以下内容:

代码语言:javascript
复制
pub unsafe fn downcast() -> Box<i32> {
    let value = any();
    if value.is::<i32>() {
        let raw: *mut Any = Box::into_raw(value);
        Box::from_raw(raw as *mut i32)
    } else {
        std::hint::unreachable_unchecked()
    }
}

我们可以改变这一点:

代码语言:javascript
复制
pub unsafe fn downcast() -> Box<i32> {
    let value = any();
    value.is::<i32>();
    let raw: *mut Any = Box::into_raw(value);
    Box::from_raw(raw as *mut i32)
}

value.is::<i32>()未使用!我们能把它移走吗?问题就在这里。

is方法对一个dyn Any对象调用get_type_id。该方法只能在运行时确定。,它可能有副作用,。因此,可以删除而不是

您可以从以下函数中看到与示例中相同的冗长汇编代码:

代码语言:javascript
复制
#![feature(get_type_id)]
pub fn nop(any: Box<dyn Any>) {
    any.get_type_id();
}

现在,您可能会争辩说,Any::get_type_id是由编译器定义的,不能被重写,但是编译器还不够聪明,无法意识到这一点。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52322608

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档