@@ -1147,48 +1147,63 @@ pub fn with_cond<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, val: ValueRef, f: F) ->
11471147 next_cx
11481148}
11491149
1150- pub fn call_lifetime_start ( cx : Block , ptr : ValueRef ) {
1151- if cx. sess ( ) . opts . optimize == config:: No {
1150+ enum Lifetime { Start , End }
1151+
1152+ // If LLVM lifetime intrinsic support is enabled (i.e. optimizations
1153+ // on), and `ptr` is nonzero-sized, then extracts the size of `ptr`
1154+ // and the intrinsic for `lt` and passes them to `emit`, which is in
1155+ // charge of generating code to call the passed intrinsic on whatever
1156+ // block of generated code is targetted for the intrinsic.
1157+ //
1158+ // If LLVM lifetime intrinsic support is disabled (i.e. optimizations
1159+ // off) or `ptr` is zero-sized, then no-op (does not call `emit`).
1160+ fn core_lifetime_emit < ' blk , ' tcx , F > ( ccx : & ' blk CrateContext < ' blk , ' tcx > ,
1161+ ptr : ValueRef ,
1162+ lt : Lifetime ,
1163+ emit : F )
1164+ where F : FnOnce ( & ' blk CrateContext < ' blk , ' tcx > , machine:: llsize , ValueRef )
1165+ {
1166+ if ccx. sess ( ) . opts . optimize == config:: No {
11521167 return ;
11531168 }
11541169
1155- let _icx = push_ctxt ( "lifetime_start" ) ;
1156- let ccx = cx. ccx ( ) ;
1170+ let _icx = push_ctxt ( match lt {
1171+ Lifetime :: Start => "lifetime_start" ,
1172+ Lifetime :: End => "lifetime_end"
1173+ } ) ;
11571174
11581175 let size = machine:: llsize_of_alloc ( ccx, val_ty ( ptr) . element_type ( ) ) ;
11591176 if size == 0 {
11601177 return ;
11611178 }
11621179
1163- let ptr = PointerCast ( cx, ptr, Type :: i8p ( ccx) ) ;
1164- let lifetime_start = ccx. get_intrinsic ( & "llvm.lifetime.start" ) ;
1165- Call ( cx,
1166- lifetime_start,
1167- & [ C_u64 ( ccx, size) , ptr] ,
1168- None ,
1169- DebugLoc :: None ) ;
1180+ let lifetime_intrinsic = ccx. get_intrinsic ( match lt {
1181+ Lifetime :: Start => "llvm.lifetime.start" ,
1182+ Lifetime :: End => "llvm.lifetime.end"
1183+ } ) ;
1184+ emit ( ccx, size, lifetime_intrinsic)
11701185}
11711186
1172- pub fn call_lifetime_end ( cx : Block , ptr : ValueRef ) {
1173- if cx. sess ( ) . opts . optimize == config:: No {
1174- return ;
1175- }
1176-
1177- let _icx = push_ctxt ( "lifetime_end" ) ;
1178- let ccx = cx. ccx ( ) ;
1179-
1180- let size = machine:: llsize_of_alloc ( ccx, val_ty ( ptr) . element_type ( ) ) ;
1181- if size == 0 {
1182- return ;
1183- }
1187+ pub fn call_lifetime_start ( cx : Block , ptr : ValueRef ) {
1188+ core_lifetime_emit ( cx. ccx ( ) , ptr, Lifetime :: Start , |ccx, size, lifetime_start| {
1189+ let ptr = PointerCast ( cx, ptr, Type :: i8p ( ccx) ) ;
1190+ Call ( cx,
1191+ lifetime_start,
1192+ & [ C_u64 ( ccx, size) , ptr] ,
1193+ None ,
1194+ DebugLoc :: None ) ;
1195+ } )
1196+ }
11841197
1185- let ptr = PointerCast ( cx, ptr, Type :: i8p ( ccx) ) ;
1186- let lifetime_end = ccx. get_intrinsic ( & "llvm.lifetime.end" ) ;
1187- Call ( cx,
1188- lifetime_end,
1189- & [ C_u64 ( ccx, size) , ptr] ,
1190- None ,
1191- DebugLoc :: None ) ;
1198+ pub fn call_lifetime_end ( cx : Block , ptr : ValueRef ) {
1199+ core_lifetime_emit ( cx. ccx ( ) , ptr, Lifetime :: End , |ccx, size, lifetime_end| {
1200+ let ptr = PointerCast ( cx, ptr, Type :: i8p ( ccx) ) ;
1201+ Call ( cx,
1202+ lifetime_end,
1203+ & [ C_u64 ( ccx, size) , ptr] ,
1204+ None ,
1205+ DebugLoc :: None ) ;
1206+ } )
11921207}
11931208
11941209// Generates code for resumption of unwind at the end of a landing pad.
@@ -1285,12 +1300,81 @@ fn memfill<'a, 'tcx>(b: &Builder<'a, 'tcx>, llptr: ValueRef, ty: Ty<'tcx>, byte:
12851300 None ) ;
12861301}
12871302
1288- pub fn alloc_ty < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > , t : Ty < ' tcx > , name : & str ) -> ValueRef {
1303+ /// In general, when we create an scratch value in an alloca, the
1304+ /// creator may not know if the block (that initializes the scratch
1305+ /// with the desired value) actually dominates the cleanup associated
1306+ /// with the scratch value.
1307+ ///
1308+ /// To deal with this, when we do an alloca (at the *start* of whole
1309+ /// function body), we optionally can also set the associated
1310+ /// dropped-flag state of the alloca to "dropped."
1311+ #[ derive( Copy , Clone , Debug ) ]
1312+ pub enum InitAlloca {
1313+ /// Indicates that the state should have its associated drop flag
1314+ /// set to "dropped" at the point of allocation.
1315+ Dropped ,
1316+ /// Indicates the value of the associated drop flag is irrelevant.
1317+ /// The embedded string literal is a programmer provided argument
1318+ /// for why. This is a safeguard forcing compiler devs to
1319+ /// document; it might be a good idea to also emit this as a
1320+ /// comment with the alloca itself when emitting LLVM output.ll.
1321+ Uninit ( & ' static str ) ,
1322+ }
1323+
1324+
1325+ pub fn alloc_ty < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > ,
1326+ t : Ty < ' tcx > ,
1327+ name : & str ) -> ValueRef {
1328+ // pnkfelix: I do not know why alloc_ty meets the assumptions for
1329+ // passing Uninit, but it was never needed (even back when we had
1330+ // the original boolean `zero` flag on `lvalue_scratch_datum`).
1331+ alloc_ty_init ( bcx, t, InitAlloca :: Uninit ( "all alloc_ty are uninit" ) , name)
1332+ }
1333+
1334+ /// This variant of `fn alloc_ty` does not necessarily assume that the
1335+ /// alloca should be created with no initial value. Instead the caller
1336+ /// controls that assumption via the `init` flag.
1337+ ///
1338+ /// Note that if the alloca *is* initialized via `init`, then we will
1339+ /// also inject an `llvm.lifetime.start` before that initialization
1340+ /// occurs, and thus callers should not call_lifetime_start
1341+ /// themselves. But if `init` says "uninitialized", then callers are
1342+ /// in charge of choosing where to call_lifetime_start and
1343+ /// subsequently populate the alloca.
1344+ ///
1345+ /// (See related discussion on PR #30823.)
1346+ pub fn alloc_ty_init < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > ,
1347+ t : Ty < ' tcx > ,
1348+ init : InitAlloca ,
1349+ name : & str ) -> ValueRef {
12891350 let _icx = push_ctxt ( "alloc_ty" ) ;
12901351 let ccx = bcx. ccx ( ) ;
12911352 let ty = type_of:: type_of ( ccx, t) ;
12921353 assert ! ( !t. has_param_types( ) ) ;
1293- alloca ( bcx, ty, name)
1354+ match init {
1355+ InitAlloca :: Dropped => alloca_dropped ( bcx, t, name) ,
1356+ InitAlloca :: Uninit ( _) => alloca ( bcx, ty, name) ,
1357+ }
1358+ }
1359+
1360+ pub fn alloca_dropped < ' blk , ' tcx > ( cx : Block < ' blk , ' tcx > , ty : Ty < ' tcx > , name : & str ) -> ValueRef {
1361+ let _icx = push_ctxt ( "alloca_dropped" ) ;
1362+ let llty = type_of:: type_of ( cx. ccx ( ) , ty) ;
1363+ if cx. unreachable . get ( ) {
1364+ unsafe { return llvm:: LLVMGetUndef ( llty. ptr_to ( ) . to_ref ( ) ) ; }
1365+ }
1366+ let p = alloca ( cx, llty, name) ;
1367+ let b = cx. fcx . ccx . builder ( ) ;
1368+ b. position_before ( cx. fcx . alloca_insert_pt . get ( ) . unwrap ( ) ) ;
1369+
1370+ // This is just like `call_lifetime_start` (but latter expects a
1371+ // Block, which we do not have for `alloca_insert_pt`).
1372+ core_lifetime_emit ( cx. ccx ( ) , p, Lifetime :: Start , |ccx, size, lifetime_start| {
1373+ let ptr = b. pointercast ( p, Type :: i8p ( ccx) ) ;
1374+ b. call ( lifetime_start, & [ C_u64 ( ccx, size) , ptr] , None ) ;
1375+ } ) ;
1376+ memfill ( & b, p, ty, adt:: DTOR_DONE ) ;
1377+ p
12941378}
12951379
12961380pub fn alloca ( cx : Block , ty : Type , name : & str ) -> ValueRef {
@@ -1639,6 +1723,8 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>,
16391723 let fcx = bcx. fcx ;
16401724 let arg_scope_id = cleanup:: CustomScope ( arg_scope) ;
16411725
1726+ debug ! ( "create_datums_for_fn_args" ) ;
1727+
16421728 // Return an array wrapping the ValueRefs that we get from `get_param` for
16431729 // each argument into datums.
16441730 //
@@ -1650,6 +1736,7 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>,
16501736 // This alloca should be optimized away by LLVM's mem-to-reg pass in
16511737 // the event it's not truly needed.
16521738 let mut idx = fcx. arg_offset ( ) as c_uint ;
1739+ let uninit_reason = InitAlloca :: Uninit ( "fn_arg populate dominates dtor" ) ;
16531740 for ( i, & arg_ty) in arg_tys. iter ( ) . enumerate ( ) {
16541741 let arg_datum = if !has_tupled_arg || i < arg_tys. len ( ) - 1 {
16551742 if type_of:: arg_is_indirect ( bcx. ccx ( ) , arg_ty) &&
@@ -1669,9 +1756,12 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>,
16691756 let data = get_param ( fcx. llfn , idx) ;
16701757 let extra = get_param ( fcx. llfn , idx + 1 ) ;
16711758 idx += 2 ;
1672- unpack_datum ! ( bcx, datum:: lvalue_scratch_datum( bcx, arg_ty, "" ,
1759+ unpack_datum ! ( bcx, datum:: lvalue_scratch_datum( bcx, arg_ty, "" , uninit_reason ,
16731760 arg_scope_id, ( data, extra) ,
16741761 |( data, extra) , bcx, dst| {
1762+ debug!( "populate call for create_datum_for_fn_args \
1763+ early fat arg, on arg[{}] ty={:?}", i, arg_ty) ;
1764+
16751765 Store ( bcx, data, expr:: get_dataptr( bcx, dst) ) ;
16761766 Store ( bcx, extra, expr:: get_meta( bcx, dst) ) ;
16771767 bcx
@@ -1684,9 +1774,16 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>,
16841774 datum:: lvalue_scratch_datum( bcx,
16851775 arg_ty,
16861776 "" ,
1777+ uninit_reason,
16871778 arg_scope_id,
16881779 tmp,
1689- |tmp, bcx, dst| tmp. store_to( bcx, dst) ) )
1780+ |tmp, bcx, dst| {
1781+
1782+ debug!( "populate call for create_datum_for_fn_args \
1783+ early thin arg, on arg[{}] ty={:?}", i, arg_ty) ;
1784+
1785+ tmp. store_to( bcx, dst)
1786+ } ) )
16901787 }
16911788 } else {
16921789 // FIXME(pcwalton): Reduce the amount of code bloat this is responsible for.
@@ -1696,11 +1793,14 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>,
16961793 datum:: lvalue_scratch_datum( bcx,
16971794 arg_ty,
16981795 "tupled_args" ,
1796+ uninit_reason,
16991797 arg_scope_id,
17001798 ( ) ,
17011799 |( ) ,
17021800 mut bcx,
1703- llval| {
1801+ llval| {
1802+ debug!( "populate call for create_datum_for_fn_args \
1803+ tupled_args, on arg[{}] ty={:?}", i, arg_ty) ;
17041804 for ( j, & tupled_arg_ty) in
17051805 tupled_arg_tys. iter( ) . enumerate( ) {
17061806 let lldest = StructGEP ( bcx, llval, j) ;
0 commit comments