Skip to content

Commit c1fff48

Browse files
committed
Port new Place into llvm codegen
1 parent 091802d commit c1fff48

File tree

7 files changed

+240
-202
lines changed

7 files changed

+240
-202
lines changed

src/librustc_codegen_llvm/mir/analyze.rs

Lines changed: 47 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,19 @@ impl Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'll, 'tcx> {
110110
location: Location) {
111111
debug!("visit_assign(block={:?}, place={:?}, rvalue={:?})", block, place, rvalue);
112112

113-
if let mir::Place::Local(index) = *place {
114-
self.assign(index, location);
115-
if !self.fx.rvalue_creates_operand(rvalue) {
116-
self.not_ssa(index);
113+
match place {
114+
mir::Place {
115+
base: mir::PlaceBase::Local(index),
116+
elems,
117+
} if elems.is_empty() => {
118+
self.assign(*index, location);
119+
if !self.fx.rvalue_creates_operand(rvalue) {
120+
self.not_ssa(*index);
121+
}
122+
},
123+
_ => {
124+
self.visit_place(place, PlaceContext::Store, location);
117125
}
118-
} else {
119-
self.visit_place(place, PlaceContext::Store, location);
120126
}
121127

122128
self.visit_rvalue(rvalue, location);
@@ -152,43 +158,48 @@ impl Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'll, 'tcx> {
152158

153159
fn visit_place(&mut self,
154160
place: &mir::Place<'tcx>,
155-
context: PlaceContext<'tcx>,
161+
mut context: PlaceContext<'tcx>,
156162
location: Location) {
157-
debug!("visit_place(place={:?}, context={:?})", place, context);
158163
let cx = self.fx.cx;
159164

160-
if let mir::Place::Projection(ref proj) = *place {
161-
// Allow uses of projections that are ZSTs or from scalar fields.
162-
let is_consume = match context {
163-
PlaceContext::Copy | PlaceContext::Move => true,
164-
_ => false
165-
};
166-
if is_consume {
167-
let base_ty = proj.base.ty(self.fx.mir, cx.tcx);
168-
let base_ty = self.fx.monomorphize(&base_ty);
169-
170-
// ZSTs don't require any actual memory access.
171-
let elem_ty = base_ty.projection_ty(cx.tcx, &proj.elem).to_ty(cx.tcx);
172-
let elem_ty = self.fx.monomorphize(&elem_ty);
173-
if cx.layout_of(elem_ty).is_zst() {
174-
return;
175-
}
165+
if !place.elems.is_empty() {
166+
for (i, elem) in place.elems.iter().cloned().enumerate().rev() {
167+
debug!("visit_place(place={:?}, context={:?})", place, context);
168+
169+
// Allow uses of projections that are ZSTs or from scalar fields.
170+
let is_consume = match context {
171+
PlaceContext::Copy | PlaceContext::Move => true,
172+
_ => false
173+
};
176174

177-
if let mir::ProjectionElem::Field(..) = proj.elem {
178-
let layout = cx.layout_of(base_ty.to_ty(cx.tcx));
179-
if layout.is_llvm_immediate() || layout.is_llvm_scalar_pair() {
180-
// Recurse with the same context, instead of `Projection`,
181-
// potentially stopping at non-operand projections,
182-
// which would trigger `not_ssa` on locals.
183-
self.visit_place(&proj.base, context, location);
175+
let base = place.elem_base(cx.tcx, i);
176+
if is_consume {
177+
let base_ty = base.ty(self.fx.mir, cx.tcx);
178+
let base_ty = self.fx.monomorphize(&base_ty);
179+
180+
// ZSTs don't require any actual memory access.
181+
let elem_ty = base_ty.projection_ty(cx.tcx, &elem).to_ty(cx.tcx);
182+
let elem_ty = self.fx.monomorphize(&elem_ty);
183+
if cx.layout_of(elem_ty).is_zst() {
184184
return;
185185
}
186+
187+
if let mir::ProjectionElem::Field(..) = elem {
188+
let layout = cx.layout_of(base_ty.to_ty(cx.tcx));
189+
if layout.is_llvm_immediate() || layout.is_llvm_scalar_pair() {
190+
// Recurse with the same context, instead of `Projection`,
191+
// potentially stopping at non-operand projections,
192+
// which would trigger `not_ssa` on locals.
193+
continue;
194+
}
195+
}
186196
}
187-
}
188197

189-
// A deref projection only reads the pointer, never needs the place.
190-
if let mir::ProjectionElem::Deref = proj.elem {
191-
return self.visit_place(&proj.base, PlaceContext::Copy, location);
198+
// A deref projection only reads the pointer, never needs the place.
199+
if let mir::ProjectionElem::Deref = elem {
200+
context = PlaceContext::Copy;
201+
continue;
202+
}
192203
}
193204
}
194205

@@ -234,7 +245,7 @@ impl Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'll, 'tcx> {
234245
}
235246

236247
PlaceContext::Drop => {
237-
let ty = mir::Place::Local(local).ty(self.fx.mir, self.fx.cx.tcx);
248+
let ty = mir::Place::local(local).ty(self.fx.mir, self.fx.cx.tcx);
238249
let ty = self.fx.monomorphize(&ty.to_ty(self.fx.cx.tcx));
239250

240251
// Only need the place if we're actually dropping it.

src/librustc_codegen_llvm/mir/block.rs

Lines changed: 71 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
231231
}
232232

233233
PassMode::Direct(_) | PassMode::Pair(..) => {
234-
let op = self.codegen_consume(&bx, &mir::Place::Local(mir::RETURN_PLACE));
234+
let op = self.codegen_consume(&bx, &mir::Place::local(mir::RETURN_PLACE));
235235
if let Ref(llval, align) = op.val {
236236
bx.load(llval, align)
237237
} else {
@@ -514,16 +514,24 @@ impl FunctionCx<'a, 'll, 'tcx> {
514514
// checked by const-qualification, which also
515515
// promotes any complex rvalues to constants.
516516
if i == 2 && intrinsic.unwrap().starts_with("simd_shuffle") {
517-
match *arg {
517+
match arg {
518518
// The shuffle array argument is usually not an explicit constant,
519519
// but specified directly in the code. This means it gets promoted
520520
// and we can then extract the value by evaluating the promoted.
521-
mir::Operand::Copy(mir::Place::Promoted(box(index, ty))) |
522-
mir::Operand::Move(mir::Place::Promoted(box(index, ty))) => {
521+
mir::Operand::Copy(mir::Place {
522+
base: mir::PlaceBase::Promoted(box (index, ty)),
523+
elems,
524+
}) |
525+
mir::Operand::Move(mir::Place {
526+
base: mir::PlaceBase::Promoted(box (index, ty)),
527+
elems,
528+
})
529+
if elems.is_empty()
530+
=> {
523531
let param_env = ty::ParamEnv::reveal_all();
524532
let cid = mir::interpret::GlobalId {
525533
instance: self.instance,
526-
promoted: Some(index),
534+
promoted: Some(*index),
527535
};
528536
let c = bx.tcx().const_eval(param_env.and(cid));
529537
let (llval, ty) = self.simd_shuffle_indices(
@@ -817,37 +825,42 @@ impl FunctionCx<'a, 'll, 'tcx> {
817825
if fn_ret.is_ignore() {
818826
return ReturnDest::Nothing;
819827
}
820-
let dest = if let mir::Place::Local(index) = *dest {
821-
match self.locals[index] {
822-
LocalRef::Place(dest) => dest,
823-
LocalRef::Operand(None) => {
824-
// Handle temporary places, specifically Operand ones, as
825-
// they don't have allocas
826-
return if fn_ret.is_indirect() {
827-
// Odd, but possible, case, we have an operand temporary,
828-
// but the calling convention has an indirect return.
829-
let tmp = PlaceRef::alloca(bx, fn_ret.layout, "tmp_ret");
830-
tmp.storage_live(bx);
831-
llargs.push(tmp.llval);
832-
ReturnDest::IndirectOperand(tmp, index)
833-
} else if is_intrinsic {
834-
// Currently, intrinsics always need a location to store
835-
// the result. so we create a temporary alloca for the
836-
// result
837-
let tmp = PlaceRef::alloca(bx, fn_ret.layout, "tmp_ret");
838-
tmp.storage_live(bx);
839-
ReturnDest::IndirectOperand(tmp, index)
840-
} else {
841-
ReturnDest::DirectOperand(index)
842-
};
843-
}
844-
LocalRef::Operand(Some(_)) => {
845-
bug!("place local already assigned to");
828+
let dest = match dest {
829+
mir::Place {
830+
base: mir::PlaceBase::Local(index),
831+
elems,
832+
} if elems.is_empty() => {
833+
match self.locals[*index] {
834+
LocalRef::Place(dest) => dest,
835+
LocalRef::Operand(None) => {
836+
// Handle temporary places, specifically Operand ones, as
837+
// they don't have allocas
838+
return if fn_ret.is_indirect() {
839+
// Odd, but possible, case, we have an operand temporary,
840+
// but the calling convention has an indirect return.
841+
let tmp = PlaceRef::alloca(bx, fn_ret.layout, "tmp_ret");
842+
tmp.storage_live(bx);
843+
llargs.push(tmp.llval);
844+
ReturnDest::IndirectOperand(tmp, *index)
845+
} else if is_intrinsic {
846+
// Currently, intrinsics always need a location to store
847+
// the result. so we create a temporary alloca for the
848+
// result
849+
let tmp = PlaceRef::alloca(bx, fn_ret.layout, "tmp_ret");
850+
tmp.storage_live(bx);
851+
ReturnDest::IndirectOperand(tmp, *index)
852+
} else {
853+
ReturnDest::DirectOperand(*index)
854+
};
855+
}
856+
LocalRef::Operand(Some(_)) => {
857+
bug!("place local already assigned to");
858+
}
846859
}
847860
}
848-
} else {
849-
self.codegen_place(bx, dest)
861+
_ => self.codegen_place(bx, dest),
850862
};
863+
851864
if fn_ret.is_indirect() {
852865
if dest.align.abi() < dest.layout.align.abi() {
853866
// Currently, MIR code generation does not create calls
@@ -868,27 +881,33 @@ impl FunctionCx<'a, 'll, 'tcx> {
868881
fn codegen_transmute(&mut self, bx: &Builder<'a, 'll, 'tcx>,
869882
src: &mir::Operand<'tcx>,
870883
dst: &mir::Place<'tcx>) {
871-
if let mir::Place::Local(index) = *dst {
872-
match self.locals[index] {
873-
LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place),
874-
LocalRef::Operand(None) => {
875-
let dst_layout = bx.cx.layout_of(self.monomorphized_place_ty(dst));
876-
assert!(!dst_layout.ty.has_erasable_regions());
877-
let place = PlaceRef::alloca(bx, dst_layout, "transmute_temp");
878-
place.storage_live(bx);
879-
self.codegen_transmute_into(bx, src, place);
880-
let op = place.load(bx);
881-
place.storage_dead(bx);
882-
self.locals[index] = LocalRef::Operand(Some(op));
883-
}
884-
LocalRef::Operand(Some(op)) => {
885-
assert!(op.layout.is_zst(),
886-
"assigning to initialized SSAtemp");
884+
match dst {
885+
mir::Place {
886+
base: mir::PlaceBase::Local(index),
887+
elems,
888+
} if elems.is_empty() => {
889+
match self.locals[*index] {
890+
LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place),
891+
LocalRef::Operand(None) => {
892+
let dst_layout = bx.cx.layout_of(self.monomorphized_place_ty(dst));
893+
assert!(!dst_layout.ty.has_erasable_regions());
894+
let place = PlaceRef::alloca(bx, dst_layout, "transmute_temp");
895+
place.storage_live(bx);
896+
self.codegen_transmute_into(bx, src, place);
897+
let op = place.load(bx);
898+
place.storage_dead(bx);
899+
self.locals[*index] = LocalRef::Operand(Some(op));
900+
}
901+
LocalRef::Operand(Some(op)) => {
902+
assert!(op.layout.is_zst(),
903+
"assigning to initialized SSAtemp");
904+
}
887905
}
888906
}
889-
} else {
890-
let dst = self.codegen_place(bx, dst);
891-
self.codegen_transmute_into(bx, src, dst);
907+
_ => {
908+
let dst = self.codegen_place(bx, dst);
909+
self.codegen_transmute_into(bx, src, dst);
910+
}
892911
}
893912
}
894913

src/librustc_codegen_llvm/mir/operand.rs

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -310,45 +310,47 @@ impl FunctionCx<'a, 'll, 'tcx> {
310310
{
311311
debug!("maybe_codegen_consume_direct(place={:?})", place);
312312

313+
let mut result = None;
313314
// watch out for locals that do not have an
314315
// alloca; they are handled somewhat differently
315-
if let mir::Place::Local(index) = *place {
316-
match self.locals[index] {
317-
LocalRef::Operand(Some(o)) => {
318-
return Some(o);
319-
}
320-
LocalRef::Operand(None) => {
321-
bug!("use of {:?} before def", place);
322-
}
323-
LocalRef::Place(..) => {
324-
// use path below
325-
}
326-
}
327-
}
328-
329-
// Moves out of scalar and scalar pair fields are trivial.
330-
if let &mir::Place::Projection(ref proj) = place {
331-
if let Some(o) = self.maybe_codegen_consume_direct(bx, &proj.base) {
332-
match proj.elem {
333-
mir::ProjectionElem::Field(ref f, _) => {
334-
return Some(o.extract_field(bx, f.index()));
316+
if place.elems.is_empty() {
317+
if let mir::PlaceBase::Local(index) = place.base {
318+
match self.locals[index] {
319+
LocalRef::Operand(Some(o)) => {
320+
result = Some(o);
335321
}
336-
mir::ProjectionElem::Index(_) |
337-
mir::ProjectionElem::ConstantIndex { .. } => {
338-
// ZSTs don't require any actual memory access.
339-
// FIXME(eddyb) deduplicate this with the identical
340-
// checks in `codegen_consume` and `extract_field`.
341-
let elem = o.layout.field(bx.cx, 0);
342-
if elem.is_zst() {
343-
return Some(OperandRef::new_zst(bx.cx, elem));
344-
}
322+
LocalRef::Operand(None) => {
323+
bug!("use of {:?} before def", place);
345324
}
346-
_ => {}
325+
LocalRef::Place(..) => {
326+
// use path below
327+
}
328+
};
329+
}
330+
} else {
331+
// Moves out of scalar and scalar pair fields are trivial.
332+
for e in place.elems.iter() {
333+
if let Some(o) = result {
334+
match e {
335+
mir::ProjectionElem::Field(ref f, _) => {
336+
result = Some(o.extract_field(bx, f.index()));
337+
}
338+
mir::ProjectionElem::Index(_) |
339+
mir::ProjectionElem::ConstantIndex { .. } => {
340+
// ZSTs don't require any actual memory access.
341+
// FIXME(eddyb) deduplicate this with the identical
342+
// checks in `codegen_consume` and `extract_field`.
343+
let elem = o.layout.field(bx.cx, 0);
344+
if elem.is_zst() {
345+
result = Some(OperandRef::new_zst(bx.cx, elem));
346+
}
347+
}
348+
_ => {}
349+
};
347350
}
348351
}
349352
}
350-
351-
None
353+
result
352354
}
353355

354356
pub fn codegen_consume(&mut self,

0 commit comments

Comments
 (0)