Merge pull request #1057 from spastorino/store-pairs-in-ssa
Store pairs in ssa
This commit is contained in:
commit
d032c24476
6 changed files with 131 additions and 20 deletions
|
@ -78,6 +78,10 @@ pub(super) fn add_local_place_comments<'tcx>(
|
||||||
assert_eq!(local, place_local);
|
assert_eq!(local, place_local);
|
||||||
("ssa", Cow::Owned(format!(",var={}", var.index())))
|
("ssa", Cow::Owned(format!(",var={}", var.index())))
|
||||||
}
|
}
|
||||||
|
CPlaceInner::VarPair(place_local, var1, var2) => {
|
||||||
|
assert_eq!(local, place_local);
|
||||||
|
("ssa", Cow::Owned(format!(",var=({}, {})", var1.index(), var2.index())))
|
||||||
|
}
|
||||||
CPlaceInner::Addr(ptr, meta) => {
|
CPlaceInner::Addr(ptr, meta) => {
|
||||||
let meta = if let Some(meta) = meta {
|
let meta = if let Some(meta) = meta {
|
||||||
Cow::Owned(format!(",meta={}", meta))
|
Cow::Owned(format!(",meta={}", meta))
|
||||||
|
|
|
@ -290,7 +290,11 @@ fn local_place<'tcx>(
|
||||||
is_ssa: bool,
|
is_ssa: bool,
|
||||||
) -> CPlace<'tcx> {
|
) -> CPlace<'tcx> {
|
||||||
let place = if is_ssa {
|
let place = if is_ssa {
|
||||||
CPlace::new_var(fx, local, layout)
|
if let rustc_target::abi::Abi::ScalarPair(_, _) = layout.abi {
|
||||||
|
CPlace::new_var_pair(fx, local, layout)
|
||||||
|
} else {
|
||||||
|
CPlace::new_var(fx, local, layout)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
CPlace::new_stack_slot(fx, layout)
|
CPlace::new_stack_slot(fx, layout)
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,7 +11,8 @@ pub(crate) enum SsaKind {
|
||||||
|
|
||||||
pub(crate) fn analyze(fx: &FunctionCx<'_, '_, impl Backend>) -> IndexVec<Local, SsaKind> {
|
pub(crate) fn analyze(fx: &FunctionCx<'_, '_, impl Backend>) -> IndexVec<Local, SsaKind> {
|
||||||
let mut flag_map = fx.mir.local_decls.iter().map(|local_decl| {
|
let mut flag_map = fx.mir.local_decls.iter().map(|local_decl| {
|
||||||
if fx.clif_type(fx.monomorphize(&local_decl.ty)).is_some() {
|
let ty = fx.monomorphize(&local_decl.ty);
|
||||||
|
if fx.clif_type(ty).is_some() || fx.clif_pair_type(ty).is_some() {
|
||||||
SsaKind::Ssa
|
SsaKind::Ssa
|
||||||
} else {
|
} else {
|
||||||
SsaKind::NotSsa
|
SsaKind::NotSsa
|
||||||
|
|
|
@ -67,6 +67,26 @@ fn clif_type_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<types::Typ
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clif_pair_type_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<(types::Type, types::Type)> {
|
||||||
|
Some(match ty.kind {
|
||||||
|
ty::Tuple(substs) if substs.len() == 2 => {
|
||||||
|
let mut types = substs.types();
|
||||||
|
(
|
||||||
|
clif_type_from_ty(tcx, types.next().unwrap())?,
|
||||||
|
clif_type_from_ty(tcx, types.next().unwrap())?,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ty::RawPtr(TypeAndMut { ty: pointee_ty, mutbl: _ }) | ty::Ref(_, pointee_ty, _) => {
|
||||||
|
if has_ptr_meta(tcx, pointee_ty) {
|
||||||
|
(pointer_ty(tcx), pointer_ty(tcx))
|
||||||
|
} else {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Is a pointer to this type a fat ptr?
|
/// Is a pointer to this type a fat ptr?
|
||||||
pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||||
let ptr_ty = tcx.mk_ptr(TypeAndMut { ty, mutbl: rustc_hir::Mutability::Not });
|
let ptr_ty = tcx.mk_ptr(TypeAndMut { ty, mutbl: rustc_hir::Mutability::Not });
|
||||||
|
@ -321,6 +341,10 @@ impl<'tcx, B: Backend + 'static> FunctionCx<'_, 'tcx, B> {
|
||||||
clif_type_from_ty(self.tcx, ty)
|
clif_type_from_ty(self.tcx, ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn clif_pair_type(&self, ty: Ty<'tcx>) -> Option<(Type, Type)> {
|
||||||
|
clif_pair_type_from_ty(self.tcx, ty)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn get_block(&self, bb: BasicBlock) -> Block {
|
pub(crate) fn get_block(&self, bb: BasicBlock) -> Block {
|
||||||
*self.block_map.get(bb).unwrap()
|
*self.block_map.get(bb).unwrap()
|
||||||
}
|
}
|
||||||
|
|
|
@ -405,6 +405,11 @@ fn place_location<'tcx>(
|
||||||
AttributeValue::Exprloc(Expression::new())
|
AttributeValue::Exprloc(Expression::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
CPlaceInner::VarPair(_, _, _) => {
|
||||||
|
// FIXME implement this
|
||||||
|
|
||||||
|
AttributeValue::Exprloc(Expression::new())
|
||||||
|
}
|
||||||
CPlaceInner::Addr(_, _) => {
|
CPlaceInner::Addr(_, _) => {
|
||||||
// FIXME implement this (used by arguments and returns)
|
// FIXME implement this (used by arguments and returns)
|
||||||
|
|
||||||
|
|
|
@ -179,12 +179,25 @@ impl<'tcx> CValue<'tcx> {
|
||||||
_ => unreachable!("value_field for ByVal with abi {:?}", layout.abi),
|
_ => unreachable!("value_field for ByVal with abi {:?}", layout.abi),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
CValueInner::ByValPair(val1, val2) => {
|
||||||
|
match layout.abi {
|
||||||
|
Abi::ScalarPair(_, _) => {
|
||||||
|
let val = match field.as_u32() {
|
||||||
|
0 => val1,
|
||||||
|
1 => val2,
|
||||||
|
_ => bug!("field should be 0 or 1"),
|
||||||
|
};
|
||||||
|
let field_layout = layout.field(&*fx, usize::from(field));
|
||||||
|
CValue::by_val(val, field_layout)
|
||||||
|
}
|
||||||
|
_ => unreachable!("value_field for ByValPair with abi {:?}", layout.abi),
|
||||||
|
}
|
||||||
|
}
|
||||||
CValueInner::ByRef(ptr, None) => {
|
CValueInner::ByRef(ptr, None) => {
|
||||||
let (field_ptr, field_layout) = codegen_field(fx, ptr, None, layout, field);
|
let (field_ptr, field_layout) = codegen_field(fx, ptr, None, layout, field);
|
||||||
CValue::by_ref(field_ptr, field_layout)
|
CValue::by_ref(field_ptr, field_layout)
|
||||||
}
|
}
|
||||||
CValueInner::ByRef(_, Some(_)) => todo!(),
|
CValueInner::ByRef(_, Some(_)) => todo!(),
|
||||||
_ => bug!("place_field for {:?}", self),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,6 +271,7 @@ pub(crate) struct CPlace<'tcx> {
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub(crate) enum CPlaceInner {
|
pub(crate) enum CPlaceInner {
|
||||||
Var(Local, Variable),
|
Var(Local, Variable),
|
||||||
|
VarPair(Local, Variable, Variable),
|
||||||
Addr(Pointer, Option<Value>),
|
Addr(Pointer, Option<Value>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,6 +326,25 @@ impl<'tcx> CPlace<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn new_var_pair(
|
||||||
|
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
|
||||||
|
local: Local,
|
||||||
|
layout: TyAndLayout<'tcx>,
|
||||||
|
) -> CPlace<'tcx> {
|
||||||
|
let var1 = Variable::with_u32(fx.next_ssa_var);
|
||||||
|
fx.next_ssa_var += 1;
|
||||||
|
let var2 = Variable::with_u32(fx.next_ssa_var);
|
||||||
|
fx.next_ssa_var += 1;
|
||||||
|
|
||||||
|
let (ty1, ty2) = fx.clif_pair_type(layout.ty).unwrap();
|
||||||
|
fx.bcx.declare_var(var1, ty1);
|
||||||
|
fx.bcx.declare_var(var2, ty2);
|
||||||
|
CPlace {
|
||||||
|
inner: CPlaceInner::VarPair(local, var1, var2),
|
||||||
|
layout,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn for_ptr(ptr: Pointer, layout: TyAndLayout<'tcx>) -> CPlace<'tcx> {
|
pub(crate) fn for_ptr(ptr: Pointer, layout: TyAndLayout<'tcx>) -> CPlace<'tcx> {
|
||||||
CPlace {
|
CPlace {
|
||||||
inner: CPlaceInner::Addr(ptr, None),
|
inner: CPlaceInner::Addr(ptr, None),
|
||||||
|
@ -334,6 +367,13 @@ impl<'tcx> CPlace<'tcx> {
|
||||||
fx.bcx.set_val_label(val, cranelift_codegen::ir::ValueLabel::new(var.index()));
|
fx.bcx.set_val_label(val, cranelift_codegen::ir::ValueLabel::new(var.index()));
|
||||||
CValue::by_val(val, layout)
|
CValue::by_val(val, layout)
|
||||||
}
|
}
|
||||||
|
CPlaceInner::VarPair(_local, var1, var2) => {
|
||||||
|
let val1 = fx.bcx.use_var(var1);
|
||||||
|
fx.bcx.set_val_label(val1, cranelift_codegen::ir::ValueLabel::new(var1.index()));
|
||||||
|
let val2 = fx.bcx.use_var(var2);
|
||||||
|
fx.bcx.set_val_label(val2, cranelift_codegen::ir::ValueLabel::new(var2.index()));
|
||||||
|
CValue::by_val_pair(val1, val2, layout)
|
||||||
|
}
|
||||||
CPlaceInner::Addr(ptr, extra) => {
|
CPlaceInner::Addr(ptr, extra) => {
|
||||||
if let Some(extra) = extra {
|
if let Some(extra) = extra {
|
||||||
CValue::by_ref_unsized(ptr, extra, layout)
|
CValue::by_ref_unsized(ptr, extra, layout)
|
||||||
|
@ -354,7 +394,8 @@ impl<'tcx> CPlace<'tcx> {
|
||||||
pub(crate) fn to_ptr_maybe_unsized(self) -> (Pointer, Option<Value>) {
|
pub(crate) fn to_ptr_maybe_unsized(self) -> (Pointer, Option<Value>) {
|
||||||
match self.inner {
|
match self.inner {
|
||||||
CPlaceInner::Addr(ptr, extra) => (ptr, extra),
|
CPlaceInner::Addr(ptr, extra) => (ptr, extra),
|
||||||
CPlaceInner::Var(_, _) => bug!("Expected CPlace::Addr, found {:?}", self),
|
CPlaceInner::Var(_, _)
|
||||||
|
| CPlaceInner::VarPair(_, _, _) => bug!("Expected CPlace::Addr, found {:?}", self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,6 +469,30 @@ impl<'tcx> CPlace<'tcx> {
|
||||||
#[cfg_attr(not(debug_assertions), allow(unused_variables))]
|
#[cfg_attr(not(debug_assertions), allow(unused_variables))]
|
||||||
method: &'static str,
|
method: &'static str,
|
||||||
) {
|
) {
|
||||||
|
fn transmute_value<'tcx>(
|
||||||
|
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
|
||||||
|
var: Variable,
|
||||||
|
data: Value,
|
||||||
|
dst_ty: Type,
|
||||||
|
) {
|
||||||
|
let src_ty = fx.bcx.func.dfg.value_type(data);
|
||||||
|
let data = match (src_ty, dst_ty) {
|
||||||
|
(_, _) if src_ty == dst_ty => data,
|
||||||
|
|
||||||
|
// This is a `write_cvalue_transmute`.
|
||||||
|
(types::I32, types::F32) | (types::F32, types::I32)
|
||||||
|
| (types::I64, types::F64) | (types::F64, types::I64) => {
|
||||||
|
fx.bcx.ins().bitcast(dst_ty, data)
|
||||||
|
}
|
||||||
|
_ if src_ty.is_vector() && dst_ty.is_vector() => {
|
||||||
|
fx.bcx.ins().raw_bitcast(dst_ty, data)
|
||||||
|
}
|
||||||
|
_ => unreachable!("write_cvalue_transmute: {:?} -> {:?}", src_ty, dst_ty),
|
||||||
|
};
|
||||||
|
fx.bcx.set_val_label(data, cranelift_codegen::ir::ValueLabel::new(var.index()));
|
||||||
|
fx.bcx.def_var(var, data);
|
||||||
|
}
|
||||||
|
|
||||||
assert_eq!(self.layout().size, from.layout().size);
|
assert_eq!(self.layout().size, from.layout().size);
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
|
@ -447,23 +512,15 @@ impl<'tcx> CPlace<'tcx> {
|
||||||
let to_ptr = match self.inner {
|
let to_ptr = match self.inner {
|
||||||
CPlaceInner::Var(_local, var) => {
|
CPlaceInner::Var(_local, var) => {
|
||||||
let data = CValue(from.0, dst_layout).load_scalar(fx);
|
let data = CValue(from.0, dst_layout).load_scalar(fx);
|
||||||
let src_ty = fx.bcx.func.dfg.value_type(data);
|
|
||||||
let dst_ty = fx.clif_type(self.layout().ty).unwrap();
|
let dst_ty = fx.clif_type(self.layout().ty).unwrap();
|
||||||
let data = match (src_ty, dst_ty) {
|
transmute_value(fx, var, data, dst_ty);
|
||||||
(_, _) if src_ty == dst_ty => data,
|
return;
|
||||||
|
}
|
||||||
// This is a `write_cvalue_transmute`.
|
CPlaceInner::VarPair(_local, var1, var2) => {
|
||||||
(types::I32, types::F32) | (types::F32, types::I32)
|
let (data1, data2) = CValue(from.0, dst_layout).load_scalar_pair(fx);
|
||||||
| (types::I64, types::F64) | (types::F64, types::I64) => {
|
let (dst_ty1, dst_ty2) = fx.clif_pair_type(self.layout().ty).unwrap();
|
||||||
fx.bcx.ins().bitcast(dst_ty, data)
|
transmute_value(fx, var1, data1, dst_ty1);
|
||||||
}
|
transmute_value(fx, var2, data2, dst_ty2);
|
||||||
_ if src_ty.is_vector() && dst_ty.is_vector() => {
|
|
||||||
fx.bcx.ins().raw_bitcast(dst_ty, data)
|
|
||||||
}
|
|
||||||
_ => unreachable!("write_cvalue_transmute: {:?} -> {:?}", src_ty, dst_ty),
|
|
||||||
};
|
|
||||||
fx.bcx.set_val_label(data, cranelift_codegen::ir::ValueLabel::new(var.index()));
|
|
||||||
fx.bcx.def_var(var, data);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CPlaceInner::Addr(ptr, None) => {
|
CPlaceInner::Addr(ptr, None) => {
|
||||||
|
@ -529,6 +586,22 @@ impl<'tcx> CPlace<'tcx> {
|
||||||
field: mir::Field,
|
field: mir::Field,
|
||||||
) -> CPlace<'tcx> {
|
) -> CPlace<'tcx> {
|
||||||
let layout = self.layout();
|
let layout = self.layout();
|
||||||
|
if let CPlaceInner::VarPair(local, var1, var2) = self.inner {
|
||||||
|
let layout = layout.field(&*fx, field.index());
|
||||||
|
|
||||||
|
match field.as_u32() {
|
||||||
|
0 => return CPlace {
|
||||||
|
inner: CPlaceInner::Var(local, var1),
|
||||||
|
layout,
|
||||||
|
},
|
||||||
|
1 => return CPlace {
|
||||||
|
inner: CPlaceInner::Var(local, var2),
|
||||||
|
layout,
|
||||||
|
},
|
||||||
|
_ => unreachable!("field should be 0 or 1"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let (base, extra) = self.to_ptr_maybe_unsized();
|
let (base, extra) = self.to_ptr_maybe_unsized();
|
||||||
|
|
||||||
let (field_ptr, field_layout) = codegen_field(fx, base, extra, layout, field);
|
let (field_ptr, field_layout) = codegen_field(fx, base, extra, layout, field);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue