@@ -21,6 +21,8 @@ use common::{CodegenCx, C_undef, C_usize};
2121use builder:: { Builder , MemFlags } ;
2222use value:: Value ;
2323use type_of:: LayoutLlvmExt ;
24+ use type_:: Type ;
25+ use glue;
2426
2527use std:: fmt;
2628
@@ -36,6 +38,10 @@ pub enum OperandValue<'ll> {
3638 /// A reference to the actual operand. The data is guaranteed
3739 /// to be valid for the operand's lifetime.
3840 Ref ( & ' ll Value , Align ) ,
41+ /// A reference to the unsized operand. The data is guaranteed
42+ /// to be valid for the operand's lifetime.
43+ /// The second field is the extra.
44+ UnsizedRef ( & ' ll Value , & ' ll Value ) ,
3945 /// A single LLVM value.
4046 Immediate ( & ' ll Value ) ,
4147 /// A pair of immediate LLVM values. Used by fat pointers too.
@@ -148,7 +154,8 @@ impl OperandRef<'ll, 'tcx> {
148154 let ( llptr, llextra) = match self . val {
149155 OperandValue :: Immediate ( llptr) => ( llptr, None ) ,
150156 OperandValue :: Pair ( llptr, llextra) => ( llptr, Some ( llextra) ) ,
151- OperandValue :: Ref ( ..) => bug ! ( "Deref of by-Ref operand {:?}" , self )
157+ OperandValue :: Ref ( ..) |
158+ OperandValue :: UnsizedRef ( ..) => bug ! ( "Deref of by-Ref operand {:?}" , self )
152159 } ;
153160 let layout = cx. layout_of ( projected_ty) ;
154161 PlaceRef {
@@ -243,7 +250,8 @@ impl OperandRef<'ll, 'tcx> {
243250 * a = bx. bitcast ( * a, field. scalar_pair_element_llvm_type ( bx. cx , 0 , true ) ) ;
244251 * b = bx. bitcast ( * b, field. scalar_pair_element_llvm_type ( bx. cx , 1 , true ) ) ;
245252 }
246- OperandValue :: Ref ( ..) => bug ! ( )
253+ OperandValue :: Ref ( ..) |
254+ OperandValue :: UnsizedRef ( ..) => bug ! ( )
247255 }
248256
249257 OperandRef {
@@ -287,6 +295,9 @@ impl OperandValue<'ll> {
287295 base:: memcpy_ty ( bx, dest. llval , r, dest. layout ,
288296 source_align. min ( dest. align ) , flags)
289297 }
298+ OperandValue :: UnsizedRef ( ..) => {
299+ bug ! ( "cannot directly store unsized values" ) ;
300+ }
290301 OperandValue :: Immediate ( s) => {
291302 let val = base:: from_immediate ( bx, s) ;
292303 bx. store_with_flags ( val, dest. llval , dest. align , flags) ;
@@ -300,6 +311,35 @@ impl OperandValue<'ll> {
300311 }
301312 }
302313 }
314+
315+ pub fn store_unsized ( self , bx : & Builder < ' a , ' ll , ' tcx > , indirect_dest : PlaceRef < ' ll , ' tcx > ) {
316+ debug ! ( "OperandRef::store_unsized: operand={:?}, indirect_dest={:?}" , self , indirect_dest) ;
317+ let flags = MemFlags :: empty ( ) ;
318+
319+ // `indirect_dest` must have `*mut T` type. We extract `T` out of it.
320+ let unsized_ty = indirect_dest. layout . ty . builtin_deref ( true )
321+ . unwrap_or_else ( || bug ! ( "indirect_dest has non-pointer type: {:?}" , indirect_dest) ) . ty ;
322+
323+ let ( llptr, llextra) =
324+ if let OperandValue :: UnsizedRef ( llptr, llextra) = self {
325+ ( llptr, llextra)
326+ } else {
327+ bug ! ( "store_unsized called with a sized value" )
328+ } ;
329+
330+ // FIXME: choose an appropriate alignment, or use dynamic align somehow
331+ let max_align = Align :: from_bits ( 128 , 128 ) . unwrap ( ) ;
332+ let min_align = Align :: from_bits ( 8 , 8 ) . unwrap ( ) ;
333+
334+ // Allocate an appropriate region on the stack, and copy the value into it
335+ let ( llsize, _) = glue:: size_and_align_of_dst ( & bx, unsized_ty, Some ( llextra) ) ;
336+ let lldst = bx. array_alloca ( Type :: i8 ( bx. cx ) , llsize, "unsized_tmp" , max_align) ;
337+ base:: call_memcpy ( & bx, lldst, llptr, llsize, min_align, flags) ;
338+
339+ // Store the allocated region and the extra to the indirect place.
340+ let indirect_operand = OperandValue :: Pair ( lldst, llextra) ;
341+ indirect_operand. store ( & bx, indirect_dest) ;
342+ }
303343}
304344
305345impl FunctionCx < ' a , ' ll , ' tcx > {
@@ -320,7 +360,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
320360 LocalRef :: Operand ( None ) => {
321361 bug ! ( "use of {:?} before def" , place) ;
322362 }
323- LocalRef :: Place ( ..) => {
363+ LocalRef :: Place ( ..) | LocalRef :: UnsizedPlace ( .. ) => {
324364 // use path below
325365 }
326366 }
0 commit comments