diff --git a/cranelift/codegen/src/lib.rs b/cranelift/codegen/src/lib.rs index 5b80073b7f..331c8f81b7 100644 --- a/cranelift/codegen/src/lib.rs +++ b/cranelift/codegen/src/lib.rs @@ -97,6 +97,7 @@ mod inst_predicates; mod iterators; mod legalizer; mod licm; +mod log; mod nan_canonicalization; mod partition_slice; mod postopt; diff --git a/cranelift/codegen/src/log.rs b/cranelift/codegen/src/log.rs new file mode 100644 index 0000000000..c5bd59aa58 --- /dev/null +++ b/cranelift/codegen/src/log.rs @@ -0,0 +1,39 @@ +//! This module implements deferred display helpers. +//! +//! These are particularly useful in logging contexts, where the maximum logging level filter might +//! be enabled, but we don't want the arguments to be evaluated early: +//! +//! ``` +//! log::set_max_level(log::LevelFilter::max()); +//! fn expensive_calculation() -> String { +//! "a string that is very slow to generate".into() +//! } +//! log::debug!("{}", expensive_calculation()); +//! ``` +//! +//! If the associated log implementation filters out log debug entries, the expensive calculation +//! would have been spurious. In this case, we can wrap the expensive computation within an +//! `DeferredDisplay`, so that the computation only happens when the actual `fmt` function is +//! called. + +use core::fmt; + +pub(crate) struct DeferredDisplay(F); + +impl T, T: fmt::Display> DeferredDisplay { + pub(crate) fn new(f: F) -> Self { + Self(f) + } +} + +impl T, T: fmt::Display> fmt::Display for DeferredDisplay { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0().fmt(f) + } +} + +impl T, T: fmt::Debug> fmt::Debug for DeferredDisplay { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0().fmt(f) + } +} diff --git a/cranelift/codegen/src/machinst/compile.rs b/cranelift/codegen/src/machinst/compile.rs index 0aaee5e98f..2dfbb85785 100644 --- a/cranelift/codegen/src/machinst/compile.rs +++ b/cranelift/codegen/src/machinst/compile.rs @@ -1,11 +1,12 @@ //! Compilation backend pipeline: optimized IR to VCode / binemit. use crate::ir::Function; +use crate::log::DeferredDisplay; use crate::machinst::*; use crate::settings; use crate::timing; -use log::{debug, log_enabled, Level}; +use log::debug; use regalloc::{allocate_registers_with_opts, Algorithm, Options, PrettyPrint}; /// Compile the given function down to VCode with allocated registers, ready @@ -29,15 +30,12 @@ where lower.lower(b)? }; - // Creating the vcode string representation may be costly for large functions, so don't do it - // if the Debug level hasn't been statically (through features) or dynamically (through - // RUST_LOG) enabled. - if log_enabled!(Level::Debug) { - debug!( - "vcode from lowering: \n{}", - vcode.show_rru(Some(b.reg_universe())) - ); - } + // Creating the vcode string representation may be costly for large functions, so defer its + // rendering. + debug!( + "vcode from lowering: \n{}", + DeferredDisplay::new(|| vcode.show_rru(Some(b.reg_universe()))) + ); // Perform register allocation. let (run_checker, algorithm) = match vcode.flags().regalloc() { @@ -106,12 +104,10 @@ where vcode.replace_insns_from_regalloc(result); } - if log_enabled!(Level::Debug) { - debug!( - "vcode after regalloc: final version:\n{}", - vcode.show_rru(Some(b.reg_universe())) - ); - } + debug!( + "vcode after regalloc: final version:\n{}", + DeferredDisplay::new(|| vcode.show_rru(Some(b.reg_universe()))) + ); Ok(vcode) }