From aa80ed0a2ddf61acc136e5ae89ee1608046b9493 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 2 Jul 2020 19:23:21 -0300 Subject: [PATCH 1/3] Store pairs in SSA --- src/abi/comments.rs | 4 ++ src/abi/mod.rs | 6 ++- src/analyze.rs | 3 +- src/common.rs | 17 +++++++ src/debuginfo/mod.rs | 5 +++ src/value_and_place.rs | 100 ++++++++++++++++++++++++++++++++++++++++- 6 files changed, 131 insertions(+), 4 deletions(-) diff --git a/src/abi/comments.rs b/src/abi/comments.rs index 0bfc00c8367..7c4d7b12f6e 100644 --- a/src/abi/comments.rs +++ b/src/abi/comments.rs @@ -78,6 +78,10 @@ pub(super) fn add_local_place_comments<'tcx>( assert_eq!(local, place_local); ("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) => { let meta = if let Some(meta) = meta { Cow::Owned(format!(",meta={}", meta)) diff --git a/src/abi/mod.rs b/src/abi/mod.rs index a70314758d0..066383fd831 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -290,7 +290,11 @@ fn local_place<'tcx>( is_ssa: bool, ) -> CPlace<'tcx> { 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 { CPlace::new_stack_slot(fx, layout) }; diff --git a/src/analyze.rs b/src/analyze.rs index afb8ac409fe..c3436785d90 100644 --- a/src/analyze.rs +++ b/src/analyze.rs @@ -11,7 +11,8 @@ pub(crate) enum SsaKind { pub(crate) fn analyze(fx: &FunctionCx<'_, '_, impl Backend>) -> IndexVec { 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 } else { SsaKind::NotSsa diff --git a/src/common.rs b/src/common.rs index 248ac14d7e4..02b05e5b2dd 100644 --- a/src/common.rs +++ b/src/common.rs @@ -67,6 +67,19 @@ fn clif_type_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option(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())?, + ) + } + _ => return None, + }) +} + /// Is a pointer to this type a fat ptr? 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 }); @@ -321,6 +334,10 @@ impl<'tcx, B: Backend + 'static> FunctionCx<'_, 'tcx, B> { 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 { *self.block_map.get(bb).unwrap() } diff --git a/src/debuginfo/mod.rs b/src/debuginfo/mod.rs index 4b22f06f3d1..709c85d2409 100644 --- a/src/debuginfo/mod.rs +++ b/src/debuginfo/mod.rs @@ -405,6 +405,11 @@ fn place_location<'tcx>( AttributeValue::Exprloc(Expression::new()) } } + CPlaceInner::VarPair(_, _, _) => { + // FIXME implement this + + AttributeValue::Exprloc(Expression::new()) + } CPlaceInner::Addr(_, _) => { // FIXME implement this (used by arguments and returns) diff --git a/src/value_and_place.rs b/src/value_and_place.rs index c25458856b6..a55bfddeaaf 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -179,12 +179,25 @@ impl<'tcx> CValue<'tcx> { _ => 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) => { let (field_ptr, field_layout) = codegen_field(fx, ptr, None, layout, field); CValue::by_ref(field_ptr, field_layout) } CValueInner::ByRef(_, Some(_)) => todo!(), - _ => bug!("place_field for {:?}", self), } } @@ -258,6 +271,7 @@ pub(crate) struct CPlace<'tcx> { #[derive(Debug, Copy, Clone)] pub(crate) enum CPlaceInner { Var(Local, Variable), + VarPair(Local, Variable, Variable), Addr(Pointer, Option), } @@ -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> { CPlace { 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())); 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) => { if let Some(extra) = extra { 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) { match self.inner { CPlaceInner::Addr(ptr, extra) => (ptr, extra), - CPlaceInner::Var(_, _) => bug!("Expected CPlace::Addr, found {:?}", self), + CPlaceInner::Var(_, _) + | CPlaceInner::VarPair(_, _, _) => bug!("Expected CPlace::Addr, found {:?}", self), } } @@ -466,6 +507,45 @@ impl<'tcx> CPlace<'tcx> { fx.bcx.def_var(var, data); return; } + CPlaceInner::VarPair(_local, var1, var2) => { + let (data1, data2) = CValue(from.0, dst_layout).load_scalar_pair(fx); + let (dst_ty1, dst_ty2) = fx.clif_pair_type(self.layout().ty).unwrap(); + + let src_ty1 = fx.bcx.func.dfg.value_type(data1); + let data = match (src_ty1, dst_ty1) { + (_, _) if src_ty1 == dst_ty1 => data1, + + // 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_ty1, data1) + } + _ if src_ty1.is_vector() && dst_ty1.is_vector() => { + fx.bcx.ins().raw_bitcast(dst_ty1, data1) + } + _ => unreachable!("write_cvalue_transmute: {:?} -> {:?}", src_ty1, dst_ty1), + }; + fx.bcx.set_val_label(data, cranelift_codegen::ir::ValueLabel::new(var1.index())); + fx.bcx.def_var(var1, data); + + let src_ty2 = fx.bcx.func.dfg.value_type(data2); + let data = match (src_ty2, dst_ty2) { + (_, _) if src_ty2 == dst_ty2 => data2, + + // 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_ty2, data2) + } + _ if src_ty2.is_vector() && dst_ty2.is_vector() => { + fx.bcx.ins().raw_bitcast(dst_ty2, data2) + } + _ => unreachable!("write_cvalue_transmute: {:?} -> {:?}", src_ty2, dst_ty2), + }; + fx.bcx.set_val_label(data, cranelift_codegen::ir::ValueLabel::new(var2.index())); + fx.bcx.def_var(var2, data); + return; + } CPlaceInner::Addr(ptr, None) => { if dst_layout.size == Size::ZERO || dst_layout.abi == Abi::Uninhabited { return; @@ -529,6 +609,22 @@ impl<'tcx> CPlace<'tcx> { field: mir::Field, ) -> CPlace<'tcx> { 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 (field_ptr, field_layout) = codegen_field(fx, base, extra, layout, field); From 9ec2be7d63ce1857721efab8b4a6d5fdd762e1b0 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 3 Jul 2020 09:43:02 -0300 Subject: [PATCH 2/3] Extract transmute_value as a function to avoid code repetition --- src/value_and_place.rs | 77 +++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 50 deletions(-) diff --git a/src/value_and_place.rs b/src/value_and_place.rs index a55bfddeaaf..1d0990163bb 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -469,6 +469,30 @@ impl<'tcx> CPlace<'tcx> { #[cfg_attr(not(debug_assertions), allow(unused_variables))] 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); #[cfg(debug_assertions)] @@ -488,62 +512,15 @@ impl<'tcx> CPlace<'tcx> { let to_ptr = match self.inner { CPlaceInner::Var(_local, var) => { 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 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); + transmute_value(fx, var, data, dst_ty); return; } CPlaceInner::VarPair(_local, var1, var2) => { let (data1, data2) = CValue(from.0, dst_layout).load_scalar_pair(fx); let (dst_ty1, dst_ty2) = fx.clif_pair_type(self.layout().ty).unwrap(); - - let src_ty1 = fx.bcx.func.dfg.value_type(data1); - let data = match (src_ty1, dst_ty1) { - (_, _) if src_ty1 == dst_ty1 => data1, - - // 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_ty1, data1) - } - _ if src_ty1.is_vector() && dst_ty1.is_vector() => { - fx.bcx.ins().raw_bitcast(dst_ty1, data1) - } - _ => unreachable!("write_cvalue_transmute: {:?} -> {:?}", src_ty1, dst_ty1), - }; - fx.bcx.set_val_label(data, cranelift_codegen::ir::ValueLabel::new(var1.index())); - fx.bcx.def_var(var1, data); - - let src_ty2 = fx.bcx.func.dfg.value_type(data2); - let data = match (src_ty2, dst_ty2) { - (_, _) if src_ty2 == dst_ty2 => data2, - - // 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_ty2, data2) - } - _ if src_ty2.is_vector() && dst_ty2.is_vector() => { - fx.bcx.ins().raw_bitcast(dst_ty2, data2) - } - _ => unreachable!("write_cvalue_transmute: {:?} -> {:?}", src_ty2, dst_ty2), - }; - fx.bcx.set_val_label(data, cranelift_codegen::ir::ValueLabel::new(var2.index())); - fx.bcx.def_var(var2, data); + transmute_value(fx, var1, data1, dst_ty1); + transmute_value(fx, var2, data2, dst_ty2); return; } CPlaceInner::Addr(ptr, None) => { From ef01b4e3dda14e592946d74169b6ed9ed71cc9b7 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 3 Jul 2020 09:48:19 -0300 Subject: [PATCH 3/3] Store fat pointers in ssa variables --- src/common.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/common.rs b/src/common.rs index 02b05e5b2dd..c5f2e3dee43 100644 --- a/src/common.rs +++ b/src/common.rs @@ -76,6 +76,13 @@ fn clif_pair_type_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<(type 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, }) }