From 34d3fcbb568d3d408d3a826265bf69b8c0477e52 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 24 Apr 2023 17:57:41 -0700 Subject: [PATCH 1/8] Add test of --print + -o --- tests/run-make/print-cfg/Makefile | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/run-make/print-cfg/Makefile b/tests/run-make/print-cfg/Makefile index 126f5768c90f2..bd24e7707b7a9 100644 --- a/tests/run-make/print-cfg/Makefile +++ b/tests/run-make/print-cfg/Makefile @@ -2,7 +2,7 @@ include ../tools.mk -all: default +all: default output_to_file $(RUSTC) --target x86_64-pc-windows-gnu --print cfg | $(CGREP) windows $(RUSTC) --target x86_64-pc-windows-gnu --print cfg | $(CGREP) x86_64 $(RUSTC) --target i686-pc-windows-msvc --print cfg | $(CGREP) msvc @@ -11,6 +11,14 @@ all: default $(RUSTC) --target arm-unknown-linux-gnueabihf --print cfg | $(CGREP) target_abi= $(RUSTC) --target arm-unknown-linux-gnueabihf --print cfg | $(CGREP) eabihf +output_to_file: + -rm $(TMPDIR)/cfg.txt + $(RUSTC) --target x86_64-pc-windows-gnu --print=cfg -o $(TMPDIR)/cfg.txt + $(CGREP) windows < $(TMPDIR)/cfg.txt + -rm $(TMPDIR)/cfg.txt + $(RUSTC) --target x86_64-pc-windows-gnu --print=target-cpus -o $(TMPDIR)/cfg.txt + $(CGREP) native < $(TMPDIR)/cfg.txt + ifdef IS_WINDOWS default: $(RUSTC) --print cfg | $(CGREP) windows From a32f1ae0b1c42f55a78bc88730a2073927dcb083 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 24 Apr 2023 17:25:27 -0700 Subject: [PATCH 2/8] Respect -o output file in --print --- compiler/rustc_driver_impl/src/lib.rs | 62 +++++++++++++++++++++------ 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 2e26ce111f01d..7168188d4863e 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -51,7 +51,8 @@ use std::cmp::max; use std::collections::BTreeMap; use std::env; use std::ffi::OsString; -use std::fs; +use std::fmt; +use std::fs::{self, File}; use std::io::{self, IsTerminal, Read, Write}; use std::panic::{self, catch_unwind}; use std::path::PathBuf; @@ -67,6 +68,11 @@ macro do_not_use_print($($t:tt)*) { ) } +#[allow(unused_macros)] +macro do_not_use_safe_print($($t:tt)*) { + std::compile_error!("Don't use `safe_print` or `safe_println` here, use `println_info` instead") +} + // This import blocks the use of panicking `print` and `println` in all the code // below. Please use `safe_print` and `safe_println` to avoid ICE when // encountering an I/O error during print. @@ -718,6 +724,13 @@ fn print_crate_info( parse_attrs: bool, ) -> Compilation { use rustc_session::config::PrintRequest::*; + + // This import prevents the following code from using the printing macros + // used by the rest of the module. Within this function, we only write to + // the output specified by `sess.io.output_file`. + #[allow(unused_imports)] + use {do_not_use_safe_print as safe_print, do_not_use_safe_print as safe_println}; + // NativeStaticLibs and LinkArgs are special - printed during linking // (empty iterator returns true) if sess.opts.prints.iter().all(|&p| p == NativeStaticLibs || p == LinkArgs) { @@ -736,17 +749,42 @@ fn print_crate_info( } else { None }; + + let mut output_io: Box = match &sess.io.output_file { + Some(OutFileName::Real(output_file_path)) => match File::create(output_file_path) { + Ok(output_file) => Box::new(output_file), + Err(err) => handler.early_error(format!( + "failed to create {}: {}", + output_file_path.display(), + err, + )), + }, + None | Some(OutFileName::Stdout) => Box::new(io::stdout()), + }; + + fn write_output(output_io: &mut dyn Write, args: fmt::Arguments<'_>) { + if let Err(_) = output_io.write_fmt(args) { + rustc_errors::FatalError.raise(); + } + } + + macro_rules! println_info { + ($($arg:tt)*) => { + write_output(&mut *output_io, format_args!("{}\n", format_args!($($arg)*))) + }; + } + for req in &sess.opts.prints { match *req { TargetList => { let mut targets = rustc_target::spec::TARGETS.to_vec(); targets.sort_unstable(); - safe_println!("{}", targets.join("\n")); + println_info!("{}", targets.join("\n")); } - Sysroot => safe_println!("{}", sess.sysroot.display()), - TargetLibdir => safe_println!("{}", sess.target_tlib_path.dir.display()), + Sysroot => println_info!("{}", sess.sysroot.display()), + TargetLibdir => println_info!("{}", sess.target_tlib_path.dir.display()), TargetSpec => { - safe_println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap()); + println_info!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap()); } AllTargetSpecs => { let mut targets = BTreeMap::new(); @@ -755,7 +793,7 @@ fn print_crate_info( let target = Target::expect_builtin(&triple); targets.insert(name, target.to_json()); } - safe_println!("{}", serde_json::to_string_pretty(&targets).unwrap()); + println_info!("{}", serde_json::to_string_pretty(&targets).unwrap()); } FileNames | CrateName => { let Some(attrs) = attrs.as_ref() else { @@ -765,14 +803,14 @@ fn print_crate_info( let t_outputs = rustc_interface::util::build_output_filenames(attrs, sess); let id = rustc_session::output::find_crate_name(sess, attrs); if *req == PrintRequest::CrateName { - safe_println!("{id}"); + println_info!("{id}"); continue; } let crate_types = collect_crate_types(sess, attrs); for &style in &crate_types { let fname = rustc_session::output::filename_for_input(sess, style, id, &t_outputs); - safe_println!("{}", fname.as_path().file_name().unwrap().to_string_lossy()); + println_info!("{}", fname.as_path().file_name().unwrap().to_string_lossy()); } } Cfg => { @@ -806,13 +844,13 @@ fn print_crate_info( cfgs.sort(); for cfg in cfgs { - safe_println!("{cfg}"); + println_info!("{cfg}"); } } CallingConventions => { let mut calling_conventions = rustc_target::spec::abi::all_names(); calling_conventions.sort_unstable(); - safe_println!("{}", calling_conventions.join("\n")); + println_info!("{}", calling_conventions.join("\n")); } RelocationModels | CodeModels @@ -830,7 +868,7 @@ fn print_crate_info( for split in &[Off, Packed, Unpacked] { if sess.target.options.supported_split_debuginfo.contains(split) { - safe_println!("{split}"); + println_info!("{split}"); } } } @@ -838,7 +876,7 @@ fn print_crate_info( use rustc_target::spec::current_apple_deployment_target; if sess.target.is_like_osx { - safe_println!( + println_info!( "deployment_target={}", current_apple_deployment_target(&sess.target) .expect("unknown Apple target OS") From 62ecfd36c62e413d2e5e8883ab991a3d27dd5224 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 13 Jul 2023 15:02:56 -0700 Subject: [PATCH 3/8] Implement -o in rustc_driver_impl using pretty::write_or_print --- compiler/rustc_driver_impl/messages.ftl | 2 +- compiler/rustc_driver_impl/src/lib.rs | 37 +++++++----------------- compiler/rustc_driver_impl/src/pretty.rs | 2 +- tests/ui/unpretty/avoid-crash.stderr | 2 +- 4 files changed, 14 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_driver_impl/messages.ftl b/compiler/rustc_driver_impl/messages.ftl index 22b4ec6b0d1b1..77537ab591dee 100644 --- a/compiler/rustc_driver_impl/messages.ftl +++ b/compiler/rustc_driver_impl/messages.ftl @@ -16,4 +16,4 @@ driver_impl_rlink_unable_to_read = failed to read rlink file: `{$err}` driver_impl_rlink_wrong_file_type = The input does not look like a .rlink file -driver_impl_unpretty_dump_fail = pretty-print failed to write `{$path}` due to error `{$err}` +driver_impl_unpretty_dump_fail = failed to write `{$path}` due to error `{$err}` diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 7168188d4863e..7d12b6c11fa3c 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -51,8 +51,8 @@ use std::cmp::max; use std::collections::BTreeMap; use std::env; use std::ffi::OsString; -use std::fmt; -use std::fs::{self, File}; +use std::fmt::Write as _; +use std::fs; use std::io::{self, IsTerminal, Read, Write}; use std::panic::{self, catch_unwind}; use std::path::PathBuf; @@ -750,30 +750,12 @@ fn print_crate_info( None }; - let mut output_io: Box = match &sess.io.output_file { - Some(OutFileName::Real(output_file_path)) => match File::create(output_file_path) { - Ok(output_file) => Box::new(output_file), - Err(err) => handler.early_error(format!( - "failed to create {}: {}", - output_file_path.display(), - err, - )), - }, - None | Some(OutFileName::Stdout) => Box::new(io::stdout()), - }; - - fn write_output(output_io: &mut dyn Write, args: fmt::Arguments<'_>) { - if let Err(_) = output_io.write_fmt(args) { - rustc_errors::FatalError.raise(); - } - } - - macro_rules! println_info { - ($($arg:tt)*) => { - write_output(&mut *output_io, format_args!("{}\n", format_args!($($arg)*))) - }; + let mut crate_info = String::new(); + macro println_info($($arg:tt)*) { + crate_info.write_fmt(format_args!("{}\n", format_args!($($arg)*))).unwrap() } + let mut how_to_proceed = Compilation::Stop; for req in &sess.opts.prints { match *req { TargetList => { @@ -798,7 +780,8 @@ fn print_crate_info( FileNames | CrateName => { let Some(attrs) = attrs.as_ref() else { // no crate attributes, print out an error and exit - return Compilation::Continue; + how_to_proceed = Compilation::Continue; + break; }; let t_outputs = rustc_interface::util::build_output_filenames(attrs, sess); let id = rustc_session::output::find_crate_name(sess, attrs); @@ -888,7 +871,9 @@ fn print_crate_info( } } } - Compilation::Stop + + pretty::write_or_print(&crate_info, sess); + how_to_proceed } /// Prints version information diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index 24a5f4030b88d..273825b53ff8d 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -357,7 +357,7 @@ fn get_source(sess: &Session) -> (String, FileName) { (src, src_name) } -fn write_or_print(out: &str, sess: &Session) { +pub fn write_or_print(out: &str, sess: &Session) { match &sess.io.output_file { None | Some(OutFileName::Stdout) => print!("{out}"), Some(OutFileName::Real(p)) => { diff --git a/tests/ui/unpretty/avoid-crash.stderr b/tests/ui/unpretty/avoid-crash.stderr index 11cd3866fa869..15bcc277e6491 100644 --- a/tests/ui/unpretty/avoid-crash.stderr +++ b/tests/ui/unpretty/avoid-crash.stderr @@ -1,4 +1,4 @@ -error: pretty-print failed to write `/tmp/` due to $ERROR_MESSAGE +error: failed to write `/tmp/` due to $ERROR_MESSAGE error: aborting due to previous error From 294a4f505a35f410280d4c0b3e74d9f8826faba3 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 13 Jul 2023 15:20:14 -0700 Subject: [PATCH 4/8] Implement printing to file in codegen_backend.print --- compiler/rustc_codegen_llvm/src/lib.rs | 23 ++++++++++--------- .../rustc_codegen_ssa/src/traits/backend.rs | 20 +++++++++++++++- compiler/rustc_codegen_ssa/src/traits/mod.rs | 4 +++- compiler/rustc_driver_impl/src/lib.rs | 2 +- 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 24ba28bbc82c2..08f4a56eed916 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -262,10 +262,10 @@ impl CodegenBackend for LlvmCodegenBackend { |tcx, ()| llvm_util::global_llvm_features(tcx.sess, true) } - fn print(&self, req: PrintRequest, sess: &Session) { + fn print(&self, req: PrintRequest, out: &mut dyn PrintBackendInfo, sess: &Session) { match req { PrintRequest::RelocationModels => { - println!("Available relocation models:"); + writeln!(out, "Available relocation models:"); for name in &[ "static", "pic", @@ -276,26 +276,27 @@ impl CodegenBackend for LlvmCodegenBackend { "ropi-rwpi", "default", ] { - println!(" {}", name); + writeln!(out, " {}", name); } - println!(); + writeln!(out); } PrintRequest::CodeModels => { - println!("Available code models:"); + writeln!(out, "Available code models:"); for name in &["tiny", "small", "kernel", "medium", "large"] { - println!(" {}", name); + writeln!(out, " {}", name); } - println!(); + writeln!(out); } PrintRequest::TlsModels => { - println!("Available TLS models:"); + writeln!(out, "Available TLS models:"); for name in &["global-dynamic", "local-dynamic", "initial-exec", "local-exec"] { - println!(" {}", name); + writeln!(out, " {}", name); } - println!(); + writeln!(out); } PrintRequest::StackProtectorStrategies => { - println!( + writeln!( + out, r#"Available stack protector strategies: all Generate stack canaries in all functions. diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index b3c9ecf8b938b..f2f59ff0a3093 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -23,6 +23,8 @@ use rustc_span::symbol::Symbol; use rustc_target::abi::call::FnAbi; use rustc_target::spec::Target; +use std::fmt; + pub trait BackendTypes { type Value: CodegenObject; type Function: CodegenObject; @@ -61,7 +63,7 @@ pub trait CodegenBackend { fn locale_resource(&self) -> &'static str; fn init(&self, _sess: &Session) {} - fn print(&self, _req: PrintRequest, _sess: &Session) {} + fn print(&self, _req: PrintRequest, _out: &mut dyn PrintBackendInfo, _sess: &Session) {} fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec { vec![] } @@ -162,3 +164,19 @@ pub trait ExtraBackendMethods: std::thread::Builder::new().name(name).spawn(f) } } + +pub trait PrintBackendInfo { + fn infallible_write_fmt(&mut self, args: fmt::Arguments<'_>); +} + +impl PrintBackendInfo for String { + fn infallible_write_fmt(&mut self, args: fmt::Arguments<'_>) { + fmt::Write::write_fmt(self, args).unwrap(); + } +} + +impl dyn PrintBackendInfo + '_ { + pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) { + self.infallible_write_fmt(args); + } +} diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index 8cb58bd4c704d..728c2bc8c49bc 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -30,7 +30,9 @@ mod write; pub use self::abi::AbiBuilderMethods; pub use self::asm::{AsmBuilderMethods, AsmMethods, GlobalAsmOperandRef, InlineAsmOperandRef}; -pub use self::backend::{Backend, BackendTypes, CodegenBackend, ExtraBackendMethods}; +pub use self::backend::{ + Backend, BackendTypes, CodegenBackend, ExtraBackendMethods, PrintBackendInfo, +}; pub use self::builder::{BuilderMethods, OverflowOp}; pub use self::consts::ConstMethods; pub use self::coverageinfo::CoverageInfoBuilderMethods; diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 7d12b6c11fa3c..d9a81287f9ecc 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -841,7 +841,7 @@ fn print_crate_info( | TargetCPUs | StackProtectorStrategies | TargetFeatures => { - codegen_backend.print(*req, sess); + codegen_backend.print(*req, &mut crate_info, sess); } // Any output here interferes with Cargo's parsing of other printed output NativeStaticLibs => {} From 299d8b9cef3fdd57f9d90cdcb20321449d8893b1 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 13 Jul 2023 16:54:25 -0700 Subject: [PATCH 5/8] Implement printing to file in llvm_util --- compiler/rustc_codegen_llvm/src/lib.rs | 2 +- compiler/rustc_codegen_llvm/src/llvm_util.rs | 25 ++++++++++---------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 08f4a56eed916..514edf4653bb4 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -320,7 +320,7 @@ impl CodegenBackend for LlvmCodegenBackend { "# ); } - req => llvm_util::print(req, sess), + req => llvm_util::print(req, out, sess), } } diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 03be0654b50bb..2fd0e444e2cb1 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -8,6 +8,7 @@ use libc::c_int; use rustc_codegen_ssa::target_features::{ supported_target_features, tied_target_features, RUSTC_SPECIFIC_FEATURES, }; +use rustc_codegen_ssa::traits::PrintBackendInfo; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::small_c_str::SmallCStr; use rustc_fs_util::path_to_c_string; @@ -350,7 +351,7 @@ fn llvm_target_features(tm: &llvm::TargetMachine) -> Vec<(&str, &str)> { ret } -fn print_target_features(sess: &Session, tm: &llvm::TargetMachine) { +fn print_target_features(out: &mut dyn PrintBackendInfo, sess: &Session, tm: &llvm::TargetMachine) { let mut llvm_target_features = llvm_target_features(tm); let mut known_llvm_target_features = FxHashSet::<&'static str>::default(); let mut rustc_target_features = supported_target_features(sess) @@ -383,24 +384,24 @@ fn print_target_features(sess: &Session, tm: &llvm::TargetMachine) { .max() .unwrap_or(0); - println!("Features supported by rustc for this target:"); + writeln!(out, "Features supported by rustc for this target:"); for (feature, desc) in &rustc_target_features { - println!(" {1:0$} - {2}.", max_feature_len, feature, desc); + writeln!(out, " {1:0$} - {2}.", max_feature_len, feature, desc); } - println!("\nCode-generation features supported by LLVM for this target:"); + writeln!(out, "\nCode-generation features supported by LLVM for this target:"); for (feature, desc) in &llvm_target_features { - println!(" {1:0$} - {2}.", max_feature_len, feature, desc); + writeln!(out, " {1:0$} - {2}.", max_feature_len, feature, desc); } if llvm_target_features.is_empty() { - println!(" Target features listing is not supported by this LLVM version."); + writeln!(out, " Target features listing is not supported by this LLVM version."); } - println!("\nUse +feature to enable a feature, or -feature to disable it."); - println!("For example, rustc -C target-cpu=mycpu -C target-feature=+feature1,-feature2\n"); - println!("Code-generation features cannot be used in cfg or #[target_feature],"); - println!("and may be renamed or removed in a future version of LLVM or rustc.\n"); + writeln!(out, "\nUse +feature to enable a feature, or -feature to disable it."); + writeln!(out, "For example, rustc -C target-cpu=mycpu -C target-feature=+feature1,-feature2\n"); + writeln!(out, "Code-generation features cannot be used in cfg or #[target_feature],"); + writeln!(out, "and may be renamed or removed in a future version of LLVM or rustc.\n"); } -pub(crate) fn print(req: PrintRequest, sess: &Session) { +pub(crate) fn print(req: PrintRequest, out: &mut dyn PrintBackendInfo, sess: &Session) { require_inited(); let tm = create_informational_target_machine(sess); match req { @@ -412,7 +413,7 @@ pub(crate) fn print(req: PrintRequest, sess: &Session) { .unwrap_or_else(|e| bug!("failed to convert to cstring: {}", e)); unsafe { llvm::LLVMRustPrintTargetCPUs(tm, cpu_cstring.as_ptr()) }; } - PrintRequest::TargetFeatures => print_target_features(sess, tm), + PrintRequest::TargetFeatures => print_target_features(out, sess, tm), _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req), } } From df5dede62527ef81f600a199063ced9a9384a615 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 13 Jul 2023 16:56:29 -0700 Subject: [PATCH 6/8] Implement printing to file in PassWrapper --- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 7 +++- compiler/rustc_codegen_llvm/src/llvm_util.rs | 18 +++++++++-- .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 32 +++++++++++++------ 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index e1dfc1b2dd6fa..3b857164a27e1 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2281,7 +2281,12 @@ extern "C" { pub fn LLVMRustHasFeature(T: &TargetMachine, s: *const c_char) -> bool; - pub fn LLVMRustPrintTargetCPUs(T: &TargetMachine, cpu: *const c_char); + pub fn LLVMRustPrintTargetCPUs( + T: &TargetMachine, + cpu: *const c_char, + print: unsafe extern "C" fn(out: *mut c_void, string: *const c_char, len: usize), + out: *mut c_void, + ); pub fn LLVMRustGetTargetFeaturesCount(T: &TargetMachine) -> size_t; pub fn LLVMRustGetTargetFeature( T: &TargetMachine, diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 2fd0e444e2cb1..e2d087e3deab0 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -17,8 +17,8 @@ use rustc_session::config::PrintRequest; use rustc_session::Session; use rustc_span::symbol::Symbol; use rustc_target::spec::{MergeFunctions, PanicStrategy}; -use std::ffi::{CStr, CString}; +use std::ffi::{c_char, c_void, CStr, CString}; use std::path::Path; use std::ptr; use std::slice; @@ -401,7 +401,7 @@ fn print_target_features(out: &mut dyn PrintBackendInfo, sess: &Session, tm: &ll writeln!(out, "and may be renamed or removed in a future version of LLVM or rustc.\n"); } -pub(crate) fn print(req: PrintRequest, out: &mut dyn PrintBackendInfo, sess: &Session) { +pub(crate) fn print(req: PrintRequest, mut out: &mut dyn PrintBackendInfo, sess: &Session) { require_inited(); let tm = create_informational_target_machine(sess); match req { @@ -411,7 +411,19 @@ pub(crate) fn print(req: PrintRequest, out: &mut dyn PrintBackendInfo, sess: &Se // at least as long as the C function let cpu_cstring = CString::new(handle_native(sess.target.cpu.as_ref())) .unwrap_or_else(|e| bug!("failed to convert to cstring: {}", e)); - unsafe { llvm::LLVMRustPrintTargetCPUs(tm, cpu_cstring.as_ptr()) }; + unsafe extern "C" fn callback(out: *mut c_void, string: *const c_char, len: usize) { + let out = &mut *(out as *mut &mut dyn PrintBackendInfo); + let bytes = slice::from_raw_parts(string as *const u8, len); + write!(out, "{}", String::from_utf8_lossy(bytes)); + } + unsafe { + llvm::LLVMRustPrintTargetCPUs( + tm, + cpu_cstring.as_ptr(), + callback, + &mut out as *mut &mut dyn PrintBackendInfo as *mut c_void, + ); + } } PrintRequest::TargetFeatures => print_target_features(out, sess, tm), _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req), diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index eb3d67e720f2d..e5fb6b0953f5a 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1,5 +1,6 @@ #include +#include #include #include @@ -306,44 +307,55 @@ static size_t getLongestEntryLength(ArrayRef Table) { return MaxLen; } -extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM, const char* TargetCPU) { +using PrintBackendInfo = void(void*, const char* Data, size_t Len); + +extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM, + const char* TargetCPU, + PrintBackendInfo Print, + void* Out) { const TargetMachine *Target = unwrap(TM); const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo(); const Triple::ArchType HostArch = Triple(sys::getDefaultTargetTriple()).getArch(); const Triple::ArchType TargetArch = Target->getTargetTriple().getArch(); + std::ostringstream Buf; + #if LLVM_VERSION_GE(17, 0) const ArrayRef CPUTable = MCInfo->getAllProcessorDescriptions(); #elif defined(LLVM_RUSTLLVM) const ArrayRef CPUTable = MCInfo->getCPUTable(); #else - printf("Full target CPU help is not supported by this LLVM version.\n\n"); + Buf << "Full target CPU help is not supported by this LLVM version.\n\n"; SubtargetSubTypeKV TargetCPUKV = { TargetCPU, {{}}, {{}} }; const ArrayRef CPUTable = TargetCPUKV; #endif unsigned MaxCPULen = getLongestEntryLength(CPUTable); - printf("Available CPUs for this target:\n"); + Buf << "Available CPUs for this target:\n"; // Don't print the "native" entry when the user specifies --target with a // different arch since that could be wrong or misleading. if (HostArch == TargetArch) { MaxCPULen = std::max(MaxCPULen, (unsigned) std::strlen("native")); const StringRef HostCPU = sys::getHostCPUName(); - printf(" %-*s - Select the CPU of the current host (currently %.*s).\n", - MaxCPULen, "native", (int)HostCPU.size(), HostCPU.data()); + Buf << " " << std::left << std::setw(MaxCPULen) << "native" + << " - Select the CPU of the current host " + "(currently " << HostCPU.str() << ").\n"; } for (auto &CPU : CPUTable) { // Compare cpu against current target to label the default if (strcmp(CPU.Key, TargetCPU) == 0) { - printf(" %-*s - This is the default target CPU" - " for the current build target (currently %s).", - MaxCPULen, CPU.Key, Target->getTargetTriple().str().c_str()); + Buf << " " << std::left << std::setw(MaxCPULen) << CPU.Key + << " - This is the default target CPU for the current build target " + "(currently " << Target->getTargetTriple().str() << ")."; } else { - printf(" %-*s", MaxCPULen, CPU.Key); + Buf << " " << CPU.Key; } - printf("\n"); + Buf << "\n"; } + + const auto &BufString = Buf.str(); + Print(Out, BufString.data(), BufString.size()); } extern "C" size_t LLVMRustGetTargetFeaturesCount(LLVMTargetMachineRef TM) { From 3a4d73fc69b9cca64f97347a5e67037e0963e590 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 14 Jul 2023 10:38:26 -0700 Subject: [PATCH 7/8] Extend testing of --print -o --- tests/run-make/print-cfg/Makefile | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/run-make/print-cfg/Makefile b/tests/run-make/print-cfg/Makefile index bd24e7707b7a9..24b5427d70826 100644 --- a/tests/run-make/print-cfg/Makefile +++ b/tests/run-make/print-cfg/Makefile @@ -12,9 +12,22 @@ all: default output_to_file $(RUSTC) --target arm-unknown-linux-gnueabihf --print cfg | $(CGREP) eabihf output_to_file: + # Backend-independent, printed by rustc_driver_impl/src/lib.rs -rm $(TMPDIR)/cfg.txt $(RUSTC) --target x86_64-pc-windows-gnu --print=cfg -o $(TMPDIR)/cfg.txt $(CGREP) windows < $(TMPDIR)/cfg.txt + + # Printed from CodegenBackend trait impl in rustc_codegen_llvm/src/lib.rs + -rm $(TMPDIR)/cfg.txt + $(RUSTC) --print=relocation-models -o $(TMPDIR)/cfg.txt + $(CGREP) dynamic-no-pic < $(TMPDIR)/cfg.txt + + # Printed by compiler/rustc_codegen_llvm/src/llvm_util.rs + -rm $(TMPDIR)/cfg.txt + $(RUSTC) --target wasm32-unknown-unknown --print=target-features -o $(TMPDIR)/cfg.txt + $(CGREP) reference-types < $(TMPDIR)/cfg.txt + + # Printed by C++ code in rustc_llvm/llvm-wrapper/PassWrapper.cpp -rm $(TMPDIR)/cfg.txt $(RUSTC) --target x86_64-pc-windows-gnu --print=target-cpus -o $(TMPDIR)/cfg.txt $(CGREP) native < $(TMPDIR)/cfg.txt From 89a32a465014d30ec622221da0a1848da0e3e576 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 14 Jul 2023 10:51:54 -0700 Subject: [PATCH 8/8] Add ui test of LLVM print-from-C++ changes --- tests/ui/codegen/target-cpus.rs | 4 ++++ tests/ui/codegen/target-cpus.stdout | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 tests/ui/codegen/target-cpus.rs create mode 100644 tests/ui/codegen/target-cpus.stdout diff --git a/tests/ui/codegen/target-cpus.rs b/tests/ui/codegen/target-cpus.rs new file mode 100644 index 0000000000000..1dff3ee6011bf --- /dev/null +++ b/tests/ui/codegen/target-cpus.rs @@ -0,0 +1,4 @@ +// needs-llvm-components: webassembly +// min-llvm-version: 17 +// compile-flags: --print=target-cpus --target=wasm32-unknown-unknown +// check-pass diff --git a/tests/ui/codegen/target-cpus.stdout b/tests/ui/codegen/target-cpus.stdout new file mode 100644 index 0000000000000..f60ba0f5034ba --- /dev/null +++ b/tests/ui/codegen/target-cpus.stdout @@ -0,0 +1,4 @@ +Available CPUs for this target: + bleeding-edge + generic - This is the default target CPU for the current build target (currently wasm32-unknown-unknown). + mvp