Rename rustc_mir to rustc_const_eval.
This commit is contained in:
75
compiler/rustc_const_eval/src/util/aggregate.rs
Normal file
75
compiler/rustc_const_eval/src/util/aggregate.rs
Normal file
@@ -0,0 +1,75 @@
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::{Ty, TyCtxt};
|
||||
use rustc_target::abi::VariantIdx;
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::iter::TrustedLen;
|
||||
|
||||
/// Expand `lhs = Rvalue::Aggregate(kind, operands)` into assignments to the fields.
|
||||
///
|
||||
/// Produces something like
|
||||
///
|
||||
/// (lhs as Variant).field0 = arg0; // We only have a downcast if this is an enum
|
||||
/// (lhs as Variant).field1 = arg1;
|
||||
/// discriminant(lhs) = variant_index; // If lhs is an enum or generator.
|
||||
pub fn expand_aggregate<'tcx>(
|
||||
mut lhs: Place<'tcx>,
|
||||
operands: impl Iterator<Item = (Operand<'tcx>, Ty<'tcx>)> + TrustedLen,
|
||||
kind: AggregateKind<'tcx>,
|
||||
source_info: SourceInfo,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> impl Iterator<Item = Statement<'tcx>> + TrustedLen {
|
||||
let mut set_discriminant = None;
|
||||
let active_field_index = match kind {
|
||||
AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
|
||||
if adt_def.is_enum() {
|
||||
set_discriminant = Some(Statement {
|
||||
kind: StatementKind::SetDiscriminant { place: Box::new(lhs), variant_index },
|
||||
source_info,
|
||||
});
|
||||
lhs = tcx.mk_place_downcast(lhs, adt_def, variant_index);
|
||||
}
|
||||
active_field_index
|
||||
}
|
||||
AggregateKind::Generator(..) => {
|
||||
// Right now we only support initializing generators to
|
||||
// variant 0 (Unresumed).
|
||||
let variant_index = VariantIdx::new(0);
|
||||
set_discriminant = Some(Statement {
|
||||
kind: StatementKind::SetDiscriminant { place: Box::new(lhs), variant_index },
|
||||
source_info,
|
||||
});
|
||||
|
||||
// Operands are upvars stored on the base place, so no
|
||||
// downcast is necessary.
|
||||
|
||||
None
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
operands
|
||||
.enumerate()
|
||||
.map(move |(i, (op, ty))| {
|
||||
let lhs_field = if let AggregateKind::Array(_) = kind {
|
||||
let offset = u64::try_from(i).unwrap();
|
||||
tcx.mk_place_elem(
|
||||
lhs,
|
||||
ProjectionElem::ConstantIndex {
|
||||
offset,
|
||||
min_length: offset + 1,
|
||||
from_end: false,
|
||||
},
|
||||
)
|
||||
} else {
|
||||
let field = Field::new(active_field_index.unwrap_or(i));
|
||||
tcx.mk_place_field(lhs, field, ty)
|
||||
};
|
||||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Assign(Box::new((lhs_field, Rvalue::Use(op)))),
|
||||
}
|
||||
})
|
||||
.chain(set_discriminant)
|
||||
}
|
||||
70
compiler/rustc_const_eval/src/util/alignment.rs
Normal file
70
compiler/rustc_const_eval/src/util/alignment.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_target::abi::Align;
|
||||
|
||||
/// Returns `true` if this place is allowed to be less aligned
|
||||
/// than its containing struct (because it is within a packed
|
||||
/// struct).
|
||||
pub fn is_disaligned<'tcx, L>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
local_decls: &L,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
place: Place<'tcx>,
|
||||
) -> bool
|
||||
where
|
||||
L: HasLocalDecls<'tcx>,
|
||||
{
|
||||
debug!("is_disaligned({:?})", place);
|
||||
let pack = match is_within_packed(tcx, local_decls, place) {
|
||||
None => {
|
||||
debug!("is_disaligned({:?}) - not within packed", place);
|
||||
return false;
|
||||
}
|
||||
Some(pack) => pack,
|
||||
};
|
||||
|
||||
let ty = place.ty(local_decls, tcx).ty;
|
||||
match tcx.layout_of(param_env.and(ty)) {
|
||||
Ok(layout) if layout.align.abi <= pack => {
|
||||
// If the packed alignment is greater or equal to the field alignment, the type won't be
|
||||
// further disaligned.
|
||||
debug!(
|
||||
"is_disaligned({:?}) - align = {}, packed = {}; not disaligned",
|
||||
place,
|
||||
layout.align.abi.bytes(),
|
||||
pack.bytes()
|
||||
);
|
||||
false
|
||||
}
|
||||
_ => {
|
||||
debug!("is_disaligned({:?}) - true", place);
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_within_packed<'tcx, L>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
local_decls: &L,
|
||||
place: Place<'tcx>,
|
||||
) -> Option<Align>
|
||||
where
|
||||
L: HasLocalDecls<'tcx>,
|
||||
{
|
||||
for (place_base, elem) in place.iter_projections().rev() {
|
||||
match elem {
|
||||
// encountered a Deref, which is ABI-aligned
|
||||
ProjectionElem::Deref => break,
|
||||
ProjectionElem::Field(..) => {
|
||||
let ty = place_base.ty(local_decls, tcx).ty;
|
||||
match ty.kind() {
|
||||
ty::Adt(def, _) => return def.repr.pack,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
36
compiler/rustc_const_eval/src/util/collect_writes.rs
Normal file
36
compiler/rustc_const_eval/src/util/collect_writes.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
use rustc_middle::mir::visit::PlaceContext;
|
||||
use rustc_middle::mir::visit::Visitor;
|
||||
use rustc_middle::mir::{Body, Local, Location};
|
||||
|
||||
pub trait FindAssignments {
|
||||
// Finds all statements that assign directly to local (i.e., X = ...)
|
||||
// and returns their locations.
|
||||
fn find_assignments(&self, local: Local) -> Vec<Location>;
|
||||
}
|
||||
|
||||
impl<'tcx> FindAssignments for Body<'tcx> {
|
||||
fn find_assignments(&self, local: Local) -> Vec<Location> {
|
||||
let mut visitor = FindLocalAssignmentVisitor { needle: local, locations: vec![] };
|
||||
visitor.visit_body(self);
|
||||
visitor.locations
|
||||
}
|
||||
}
|
||||
|
||||
// The Visitor walks the MIR to return the assignment statements corresponding
|
||||
// to a Local.
|
||||
struct FindLocalAssignmentVisitor {
|
||||
needle: Local,
|
||||
locations: Vec<Location>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor {
|
||||
fn visit_local(&mut self, local: &Local, place_context: PlaceContext, location: Location) {
|
||||
if self.needle != *local {
|
||||
return;
|
||||
}
|
||||
|
||||
if place_context.is_place_assignment() {
|
||||
self.locations.push(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
36
compiler/rustc_const_eval/src/util/find_self_call.rs
Normal file
36
compiler/rustc_const_eval/src/util/find_self_call.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_span::def_id::DefId;
|
||||
|
||||
/// Checks if the specified `local` is used as the `self` parameter of a method call
|
||||
/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is
|
||||
/// returned.
|
||||
pub fn find_self_call<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
local: Local,
|
||||
block: BasicBlock,
|
||||
) -> Option<(DefId, SubstsRef<'tcx>)> {
|
||||
debug!("find_self_call(local={:?}): terminator={:?}", local, &body[block].terminator);
|
||||
if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) =
|
||||
&body[block].terminator
|
||||
{
|
||||
debug!("find_self_call: func={:?}", func);
|
||||
if let Operand::Constant(box Constant { literal, .. }) = func {
|
||||
if let ty::FnDef(def_id, substs) = *literal.ty().kind() {
|
||||
if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
|
||||
tcx.opt_associated_item(def_id)
|
||||
{
|
||||
debug!("find_self_call: args={:?}", args);
|
||||
if let [Operand::Move(self_place) | Operand::Copy(self_place), ..] = **args {
|
||||
if self_place.as_local() == Some(local) {
|
||||
return Some((def_id, substs));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
8
compiler/rustc_const_eval/src/util/mod.rs
Normal file
8
compiler/rustc_const_eval/src/util/mod.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
pub mod aggregate;
|
||||
mod alignment;
|
||||
pub mod collect_writes;
|
||||
mod find_self_call;
|
||||
|
||||
pub use self::aggregate::expand_aggregate;
|
||||
pub use self::alignment::is_disaligned;
|
||||
pub use self::find_self_call::find_self_call;
|
||||
Reference in New Issue
Block a user