Skip to content

librustc: Don't create extra alloca slot for by value bindings in match. - #15076

Merged
bors merged 4 commits into
rust-lang:masterfrom
luqmana:naim
Jul 3, 2014
Merged

librustc: Don't create extra alloca slot for by value bindings in match.#15076
bors merged 4 commits into
rust-lang:masterfrom
luqmana:naim

Conversation

@luqmana

Copy link
Copy Markdown
Contributor
structWith{x:int,f:NoCopy}#[no_mangle]fnbar(){let mine = With{x:3,f:NoCopy};match mine {
c => {foo(c);}}}#[no_mangle]fnfoo(_:With){}

Before:

defineinternalvoid@bar() unnamed_addr #1 {
entry-block:
%mine = alloca %"struct.With<[]>"%__llmatch = alloca %"struct.With<[]>"*
%c = alloca %"struct.With<[]>"%0 = getelementptrinbounds %"struct.With<[]>"* %mine, i320, i320storei643, i64*%0%1 = getelementptrinbounds %"struct.With<[]>"* %mine, i320, i321store %"struct.With<[]>"* %mine, %"struct.With<[]>"** %__llmatchbrlabel%case_body
case_body: ; preds = %entry-block%2 = load %"struct.With<[]>"** %__llmatch%3 = bitcast %"struct.With<[]>"* %2toi8*%4 = bitcast %"struct.With<[]>"* %ctoi8*callvoid@llvm.memcpy.p0i8.p0i8.i64(i8*%4, i8*%3, i648, i328, i1false)
%5 = load %"struct.With<[]>"* %ccallvoid@foo(%"struct.With<[]>"%5)
brlabel%join
join: ; preds = %case_bodyretvoid
}

After:

defineinternalvoid@bar() unnamed_addr #1 {
entry-block:
%mine = alloca %"struct.With<[]>"%c = alloca %"struct.With<[]>"*
%0 = getelementptrinbounds %"struct.With<[]>"* %mine, i320, i320storei643, i64*%0%1 = getelementptrinbounds %"struct.With<[]>"* %mine, i320, i321store %"struct.With<[]>"* %mine, %"struct.With<[]>"** %cbrlabel%case_body
case_body: ; preds = %entry-block%2 = load %"struct.With<[]>"** %c%3 = load %"struct.With<[]>"* %2callvoid@foo(%"struct.With<[]>"%3)
brlabel%join
join: ; preds = %case_bodyretvoid
}

r? @pcwalton

@pcwalton

Copy link
Copy Markdown
Contributor

Does this correctly handle:

let mut x = 3;
match x {
mut y => { y = 5; }
}

In that case you must actually create an extra slot.

@pcwalton

Copy link
Copy Markdown
Contributor

(Actually I don't think you need to create an extra slot per binding, but you should create one for the matched value.)

@pcwalton

Copy link
Copy Markdown
Contributor

@luqmana I think what you need to do is to make a temporary copy of the value in the head of the match if and only if the matched value is Copy AND (there are mutable by-value bindings OR the value is not Share). That's because Cells can mess things up too. For a first cut it may be simpler to just unconditionally make a temporary copy if the value is Copy.

This is great work BTW, thanks!

@pcwalton

Copy link
Copy Markdown
Contributor

I think this may be wrong in some cases: what about

match box Foo { x: String::new("hi") } {
box Foo { x } => ... use x ...
}

This might result in use-after-free. I think we may have to restrict the optimization to cases in which it's a local variable or an rvalue guaranteed to be on the stack that you're moving out of.

@pcwalton

Copy link
Copy Markdown
Contributor

@bors: retry

bors added a commit that referenced this pull request Jul 3, 2014
```Rust
struct With {
x: int,
f: NoCopy
}
#[no_mangle]
fn bar() {
let mine = With { x: 3, f: NoCopy };
match mine {
c => {
foo(c);
}
}
}
#[no_mangle]
fn foo(_: With) {}
```
Before:
```LLVM
define internal void @bar() unnamed_addr #1 {
entry-block:
%mine = alloca %"struct.With<[]>"
%__llmatch = alloca %"struct.With<[]>"*
%c = alloca %"struct.With<[]>"
%0 = getelementptr inbounds %"struct.With<[]>"* %mine, i32 0, i32 0
store i64 3, i64* %0
%1 = getelementptr inbounds %"struct.With<[]>"* %mine, i32 0, i32 1
store %"struct.With<[]>"* %mine, %"struct.With<[]>"** %__llmatch
br label %case_body
case_body: ; preds = %entry-block
%2 = load %"struct.With<[]>"** %__llmatch
%3 = bitcast %"struct.With<[]>"* %2 to i8*
%4 = bitcast %"struct.With<[]>"* %c to i8*
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %4, i8* %3, i64 8, i32 8, i1 false)
%5 = load %"struct.With<[]>"* %c
call void @foo(%"struct.With<[]>" %5)
br label %join
join: ; preds = %case_body
ret void
}
```
After:
```LLVM
define internal void @bar() unnamed_addr #1 {
entry-block:
%mine = alloca %"struct.With<[]>"
%c = alloca %"struct.With<[]>"*
%0 = getelementptr inbounds %"struct.With<[]>"* %mine, i32 0, i32 0
store i64 3, i64* %0
%1 = getelementptr inbounds %"struct.With<[]>"* %mine, i32 0, i32 1
store %"struct.With<[]>"* %mine, %"struct.With<[]>"** %c
br label %case_body
case_body: ; preds = %entry-block
%2 = load %"struct.With<[]>"** %c
%3 = load %"struct.With<[]>"* %2
call void @foo(%"struct.With<[]>" %3)
br label %join
join: ; preds = %case_body
ret void
}
```
r? @pcwalton
@borsbors closed this Jul 3, 2014
@bors
bors merged commit 77f72d3 into rust-lang:masterJul 3, 2014
@luqmana
luqmana deleted the naim branch July 5, 2014 02:46
bors added a commit that referenced this pull request Jul 5, 2014
Inadvertently changed the order in which destructors ran in certain cases with #15076.
Fixes#15438.
@huonw

huonw commented Jul 5, 2014

Copy link
Copy Markdown
Contributor

This apparently caused a 1 GB memory regression!

@huonw

huonw commented Jul 5, 2014

Copy link
Copy Markdown
Contributor

(IRC informs me that #15442 is the fix; nice catch @dotdash, nice fix @luqmana.)

@lilyball

Copy link
Copy Markdown
Contributor

I think this is the cause for the double-drop seen in #16151.

lnicola pushed a commit to lnicola/rust that referenced this pull request Jun 19, 2023
flip1995 pushed a commit to flip1995/rust that referenced this pull request Jun 26, 2025
…ust-lang#15076)
The lint will note `the end suggestion probably needs some adjustments
to use the expression result correctly` when the expr's is not unit. So
I extend this note to also appear when the expr is in an assignment.
changelog: [`branches_sharing_code`] fix misleading suggestions when in
assignment
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@luqmana@pcwalton@huonw@lilyball@bors