简体   繁体   English

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

[英]Can I force Rust to not optimize a single function?

I have a function where Rust's/LLVM's optimization fails and leads to a panic (in the release version), while the unoptimized code (debug version) just works fine. 我有一个功能,Rust的/ LLVM的优化失败并导致恐慌(在发布版本中),而未优化的代码(调试版本)工作正常。 If I compare the generated assembly code, I can not even grasp an idea what the optimizer tries to accomplish. 如果我比较生成的汇编代码,我甚至无法理解优化器试图完成的内容。 (A reason might be that this very function uses inline assembler.) (原因可能是这个函数使用内联汇编程序。)

Is there any way to tell Rust to leave certain functions alone during the optimisation, or do I have to switch off all optimizations? 有没有办法告诉Rust在优化过程中单独保留某些功能,还是必须关闭所有优化?

Here is the specific function: 这是具体功能:

#[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();
}

To the best of my knowledge, Rust has no facilities to specify optimisation levels on anything but the entire crate. 据我所知,除了整个箱子之外,Rust没有任何设施来指定优化级别。 Your only workaround would be to compile this function in an individual crate, compile it, and then include it as a pre-compiled dependency. 您唯一的解决方法是在单个包中编译此函数,编译它,然后将其作为预编译依赖项包含在内。 (Normal rust-dependencies are compiled at the optimisation level of the depender) (正常的rust-dependencies在依赖项的优化级别编译)

However: Specifying a different optimisation level for this single function will not solve your problem! 但是:为此单个函数指定不同的优化级别将无法解决您的问题! Sure, it may work today, but can break again each time the compiler (or optimisation flags) change. 当然,它今天可能会工作,但每次编译器(或优化标志)发生变化时都会再次中断。

TL;DR : naked functions are deeply unsafe (My respect, you're a braver person than I am!). TL; DR :裸体功能非常不安全(我的尊重,你是一个比我更勇敢的人!)。 The only reliable way to use them is to write only one single asm!() block as the entire function body, nothing else. 使用它们的唯一可靠方法是只编写一个asm!()块作为整个函数体,没有别的。 Mixing asm! 混合asm! , normal Rust and function calls like you are doing is effectively Undefined Behaviour (in the scary C/Nasal-Demon sense of the term) No amount of optimisation-tweaking will change this. ,正常的Rust和函数调用就像你正在做的那样是有效的Undefined Behavior(在可怕的C / Nasal-Demon意义上的术语) 没有多少优化调整会改变这一点。


Naked functions are still unstable until the Rust authors "get it right". 裸体函数仍然不稳定,直到Rust作者“正确”。 As you have discovered, there are many subtle problems with this. 正如您所发现的,这有许多微妙的问题。 Tracking issue for stabilisation here 跟踪稳定问题

In the naked-fn RFC , under "Motivation", we find: 裸体RFC中 ,在“Motivation”下,我们发现:

Because the compiler depends on a function prologue and epilogue to maintain storage for local variable bindings, it is generally unsafe to write anything but inline assembly inside a naked function . 因为编译器依赖于函数序言和结尾来维护局部变量绑定的存储,所以在裸函数内写入除内联汇编之外的任何东西通常都是不安全的 The LLVM language reference describes this feature as having "very system-specific consequences", which the programmer must be aware of. LLVM语言参考将此功能描述为具有“非常系统特定的后果”,程序员必须注意这些后果。

(emphasis mine) (强调我的)

A little bit lower in the RFC, under unresolved questions , we learn that this is not just a problem for Rust. 在RFC中稍微低一些,在未解决的问题下 ,我们了解到这不仅仅是Rust的一个问题。 Other languages also experience problems with this feature: 其他语言也遇到此功能的问题:

.. most compilers supporting similar features either require or strongly recommend that authors write only inline assembly inside naked functions to ensure no code is generated that assumes a particular stack layout. ..大多数支持类似功能的编译器要求或强烈建议作者在裸函数内只编写内联汇编,以确保不会生成假定特定堆栈布局的代码。

The reason is that all compilers make a LOT of assumptions about how functions are called (keywords: "Caller-Saved Registers", "Callee-saved registers", "Calling convention", "Red zone") . 原因是所有编译器都对如何调用函数做了很多假设(关键字:“Caller-Saved Registers”,“Callee-saved register”,“Calling convention”,“Red zone”)。 Naked functions don't obey these assumptions, and thus any code a compiler generates is highly likely to be wrong. 裸函数不遵守这些假设,因此编译器生成的任何代码都很可能是错误的。 The "solution" is to not let the compiler generate anything, ie write the entire function by hand in assembly. “解决方案”是不让编译器生成任何东西,即在汇编中手动编写整个函数。

As such, the way you are mixing 'normal' code ( let mut nr: u32 = 0; ), function calls ( swi_service_routine(nr); ) and raw assembler in a naked function is unspecified behaviour . 因此,混合“普通”代码( let mut nr: u32 = 0; ),函数调用( swi_service_routine(nr); )和裸函数中的原始汇编程序的方式是未指定的行为 (Yes, such a thing exists in Rust, but only in Unstable). (是的,这样的东西存在于Rust中,但只存在于Unstable中)。

Naked functions cause enough problems that they deserve their own label in the Rust bugtracker. 裸函数会导致足够的问题,他们在Rust bugtracker中应该得到自己的标签 In one of the A-naked issues, we find this comment , by knowledgeable user Tari (among others, author of llvm-sys . He explains: 在其中一个A-naked问题中,我们通过知识渊博的用户Tari(其中包括llvm-sys作者)发现了这个评论 。他解释说:

The actual correctness of non-asm code in naked functions depends on the optimizer and code generator, which in general we cannot make any guarantees about what it will do. 裸函数中非asm代码的实际正确性取决于优化器和代码生成器,通常我们无法保证它将执行的操作。

There is also talk about requiring unsafe for naked functions, as they break many of Rust's normal assumptions. 还谈到要求裸体功能unsafe ,因为它们破坏了Rust的许多正常假设。 The fact that they don't require this yet in all cases is an open bug 事实上,他们在所有情况下都不需要这个是一个开放的错误


So, the proper solution to your "optimisation problem" is to stop relying on optimisation at all. 因此,对“优化问题”的正确解决方案是停止依赖优化。 Instead, write only a single asm!() block. 相反,只写一个asm!()块。

For your Cpu::save_context() / Cpu::restore_context_and_return() pair: I can understand the desire for code-reuse. 对于你的Cpu::save_context() / Cpu::restore_context_and_return()对:我可以理解代码重用的愿望。 To get it, change those into a macro that inserts the relevant asm!(...) . 为了得到它,将它们更改为插入相关asm!(...)的宏asm!(...) A concatenation of asm!(...); asm!(...); asm!(...); asm!(...); asm!(...); asm!(...);的串联asm!(...); asm!(...); asm!(...); asm!(...); asm!(...); asm!(...); should be equivalent to a single asm!() . 应该相当于一个asm!()

If you are using cargo, you can tell it not to optimize anything at all, or by levels 如果您正在使用货物,您可以告诉它不要优化任何东西,或按级别优化

cargo optimize 货物优化

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM