我可以强制Rust不优化单个函数吗?

Mat*_*ias 10 optimization rust llvm-codegen

我有一个功能,Rust的/ LLVM的优化失败并导致恐慌(在发布版本中),而未优化的代码(调试版本)工作正常.如果我比较生成的汇编代码,我甚至无法理解优化器试图完成的任务.(原因可能是这个函数使用内联汇编程序.)

有没有办法告诉Rust在优化过程中单独保留某些功能,还是必须关闭所有优化?

这是具体功能:

#[naked]
pub extern "C" fn dispatch_svc(){
    Cpu::save_context();
    let mut nr: u32 = 0;
    unsafe {
        asm!("ldr r0, [lr, #-4]
              bic $0, r0, #0xff000000":"=r"(nr)::"r0":"volatile")
    };
    swi_service_routine(nr);
    Cpu::restore_context_and_return();
}
Run Code Online (Sandbox Code Playgroud)

Jul*_*ers 6

据我所知,除了整个箱子之外,Rust没有任何设施来指定优化级别.您唯一的解决方法是在单个包中编译此函数,编译它,然后将其作为预编译依赖项包含在内.(正常的rust-dependencies在依赖项的优化级别编译)

但是:为此单个函数指定不同的优化级别将无法解决您的问题!当然,它今天可能会起作用,但每次编译器(或优化标志)发生变化时都会再次中断.

TL; DR:裸体功能非常不安全(我的尊重,你是一个比我更勇敢的人!).使用它们的唯一可靠方法是只将一个asm!()块写为整个函数体,而不是其他任何块.asm!正如你所做的那样混合,正常的Rust和函数调用实际上是未定义的行为(在可怕的C/Nasal-Demon意义上)没有任何优化调整会改变这一点.


裸体函数仍然不稳定,直到Rust作者"正确".正如您所发现的,这有许多微妙的问题.跟踪稳定问题

裸体RFC中,在"Motivation"下,我们发现:

因为编译器依赖于函数序言和结尾来维护局部变量绑定的存储,所以在裸函数内写入除内联汇编之外的任何东西通常都是不安全的.LLVM语言参考将此功能描述为具有"非常系统特定的后果",程序员必须注意这些后果.

(强调我的)

在RFC中稍微低一些,在未解决的问题下,我们了解到这不仅仅是Rust的一个问题.其他语言也遇到此功能的问题:

..大多数支持类似功能的编译器要求或强烈建议作者在裸函数内只编写内联汇编,以确保不会生成假定特定堆栈布局的代码.

原因是所有编译器都对如何调用函数做了很多假设(关键字:"Caller-Saved Registers","Callee-saved register","Calling convention","Red zone").裸函数不遵守这些假设,因此编译器生成的任何代码都很可能是错误的."解决方案"是不让编译器生成任何东西,即在汇编中手动编写整个函数.

因此,在裸函数中混合"普通"code(let mut nr: u32 = 0; ),函数调用(swi_service_routine(nr);)和原始汇编程序的方式是未指定的行为.(是的,这样的东西存在于Rust中,但只存在于Unstable中).

裸函数会导致足够的问题,他们在Rust bugtracker中应该得到自己的标签.在其中一个A-naked问题中,我们通过知识渊博的用户Tari(其中包括作者)发现了这一评论llvm-sys.他解释说:

裸函数中非asm代码的实际正确性取决于优化器和代码生成器,通常我们无法保证它将执行的操作.

还有关于要求unsafe裸功能的讨论,因为它们破坏了Rust的许多正常假设.事实上,他们在所有情况下都不需要这个是一个开放的错误


因此,对"优化问题" 的正确解决方案是停止依赖优化.相反,只写一个asm!()块.

对于你的Cpu::save_context()/ Cpu::restore_context_and_return()pair:我可以理解代码重用的愿望.为了得到它,将它们更改为插入相关的宏asm!(...).串联asm!(...); asm!(...); asm!(...); 应该等同于单个asm!().


小智 -5

如果您使用货物,您可以告诉它根本不优化任何内容,或者按级别优化

货物优化

  • 谢谢,但我知道这种全局优化。问题是是否有更细粒度的控制。 (5认同)