Why does rust use -O3 for release builds instead of -O2?

Hello! I hope that you are doing well.

I recently found that that rustc by default uses the equivalent to -O3 when compiling for release builds. I find this odd as there is a lot of data on the internet that implies that -O2 sometimes beats -O3 because of less coad bloat, and -O3 can cause weird program behaviour, and possibly other things I can’t really remember right now.

Is there any deeper reason for choosing this flag for release builds?

Thanks!

Twenty years ago option O3 was not working fully reliable for C and C++. But today O3 should be fine, and when you find a case where O2 is faster than O3, it is some form of a bug that you should report to the compiler devs. O2 might give smaller executables (e.g. no loop unrolling) and might compile a bit faster, so there are use cases for O2. More interesting is the use of LTO and PGO -- LTO can drastically increase compile times, and PGO can is some cases significantly improve performance. But both might not work fully reliable.

1 Like

This discussion may be relevant:

#t-compiler/major changes > Changing `-O` to `opt-level=3` compiler-team#828 - rust-lang - Zulip

1 Like

Note that -Ox means a little bit different things for GCC and LLVM - they enable different optimizations.
For confusing example, GCC started with mainly -Os, -O2, -O3. LLVM softened meaning of -Os and then LLVM added -Oz which is conceptually closer to GCC's -Os.
From what I heard similar thing happened to -O3 - LLVM ecosystem changed the recomended default to -O3, and so -O3 had to become a bit more balanced than GCC's -O3.
So -Ox recomendations for GCC may not apply to LLVM and vice versa.

If you only care about performace, -O3 should not be bad in either case these days.
Though there are some cases where the bigger size matters for performace, the main example is that less of your code can fit into processor cache.

TLDR: Culturally GCC defaults to -O2 and LLVM to -O3. If you do not care, they are mostly the same. If you do care, test the difference.

9 Likes

Note also that some people discouraged use of -O3 for C/C++ because of the nature of UB in those languages. In C, you might write some code that's subtly UB, that the optimizer consequently optimizes in a way that breaks your program. The same issue isn't prevalent in Rust, because of how it handles unsafe code and UB, so it's safe to apply much more aggressive optimizations.

5 Likes

Makes sense, Thanks!

Thanks to everyone for replying with their respective POVs!