about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduard-Mihai Burtescu <edy.burt@gmail.com>2017-10-09 00:38:10 +0300
committerEduard-Mihai Burtescu <edy.burt@gmail.com>2017-11-19 02:43:55 +0200
commit0b8697241f3988bfa55b9f17d60732dab0e3d75d (patch)
tree9e525a518aa4c569843d76702f1f3c7d56cf8cb8
parentc4d9ada70108210a2a2f7d3025a0d693fc3e3e9d (diff)
downloadrust-0b8697241f3988bfa55b9f17d60732dab0e3d75d.tar.gz
rust-0b8697241f3988bfa55b9f17d60732dab0e3d75d.zip
rustc_trans: be more relaxed with non-lvalue consumes, especially ZSTs.
-rw-r--r--src/librustc_trans/mir/analyze.rs30
-rw-r--r--src/librustc_trans/mir/operand.rs53
2 files changed, 59 insertions, 24 deletions
diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs
index 3129ed028d4..3f3c5ac0a62 100644
--- a/src/librustc_trans/mir/analyze.rs
+++ b/src/librustc_trans/mir/analyze.rs
@@ -136,19 +136,29 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
                     context: LvalueContext<'tcx>,
                     location: Location) {
         debug!("visit_lvalue(lvalue={:?}, context={:?})", lvalue, context);
+        let ccx = self.cx.ccx;
 
         if let mir::Lvalue::Projection(ref proj) = *lvalue {
-            // Allow uses of projections of immediate pair fields.
+            // Allow uses of projections that are ZSTs or from immediate scalar fields.
             if let LvalueContext::Consume = context {
-                if let mir::Lvalue::Local(_) = proj.base {
-                    if let mir::ProjectionElem::Field(..) = proj.elem {
-                        let ty = proj.base.ty(self.cx.mir, self.cx.ccx.tcx());
-
-                        let ty = self.cx.monomorphize(&ty.to_ty(self.cx.ccx.tcx()));
-                        let layout = self.cx.ccx.layout_of(ty);
-                        if layout.is_llvm_scalar_pair() {
-                            return;
-                        }
+                let base_ty = proj.base.ty(self.cx.mir, ccx.tcx());
+                let base_ty = self.cx.monomorphize(&base_ty);
+
+                // ZSTs don't require any actual memory access.
+                let elem_ty = base_ty.projection_ty(ccx.tcx(), &proj.elem).to_ty(ccx.tcx());
+                let elem_ty = self.cx.monomorphize(&elem_ty);
+                if ccx.layout_of(elem_ty).is_zst() {
+                    return;
+                }
+
+                if let mir::ProjectionElem::Field(..) = proj.elem {
+                    let layout = ccx.layout_of(base_ty.to_ty(ccx.tcx()));
+                    if layout.is_llvm_scalar_pair() {
+                        // Recurse as a `Consume` instead of `Projection`,
+                        // potentially stopping at non-operand projections,
+                        // which would trigger `mark_as_lvalue` on locals.
+                        self.visit_lvalue(&proj.base, LvalueContext::Consume, location);
+                        return;
                     }
                 }
             }
diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs
index b9d4148acf6..97e7dda31aa 100644
--- a/src/librustc_trans/mir/operand.rs
+++ b/src/librustc_trans/mir/operand.rs
@@ -179,19 +179,19 @@ impl<'a, 'tcx> OperandValue {
 }
 
 impl<'a, 'tcx> MirContext<'a, 'tcx> {
-    pub fn trans_consume(&mut self,
-                         bcx: &Builder<'a, 'tcx>,
-                         lvalue: &mir::Lvalue<'tcx>)
-                         -> OperandRef<'tcx>
+    fn maybe_trans_consume_direct(&mut self,
+                                  bcx: &Builder<'a, 'tcx>,
+                                  lvalue: &mir::Lvalue<'tcx>)
+                                   -> Option<OperandRef<'tcx>>
     {
-        debug!("trans_consume(lvalue={:?})", lvalue);
+        debug!("maybe_trans_consume_direct(lvalue={:?})", lvalue);
 
         // watch out for locals that do not have an
         // alloca; they are handled somewhat differently
         if let mir::Lvalue::Local(index) = *lvalue {
             match self.locals[index] {
                 LocalRef::Operand(Some(o)) => {
-                    return o;
+                    return Some(o);
                 }
                 LocalRef::Operand(None) => {
                     bug!("use of {:?} before def", lvalue);
@@ -204,21 +204,24 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
 
         // Moves out of pair fields are trivial.
         if let &mir::Lvalue::Projection(ref proj) = lvalue {
-            if let mir::Lvalue::Local(index) = proj.base {
-                if let LocalRef::Operand(Some(o)) = self.locals[index] {
-                    match (o.val, &proj.elem) {
-                        (OperandValue::Pair(a, b),
-                         &mir::ProjectionElem::Field(ref f, ty)) => {
-                            let layout = bcx.ccx.layout_of(self.monomorphize(&ty));
+            if let mir::ProjectionElem::Field(ref f, _) = proj.elem {
+                if let Some(o) = self.maybe_trans_consume_direct(bcx, &proj.base) {
+                    let layout = o.layout.field(bcx.ccx, f.index());
+
+                    // Handled in `trans_consume`.
+                    assert!(!layout.is_zst());
+
+                    match o.val {
+                        OperandValue::Pair(a, b) => {
                             let llval = [a, b][f.index()];
                             // HACK(eddyb) have to bitcast pointers
                             // until LLVM removes pointee types.
                             let llval = bcx.bitcast(llval,
                                 layout.immediate_llvm_type(bcx.ccx));
-                            return OperandRef {
+                            return Some(OperandRef {
                                 val: OperandValue::Immediate(llval),
                                 layout
-                            };
+                            });
                         }
                         _ => {}
                     }
@@ -226,6 +229,28 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
             }
         }
 
+        None
+    }
+
+    pub fn trans_consume(&mut self,
+                         bcx: &Builder<'a, 'tcx>,
+                         lvalue: &mir::Lvalue<'tcx>)
+                         -> OperandRef<'tcx>
+    {
+        debug!("trans_consume(lvalue={:?})", lvalue);
+
+        let ty = self.monomorphized_lvalue_ty(lvalue);
+        let layout = bcx.ccx.layout_of(ty);
+
+        // ZSTs don't require any actual memory access.
+        if layout.is_zst() {
+            return OperandRef::new_zst(bcx.ccx, layout);
+        }
+
+        if let Some(o) = self.maybe_trans_consume_direct(bcx, lvalue) {
+            return o;
+        }
+
         // for most lvalues, to consume them we just load them
         // out from their home
         self.trans_lvalue(bcx, lvalue).load(bcx)