4 ms·
Since LLVM does not have the necessary information to do the optimizations, I wonder whether the same problem occurs in C++ code compiled with clang.
by domoritz 10y ago
Since LLVM does not have the necessary information to do the optimizations, I wonder whether the same problem occurs in C++ code compiled with clang.
- msbarnett 10y agoIt may not. It's possible that this may be happening because rustc is failing to mark the reference as both readonly and unaliased, whereas clang might mark the equivalent as both. You'd need to examine the IR from both front ends to really figure out the source of any differences in the generated ASM
- shepmaster 10y agoBoth Rust playgrounds (official[1], my take[2]) allow viewing the LLVM IR of a Rust program. The call to the print is call void @_ZN3std2io5stdio6_print17h690779b3bd8114d5E(%"core::fmt::Arguments"* noalias nocapture nonnull dereferenceable(48) %_3) The entire chunk of `main` preceding that call: %size = alloca i64, align 8 %_3 = alloca %"core::fmt::Arguments", align 8 %_8 = alloca [1 x %"core::fmt::ArgumentV1"], align 8 %0 = bitcast i64* %size to i8* call void @llvm.lifetime.start(i64 8, i8* %0) store i64 33554432, i64* %size, align 8 %1 = bitcast %"core::fmt::Arguments"* %_3 to i8* call void @llvm.lifetime.start(i64 48, i8* %1) %2 = bitcast [1 x %"core::fmt::ArgumentV1"]* %_8 to i8* call void @llvm.lifetime.start(i64 16, i8* %2) %3 = ptrtoint i64* %size to i64 %4 = bitcast [1 x %"core::fmt::ArgumentV1"]* %_8 to i64* store i64 %3, i64* %4, align 8 %5 = getelementptr inbounds [1 x %"core::fmt::ArgumentV1"], [1 x %"core::fmt::ArgumentV1"]* %_8, i64 0, i64 0, i32 1 %6 = bitcast i8 (%"core::fmt::Void"*, %"core::fmt::Formatter"*)** %5 to i64* store i64 ptrtoint (i8 (i64*, %"core::fmt::Formatter"*)* @"_ZN4core3fmt3num54_$LT$impl$u20$core..fmt..Display$u20$for$u20$usize$GT$3fmt17hb872170870cc06d9E" to i64), i64* %6, align 8 %7 = getelementptr inbounds [1 x %"core::fmt::ArgumentV1"], [1 x %"core::fmt::ArgumentV1"]* %_8, i64 0, i64 0 %8 = getelementptr inbounds %"core::fmt::Arguments", %"core::fmt::Arguments"* %_3, i64 0, i32 0, i32 0 store %str_slice* getelementptr inbounds ([2 x %str_slice], [2 x %str_slice]* @ref.8, i64 0, i64 0), %str_slice** %8, align 8, !alias.scope !1, !noalias !4 %9 = getelementptr inbounds %"core::fmt::Arguments", %"core::fmt::Arguments"* %_3, i64 0, i32 0, i32 1 store i64 2, i64* %9, align 8, !alias.scope !1, !noalias !4 %_6.sroa.0.0..sroa_idx.i = getelementptr inbounds %"core::fmt::Arguments", %"core::fmt::Arguments"* %_3, i64 0, i32 1, i32 0, i32 0 store %"core::fmt::rt::v1::Argument"* null, %"core::fmt::rt::v1::Argument"** %_6.sroa.0.0..sroa_idx.i, align 8, !alias.scope !1, !noalias !4 %10 = getelementptr inbounds %"core::fmt::Arguments", %"core::fmt::Arguments"* %_3, i64 0, i32 2, i32 0 store %"core::fmt::ArgumentV1"* %7, %"core::fmt::ArgumentV1"** %10, align 8, !alias.scope !1, !noalias !4 %11 = getelementptr inbounds %"core::fmt::Arguments", %"core::fmt::Arguments"* %_3, i64 0, i32 2, i32 1 store i64 1, i64* %11, align 8, !alias.scope !1, !noalias !4 call void @_ZN3std2io5stdio6_print17h690779b3bd8114d5E(%"core::fmt::Arguments"* noalias nocapture nonnull dereferenceable(48) %_3) [1]: https://play.rust-lang.org/ https://play.rust-lang.org/ [2]: http://play.integer32.com/ http://play.integer32.com/
- msbarnett 10y agoAm I reading it right? It looks to me like rustc didn't mark the immutable borrow as readonly, so LLVM went ahead and assumed print could mutate it.
- dbaupp 10y agoI'm not 100% sure, but I believe LLVM doesn't have a way to understand the (im)mutability of pointers rewritten into memory, like the borrow is here.
- sharth 10y agoIn this particular case, you'd likely be using printf or cout, both of which perform a copy of integer parameters. So you wouldn't see this there.
- deleted 10y ago[deleted]
- DannyBee 10y agoIt depends on the system. First, the int would be by value anyway, so it wouldn't matter. But assume you handed it a pointer instead. Some are properly marked readonly in declarations, some are not[1] But this is a common problem with unmarked logging. The compiler will infer attributes all the way through things it has bitcode for. (IE it can determine it to be readonly, readnone, whatever, as long as it can see calls to either functions marked readonly/readnone, or determine the called functions to be readonly/readnone) But, usually, if you don't give it the whole program, it can't infer that your logging function does not modify its arguments. [1] Fun fact: glibc allows printf handler registration: https://www.gnu.org/software/libc/manual/html_node/Customizing-Printf.html https://www.gnu.org/software/libc/manual/html_node/Customizi... So sadly, it's printf is not readonly, because it can do anything it wants in these callbacks. (nobody uses the printf registration, though, so it may be time to just add a compiler option required to make it work, and not screw everyone else using printf over)
- fnord123 10y agoIf you use printf and cout in the same program then yes you can have dramatic performance problems with cout unless you use `std::ios_base::sync_with_stdio(false);` It's not the same issue but it's the same area of stupid stuff you have to find out about and roll your eyes.