Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code bloat from monomorphization of methods applied to arrays #77767

Open
glandium opened this issue Oct 9, 2020 · 2 comments
Open

Code bloat from monomorphization of methods applied to arrays #77767

glandium opened this issue Oct 9, 2020 · 2 comments
Labels
A-array Area: `[T; N]` A-fmt Area: `std::fmt` C-enhancement Category: An issue proposing an enhancement or a PR with one. I-heavy Issue: Problems and improvements with respect to binary size of generated code.

Comments

@glandium
Copy link
Contributor

glandium commented Oct 9, 2020

The following talks about Debug::fmt, but is likely true of a lot more methods applied to arrays.
Take the following code:

fn main() {
    let a = [1, 2, 3];
    let b = [1, 2, 3, 4];
    let c = [1, 2, 3, 4, 5];
    let d = [1, 2, 3, 4, 5, 6];
    println!("{:?}", a);
    println!("{:?}", b);
    println!("{:?}", c);
    println!("{:?}", d);
}

Compiled with --release, you end up with 4 different functions for core::array::<impl core::fmt::Debug for [T; N]>::fmt (BTW, shouldn't they each have their N replaced by the actual number?). To add insult to injury, each of these have their loops unrolled, so the longer the array, the larger the function, up to 59 (!).
Almost ironically, building with -C opt-level=1 generates 4 functions that create a slice and a separate, common, fmt function for it.
This is one of these cases where you'd probably want a #[inline(never)] at the call site in core::array::<impl core::fmt::Debug for [T; N]>::fmt if that were possible.

@jonas-schievink jonas-schievink added A-fmt Area: `std::fmt` C-enhancement Category: An issue proposing an enhancement or a PR with one. I-heavy Issue: Problems and improvements with respect to binary size of generated code. labels Oct 9, 2020
@cuviper
Copy link
Member

cuviper commented Oct 9, 2020

This is one of these cases where you'd probably want a #[inline(never)] at the call site in core::array::<impl core::fmt::Debug for [T; N]>::fmt if that were possible.

We could insert a shim #[inline(never)] function to call the slice Debug::fmt.

For other traits, I'd worry about hurting bounds-checking and vectorization if we add artificial barriers.

@scottmcm
Copy link
Member

scottmcm commented Oct 11, 2020

Given that these things are already implemented by calling the slice versions, I don't know that there's actually anything array-specific here. This is just the inliner doing what it's told to do. The same thing will plausibly happen with impl AsRef<Path> methods with outlined bodies too in -O3.

Given that -O1 is doing the right thing here, I suspect -Os is too, which is the particularly-important part IMHO.

Even for debug it's not obvious to me that inline(never) is desirable here. I could easily imagine someone expecting monomorphization of something like <[u32; 4]>::debug because there's no other way to stringify such an array in std.

Note that neither the array nor slice implementations of Debug are currently even marked #[inline]:

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: fmt::Debug, const N: usize> fmt::Debug for [T; N] {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&&self[..], f)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Debug> Debug for [T] {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
f.debug_list().entries(self.iter()).finish()
}
}

so this is all LLVM's inlining heuristic deciding that this is a good bet with no extra encouragement.

Were you seeing a regression here? I suppose that this could have changed last summer when we started using const generics for them, or if one of the LLVM upgrades changed the inlining heuristics...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-array Area: `[T; N]` A-fmt Area: `std::fmt` C-enhancement Category: An issue proposing an enhancement or a PR with one. I-heavy Issue: Problems and improvements with respect to binary size of generated code.
Projects
None yet
Development

No branches or pull requests

5 participants