librustc: Use different alloca slot for non-move bindings.

This commit is contained in:
Luqman Aden 2014-06-21 17:05:05 -04:00 committed by Luqman Aden
parent 94a56a3758
commit bedc41b257
2 changed files with 38 additions and 10 deletions

View file

@ -65,7 +65,11 @@
* per-arm `ArmData` struct. There is a mapping from identifiers to
* `BindingInfo` structs. These structs contain the mode/id/type of the
* binding, but they also contain an LLVM value which points at an alloca
* called `llmatch`.
* called `llmatch`. For by value bindings that are Copy, we also create
* an extra alloca that we copy the matched value to so that any changes
* we do to our copy is not reflected in the original and vice-versa.
* We don't do this if it's a move since the original value can't be used
* and thus allowing us to cheat in not creating an extra alloca.
*
* The `llmatch` binding always stores a pointer into the value being matched
* which points at the data for the binding. If the value being matched has
@ -352,7 +356,8 @@ fn variant_opt(bcx: &Block, pat_id: ast::NodeId) -> Opt {
#[deriving(Clone)]
pub enum TransBindingMode {
TrByValue,
TrByCopy(/* llbinding */ ValueRef),
TrByMove,
TrByRef,
}
@ -1249,7 +1254,7 @@ fn compare_values<'a>(
}
}
fn insert_lllocals<'a>(bcx: &'a Block<'a>,
fn insert_lllocals<'a>(mut bcx: &'a Block<'a>,
bindings_map: &BindingsMap,
cleanup_scope: cleanup::ScopeId)
-> &'a Block<'a> {
@ -1262,8 +1267,18 @@ fn insert_lllocals<'a>(bcx: &'a Block<'a>,
for (&ident, &binding_info) in bindings_map.iter() {
let llval = match binding_info.trmode {
// By value bindings: load from the ptr into the matched value
TrByValue => Load(bcx, binding_info.llmatch),
// By value mut binding for a copy type: load from the ptr
// into the matched value and copy to our alloca
TrByCopy(llbinding) => {
let llval = Load(bcx, binding_info.llmatch);
let datum = Datum::new(llval, binding_info.ty, Lvalue);
bcx = datum.store_to(bcx, llbinding);
llbinding
},
// By value move bindings: load from the ptr into the matched value
TrByMove => Load(bcx, binding_info.llmatch),
// By ref binding: use the ptr into the matched value
TrByRef => binding_info.llmatch
@ -1762,10 +1777,20 @@ fn create_bindings_map(bcx: &Block, pat: Gc<ast::Pat>) -> BindingsMap {
let ident = path_to_ident(path);
let variable_ty = node_id_type(bcx, p_id);
let llvariable_ty = type_of::type_of(ccx, variable_ty);
let tcx = bcx.tcx();
let llmatch;
let trmode;
match bm {
ast::BindByValue(_)
if !ty::type_moves_by_default(tcx, variable_ty) => {
llmatch = alloca(bcx,
llvariable_ty.ptr_to(),
"__llmatch");
trmode = TrByCopy(alloca(bcx,
llvariable_ty,
bcx.ident(ident).as_slice()));
}
ast::BindByValue(_) => {
// in this case, the final type of the variable will be T,
// but during matching we need to store a *T as explained
@ -1773,7 +1798,7 @@ fn create_bindings_map(bcx: &Block, pat: Gc<ast::Pat>) -> BindingsMap {
llmatch = alloca(bcx,
llvariable_ty.ptr_to(),
bcx.ident(ident).as_slice());
trmode = TrByValue;
trmode = TrByMove;
}
ast::BindByRef(_) => {
llmatch = alloca(bcx,

View file

@ -188,7 +188,7 @@ use middle::subst;
use middle::trans::adt;
use middle::trans::common::*;
use middle::trans::machine;
use middle::trans::_match::{BindingInfo, TrByValue, TrByRef};
use middle::trans::_match::{BindingInfo, TrByCopy, TrByMove, TrByRef};
use middle::trans::type_of;
use middle::trans::type_::Type;
use middle::trans;
@ -948,11 +948,14 @@ pub fn create_match_binding_metadata(bcx: &Block,
[llvm::LLVMDIBuilderCreateOpDeref(bcx.ccx().int_type.to_ref())]
};
// Regardless of the actual type (`T`) we're always passed the stack slot (alloca)
// for the binding. For ByRef bindings that's a `T*` but for ByValue bindings we
// for the binding. For ByRef bindings that's a `T*` but for ByMove bindings we
// actually have `T**`. So to get the actual variable we need to dereference once
// more.
// more. For ByCopy we just use the stack slot we created for the binding.
let var_type = match binding.trmode {
TrByValue => IndirectVariable {
TrByCopy(llbinding) => DirectVariable {
alloca: llbinding
},
TrByMove => IndirectVariable {
alloca: binding.llmatch,
address_operations: aops
},