1
Fork 0

Support unsized types

This commit is contained in:
bjorn3 2018-08-22 15:38:10 +02:00
parent 0117b7872a
commit b5082f7da8
6 changed files with 123 additions and 25 deletions

View file

@ -141,9 +141,9 @@ unsafe fn call_uninit() -> u8 {
} }
// TODO: enable when fat pointers are supported // 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 &*s
}*/ }
fn use_array(arr: [u8; 3]) -> u8 { fn use_array(arr: [u8; 3]) -> u8 {
arr[1] arr[1]

View file

@ -28,6 +28,11 @@ fn get_pass_mode<'a, 'tcx: 'a>(
ty: Ty<'tcx>, ty: Ty<'tcx>,
is_return: bool, is_return: bool,
) -> PassMode { ) -> PassMode {
assert!(
!tcx.layout_of(ParamEnv::reveal_all().and(ty))
.unwrap()
.is_unsized()
);
if ty.sty == tcx.mk_nil().sty { if ty.sty == tcx.mk_nil().sty {
if is_return { if is_return {
//if false { //if false {
@ -312,7 +317,7 @@ pub fn codegen_fn_prelude<'a, 'tcx: 'a>(
//unimplemented!("pass mode nopass"); //unimplemented!("pass mode nopass");
fx.local_map.insert( fx.local_map.insert(
RETURN_PLACE, 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) => { 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)); .insert(RETURN_PLACE, CPlace::Var(RETURN_PLACE, ret_layout));
} }
PassMode::ByRef => { PassMode::ByRef => {
fx.local_map fx.local_map.insert(
.insert(RETURN_PLACE, CPlace::Addr(ret_param.unwrap(), ret_layout)); RETURN_PLACE,
CPlace::Addr(ret_param.unwrap(), None, ret_layout),
);
} }
} }

View file

@ -309,8 +309,7 @@ fn trans_stmt<'a, 'tcx: 'a>(
} }
Rvalue::Ref(_, _, place) => { Rvalue::Ref(_, _, place) => {
let place = trans_place(fx, place); let place = trans_place(fx, place);
let addr = place.expect_addr(); place.write_place_ref(fx, lval);
lval.write_cvalue(fx, CValue::ByVal(addr, dest_layout));
} }
Rvalue::BinaryOp(bin_op, lhs, rhs) => { Rvalue::BinaryOp(bin_op, lhs, rhs) => {
let ty = fx.monomorphize(&lhs.ty(&fx.mir.local_decls, fx.tcx)); 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) => { Place::Projection(projection) => {
let base = trans_place(fx, &projection.base); let base = trans_place(fx, &projection.base);
match projection.elem { match projection.elem {
ProjectionElem::Deref => { ProjectionElem::Deref => base.place_deref(fx),
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::Field(field, _ty) => base.place_field(fx, field), ProjectionElem::Field(field, _ty) => base.place_field(fx, field),
ProjectionElem::Index(local) => { ProjectionElem::Index(local) => {
let index = fx.get_local_place(local).to_cvalue(fx).load_value(fx); let index = fx.get_local_place(local).to_cvalue(fx).load_value(fx);

View file

@ -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>( pub fn cton_type_from_ty<'a, 'tcx: 'a>(
tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty: Ty<'tcx>, ty: Ty<'tcx>,
@ -224,18 +242,19 @@ impl<'tcx> CValue<'tcx> {
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub enum CPlace<'tcx> { pub enum CPlace<'tcx> {
Var(Local, TyLayout<'tcx>), Var(Local, TyLayout<'tcx>),
Addr(Value, TyLayout<'tcx>), Addr(Value, Option<Value>, TyLayout<'tcx>),
} }
impl<'a, 'tcx: 'a> CPlace<'tcx> { impl<'a, 'tcx: 'a> CPlace<'tcx> {
pub fn layout(&self) -> TyLayout<'tcx> { pub fn layout(&self) -> TyLayout<'tcx> {
match *self { 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> { pub fn temp(fx: &mut FunctionCx<'a, 'tcx, impl Backend>, ty: Ty<'tcx>) -> CPlace<'tcx> {
let layout = fx.layout_of(ty); let layout = fx.layout_of(ty);
assert!(!layout.is_unsized());
let stack_slot = fx.bcx.create_stack_slot(StackSlotData { let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
kind: StackSlotKind::ExplicitSlot, kind: StackSlotKind::ExplicitSlot,
size: layout.size.bytes() as u32, size: layout.size.bytes() as u32,
@ -245,6 +264,7 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> {
fx.bcx fx.bcx
.ins() .ins()
.stack_addr(fx.module.pointer_type(), stack_slot, 0), .stack_addr(fx.module.pointer_type(), stack_slot, 0),
None,
layout, layout,
) )
} }
@ -255,10 +275,12 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> {
ty: Ty<'tcx>, ty: Ty<'tcx>,
) -> CPlace<'tcx> { ) -> CPlace<'tcx> {
let layout = fx.layout_of(ty); let layout = fx.layout_of(ty);
assert!(!layout.is_unsized());
CPlace::Addr( CPlace::Addr(
fx.bcx fx.bcx
.ins() .ins()
.stack_addr(fx.module.pointer_type(), stack_slot, 0), .stack_addr(fx.module.pointer_type(), stack_slot, 0),
None,
layout, 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> { pub fn to_cvalue(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>) -> CValue<'tcx> {
match self { match self {
CPlace::Var(var, layout) => CValue::ByVal(fx.bcx.use_var(mir_var(var)), layout), 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 { pub fn expect_addr(self) -> Value {
match self { 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"), 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); let data = from.load_value(fx);
fx.bcx.def_var(mir_var(var), data) fx.bcx.def_var(mir_var(var), data)
} }
CPlace::Addr(addr, layout) => { CPlace::Addr(addr, None, layout) => {
let size = layout.size.bytes() as i32; let size = layout.size.bytes() as i32;
match from { 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>, fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
field: mir::Field, field: mir::Field,
) -> CPlace<'tcx> { ) -> CPlace<'tcx> {
let base = self.expect_addr();
let layout = self.layout(); 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); 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( pub fn place_index(
@ -368,6 +398,10 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> {
) -> CPlace<'tcx> { ) -> CPlace<'tcx> {
let addr = self.expect_addr(); let addr = self.expect_addr();
let layout = self.layout(); let layout = self.layout();
if layout.is_unsized() {
unimpl!("unsized place_field");
}
match layout.ty.sty { match layout.ty.sty {
ty::Array(elem_ty, _) => { ty::Array(elem_ty, _) => {
let elem_layout = fx.layout_of(elem_ty); let elem_layout = fx.layout_of(elem_ty);
@ -375,17 +409,80 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> {
.bcx .bcx
.ins() .ins()
.imul_imm(index, elem_layout.size.bytes() as i64); .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)"), ty::Slice(_elem_ty) => unimplemented!("place_index(TySlice)"),
_ => bug!("place_index({:?})", layout.ty), _ => 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 { pub fn unchecked_cast_to(self, layout: TyLayout<'tcx>) -> Self {
match self { match self {
CPlace::Var(var, _) => CPlace::Var(var, layout), 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)
}
} }
} }

View file

@ -179,7 +179,8 @@ fn cplace_for_dataid<'a, 'tcx: 'a>(
.ins() .ins()
.global_value(fx.module.pointer_type(), local_data_id); .global_value(fx.module.pointer_type(), local_data_id);
let layout = fx.layout_of(fx.monomorphize(&ty)); 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>( fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(

View file

@ -63,7 +63,7 @@ mod prelude {
pub use rustc::mir::interpret::AllocId; pub use rustc::mir::interpret::AllocId;
pub use rustc::mir::*; pub use rustc::mir::*;
pub use rustc::session::{config::CrateType, Session}; 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::{ pub use rustc::ty::{
self, subst::Substs, FnSig, Instance, InstanceDef, ParamEnv, PolyFnSig, Ty, TyCtxt, self, subst::Substs, FnSig, Instance, InstanceDef, ParamEnv, PolyFnSig, Ty, TyCtxt,
TypeAndMut, TypeFoldable, TypeAndMut, TypeFoldable,