Hi everyone,

I believe that by-move pattern bindings don't actually have to perform any copying of bits for non-word-sized values. This applies to both `let` and `match`. It surprised me too, which is why I thought I'd send it to the mailing list first.

A by-move pattern binding is any binding not denoted by `ref`:

    let x = Some(HashMap::new());
    //  ^
    match x {
        None => ...,
        Some(map) => ...
        //   ^^^
    }

You might think that, for each by-move pattern binding, we have to generate a slot on the stack with the size of the binding and copy in all the bytes that correspond to that stack slot. Indeed, this is what we generate today. So, for the above code, we would have two stack slots, each 88 bytes long. The match expression would generate a shallow memory copy from the stack to the stack. Since there are 88 bytes, that's a lot of bytes to copy. In fact, this function is 500-1000 bytes of x86-64 assembly code, even when optimized.

I believe that we can eliminate this by converting non-word-sized (non-"immediate" in the compiler jargon) pattern bindings to references instead. Justification:

1. Every by-move pattern binding is moving out of something that can legally be moved out of in Rust.

2. The only things that can be moved out of in Rust are locals and rvalues.

3. Locals have stack slots already assigned to them. Since those stack slots are hoisted allocas, they will stick around for the lifetime of the pattern binding, since pattern bindings are locals. So it makes no sense to allocate a new slot for this.

4. Rvalues already have scratch space allocated for them (unless they are "destination-passing-style" rvalues--more on that later), so a similar argument applies.

5. We already treat non-word-sized values as pointers in codegen; we don't use LLVM first class aggregates. So all of the code that deals with aggregates in trans does not have to change.

Combined with the zeroing out optimization, this should remove a lot of useless moves. The remaining, more difficult, issue is initialization of aggregate data structures via constructor functions, which still involves a bunch of moves, but I don't really see any way short of macros to optimize that at the moment.

Thoughts? :)

Patrick
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to