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

Unused format!()s are not optimised away #75742

Open
Timmmm opened this issue Aug 20, 2020 · 4 comments
Open

Unused format!()s are not optimised away #75742

Timmmm opened this issue Aug 20, 2020 · 4 comments
Labels
A-mir-opt Area: MIR optimizations I-slow Issue: Problems and improvements with respect to performance of generated code. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@Timmmm
Copy link
Contributor

Timmmm commented Aug 20, 2020

I was slightly surprised to see that code like this:

pub fn foo() {
    format!("Hello {}", 4);
}

does not get optimised to a nop. It still calls format!(). This is surprising from a user point of view - you're calling a function, but it seems like it has no side effects and I don't use the result, so surely it should be removed?

I presume the reason it doesn't is that it allocates a String and heap allocation is considered to be a side effect? Whatever the reason I think that it would be nice if it was optimised.

If you're wondering about motivation, consider a debug trait with a default implementation that does nothing. You could call debug.write(&format!(...)) and it would be fully optimised away for the default implementation.

@nbdd0121
Copy link
Contributor

nbdd0121 commented Aug 22, 2020

struct Foo;
impl fmt::Display for Foo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        panic!();
    }
}

pub fn foo() {
    format!("{}", Foo);
}

There is just no guarantee that Display of an arbitrary type have no side-effects. It is true that it is side-effect free for i32, but it is beyond the capability of rustc to take advantage of that.

In other word: alloc::fmt::format isn't pure. It might be pure for some Argument, but we've lost that information already.

@pickfire
Copy link
Contributor

pickfire commented Aug 24, 2020

Is there any other samples other than panic!()? Wouldn't format!() here be optimized out already since it will panic? Would using const help since it should be side-effect free?

@nbdd0121
Copy link
Contributor

You can replace the panic!() there with a println!("Executed");

@tmiasko
Copy link
Contributor

tmiasko commented Aug 30, 2020

consider a debug trait with a default implementation that does nothing. You could call debug.write(&format!(...)) ...

Did you mean write trait implementation that does nothing?

The formatting in format macro is eager and so it does have side-effects, but
they are usually localized to a single memory buffer. To remove the formatting
code, the optimizer would not only have to see that the result of formatting is
unused, but also see through all the code responsible for the formatting.

At the same time there is an alternative that avoids cost of formatting when
left unused, and doesn't rely on compiler optimizations to do so: write_fmt +
format_args. Furthermore, if optimizer can determine that write_fmt happens to
be no-op, it can be easily optimized out together with format_args.

@camelid camelid added the A-mir-opt Area: MIR optimizations label Oct 20, 2020
@Enselic Enselic added I-slow Issue: Problems and improvements with respect to performance of generated code. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Dec 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-mir-opt Area: MIR optimizations I-slow Issue: Problems and improvements with respect to performance of generated code. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants