Skip to content

Commit e70ee12

Browse files
committed
auto merge of rust-lang#15921 : dotdash/rust/match_lifetimes, r=pcwalton
The allocas used in match expression currently don't get good lifetime markers, in fact they only get lifetime start markers, because their lifetimes don't match to cleanup scopes. While the bindings themselves are bog standard and just need a matching pair of start and end markers, they might need them twice, once for a guard clause and once for the match body. The __llmatch alloca OTOH needs a single lifetime start marker, but when there's a guard clause, it needs two end markers, because its lifetime ends either when the guard doesn't match or after the match body. With these intrinsics in place, LLVM can now, for example, optimize code like this: ````rust enum E { A1(int), A2(int), A3(int), A4(int), } pub fn variants(x: E) { match x { A1(m) => bar(&m), A2(m) => bar(&m), A3(m) => bar(&m), A4(m) => bar(&m), } } ```` To a single call to bar, using only a single stack slot. It still fails to eliminate some of checks. ````gas .Ltmp5: .cfi_def_cfa_offset 16 movb (%rdi), %al testb %al, %al je .LBB3_5 movzbl %al, %eax cmpl $1, %eax je .LBB3_5 cmpl $2, %eax .LBB3_5: movq 8(%rdi), %rax movq %rax, (%rsp) leaq (%rsp), %rdi callq _ZN3bar20hcb7a0d8be8e17e37daaE@PLT popq %rax retq ```` Refs rust-lang#15665
2 parents 0246419 + 0d6f257 commit e70ee12

File tree

3 files changed

+44
-16
lines changed

3 files changed

+44
-16
lines changed

src/librustc/middle/trans/_match.rs

+22-5
Original file line numberDiff line numberDiff line change
@@ -892,7 +892,12 @@ fn insert_lllocals<'a>(mut bcx: &'a Block<'a>, bindings_map: &BindingsMap,
892892
TrByCopy(llbinding) => {
893893
let llval = Load(bcx, binding_info.llmatch);
894894
let datum = Datum::new(llval, binding_info.ty, Lvalue);
895+
call_lifetime_start(bcx, llbinding);
895896
bcx = datum.store_to(bcx, llbinding);
897+
match cs {
898+
Some(cs) => bcx.fcx.schedule_lifetime_end(cs, llbinding),
899+
_ => {}
900+
}
896901

897902
llbinding
898903
},
@@ -906,7 +911,10 @@ fn insert_lllocals<'a>(mut bcx: &'a Block<'a>, bindings_map: &BindingsMap,
906911

907912
let datum = Datum::new(llval, binding_info.ty, Lvalue);
908913
match cs {
909-
Some(cs) => bcx.fcx.schedule_drop_and_zero_mem(cs, llval, binding_info.ty),
914+
Some(cs) => {
915+
bcx.fcx.schedule_drop_and_zero_mem(cs, llval, binding_info.ty);
916+
bcx.fcx.schedule_lifetime_end(cs, binding_info.llmatch);
917+
}
910918
_ => {}
911919
}
912920

