From 0117b7872ad9be5e9484bd27eb271022d31ce82e Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Thu, 23 Aug 2018 11:03:43 +0200 Subject: [PATCH 1/5] Don't grep away parts of log --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index ce8359698f0d..a3d31c6c7706 100755 --- a/build.sh +++ b/build.sh @@ -41,4 +41,4 @@ gcc target/out/mini_core.o target/out/mini_core_hello_world.o -o target/out/mini ./target/out/mini_core_hello_world $RUSTC target/libcore/src/libcore/lib.rs --color=always --crate-type lib -Cincremental=target/incremental 2>&1 | (head -n 20; echo "===="; tail -n 1000) -cat target/out/log.txt | sort | uniq -c | grep -v "rval unsize move" | grep -v "rval len" +cat target/out/log.txt | sort | uniq -c From b5082f7da85303e5aee97949e98fd137fa77f845 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 22 Aug 2018 15:38:10 +0200 Subject: [PATCH 2/5] 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, From 12282a8ebc2404add07224a74b872cecf6d602da Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 22 Aug 2018 15:38:56 +0200 Subject: [PATCH 3/5] Implement unsize array -> slice and trait object -> trait object --- examples/example.rs | 4 ++++ examples/mini_core_hello_world.rs | 3 ++- src/base.rs | 3 ++- src/common.rs | 37 +++++++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/examples/example.rs b/examples/example.rs index efe07ca2eccb..dfca3142301d 100644 --- a/examples/example.rs +++ b/examples/example.rs @@ -153,6 +153,10 @@ fn repeat_array() -> [u8; 3] { [0; 3] } +fn array_as_slice(arr: &[u8; 3]) -> &[u8] { + arr +} + /*unsafe fn use_ctlz_nonzero(a: u16) -> u16 { intrinsics::ctlz_nonzero(a) }*/ diff --git a/examples/mini_core_hello_world.rs b/examples/mini_core_hello_world.rs index 19cc727fb55e..c775beef2f09 100644 --- a/examples/mini_core_hello_world.rs +++ b/examples/mini_core_hello_world.rs @@ -43,7 +43,8 @@ static NUM_REF: &'static u8 = unsafe { &NUM }; fn main() { unsafe { - let (ptr, _): (*const u8, usize) = intrinsics::transmute("Hello!\0"); + let slice: &[u8] = b"Hello!\0" as &[u8; 7]; + let ptr: *const u8 = slice as *const [u8] as *const u8; puts(ptr); } diff --git a/src/base.rs b/src/base.rs index 8cbdf6db855a..9b44cd2e4b73 100644 --- a/src/base.rs +++ b/src/base.rs @@ -458,7 +458,8 @@ fn trans_stmt<'a, 'tcx: 'a>( unimplemented!("rval closure_fn_ptr {:?} {:?}", operand, ty) } Rvalue::Cast(CastKind::Unsize, operand, ty) => { - unimpl!("rval unsize {:?} {:?}", operand, ty); + let operand = trans_operand(fx, operand); + operand.unsize_value(fx, lval); } Rvalue::Discriminant(place) => { let place = trans_place(fx, place).to_cvalue(fx); diff --git a/src/common.rs b/src/common.rs index 768c8cd25e1a..b785177251fa 100644 --- a/src/common.rs +++ b/src/common.rs @@ -216,6 +216,43 @@ impl<'tcx> CValue<'tcx> { CValue::ByRef(field_ptr, field_layout) } + pub fn unsize_value<'a>(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>, dest: CPlace<'tcx>) { + if self.layout().ty == dest.layout().ty { + dest.write_cvalue(fx, self); // FIXME this shouldn't happen (rust-lang/rust#53602) + return; + } + match &self.layout().ty.sty { + ty::Ref(_, ty, _) | ty::RawPtr(TypeAndMut { ty, mutbl: _ }) => { + let (ptr, extra) = match ptr_referee(dest.layout().ty).sty { + ty::Slice(slice_elem_ty) => match ty.sty { + ty::Array(array_elem_ty, size) => { + assert_eq!(slice_elem_ty, array_elem_ty); + let ptr = self.load_value(fx); + let extra = fx + .bcx + .ins() + .iconst(fx.module.pointer_type(), size.unwrap_usize(fx.tcx) as i64); + (ptr, extra) + } + _ => bug!("unsize non array {:?} to slice", ty), + }, + ty::Dynamic(_, _) => match ty.sty { + ty::Dynamic(_, _) => self.load_value_pair(fx), + _ => unimpl!("unsize of type ... to {:?}", dest.layout().ty), + }, + _ => bug!( + "unsize of type {:?} to {:?}", + self.layout().ty, + dest.layout().ty + ), + }; + println!("ty {:?}", self.layout().ty); + dest.write_cvalue(fx, CValue::ByValPair(ptr, extra, dest.layout())); + } + ty => unimpl!("unsize of non ptr {:?}", ty), + } + } + pub fn const_val<'a>( fx: &mut FunctionCx<'a, 'tcx, impl Backend>, ty: Ty<'tcx>, From fa4a37759be06c2b96c133cfc0f85b7cf2ce00b4 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 22 Aug 2018 17:58:25 +0200 Subject: [PATCH 4/5] Rvalue::Len --- src/base.rs | 10 +++++++++- src/common.rs | 15 ++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/base.rs b/src/base.rs index 9b44cd2e4b73..c0ea7644f903 100644 --- a/src/base.rs +++ b/src/base.rs @@ -474,7 +474,15 @@ fn trans_stmt<'a, 'tcx: 'a>( to.write_cvalue(fx, operand); } } - Rvalue::Len(lval) => unimpl!("rval len {:?}", lval), + Rvalue::Len(place) => { + let place = trans_place(fx, place); + let size = match place { + CPlace::Addr(_, size, _) => size.unwrap(), + CPlace::Var(_, _) => unreachable!(), + }; + let usize_layout = fx.layout_of(fx.tcx.types.usize); + lval.write_cvalue(fx, CValue::ByVal(size, usize_layout)); + } Rvalue::NullaryOp(NullOp::Box, ty) => unimplemented!("rval box {:?}", ty), Rvalue::NullaryOp(NullOp::SizeOf, ty) => { assert!( diff --git a/src/common.rs b/src/common.rs index b785177251fa..9bd3e823fcb3 100644 --- a/src/common.rs +++ b/src/common.rs @@ -433,23 +433,20 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> { fx: &mut FunctionCx<'a, 'tcx, impl Backend>, index: Value, ) -> CPlace<'tcx> { - let addr = self.expect_addr(); - let layout = self.layout(); - if layout.is_unsized() { - unimpl!("unsized place_field"); - } - - match layout.ty.sty { + match self.layout().ty.sty { ty::Array(elem_ty, _) => { let elem_layout = fx.layout_of(elem_ty); + let offset = fx .bcx .ins() .imul_imm(index, elem_layout.size.bytes() as i64); + + let addr = self.expect_addr(); CPlace::Addr(fx.bcx.ins().iadd(addr, offset), None, elem_layout) } - ty::Slice(_elem_ty) => unimplemented!("place_index(TySlice)"), - _ => bug!("place_index({:?})", layout.ty), + ty::Slice(_elem_ty) => unimpl!("place_index(TySlice)"), + _ => bug!("place_index({:?})", self.layout().ty), } } From 9878eea61c7a715d798640e932d9752043599ee3 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 25 Aug 2018 11:22:48 +0200 Subject: [PATCH 5/5] Implement indexing for slices --- examples/example.rs | 4 ++++ examples/mini_core.rs | 8 ++++++++ src/common.rs | 31 +++++++++++++++++-------------- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/examples/example.rs b/examples/example.rs index dfca3142301d..5df8e69efd3e 100644 --- a/examples/example.rs +++ b/examples/example.rs @@ -180,3 +180,7 @@ fn make_array() -> [u8; 3] { fn some_promoted_tuple() -> &'static (&'static str, &'static str) { &("abc", "some") } + +fn index_slice(s: &[u8]) -> u8 { + s[2] +} diff --git a/examples/mini_core.rs b/examples/mini_core.rs index 7813f8a4c34f..2eb2e9502565 100644 --- a/examples/mini_core.rs +++ b/examples/mini_core.rs @@ -207,3 +207,11 @@ impl Index for [T; 3] { &self[index] } } + +impl Index for [T] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} diff --git a/src/common.rs b/src/common.rs index 9bd3e823fcb3..fd98d83221a9 100644 --- a/src/common.rs +++ b/src/common.rs @@ -433,21 +433,24 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> { fx: &mut FunctionCx<'a, 'tcx, impl Backend>, index: Value, ) -> CPlace<'tcx> { - match self.layout().ty.sty { - ty::Array(elem_ty, _) => { - let elem_layout = fx.layout_of(elem_ty); - - let offset = fx - .bcx - .ins() - .imul_imm(index, elem_layout.size.bytes() as i64); - - let addr = self.expect_addr(); - CPlace::Addr(fx.bcx.ins().iadd(addr, offset), None, elem_layout) - } - ty::Slice(_elem_ty) => unimpl!("place_index(TySlice)"), + let (elem_layout, addr) = match self.layout().ty.sty { + ty::Array(elem_ty, _) => (fx.layout_of(elem_ty), self.expect_addr()), + ty::Slice(elem_ty) => ( + fx.layout_of(elem_ty), + match self { + CPlace::Addr(addr, _, _) => addr, + CPlace::Var(_, _) => bug!("Expected CPlace::Addr found CPlace::Var"), + }, + ), _ => bug!("place_index({:?})", self.layout().ty), - } + }; + + let offset = fx + .bcx + .ins() + .imul_imm(index, elem_layout.size.bytes() as i64); + + CPlace::Addr(fx.bcx.ins().iadd(addr, offset), None, elem_layout) } pub fn place_deref(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>) -> CPlace<'tcx> {