rustc_trans: be more relaxed with non-lvalue consumes, especially ZSTs.
This commit is contained in:
parent
c4d9ada701
commit
0b8697241f
@ -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 base_ty = proj.base.ty(self.cx.mir, ccx.tcx());
|
||||
let base_ty = self.cx.monomorphize(&base_ty);
|
||||
|
||||
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;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user