rust-lang/rust

Sub-optimal codegen for float newtypes

Closed this issue · 7 comments

It seems that floating point types wrapped in newtypes are passed to functions in general purpose registers instead of SIMD registers the way plain f32 and f64 are. Consider this code example in playpen.

Without inlining, add_f32() and add_f64() compile to a single instruction (plus return) while add_newtype_{f32|f64}() first have to move their arguments from a general purpose register perform the addition and move the result back to the GPR.

With inlining, the situation is better, but still not optimal. Once again, the functions defined on plain types work directly in SIMD registers and the loop now gets unrolled by a factor of 10. For the newtypes, the accumulator is still kept in a GPR, however the loop is unrolled by a factor of 5. Here, the accumulator is only moved from the GPR to a SIMD register at the start of a loop iteration and moved back at the end (after 5 additions have been performed).

I'm working on this

bluss commented

Probably the same issue as #24963

Apparently it will be more useful to tackle this when @eddyb is done with his current work on trans.

Hey, the situation here seems to have improved recently. The nightly compiler on playpen now produces the same code for bare f32/f64 and their newtype wrapped counterparts.

eddyb commented

@bsteinb Indeed, newtypes get unwrapped directly, for the Rust ABI at least. I think we might want a codegen test to avoid regressing on this matter.

After a bisection using the test case from #34241, I found that the commit that fixed this was 9a8b807.

This issue can be closed now.