//! Annotate the clif ir with comments describing how arguments are passed into the current function //! and where all locals are stored. use std::borrow::Cow; use rustc_middle::mir; use rustc_target::abi::call::PassMode; use cranelift_codegen::entity::EntityRef; use crate::prelude::*; pub(super) fn add_args_header_comment(fx: &mut FunctionCx<'_, '_, '_>) { if fx.clif_comments.enabled() { fx.add_global_comment( "kind loc.idx param pass mode ty".to_string(), ); } } pub(super) fn add_arg_comment<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, kind: &str, local: Option, local_field: Option, params: &[Value], arg_abi_mode: &PassMode, arg_layout: TyAndLayout<'tcx>, ) { if !fx.clif_comments.enabled() { return; } let local = if let Some(local) = local { Cow::Owned(format!("{:?}", local)) } else { Cow::Borrowed("???") }; let local_field = if let Some(local_field) = local_field { Cow::Owned(format!(".{}", local_field)) } else { Cow::Borrowed("") }; let params = match params { [] => Cow::Borrowed("-"), [param] => Cow::Owned(format!("= {:?}", param)), [param_a, param_b] => Cow::Owned(format!("= {:?},{:?}", param_a, param_b)), params => Cow::Owned(format!( "= {}", params.iter().map(ToString::to_string).collect::>().join(",") )), }; let pass_mode = format!("{:?}", arg_abi_mode); fx.add_global_comment(format!( "{kind:5}{local:>3}{local_field:<5} {params:10} {pass_mode:36} {ty:?}", kind = kind, local = local, local_field = local_field, params = params, pass_mode = pass_mode, ty = arg_layout.ty, )); } pub(super) fn add_locals_header_comment(fx: &mut FunctionCx<'_, '_, '_>) { if fx.clif_comments.enabled() { fx.add_global_comment(String::new()); fx.add_global_comment( "kind local ty size align (abi,pref)".to_string(), ); } } pub(super) fn add_local_place_comments<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, place: CPlace<'tcx>, local: Local, ) { if !fx.clif_comments.enabled() { return; } let TyAndLayout { ty, layout } = place.layout(); let rustc_target::abi::LayoutS { size, align, abi: _, variants: _, fields: _, largest_niche: _, } = layout.0.0; let (kind, extra) = match *place.inner() { CPlaceInner::Var(place_local, var) => { assert_eq!(local, place_local); ("ssa", Cow::Owned(format!(",var={}", var.index()))) } CPlaceInner::VarPair(place_local, var1, var2) => { assert_eq!(local, place_local); ("ssa", Cow::Owned(format!(",var=({}, {})", var1.index(), var2.index()))) } CPlaceInner::VarLane(_local, _var, _lane) => unreachable!(), CPlaceInner::Addr(ptr, meta) => { let meta = if let Some(meta) = meta { Cow::Owned(format!(",meta={}", meta)) } else { Cow::Borrowed("") }; match ptr.debug_base_and_offset() { (crate::pointer::PointerBase::Addr(addr), offset) => { ("reuse", format!("storage={}{}{}", addr, offset, meta).into()) } (crate::pointer::PointerBase::Stack(stack_slot), offset) => { ("stack", format!("storage={}{}{}", stack_slot, offset, meta).into()) } (crate::pointer::PointerBase::Dangling(align), offset) => { ("zst", format!("align={},offset={}", align.bytes(), offset).into()) } } } }; fx.add_global_comment(format!( "{:<5} {:5} {:30} {:4}b {}, {}{}{}", kind, format!("{:?}", local), format!("{:?}", ty), size.bytes(), align.abi.bytes(), align.pref.bytes(), if extra.is_empty() { "" } else { " " }, extra, )); }