mirror of
				https://github.com/rust-lang/rust.git
				synced 2025-10-31 04:57:19 +00:00 
			
		
		
		
	 c9dd1d9983
			
		
	
	
		c9dd1d9983
		
	
	
	
	
		
			
			This makes it possible to mutably borrow different fields of the MIR body without resorting to methods like `basic_blocks_local_decls_mut_and_var_debug_info`. To preserve validity of control flow graph caches in the presence of modifications, a new struct `BasicBlocks` wraps together basic blocks and control flow graph caches. The `BasicBlocks` dereferences to `IndexVec<BasicBlock, BasicBlockData>`. On the other hand a mutable access requires explicit `as_mut()` call.
		
			
				
	
	
		
			87 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			87 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| //! Removes assignments to ZST places.
 | |
| 
 | |
| use crate::MirPass;
 | |
| use rustc_middle::mir::tcx::PlaceTy;
 | |
| use rustc_middle::mir::{Body, LocalDecls, Place, StatementKind};
 | |
| use rustc_middle::ty::{self, Ty, TyCtxt};
 | |
| 
 | |
| pub struct RemoveZsts;
 | |
| 
 | |
| impl<'tcx> MirPass<'tcx> for RemoveZsts {
 | |
|     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
 | |
|         sess.mir_opt_level() > 0
 | |
|     }
 | |
| 
 | |
|     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 | |
|         // Avoid query cycles (generators require optimized MIR for layout).
 | |
|         if tcx.type_of(body.source.def_id()).is_generator() {
 | |
|             return;
 | |
|         }
 | |
|         let param_env = tcx.param_env(body.source.def_id());
 | |
|         let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
 | |
|         let local_decls = &body.local_decls;
 | |
|         for block in basic_blocks {
 | |
|             for statement in block.statements.iter_mut() {
 | |
|                 if let StatementKind::Assign(box (place, _)) | StatementKind::Deinit(box place) =
 | |
|                     statement.kind
 | |
|                 {
 | |
|                     let place_ty = place.ty(local_decls, tcx).ty;
 | |
|                     if !maybe_zst(place_ty) {
 | |
|                         continue;
 | |
|                     }
 | |
|                     let Ok(layout) = tcx.layout_of(param_env.and(place_ty)) else {
 | |
|                         continue;
 | |
|                     };
 | |
|                     if !layout.is_zst() {
 | |
|                         continue;
 | |
|                     }
 | |
|                     if involves_a_union(place, local_decls, tcx) {
 | |
|                         continue;
 | |
|                     }
 | |
|                     if tcx.consider_optimizing(|| {
 | |
|                         format!(
 | |
|                             "RemoveZsts - Place: {:?} SourceInfo: {:?}",
 | |
|                             place, statement.source_info
 | |
|                         )
 | |
|                     }) {
 | |
|                         statement.make_nop();
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// A cheap, approximate check to avoid unnecessary `layout_of` calls.
 | |
| fn maybe_zst(ty: Ty<'_>) -> bool {
 | |
|     match ty.kind() {
 | |
|         // maybe ZST (could be more precise)
 | |
|         ty::Adt(..) | ty::Array(..) | ty::Closure(..) | ty::Tuple(..) | ty::Opaque(..) => true,
 | |
|         // definitely ZST
 | |
|         ty::FnDef(..) | ty::Never => true,
 | |
|         // unreachable or can't be ZST
 | |
|         _ => false,
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// Miri lazily allocates memory for locals on assignment,
 | |
| /// so we must preserve writes to unions and union fields,
 | |
| /// or it will ICE on reads of those fields.
 | |
| fn involves_a_union<'tcx>(
 | |
|     place: Place<'tcx>,
 | |
|     local_decls: &LocalDecls<'tcx>,
 | |
|     tcx: TyCtxt<'tcx>,
 | |
| ) -> bool {
 | |
|     let mut place_ty = PlaceTy::from_ty(local_decls[place.local].ty);
 | |
|     if place_ty.ty.is_union() {
 | |
|         return true;
 | |
|     }
 | |
|     for elem in place.projection {
 | |
|         place_ty = place_ty.projection_ty(tcx, elem);
 | |
|         if place_ty.ty.is_union() {
 | |
|             return true;
 | |
|         }
 | |
|     }
 | |
|     return false;
 | |
| }
 |