From b5082f7da85303e5aee97949e98fd137fa77f845 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 22 Aug 2018 15:38:10 +0200 Subject: [PATCH] Support unsized types --- examples/example.rs | 4 +- src/abi.rs | 13 +++-- src/base.rs | 11 +---- src/common.rs | 115 ++++++++++++++++++++++++++++++++++++++++---- src/constant.rs | 3 +- src/lib.rs | 2 +- 6 files changed, 123 insertions(+), 25 deletions(-) diff --git a/examples/example.rs b/examples/example.rs index 6d84fb148c0f..efe07ca2eccb 100644 --- a/examples/example.rs +++ b/examples/example.rs @@ -141,9 +141,9 @@ unsafe fn call_uninit() -> u8 { } // TODO: enable when fat pointers are supported -/*unsafe fn deref_str_ptr(s: *const str) -> &'static str { +unsafe fn deref_str_ptr(s: *const str) -> &'static str { &*s -}*/ +} fn use_array(arr: [u8; 3]) -> u8 { arr[1] diff --git a/src/abi.rs b/src/abi.rs index b5967e734190..112d87743fea 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -28,6 +28,11 @@ fn get_pass_mode<'a, 'tcx: 'a>( ty: Ty<'tcx>, is_return: bool, ) -> PassMode { + assert!( + !tcx.layout_of(ParamEnv::reveal_all().and(ty)) + .unwrap() + .is_unsized() + ); if ty.sty == tcx.mk_nil().sty { if is_return { //if false { @@ -312,7 +317,7 @@ pub fn codegen_fn_prelude<'a, 'tcx: 'a>( //unimplemented!("pass mode nopass"); fx.local_map.insert( RETURN_PLACE, - CPlace::Addr(null, fx.layout_of(fx.return_type())), + CPlace::Addr(null, None, fx.layout_of(fx.return_type())), ); } PassMode::ByVal(ret_ty) => { @@ -321,8 +326,10 @@ pub fn codegen_fn_prelude<'a, 'tcx: 'a>( .insert(RETURN_PLACE, CPlace::Var(RETURN_PLACE, ret_layout)); } PassMode::ByRef => { - fx.local_map - .insert(RETURN_PLACE, CPlace::Addr(ret_param.unwrap(), ret_layout)); + fx.local_map.insert( + RETURN_PLACE, + CPlace::Addr(ret_param.unwrap(), None, ret_layout), + ); } } diff --git a/src/base.rs b/src/base.rs index 8627cf66a83e..8cbdf6db855a 100644 --- a/src/base.rs +++ b/src/base.rs @@ -309,8 +309,7 @@ fn trans_stmt<'a, 'tcx: 'a>( } Rvalue::Ref(_, _, place) => { let place = trans_place(fx, place); - let addr = place.expect_addr(); - lval.write_cvalue(fx, CValue::ByVal(addr, dest_layout)); + place.write_place_ref(fx, lval); } Rvalue::BinaryOp(bin_op, lhs, rhs) => { let ty = fx.monomorphize(&lhs.ty(&fx.mir.local_decls, fx.tcx)); @@ -893,13 +892,7 @@ pub fn trans_place<'a, 'tcx: 'a>( Place::Projection(projection) => { let base = trans_place(fx, &projection.base); match projection.elem { - ProjectionElem::Deref => { - let layout = fx.layout_of(place.ty(&*fx.mir, fx.tcx).to_ty(fx.tcx)); - if layout.is_unsized() { - unimpl!("Unsized places are not yet implemented"); - } - CPlace::Addr(base.to_cvalue(fx).load_value(fx), layout) - } + ProjectionElem::Deref => base.place_deref(fx), ProjectionElem::Field(field, _ty) => base.place_field(fx, field), ProjectionElem::Index(local) => { let index = fx.get_local_place(local).to_cvalue(fx).load_value(fx); diff --git a/src/common.rs b/src/common.rs index 8f0236fb7f00..768c8cd25e1a 100644 --- a/src/common.rs +++ b/src/common.rs @@ -19,6 +19,24 @@ pub fn pointer_ty(tcx: TyCtxt) -> types::Type { } } +fn scalar_to_cton_type(tcx: TyCtxt, scalar: &Scalar) -> Type { + match scalar.value.size(tcx).bits() { + 8 => types::I8, + 16 => types::I16, + 32 => types::I32, + 64 => types::I64, + size => bug!("Unsupported scalar size {}", size), + } +} + +fn ptr_referee<'tcx>(ty: Ty<'tcx>) -> Ty<'tcx> { + match ty.sty { + ty::Ref(_, ty, _) => ty, + ty::RawPtr(TypeAndMut { ty, mutbl: _ }) => ty, + _ => bug!("{:?}", ty), + } +} + pub fn cton_type_from_ty<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>, @@ -224,18 +242,19 @@ impl<'tcx> CValue<'tcx> { #[derive(Debug, Copy, Clone)] pub enum CPlace<'tcx> { Var(Local, TyLayout<'tcx>), - Addr(Value, TyLayout<'tcx>), + Addr(Value, Option, TyLayout<'tcx>), } impl<'a, 'tcx: 'a> CPlace<'tcx> { pub fn layout(&self) -> TyLayout<'tcx> { match *self { - CPlace::Var(_, layout) | CPlace::Addr(_, layout) => layout, + CPlace::Var(_, layout) | CPlace::Addr(_, _, layout) => layout, } } pub fn temp(fx: &mut FunctionCx<'a, 'tcx, impl Backend>, ty: Ty<'tcx>) -> CPlace<'tcx> { let layout = fx.layout_of(ty); + assert!(!layout.is_unsized()); let stack_slot = fx.bcx.create_stack_slot(StackSlotData { kind: StackSlotKind::ExplicitSlot, size: layout.size.bytes() as u32, @@ -245,6 +264,7 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> { fx.bcx .ins() .stack_addr(fx.module.pointer_type(), stack_slot, 0), + None, layout, ) } @@ -255,10 +275,12 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> { ty: Ty<'tcx>, ) -> CPlace<'tcx> { let layout = fx.layout_of(ty); + assert!(!layout.is_unsized()); CPlace::Addr( fx.bcx .ins() .stack_addr(fx.module.pointer_type(), stack_slot, 0), + None, layout, ) } @@ -266,13 +288,17 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> { pub fn to_cvalue(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>) -> CValue<'tcx> { match self { CPlace::Var(var, layout) => CValue::ByVal(fx.bcx.use_var(mir_var(var)), layout), - CPlace::Addr(addr, layout) => CValue::ByRef(addr, layout), + CPlace::Addr(addr, extra, layout) => { + assert!(extra.is_none(), "unsized values are not yet supported"); + CValue::ByRef(addr, layout) + } } } pub fn expect_addr(self) -> Value { match self { - CPlace::Addr(addr, _layout) => addr, + CPlace::Addr(addr, None, _layout) => addr, + CPlace::Addr(_, _, _) => bug!("Expected sized CPlace::Addr, found {:?}", self), CPlace::Var(_, _) => bug!("Expected CPlace::Addr, found CPlace::Var"), } } @@ -308,7 +334,7 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> { let data = from.load_value(fx); fx.bcx.def_var(mir_var(var), data) } - CPlace::Addr(addr, layout) => { + CPlace::Addr(addr, None, layout) => { let size = layout.size.bytes() as i32; match from { @@ -346,6 +372,7 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> { } } } + CPlace::Addr(_, _, _) => bug!("Can't write value to unsized place {:?}", self), } } @@ -354,11 +381,14 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> { fx: &mut FunctionCx<'a, 'tcx, impl Backend>, field: mir::Field, ) -> CPlace<'tcx> { - let base = self.expect_addr(); let layout = self.layout(); + if layout.is_unsized() { + unimpl!("unsized place_field"); + } + let base = self.expect_addr(); let (field_ptr, field_layout) = codegen_field(fx, base, layout, field); - CPlace::Addr(field_ptr, field_layout) + CPlace::Addr(field_ptr, None, field_layout) } pub fn place_index( @@ -368,6 +398,10 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> { ) -> CPlace<'tcx> { let addr = self.expect_addr(); let layout = self.layout(); + if layout.is_unsized() { + unimpl!("unsized place_field"); + } + match layout.ty.sty { ty::Array(elem_ty, _) => { let elem_layout = fx.layout_of(elem_ty); @@ -375,17 +409,80 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> { .bcx .ins() .imul_imm(index, elem_layout.size.bytes() as i64); - CPlace::Addr(fx.bcx.ins().iadd(addr, offset), elem_layout) + CPlace::Addr(fx.bcx.ins().iadd(addr, offset), None, elem_layout) } ty::Slice(_elem_ty) => unimplemented!("place_index(TySlice)"), _ => bug!("place_index({:?})", layout.ty), } } + pub fn place_deref(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>) -> CPlace<'tcx> { + let inner_layout = fx.layout_of(ptr_referee(self.layout().ty)); + if !inner_layout.is_unsized() { + CPlace::Addr(self.to_cvalue(fx).load_value(fx), None, inner_layout) + } else { + match self.layout().abi { + Abi::ScalarPair(ref a, ref b) => { + let addr = self.expect_addr(); + let ptr = + fx.bcx + .ins() + .load(scalar_to_cton_type(fx.tcx, a), MemFlags::new(), addr, 0); + let extra = fx.bcx.ins().load( + scalar_to_cton_type(fx.tcx, b), + MemFlags::new(), + addr, + a.value.size(fx.tcx).bytes() as u32 as i32, + ); + println!( + "unsized deref: ptr: {:?} extra: {:?} self: {:?}", + ptr, extra, self + ); + CPlace::Addr(ptr, Some(extra), inner_layout) + } + _ => bug!( + "Fat ptr doesn't have abi ScalarPair, but it has {:?}", + self.layout().abi + ), + } + } + } + + pub fn write_place_ref(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>, dest: CPlace<'tcx>) { + if !self.layout().is_unsized() { + let ptr = CValue::ByVal(self.expect_addr(), dest.layout()); + dest.write_cvalue(fx, ptr); + } else { + match self { + CPlace::Var(_, _) => bug!("expected CPlace::Addr found CPlace::Var"), + CPlace::Addr(value, extra, _) => match dest.layout().abi { + Abi::ScalarPair(ref a, _) => { + fx.bcx + .ins() + .store(MemFlags::new(), value, dest.expect_addr(), 0); + fx.bcx.ins().store( + MemFlags::new(), + extra.expect("unsized type without metadata"), + dest.expect_addr(), + a.value.size(fx.tcx).bytes() as u32 as i32, + ); + } + _ => bug!( + "Non ScalarPair abi {:?} in write_place_ref dest", + dest.layout().abi + ), + }, + } + } + } + pub fn unchecked_cast_to(self, layout: TyLayout<'tcx>) -> Self { match self { CPlace::Var(var, _) => CPlace::Var(var, layout), - CPlace::Addr(addr, _) => CPlace::Addr(addr, layout), + CPlace::Addr(addr, extra, _) => { + assert!(!layout.is_unsized()); + CPlace::Addr(addr, extra, layout) + } } } diff --git a/src/constant.rs b/src/constant.rs index b5ce5f198f41..f912f435fcbf 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -179,7 +179,8 @@ fn cplace_for_dataid<'a, 'tcx: 'a>( .ins() .global_value(fx.module.pointer_type(), local_data_id); let layout = fx.layout_of(fx.monomorphize(&ty)); - CPlace::Addr(global_ptr, layout) + assert!(!layout.is_unsized(), "unsized statics aren't supported"); + CPlace::Addr(global_ptr, None, layout) } fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>( diff --git a/src/lib.rs b/src/lib.rs index 5397f5b48716..fa74f928ddb4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,7 +63,7 @@ mod prelude { pub use rustc::mir::interpret::AllocId; pub use rustc::mir::*; pub use rustc::session::{config::CrateType, Session}; - pub use rustc::ty::layout::{self, LayoutOf, Size, TyLayout}; + pub use rustc::ty::layout::{self, Abi, LayoutOf, Scalar, Size, TyLayout}; pub use rustc::ty::{ self, subst::Substs, FnSig, Instance, InstanceDef, ParamEnv, PolyFnSig, Ty, TyCtxt, TypeAndMut, TypeFoldable,