Hello Everyone,

I've been doing work around optimizations recently, and noticed that libextra 
was taking an 
inordinate amount of time to build. My investigations led me to find that well 
over half the time 
spent was on Loop Invariant Code motion, i.e. moving expressions that don't 
change out of the loop.

One of the more common cases turns this:

    while i < n {
        data.field[i] = something(i);
        i += 1;
    }

into this:

   let tmp = data.field;
   while i < n {
       tmp[i] = something(i);
   }

since, the field access is invariant.

Anyway, the BigInt module uses this pattern a lot. It also has 112 functions 
marked with 
#[inline(always)]. This does two things: causes massive code bloat, 2 orders of 
magnitude worth of 
code bloat, and makes later passes work much, much harder. Many of the 
functions in BigInt would 
have been inlined multiple times into one function, and in some cases, those 
functions would be 
further inlined into other functions, despite blowing past the normal inline 
cost limit.

This meant that a fairly simple, standard pass, was being called on over 100x 
more code than it 
needed to be. If you want to know why a full build takes so long, there is why.

Inlining is a pretty standard optimization, and is potentially done for every 
function that isn't 
marked with `#[inline(never)]`, but the compiler is smart enough to know when 
it's not worth it.  
`#[inline(always)]` is a very strong statement, and should be reserved for 
cases where you are 
certain that the function absolutely needs to be inlined, no exceptions. 
Remember that "always" 
means it, so every single function that uses it will get a copy.

Inlining is not a magic bullet for performance and the compiler passes are far 
smarter at knowing 
what is more efficient than you are.

Thank you for your time,
James Miller
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to