Skip to content

Commit dd812cc

Browse files
committed
auto merge of #15076 : luqmana/rust/naim, r=pcwalton
```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
2 parents eda75bc + 77f72d3 commit dd812cc

File tree

3 files changed

+89
-137
lines changed

3 files changed

+89
-137
lines changed

Diff for: mk/platform.mk

+1
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,7 @@ CFG_PATH_MUNGE_i686-pc-mingw32 :=
461461
CFG_LDPATH_i686-pc-mingw32 :=$(CFG_LDPATH_i686-pc-mingw32):$(PATH)
462462
CFG_RUN_i686-pc-mingw32=PATH="$(CFG_LDPATH_i686-pc-mingw32):$(1)" $(2)
463463
CFG_RUN_TARG_i686-pc-mingw32=$(call CFG_RUN_i686-pc-mingw32,$(HLIB$(1)_H_$(CFG_BUILD)),$(2))
464+
RUSTC_FLAGS_i686-pc-mingw32=-C link-args="-Wl,--large-address-aware"
464465

465466
# i586-mingw32msvc configuration
466467
CC_i586-mingw32msvc=$(CFG_MINGW32_CROSS_PATH)/bin/i586-mingw32msvc-gcc

Diff for: src/librustc/middle/trans/_match.rs

+63-129
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,12 @@
6464
* We store information about the bound variables for each arm as part of the
6565
* per-arm `ArmData` struct. There is a mapping from identifiers to
6666
* `BindingInfo` structs. These structs contain the mode/id/type of the
67-
* binding, but they also contain up to two LLVM values, called `llmatch` and
68-
* `llbinding` respectively (the `llbinding`, as will be described shortly, is
69-
* optional and only present for by-value bindings---therefore it is bundled
70-
* up as part of the `TransBindingMode` type). Both point at allocas.
67+
* binding, but they also contain an LLVM value which points at an alloca
68+
* called `llmatch`. For by value bindings that are Copy, we also create
69+
* an extra alloca that we copy the matched value to so that any changes
70+
* we do to our copy is not reflected in the original and vice-versa.
71+
* We don't do this if it's a move since the original value can't be used
72+
* and thus allowing us to cheat in not creating an extra alloca.
7173
*
7274
* The `llmatch` binding always stores a pointer into the value being matched
7375
* which points at the data for the binding. If the value being matched has
@@ -83,32 +85,26 @@
8385
* up against an identifier, we store the current pointer into the
8486
* corresponding alloca.
8587
*
86-
* In addition, for each by-value binding (copy or move), we will create a
87-
* second alloca (`llbinding`) that will hold the final value. In this
88-
* example, that means that `d` would have this second alloca of type `D` (and
89-
* hence `llbinding` has type `D*`).
90-
*
9188
* Once a pattern is completely matched, and assuming that there is no guard
9289
* pattern, we will branch to a block that leads to the body itself. For any
9390
* by-value bindings, this block will first load the ptr from `llmatch` (the
94-
* one of type `D*`) and copy/move the value into `llbinding` (the one of type
95-
* `D`). The second alloca then becomes the value of the local variable. For
96-
* by ref bindings, the value of the local variable is simply the first
97-
* alloca.
91+
* one of type `D*`) and then load a second time to get the actual value (the
92+
* one of type `D`). For by ref bindings, the value of the local variable is
93+
* simply the first alloca.
9894
*
9995
* So, for the example above, we would generate a setup kind of like this:
10096
*
10197
* +-------+
10298
* | Entry |
10399
* +-------+
104100
* |
105-
* +-------------------------------------------+
106-
* | llmatch_c = (addr of first half of tuple) |
107-
* | llmatch_d = (addr of first half of tuple) |
108-
* +-------------------------------------------+
101+
* +--------------------------------------------+
102+
* | llmatch_c = (addr of first half of tuple) |
103+
* | llmatch_d = (addr of second half of tuple) |
104+
* +--------------------------------------------+
109105
* |
110106
* +--------------------------------------+
111-
* | *llbinding_d = **llmatch_dlbinding_d |
107+
* | *llbinding_d = **llmatch_d |
112108
* +--------------------------------------+
113109
*
114110
* If there is a guard, the situation is slightly different, because we must
@@ -127,22 +123,20 @@
127123
* +-------------------------------------------+
128124
* |
129125
* +-------------------------------------------------+
130-
* | *llbinding_d = **llmatch_dlbinding_d |
126+
* | *llbinding_d = **llmatch_d |
131127
* | check condition |
132-
* | if false { free *llbinding_d, goto next case } |
128+
* | if false { goto next case } |
133129
* | if true { goto body } |
134130
* +-------------------------------------------------+
135131
*
136132
* The handling for the cleanups is a bit... sensitive. Basically, the body
137133
* is the one that invokes `add_clean()` for each binding. During the guard
138134
* evaluation, we add temporary cleanups and revoke them after the guard is
139-
* evaluated (it could fail, after all). Presuming the guard fails, we drop
140-
* the various values we copied explicitly. Note that guards and moves are
135+
* evaluated (it could fail, after all). Note that guards and moves are
141136
* just plain incompatible.
142137
*
143138
* Some relevant helper functions that manage bindings:
144139
* - `create_bindings_map()`
145-
* - `store_non_ref_bindings()`
146140
* - `insert_lllocals()`
147141
*
148142
*
@@ -216,7 +210,6 @@ use middle::trans::datum;
216210
use middle::trans::datum::*;
217211
use middle::trans::expr::Dest;
218212
use middle::trans::expr;
219-
use middle::trans::glue;
220213
use middle::trans::tvec;
221214
use middle::trans::type_of;
222215
use middle::trans::debuginfo;
@@ -357,8 +350,9 @@ fn variant_opt(bcx: &Block, pat_id: ast::NodeId) -> Opt {
357350
}
358351

359352
#[deriving(Clone)]
360-
enum TransBindingMode {
361-
TrByValue(/*llbinding:*/ ValueRef),
353+
pub enum TransBindingMode {
354+
TrByCopy(/* llbinding */ ValueRef),
355+
TrByMove,
362356
TrByRef,
363357
}
364358

@@ -371,12 +365,12 @@ enum TransBindingMode {
371365
* - `id` is the node id of the binding
372366
* - `ty` is the Rust type of the binding */
373367
#[deriving(Clone)]
374-
struct BindingInfo {
375-
llmatch: ValueRef,
376-
trmode: TransBindingMode,
377-
id: ast::NodeId,
378-
span: Span,
379-
ty: ty::t,
368+
pub struct BindingInfo {
369+
pub llmatch: ValueRef,
370+
pub trmode: TransBindingMode,
371+
pub id: ast::NodeId,
372+
pub span: Span,
373+
pub ty: ty::t,
380374
}
381375

382376
type BindingsMap = HashMap<Ident, BindingInfo>;
@@ -970,64 +964,34 @@ fn compare_values<'a>(
970964
}
971965
}
972966

973-
fn store_non_ref_bindings<'a>(
974-
bcx: &'a Block<'a>,
975-
bindings_map: &BindingsMap,
976-
opt_cleanup_scope: Option<cleanup::ScopeId>)
977-
-> &'a Block<'a>
978-
{
979-
/*!
980-
* For each copy/move binding, copy the value from the value being
981-
* matched into its final home. This code executes once one of
982-
* the patterns for a given arm has completely matched. It adds
983-
* cleanups to the `opt_cleanup_scope`, if one is provided.
984-
*/
985-
986-
let fcx = bcx.fcx;
987-
let mut bcx = bcx;
988-
for (_, &binding_info) in bindings_map.iter() {
989-
match binding_info.trmode {
990-
TrByValue(lldest) => {
991-
let llval = Load(bcx, binding_info.llmatch); // get a T*
992-
let datum = Datum::new(llval, binding_info.ty, Lvalue);
993-
bcx = datum.store_to(bcx, lldest);
994-
995-
match opt_cleanup_scope {
996-
None => {}
997-
Some(s) => {
998-
fcx.schedule_drop_mem(s, lldest, binding_info.ty);
999-
}
1000-
}
1001-
}
1002-
TrByRef => {}
1003-
}
1004-
}
1005-
return bcx;
1006-
}
1007-
1008-
fn insert_lllocals<'a>(bcx: &'a Block<'a>,
1009-
bindings_map: &BindingsMap,
1010-
cleanup_scope: cleanup::ScopeId)
967+
fn insert_lllocals<'a>(mut bcx: &'a Block<'a>,
968+
bindings_map: &BindingsMap)
1011969
-> &'a Block<'a> {
1012970
/*!
1013971
* For each binding in `data.bindings_map`, adds an appropriate entry into
1014-
* the `fcx.lllocals` map, scheduling cleanup in `cleanup_scope`.
972+
* the `fcx.lllocals` map
1015973
*/
1016974

1017-
let fcx = bcx.fcx;
1018-
1019975
for (&ident, &binding_info) in bindings_map.iter() {
1020976
let llval = match binding_info.trmode {
1021-
// By value bindings: use the stack slot that we
1022-
// copied/moved the value into
1023-
TrByValue(lldest) => lldest,
977+
// By value mut binding for a copy type: load from the ptr
978+
// into the matched value and copy to our alloca
979+
TrByCopy(llbinding) => {
980+
let llval = Load(bcx, binding_info.llmatch);
981+
let datum = Datum::new(llval, binding_info.ty, Lvalue);
982+
bcx = datum.store_to(bcx, llbinding);
983+
984+
llbinding
985+
},
986+
987+
// By value move bindings: load from the ptr into the matched value
988+
TrByMove => Load(bcx, binding_info.llmatch),
1024989

1025990
// By ref binding: use the ptr into the matched value
1026991
TrByRef => binding_info.llmatch
1027992
};
1028993

1029994
let datum = Datum::new(llval, binding_info.ty, Lvalue);
1030-
fcx.schedule_drop_mem(cleanup_scope, llval, binding_info.ty);
1031995

1032996
debug!("binding {:?} to {}",
1033997
binding_info.id,
@@ -1037,9 +1001,7 @@ fn insert_lllocals<'a>(bcx: &'a Block<'a>,
10371001
if bcx.sess().opts.debuginfo == FullDebugInfo {
10381002
debuginfo::create_match_binding_metadata(bcx,
10391003
ident,
1040-
binding_info.id,
1041-
binding_info.span,
1042-
datum);
1004+
binding_info);
10431005
}
10441006
}
10451007
bcx
@@ -1061,28 +1023,16 @@ fn compile_guard<'a, 'b>(
10611023
vec_map_to_str(vals, |v| bcx.val_to_str(*v)));
10621024
let _indenter = indenter();
10631025

1064-
// Lest the guard itself should fail, introduce a temporary cleanup
1065-
// scope for any non-ref bindings we create.
1066-
let temp_scope = bcx.fcx.push_custom_cleanup_scope();
1067-
1068-
let mut bcx = bcx;
1069-
bcx = store_non_ref_bindings(bcx, &data.bindings_map,
1070-
Some(cleanup::CustomScope(temp_scope)));
1071-
bcx = insert_lllocals(bcx, &data.bindings_map,
1072-
cleanup::CustomScope(temp_scope));
1026+
let mut bcx = insert_lllocals(bcx, &data.bindings_map);
10731027

10741028
let val = unpack_datum!(bcx, expr::trans(bcx, guard_expr));
10751029
let val = val.to_llbool(bcx);
10761030

1077-
// Cancel cleanups now that the guard successfully executed. If
1078-
// the guard was false, we will drop the values explicitly
1079-
// below. Otherwise, we'll add lvalue cleanups at the end.
1080-
bcx.fcx.pop_custom_cleanup_scope(temp_scope);
1081-
10821031
return with_cond(bcx, Not(bcx, val), |bcx| {
1083-
// Guard does not match: free the values we copied,
1084-
// and remove all bindings from the lllocals table
1085-
let bcx = drop_bindings(bcx, data);
1032+
// Guard does not match: remove all bindings from the lllocals table
1033+
for (_, &binding_info) in data.bindings_map.iter() {
1034+
bcx.fcx.lllocals.borrow_mut().remove(&binding_info.id);
1035+
}
10861036
match chk {
10871037
// If the default arm is the only one left, move on to the next
10881038
// condition explicitly rather than (possibly) falling back to
@@ -1096,21 +1046,6 @@ fn compile_guard<'a, 'b>(
10961046
};
10971047
bcx
10981048
});
1099-
1100-
fn drop_bindings<'a>(bcx: &'a Block<'a>, data: &ArmData)
1101-
-> &'a Block<'a> {
1102-
let mut bcx = bcx;
1103-
for (_, &binding_info) in data.bindings_map.iter() {
1104-
match binding_info.trmode {
1105-
TrByValue(llval) => {
1106-
bcx = glue::drop_ty(bcx, llval, binding_info.ty);
1107-
}
1108-
TrByRef => {}
1109-
}
1110-
bcx.fcx.lllocals.borrow_mut().remove(&binding_info.id);
1111-
}
1112-
return bcx;
1113-
}
11141049
}
11151050

11161051
fn compile_submatch<'a, 'b>(
@@ -1435,18 +1370,28 @@ fn create_bindings_map(bcx: &Block, pat: Gc<ast::Pat>) -> BindingsMap {
14351370
let ident = path_to_ident(path);
14361371
let variable_ty = node_id_type(bcx, p_id);
14371372
let llvariable_ty = type_of::type_of(ccx, variable_ty);
1373+
let tcx = bcx.tcx();
14381374

14391375
let llmatch;
14401376
let trmode;
14411377
match bm {
1378+
ast::BindByValue(_)
1379+
if !ty::type_moves_by_default(tcx, variable_ty) => {
1380+
llmatch = alloca(bcx,
1381+
llvariable_ty.ptr_to(),
1382+
"__llmatch");
1383+
trmode = TrByCopy(alloca(bcx,
1384+
llvariable_ty,
1385+
bcx.ident(ident).as_slice()));
1386+
}
14421387
ast::BindByValue(_) => {
14431388
// in this case, the final type of the variable will be T,
14441389
// but during matching we need to store a *T as explained
14451390
// above
1446-
llmatch = alloca(bcx, llvariable_ty.ptr_to(), "__llmatch");
1447-
trmode = TrByValue(alloca(bcx,
1448-
llvariable_ty,
1449-
bcx.ident(ident).as_slice()));
1391+
llmatch = alloca(bcx,
1392+
llvariable_ty.ptr_to(),
1393+
bcx.ident(ident).as_slice());
1394+
trmode = TrByMove;
14501395
}
14511396
ast::BindByRef(_) => {
14521397
llmatch = alloca(bcx,
@@ -1532,20 +1477,9 @@ fn trans_match_inner<'a>(scope_cx: &'a Block<'a>,
15321477
for arm_data in arm_datas.iter() {
15331478
let mut bcx = arm_data.bodycx;
15341479

1535-
// If this arm has a guard, then the various by-value bindings have
1536-
// already been copied into their homes. If not, we do it here. This
1537-
// is just to reduce code space. See extensive comment at the start
1538-
// of the file for more details.
1539-
if arm_data.arm.guard.is_none() {
1540-
bcx = store_non_ref_bindings(bcx, &arm_data.bindings_map, None);
1541-
}
1542-
1543-
// insert bindings into the lllocals map and add cleanups
1544-
let cleanup_scope = fcx.push_custom_cleanup_scope();
1545-
bcx = insert_lllocals(bcx, &arm_data.bindings_map,
1546-
cleanup::CustomScope(cleanup_scope));
1480+
// insert bindings into the lllocals map
1481+
bcx = insert_lllocals(bcx, &arm_data.bindings_map);
15471482
bcx = expr::trans_into(bcx, &*arm_data.arm.body, dest);
1548-
bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope);
15491483
arm_cxs.push(bcx);
15501484
}
15511485

Diff for: src/librustc/middle/trans/debuginfo.rs

+25-8
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,8 @@ use metadata::csearch;
187187
use middle::subst;
188188
use middle::trans::adt;
189189
use middle::trans::common::*;
190-
use middle::trans::datum::{Datum, Lvalue};
191190
use middle::trans::machine;
191+
use middle::trans::_match::{BindingInfo, TrByCopy, TrByMove, TrByRef};
192192
use middle::trans::type_of;
193193
use middle::trans::type_::Type;
194194
use middle::trans;
@@ -958,22 +958,39 @@ pub fn create_captured_var_metadata(bcx: &Block,
958958
/// Adds the created metadata nodes directly to the crate's IR.
959959
pub fn create_match_binding_metadata(bcx: &Block,
960960
variable_ident: ast::Ident,
961-
node_id: ast::NodeId,
962-
span: Span,
963-
datum: Datum<Lvalue>) {
961+
binding: BindingInfo) {
964962
if fn_should_be_ignored(bcx.fcx) {
965963
return;
966964
}
967965

968-
let scope_metadata = scope_metadata(bcx.fcx, node_id, span);
966+
let scope_metadata = scope_metadata(bcx.fcx, binding.id, binding.span);
967+
let aops = unsafe {
968+
[llvm::LLVMDIBuilderCreateOpDeref(bcx.ccx().int_type.to_ref())]
969+
};
970+
// Regardless of the actual type (`T`) we're always passed the stack slot (alloca)
971+
// for the binding. For ByRef bindings that's a `T*` but for ByMove bindings we
972+
// actually have `T**`. So to get the actual variable we need to dereference once
973+
// more. For ByCopy we just use the stack slot we created for the binding.
974+
let var_type = match binding.trmode {
975+
TrByCopy(llbinding) => DirectVariable {
976+
alloca: llbinding
977+
},
978+
TrByMove => IndirectVariable {
979+
alloca: binding.llmatch,
980+
address_operations: aops
981+
},
982+
TrByRef => DirectVariable {
983+
alloca: binding.llmatch
984+
}
985+
};
969986

970987
declare_local(bcx,
971988
variable_ident,
972-
datum.ty,
989+
binding.ty,
973990
scope_metadata,
974-
DirectVariable { alloca: datum.val },
991+
var_type,
975992
LocalVariable,
976-
span);
993+
binding.span);
977994
}
978995

979996
/// Creates debug information for the given function argument.

0 commit comments

Comments
 (0)