@@ -945,9 +953,17 @@ fn compile_guard<'a, 'b>(
945953
let val = unpack_datum!(bcx, expr::trans(bcx, guard_expr));
946954
let val = val.to_llbool(bcx);
947955

956+
for (_, &binding_info) in data.bindings_map.iter() {
957+
match binding_info.trmode {
958+
TrByCopy(llbinding) => call_lifetime_end(bcx, llbinding),
959+
_ => {}
960+
}
961+
}
962+
948963
return with_cond(bcx, Not(bcx, val), |bcx| {
949964
// Guard does not match: remove all bindings from the lllocals table
950965
for (_, &binding_info) in data.bindings_map.iter() {
966+
call_lifetime_end(bcx, binding_info.llmatch);
951967
bcx.fcx.lllocals.borrow_mut().remove(&binding_info.id);
952968
}
953969
match chk {
@@ -988,6 +1004,7 @@ fn compile_submatch<'a, 'b>(
9881004
let data = &m[0].data;
9891005
for &(ref ident, ref value_ptr) in m[0].bound_ptrs.iter() {
9901006
let llmatch = data.bindings_map.get(ident).llmatch;
1007+
call_lifetime_start(bcx, llmatch);
9911008
Store(bcx, *value_ptr, llmatch);
9921009
}
9931010
match data.arm.guard {
@@ -1294,24 +1311,24 @@ fn create_bindings_map(bcx: &Block, pat: Gc<ast::Pat>) -> BindingsMap {
12941311
match bm {
12951312
ast::BindByValue(_)
12961313
if !ty::type_moves_by_default(tcx, variable_ty) => {
1297-
llmatch = alloca(bcx,
1314+
llmatch = alloca_no_lifetime(bcx,
12981315
llvariable_ty.ptr_to(),
12991316
"__llmatch");
1300-
trmode = TrByCopy(alloca(bcx,
1317+
trmode = TrByCopy(alloca_no_lifetime(bcx,
13011318
llvariable_ty,
13021319
bcx.ident(ident).as_slice()));
13031320
}
13041321
ast::BindByValue(_) => {
13051322
// in this case, the final type of the variable will be T,
13061323
// but during matching we need to store a *T as explained
13071324
// above
1308-
llmatch = alloca(bcx,
1325+
llmatch = alloca_no_lifetime(bcx,
13091326
llvariable_ty.ptr_to(),
13101327
bcx.ident(ident).as_slice());
13111328
trmode = TrByMove;
13121329
}
13131330
ast::BindByRef(_) => {
1314-
llmatch = alloca(bcx,
1331+
llmatch = alloca_no_lifetime(bcx,
13151332
llvariable_ty,
13161333
bcx.ident(ident).as_slice());
13171334
trmode = TrByRef;

src/librustc/middle/trans/base.rs

+16-9
Original file line numberDiff line numberDiff line change
@@ -1169,25 +1169,32 @@ pub fn alloc_ty(bcx: &Block, t: ty::t, name: &str) -> ValueRef {
11691169
}
11701170

11711171
pub fn alloca(cx: &Block, ty: Type, name: &str) -> ValueRef {
1172-
alloca_maybe_zeroed(cx, ty, name, false)
1172+
let p = alloca_no_lifetime(cx, ty, name);
1173+
call_lifetime_start(cx, p);
1174+
p
11731175
}
11741176

1175-
pub fn alloca_maybe_zeroed(cx: &Block, ty: Type, name: &str, zero: bool) -> ValueRef {
1177+
pub fn alloca_no_lifetime(cx: &Block, ty: Type, name: &str) -> ValueRef {
11761178
let _icx = push_ctxt("alloca");
11771179
if cx.unreachable.get() {
11781180
unsafe {
11791181
return llvm::LLVMGetUndef(ty.ptr_to().to_ref());
11801182
}
11811183
}
11821184
debuginfo::clear_source_location(cx.fcx);
1183-
let p = Alloca(cx, ty, name);
1184-
if zero {
1185-
let b = cx.fcx.ccx.builder();
1186-
b.position_before(cx.fcx.alloca_insert_pt.get().unwrap());
1187-
memzero(&b, p, ty);
1188-
} else {
1189-
call_lifetime_start(cx, p);
1185+
Alloca(cx, ty, name)
1186+
}
1187+
1188+
pub fn alloca_zeroed(cx: &Block, ty: Type, name: &str) -> ValueRef {
1189+
if cx.unreachable.get() {
1190+
unsafe {
1191+
return llvm::LLVMGetUndef(ty.ptr_to().to_ref());
1192+
}
11901193
}
1194+
let p = alloca_no_lifetime(cx, ty, name);
1195+
let b = cx.fcx.ccx.builder();
1196+
b.position_before(cx.fcx.alloca_insert_pt.get().unwrap());
1197+
memzero(&b, p, ty);
11911198
p
11921199
}
11931200

src/librustc/middle/trans/datum.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,11 @@ pub fn lvalue_scratch_datum<'a, A>(bcx: &'a Block<'a>,
120120
*/
121121

122122
let llty = type_of::type_of(bcx.ccx(), ty);
123-
let scratch = alloca_maybe_zeroed(bcx, llty, name, zero);
123+
let scratch = if zero {
124+
alloca_zeroed(bcx, llty, name)
125+
} else {
126+
alloca(bcx, llty, name)
127+
};
124128

125129
// Subtle. Populate the scratch memory *before* scheduling cleanup.
126130
let bcx = populate(arg, bcx, scratch);
@@ -145,7 +149,7 @@ pub fn rvalue_scratch_datum(bcx: &Block,
145149
*/
146150

147151
let llty = type_of::type_of(bcx.ccx(), ty);
148-
let scratch = alloca_maybe_zeroed(bcx, llty, name, false);
152+
let scratch = alloca(bcx, llty, name);
149153
Datum::new(scratch, ty, Rvalue::new(ByRef))
150154
}
151155

0 commit comments

Comments
 (0)