Consider aggressively avoiding generating memcpys for moves if we can avoid it

053c099
Opened by Patrick Walton at 2020-05-14 20:14:43

Given that our assembler output tends to have a lot of moves in it and LLVM is bad at optimizing them out, I'm beginning to wonder if we shouldn't take more aggressive steps. For example:

  • Convert (non-POD?) by-value move parameters in the Rust ABI to be passed by reference.
  • Non-immediate values that go dead by dint of being moved into a new place should not be memcpy'd there.

Any others?

  1. Is there any reason to use memcpy instead of a load instruction when we're only copying a single element with a known type? It seems like the reasons for doing it may no longer be true. If the issue is that it generates poor code with large types and --opt-level=0 we could teach LLVM to output a memcpy for those loads (if it doesn't already).

    Daniel Micay at 2014-04-23 21:06:42

  2. Triage: no change

    Steve Klabnik at 2015-04-20 22:36:31

  3. Triage: I know @pcwalton was doing some work on a related area recently, but don't believe it bore any fruit.

    Steve Klabnik at 2016-11-15 21:10:58

  4. I'm going to resurrect this bug as a tracking bug for various bad memcpy instances.

    Here's one that has been affecting Stylo (cc @bholley): https://bugzilla.mozilla.org/show_bug.cgi?id=1380198

    Patrick Walton at 2017-07-12 01:39:21

  5. Let's close this or actually treat it as a tracking bug and put more details in it, it's not currently very actionable. I vote for closing it. Cc @rust-lang/compiler @rust-lang/wg-codegen

    Anthony Ramine at 2018-03-31 08:25:00

  6. I think we can address a few of these issues with mir optimizations and ABI adjustments as noted above.

    • ABI: large by move values are actually just passed as pointers to the memory, expose this in MIR so we can do fancy stuff like deduplicating large in let large = foo(large); if foo does return the argument again (after modifications).
    • dedup locals (in MIR, not sure how good of an idea that is) let foo = large; drop(foo); let bar = other_large; (foo and bar should have the same local)

    Oli Scherer at 2018-03-31 08:57:32

  7. The plan is getting something like #47954 into the compiler in the coming months.

    Eduard-Mihai Burtescu at 2018-04-01 14:24:15

  8. @oli-obk your last point can be achieved by moving the StorageDead earlier (shrinking "storage liveness ranges"), which will result in LLVM reusing the stack space.

    Eduard-Mihai Burtescu at 2018-04-01 14:27:46