diff --git a/example/mini_core.rs b/example/mini_core.rs index 0aba44a88c5..2e165cc3c12 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -628,11 +628,6 @@ impl Deref for Box { } } -#[lang = "exchange_malloc"] -unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { - libc::malloc(size) -} - #[lang = "drop"] pub trait Drop { fn drop(&mut self); diff --git a/rust-toolchain b/rust-toolchain index 655fa6abbab..d78b1d7f192 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2026-02-14" +channel = "nightly-2026-03-13" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/src/back/lto.rs b/src/back/lto.rs index 9a9040708ef..347a15a392a 100644 --- a/src/back/lto.rs +++ b/src/back/lto.rs @@ -17,31 +17,26 @@ // /usr/bin/ld: warning: type of symbol `_RNvNvNvNvNtNtNtCsAj5i4SGTR7_3std4sync4mpmc5waker17current_thread_id5DUMMY7___getit5___KEY' changed from 1 to 6 in /tmp/ccKeUSiR.ltrans0.ltrans.o // /usr/bin/ld: warning: incremental linking of LTO and non-LTO objects; using -flinker-output=nolto-rel which will bypass whole program optimization // cSpell:enable -use std::ffi::{CStr, CString}; +use std::ffi::CString; use std::fs::{self, File}; use std::path::{Path, PathBuf}; -use std::sync::Arc; -use std::sync::atomic::Ordering; -use gccjit::{Context, OutputKind}; +use gccjit::OutputKind; use object::read::archive::ArchiveFile; -use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared}; +use rustc_codegen_ssa::back::lto::SerializedModule; use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput, SharedEmitter}; use rustc_codegen_ssa::traits::*; -use rustc_codegen_ssa::{ModuleCodegen, ModuleKind, looks_like_rust_object_file}; +use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, ModuleKind, looks_like_rust_object_file}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_errors::{DiagCtxt, DiagCtxtHandle}; use rustc_log::tracing::info; -use rustc_middle::bug; -use rustc_middle::dep_graph::WorkProduct; use rustc_session::config::Lto; -use rustc_target::spec::RelocModel; use tempfile::{TempDir, tempdir}; -use crate::back::write::save_temp_bitcode; +use crate::back::write::{codegen, save_temp_bitcode}; use crate::errors::LtoBitcodeFromRlib; -use crate::{GccCodegenBackend, GccContext, LTO_SUPPORTED, LtoMode, SyncContext, to_gcc_opt_level}; +use crate::{GccCodegenBackend, GccContext, LtoMode, to_gcc_opt_level}; struct LtoData { // TODO(antoyo): use symbols_below_threshold. @@ -117,7 +112,7 @@ pub(crate) fn run_fat( shared_emitter: &SharedEmitter, each_linked_rlib_for_lto: &[PathBuf], modules: Vec>, -) -> ModuleCodegen { +) -> CompiledModule { let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); let dcx = dcx.handle(); let lto_data = prepare_lto(cgcx, each_linked_rlib_for_lto, dcx); @@ -137,12 +132,12 @@ pub(crate) fn run_fat( fn fat_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, - _dcx: DiagCtxtHandle<'_>, + dcx: DiagCtxtHandle<'_>, modules: Vec>, mut serialized_modules: Vec<(SerializedModule, CString)>, tmp_path: TempDir, //symbols_below_threshold: &[String], -) -> ModuleCodegen { +) -> CompiledModule { let _timer = prof.generic_activity("GCC_fat_lto_build_monolithic_module"); info!("going for a fat lto"); @@ -265,7 +260,7 @@ fn fat_lto( // of now. module.module_llvm.temp_dir = Some(tmp_path); - module + codegen(cgcx, prof, dcx, module, &cgcx.module_config) } pub struct ModuleBuffer(PathBuf); @@ -281,385 +276,3 @@ impl ModuleBufferMethods for ModuleBuffer { &[] } } - -/// Performs thin LTO by performing necessary global analysis and returning two -/// lists, one of the modules that need optimization and another for modules that -/// can simply be copied over from the incr. comp. cache. -pub(crate) fn run_thin( - cgcx: &CodegenContext, - prof: &SelfProfilerRef, - dcx: DiagCtxtHandle<'_>, - each_linked_rlib_for_lto: &[PathBuf], - modules: Vec<(String, ThinBuffer)>, - cached_modules: Vec<(SerializedModule, WorkProduct)>, -) -> (Vec>, Vec) { - let lto_data = prepare_lto(cgcx, each_linked_rlib_for_lto, dcx); - if cgcx.use_linker_plugin_lto { - unreachable!( - "We should never reach this case if the LTO step \ - is deferred to the linker" - ); - } - thin_lto( - cgcx, - prof, - dcx, - modules, - lto_data.upstream_modules, - lto_data.tmp_path, - cached_modules, - //<o_data.symbols_below_threshold, - ) -} - -pub(crate) fn prepare_thin(module: ModuleCodegen) -> (String, ThinBuffer) { - let name = module.name; - //let buffer = ThinBuffer::new(module.module_llvm.context, true); - let buffer = ThinBuffer::new(&module.module_llvm.context); - (name, buffer) -} - -/// Prepare "thin" LTO to get run on these modules. -/// -/// The general structure of ThinLTO is quite different from the structure of -/// "fat" LTO above. With "fat" LTO all LLVM modules in question are merged into -/// one giant LLVM module, and then we run more optimization passes over this -/// big module after internalizing most symbols. Thin LTO, on the other hand, -/// avoid this large bottleneck through more targeted optimization. -/// -/// At a high level Thin LTO looks like: -/// -/// 1. Prepare a "summary" of each LLVM module in question which describes -/// the values inside, cost of the values, etc. -/// 2. Merge the summaries of all modules in question into one "index" -/// 3. Perform some global analysis on this index -/// 4. For each module, use the index and analysis calculated previously to -/// perform local transformations on the module, for example inlining -/// small functions from other modules. -/// 5. Run thin-specific optimization passes over each module, and then code -/// generate everything at the end. -/// -/// The summary for each module is intended to be quite cheap, and the global -/// index is relatively quite cheap to create as well. As a result, the goal of -/// ThinLTO is to reduce the bottleneck on LTO and enable LTO to be used in more -/// situations. For example one cheap optimization is that we can parallelize -/// all codegen modules, easily making use of all the cores on a machine. -/// -/// With all that in mind, the function here is designed at specifically just -/// calculating the *index* for ThinLTO. This index will then be shared amongst -/// all of the `LtoModuleCodegen` units returned below and destroyed once -/// they all go out of scope. -fn thin_lto( - _cgcx: &CodegenContext, - prof: &SelfProfilerRef, - _dcx: DiagCtxtHandle<'_>, - modules: Vec<(String, ThinBuffer)>, - serialized_modules: Vec<(SerializedModule, CString)>, - tmp_path: TempDir, - cached_modules: Vec<(SerializedModule, WorkProduct)>, - //_symbols_below_threshold: &[String], -) -> (Vec>, Vec) { - let _timer = prof.generic_activity("LLVM_thin_lto_global_analysis"); - info!("going for that thin, thin LTO"); - - /*let green_modules: FxHashMap<_, _> = - cached_modules.iter().map(|(_, wp)| (wp.cgu_name.clone(), wp.clone())).collect();*/ - - let full_scope_len = modules.len() + serialized_modules.len() + cached_modules.len(); - let mut thin_buffers = Vec::with_capacity(modules.len()); - let mut module_names = Vec::with_capacity(full_scope_len); - //let mut thin_modules = Vec::with_capacity(full_scope_len); - - for (i, (name, buffer)) in modules.into_iter().enumerate() { - info!("local module: {} - {}", i, name); - let cname = CString::new(name.as_bytes()).unwrap(); - /*thin_modules.push(llvm::ThinLTOModule { - identifier: cname.as_ptr(), - data: buffer.data().as_ptr(), - len: buffer.data().len(), - });*/ - thin_buffers.push(buffer); - module_names.push(cname); - } - - // FIXME: All upstream crates are deserialized internally in the - // function below to extract their summary and modules. Note that - // unlike the loop above we *must* decode and/or read something - // here as these are all just serialized files on disk. An - // improvement, however, to make here would be to store the - // module summary separately from the actual module itself. Right - // now this is store in one large bitcode file, and the entire - // file is deflate-compressed. We could try to bypass some of the - // decompression by storing the index uncompressed and only - // lazily decompressing the bytecode if necessary. - // - // Note that truly taking advantage of this optimization will - // likely be further down the road. We'd have to implement - // incremental ThinLTO first where we could actually avoid - // looking at upstream modules entirely sometimes (the contents, - // we must always unconditionally look at the index). - let mut serialized = Vec::with_capacity(serialized_modules.len() + cached_modules.len()); - - let cached_modules = - cached_modules.into_iter().map(|(sm, wp)| (sm, CString::new(wp.cgu_name).unwrap())); - - for (module, name) in serialized_modules.into_iter().chain(cached_modules) { - info!("upstream or cached module {:?}", name); - /*thin_modules.push(llvm::ThinLTOModule { - identifier: name.as_ptr(), - data: module.data().as_ptr(), - len: module.data().len(), - });*/ - - match module { - SerializedModule::Local(_) => { - //let path = module_buffer.0.to_str().expect("path"); - //let my_path = PathBuf::from(path); - //let exists = my_path.exists(); - /*module.module_llvm.should_combine_object_files = true; - module - .module_llvm - .context - .add_driver_option(module_buffer.0.to_str().expect("path"));*/ - } - SerializedModule::FromRlib(_) => unimplemented!("from rlib"), - SerializedModule::FromUncompressedFile(_) => { - unimplemented!("from uncompressed file") - } - } - - serialized.push(module); - module_names.push(name); - } - - // Sanity check - //assert_eq!(thin_modules.len(), module_names.len()); - - // Delegate to the C++ bindings to create some data here. Once this is a - // tried-and-true interface we may wish to try to upstream some of this - // to LLVM itself, right now we reimplement a lot of what they do - // upstream... - /*let data = llvm::LLVMRustCreateThinLTOData( - thin_modules.as_ptr(), - thin_modules.len() as u32, - symbols_below_threshold.as_ptr(), - symbols_below_threshold.len() as u32, - ) - .ok_or_else(|| write::llvm_err(dcx, LlvmError::PrepareThinLtoContext))?; - */ - - let data = ThinData; //(Arc::new(tmp_path))/*(data)*/; - - info!("thin LTO data created"); - - /*let (key_map_path, prev_key_map, curr_key_map) = - if let Some(ref incr_comp_session_dir) = cgcx.incr_comp_session_dir { - let path = incr_comp_session_dir.join(THIN_LTO_KEYS_INCR_COMP_FILE_NAME); - // If the previous file was deleted, or we get an IO error - // reading the file, then we'll just use `None` as the - // prev_key_map, which will force the code to be recompiled. - let prev = - if path.exists() { ThinLTOKeysMap::load_from_file(&path).ok() } else { None }; - let curr = ThinLTOKeysMap::from_thin_lto_modules(&data, &thin_modules, &module_names); - (Some(path), prev, curr) - } - else { - // If we don't compile incrementally, we don't need to load the - // import data from LLVM. - assert!(green_modules.is_empty()); - let curr = ThinLTOKeysMap::default(); - (None, None, curr) - }; - info!("thin LTO cache key map loaded"); - info!("prev_key_map: {:#?}", prev_key_map); - info!("curr_key_map: {:#?}", curr_key_map);*/ - - // Throw our data in an `Arc` as we'll be sharing it across threads. We - // also put all memory referenced by the C++ data (buffers, ids, etc) - // into the arc as well. After this we'll create a thin module - // codegen per module in this data. - let shared = - Arc::new(ThinShared { data, thin_buffers, serialized_modules: serialized, module_names }); - - let copy_jobs = vec![]; - let mut opt_jobs = vec![]; - - info!("checking which modules can be-reused and which have to be re-optimized."); - for (module_index, module_name) in shared.module_names.iter().enumerate() { - let module_name = module_name_to_str(module_name); - /*if let (Some(prev_key_map), true) = - (prev_key_map.as_ref(), green_modules.contains_key(module_name)) - { - assert!(cgcx.incr_comp_session_dir.is_some()); - - // If a module exists in both the current and the previous session, - // and has the same LTO cache key in both sessions, then we can re-use it - if prev_key_map.keys.get(module_name) == curr_key_map.keys.get(module_name) { - let work_product = green_modules[module_name].clone(); - copy_jobs.push(work_product); - info!(" - {}: re-used", module_name); - assert!(cgcx.incr_comp_session_dir.is_some()); - continue; - } - }*/ - - info!(" - {}: re-compiled", module_name); - opt_jobs.push(ThinModule { shared: shared.clone(), idx: module_index }); - } - - // Save the current ThinLTO import information for the next compilation - // session, overwriting the previous serialized data (if any). - /*if let Some(path) = key_map_path { - if let Err(err) = curr_key_map.save_to_file(&path) { - return Err(write::llvm_err(dcx, LlvmError::WriteThinLtoKey { err })); - } - }*/ - - // NOTE: save the temporary directory used by LTO so that it gets deleted after linking instead - // of now. - //module.module_llvm.temp_dir = Some(tmp_path); - // TODO: save the directory so that it gets deleted later. - std::mem::forget(tmp_path); - - (opt_jobs, copy_jobs) -} - -pub fn optimize_thin_module( - thin_module: ThinModule, - _cgcx: &CodegenContext, -) -> ModuleCodegen { - //let module_name = &thin_module.shared.module_names[thin_module.idx]; - - // Right now the implementation we've got only works over serialized - // modules, so we create a fresh new LLVM context and parse the module - // into that context. One day, however, we may do this for upstream - // crates but for locally codegened modules we may be able to reuse - // that LLVM Context and Module. - //let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); - //let llmod_raw = parse_module(llcx, module_name, thin_module.data(), &dcx)? as *const _; - let mut lto_mode = LtoMode::None; - let context = match thin_module.shared.thin_buffers.get(thin_module.idx) { - Some(thin_buffer) => Arc::clone(&thin_buffer.context), - None => { - let context = Context::default(); - let len = thin_module.shared.thin_buffers.len(); - let module = &thin_module.shared.serialized_modules[thin_module.idx - len]; - match *module { - SerializedModule::Local(ref module_buffer) => { - let path = module_buffer.0.to_str().expect("path"); - context.add_driver_option(path); - lto_mode = LtoMode::Thin; - /*module.module_llvm.should_combine_object_files = true; - module - .module_llvm - .context - .add_driver_option(module_buffer.0.to_str().expect("path"));*/ - } - SerializedModule::FromRlib(_) => unimplemented!("from rlib"), - SerializedModule::FromUncompressedFile(_) => { - unimplemented!("from uncompressed file") - } - } - Arc::new(SyncContext::new(context)) - } - }; - let lto_supported = LTO_SUPPORTED.load(Ordering::SeqCst); - let module = ModuleCodegen::new_regular( - thin_module.name().to_string(), - GccContext { - context, - lto_mode, - lto_supported, - // TODO(antoyo): use the correct relocation model here. - relocation_model: RelocModel::Pic, - temp_dir: None, - }, - ); - /*{ - let target = &*module.module_llvm.tm; - let llmod = module.module_llvm.llmod(); - save_temp_bitcode(cgcx, &module, "thin-lto-input"); - - // Up next comes the per-module local analyses that we do for Thin LTO. - // Each of these functions is basically copied from the LLVM - // implementation and then tailored to suit this implementation. Ideally - // each of these would be supported by upstream LLVM but that's perhaps - // a patch for another day! - // - // You can find some more comments about these functions in the LLVM - // bindings we've got (currently `PassWrapper.cpp`) - { - let _timer = - cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_rename", thin_module.name()); - unsafe { llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) }; - save_temp_bitcode(cgcx, &module, "thin-lto-after-rename"); - } - - { - let _timer = cgcx - .prof - .generic_activity_with_arg("LLVM_thin_lto_resolve_weak", thin_module.name()); - if !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) { - return Err(write::llvm_err(&dcx, LlvmError::PrepareThinLtoModule)); - } - save_temp_bitcode(cgcx, &module, "thin-lto-after-resolve"); - } - - { - let _timer = cgcx - .prof - .generic_activity_with_arg("LLVM_thin_lto_internalize", thin_module.name()); - if !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) { - return Err(write::llvm_err(&dcx, LlvmError::PrepareThinLtoModule)); - } - save_temp_bitcode(cgcx, &module, "thin-lto-after-internalize"); - } - - { - let _timer = - cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_import", thin_module.name()); - if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target) { - return Err(write::llvm_err(&dcx, LlvmError::PrepareThinLtoModule)); - } - save_temp_bitcode(cgcx, &module, "thin-lto-after-import"); - } - - // Alright now that we've done everything related to the ThinLTO - // analysis it's time to run some optimizations! Here we use the same - // `run_pass_manager` as the "fat" LTO above except that we tell it to - // populate a thin-specific pass manager, which presumably LLVM treats a - // little differently. - { - info!("running thin lto passes over {}", module.name); - run_pass_manager(cgcx, &dcx, &mut module, true)?; - save_temp_bitcode(cgcx, &module, "thin-lto-after-pm"); - } - }*/ - // FIXME: switch to #[expect] when the clippy bug is fixed. - #[allow(clippy::let_and_return)] - module -} - -pub struct ThinBuffer { - context: Arc, -} - -impl ThinBuffer { - pub(crate) fn new(context: &Arc) -> Self { - Self { context: Arc::clone(context) } - } -} - -impl ThinBufferMethods for ThinBuffer { - fn data(&self) -> &[u8] { - &[] - } -} - -pub struct ThinData; //(Arc); - -fn module_name_to_str(c_str: &CStr) -> &str { - c_str.to_str().unwrap_or_else(|e| { - bug!("Encountered non-utf8 GCC module name `{}`: {}", c_str.to_string_lossy(), e) - }) -} diff --git a/src/back/write.rs b/src/back/write.rs index ddf13558027..24ea2b66ba7 100644 --- a/src/back/write.rs +++ b/src/back/write.rs @@ -2,12 +2,10 @@ use std::{env, fs}; use gccjit::{Context, OutputKind}; use rustc_codegen_ssa::back::link::ensure_removed; -use rustc_codegen_ssa::back::write::{ - BitcodeSection, CodegenContext, EmitObj, ModuleConfig, SharedEmitter, -}; +use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig}; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_errors::DiagCtxt; +use rustc_errors::DiagCtxtHandle; use rustc_fs_util::link_or_copy; use rustc_log::tracing::debug; use rustc_session::config::OutputType; @@ -20,13 +18,10 @@ use crate::{GccContext, LtoMode}; pub(crate) fn codegen( cgcx: &CodegenContext, prof: &SelfProfilerRef, - shared_emitter: &SharedEmitter, + dcx: DiagCtxtHandle<'_>, module: ModuleCodegen, config: &ModuleConfig, ) -> CompiledModule { - let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); - let dcx = dcx.handle(); - let _timer = prof.generic_activity_with_arg("GCC_module_codegen", &*module.name); { let context = &module.module_llvm.context; diff --git a/src/builder.rs b/src/builder.rs index e1937f5c11e..1d5db049f7d 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -485,13 +485,14 @@ impl<'a, 'gcc, 'tcx> Deref for Builder<'a, 'gcc, 'tcx> { } impl<'gcc, 'tcx> BackendTypes for Builder<'_, 'gcc, 'tcx> { - type Value = as BackendTypes>::Value; - type Metadata = as BackendTypes>::Metadata; type Function = as BackendTypes>::Function; type BasicBlock = as BackendTypes>::BasicBlock; - type Type = as BackendTypes>::Type; type Funclet = as BackendTypes>::Funclet; + type Value = as BackendTypes>::Value; + type Type = as BackendTypes>::Type; + type FunctionSignature = as BackendTypes>::FunctionSignature; + type DIScope = as BackendTypes>::DIScope; type DILocation = as BackendTypes>::DILocation; type DIVariable = as BackendTypes>::DIVariable; @@ -1655,6 +1656,10 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { unimplemented!(); } + fn get_funclet_cleanuppad(&self, _funclet: &Funclet) -> RValue<'gcc> { + unimplemented!(); + } + // Atomic Operations fn atomic_cmpxchg( &mut self, diff --git a/src/common.rs b/src/common.rs index 86a4eeac89d..79cae9e0282 100644 --- a/src/common.rs +++ b/src/common.rs @@ -5,9 +5,10 @@ use rustc_codegen_ssa::traits::{ BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, StaticCodegenMethods, }; use rustc_middle::mir::Mutability; -use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, PointerArithmetic, Scalar}; +use rustc_middle::mir::interpret::{GlobalAlloc, PointerArithmetic, Scalar}; use rustc_middle::ty::layout::LayoutOf; +use crate::consts::const_alloc_to_gcc; use crate::context::{CodegenCx, new_array_type}; use crate::type_of::LayoutGccExt; @@ -260,11 +261,13 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { }; } - let init = self.const_data_from_alloc(alloc); - let alloc = alloc.inner(); - let value = match alloc.mutability { - Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None), - _ => self.static_addr_of(init, alloc.align, None), + let value = match alloc.inner().mutability { + Mutability::Mut => self.static_addr_of_mut( + const_alloc_to_gcc(self, alloc), + alloc.inner().align, + None, + ), + _ => self.static_addr_of(alloc, None), }; if !self.sess().fewer_names() { // TODO(antoyo): set value name. @@ -282,8 +285,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { }), ))) .unwrap_memory(); - let init = self.const_data_from_alloc(alloc); - self.static_addr_of(init, alloc.inner().align, None) + self.static_addr_of(alloc, None) } GlobalAlloc::TypeId { .. } => { let val = self.const_usize(offset.bytes()); @@ -311,22 +313,6 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { } } - fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value { - // We ignore the alignment for the purpose of deduping RValues - // The alignment is not handled / used in any way by `const_alloc_to_gcc`, - // so it is OK to overwrite it here. - let mut mock_alloc = alloc.inner().clone(); - mock_alloc.align = rustc_abi::Align::MAX; - // Check if the rvalue is already in the cache - if so, just return it directly. - if let Some(res) = self.const_cache.borrow().get(&mock_alloc) { - return *res; - } - // Rvalue not in the cache - convert and add it. - let res = crate::consts::const_alloc_to_gcc_uncached(self, alloc); - self.const_cache.borrow_mut().insert(mock_alloc, res); - res - } - fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value { self.context .new_array_access(None, base_addr, self.const_usize(offset.bytes())) diff --git a/src/consts.rs b/src/consts.rs index 6fb96f8832b..8afa57bc28f 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -22,6 +22,25 @@ use crate::base; use crate::context::CodegenCx; use crate::type_of::LayoutGccExt; +pub(crate) fn const_alloc_to_gcc<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + alloc: ConstAllocation<'_>, +) -> RValue<'gcc> { + // We ignore the alignment for the purpose of deduping RValues + // The alignment is not handled / used in any way by `const_alloc_to_gcc`, + // so it is OK to overwrite it here. + let mut mock_alloc = alloc.inner().clone(); + mock_alloc.align = rustc_abi::Align::MAX; + // Check if the rvalue is already in the cache - if so, just return it directly. + if let Some(res) = cx.const_cache.borrow().get(&mock_alloc) { + return *res; + } + // Rvalue not in the cache - convert and add it. + let res = crate::consts::const_alloc_to_gcc_uncached(cx, alloc); + cx.const_cache.borrow_mut().insert(mock_alloc, res); + res +} + fn set_global_alignment<'gcc, 'tcx>( cx: &CodegenCx<'gcc, 'tcx>, gv: LValue<'gcc>, @@ -37,7 +56,10 @@ fn set_global_alignment<'gcc, 'tcx>( } impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> { - fn static_addr_of(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> { + fn static_addr_of(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> RValue<'gcc> { + let cv = const_alloc_to_gcc(self, alloc); + let align = alloc.inner().align; + if let Some(variable) = self.const_globals.borrow().get(&cv) { if let Some(global_variable) = self.global_lvalues.borrow().get(variable) { let alignment = align.bits() as i32; @@ -361,7 +383,7 @@ fn codegen_static_initializer<'gcc, 'tcx>( def_id: DefId, ) -> Result<(RValue<'gcc>, ConstAllocation<'tcx>), ErrorHandled> { let alloc = cx.tcx.eval_static_initializer(def_id)?; - Ok((cx.const_data_from_alloc(alloc), alloc)) + Ok((const_alloc_to_gcc(cx, alloc), alloc)) } fn check_and_apply_linkage<'gcc, 'tcx>( diff --git a/src/context.rs b/src/context.rs index 03f207f4572..64ab92b3a91 100644 --- a/src/context.rs +++ b/src/context.rs @@ -21,8 +21,7 @@ use rustc_middle::ty::{self, ExistentialTraitRef, Instance, Ty, TyCtxt}; use rustc_session::Session; #[cfg(feature = "master")] use rustc_session::config::DebugInfo; -use rustc_span::source_map::respan; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{DUMMY_SP, Span, respan}; use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, TlsModel, X86Abi}; #[cfg(feature = "master")] @@ -380,14 +379,14 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> { - type Value = RValue<'gcc>; - type Metadata = RValue<'gcc>; type Function = Function<'gcc>; - type BasicBlock = Block<'gcc>; - type Type = Type<'gcc>; type Funclet = (); // TODO(antoyo) + type Value = RValue<'gcc>; + type Type = Type<'gcc>; + type FunctionSignature = Type<'gcc>; + type DIScope = (); // TODO(antoyo) type DILocation = Location<'gcc>; type DIVariable = (); // TODO(antoyo) @@ -539,7 +538,7 @@ impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { | LayoutError::InvalidSimd { .. } | LayoutError::ReferencesError(_) = err { - self.tcx.dcx().emit_fatal(respan(span, err.into_diagnostic())) + self.tcx.dcx().span_fatal(span, err.to_string()) } else { self.tcx.dcx().emit_fatal(ssa_errors::FailedToGetLayout { span, ty, err }) } diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index ffcae6a1cdd..61917e5b24c 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -469,7 +469,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc let layout = self.layout_of(tp_ty).layout; let _use_integer_compare = match layout.backend_repr() { Scalar(_) | ScalarPair(_, _) => true, - SimdVector { .. } | ScalableVector { .. } => false, + SimdVector { .. } | SimdScalableVector { .. } => false, Memory { .. } => { // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), @@ -676,7 +676,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc &mut self, _vtable: Self::Value, _vtable_byte_offset: u64, - _typeid: Self::Value, + _typeid: &[u8], ) -> Self::Value { // Unsupported. self.context.new_rvalue_from_int(self.int_type, 0) diff --git a/src/lib.rs b/src/lib.rs index 1b3d78c42e6..592eb68ce27 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,7 @@ #![warn(unused_lifetimes)] #![deny(clippy::pattern_type_mismatch)] #![expect(clippy::uninlined_format_args)] +#![allow(clippy::collapsible_match)] // The rustc crates we need extern crate rustc_abi; @@ -76,7 +77,6 @@ use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex}; -use back::lto::{ThinBuffer, ThinData}; use gccjit::{CType, Context, OptimizationLevel}; #[cfg(feature = "master")] use gccjit::{TargetInfo, Version}; @@ -88,11 +88,11 @@ use rustc_codegen_ssa::back::write::{ use rustc_codegen_ssa::base::codegen_crate; use rustc_codegen_ssa::target_features::cfg_target_feature; use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBackendMethods}; -use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetConfig}; +use rustc_codegen_ssa::{CompiledModule, CompiledModules, CrateInfo, ModuleCodegen, TargetConfig}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sync::IntoDynSyncSend; -use rustc_errors::DiagCtxtHandle; +use rustc_errors::{DiagCtxt, DiagCtxtHandle}; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; @@ -177,8 +177,6 @@ pub struct GccCodegenBackend { lto_supported: Arc, } -static LTO_SUPPORTED: AtomicBool = AtomicBool::new(false); - fn load_libgccjit_if_needed(libgccjit_target_lib_file: &Path) { if gccjit::is_loaded() { // Do not load a libgccjit second time. @@ -251,7 +249,6 @@ impl CodegenBackend for GccCodegenBackend { #[cfg(feature = "master")] { let lto_supported = gccjit::is_lto_supported(); - LTO_SUPPORTED.store(lto_supported, Ordering::SeqCst); self.lto_supported.store(lto_supported, Ordering::SeqCst); gccjit::set_global_personality_function_name(b"rust_eh_personality\0"); @@ -281,16 +278,21 @@ impl CodegenBackend for GccCodegenBackend { } } + fn thin_lto_supported(&self) -> bool { + false + } + fn provide(&self, providers: &mut Providers) { providers.queries.global_backend_features = |tcx, ()| gcc_util::global_gcc_features(tcx.sess) } - fn codegen_crate(&self, tcx: TyCtxt<'_>) -> Box { - let target_cpu = target_cpu(tcx.sess); - let res = codegen_crate(self.clone(), tcx, target_cpu.to_string()); + fn target_cpu(&self, sess: &Session) -> String { + target_cpu(sess).to_owned() + } - Box::new(res) + fn codegen_crate(&self, tcx: TyCtxt<'_>, crate_info: &CrateInfo) -> Box { + Box::new(codegen_crate(self.clone(), tcx, crate_info)) } fn join_codegen( @@ -298,7 +300,7 @@ impl CodegenBackend for GccCodegenBackend { ongoing_codegen: Box, sess: &Session, _outputs: &OutputFilenames, - ) -> (CodegenResults, FxIndexMap) { + ) -> (CompiledModules, FxIndexMap) { ongoing_codegen .downcast::>() .expect("Expected GccCodegenBackend's OngoingCodegen, found Box") @@ -369,16 +371,6 @@ impl ExtraBackendMethods for GccCodegenBackend { self.lto_supported.load(Ordering::SeqCst), ) } - - fn target_machine_factory( - &self, - _sess: &Session, - _opt_level: OptLevel, - _features: &[String], - ) -> TargetMachineFactoryFn { - // TODO(antoyo): set opt level. - Arc::new(|_, _| ()) - } } #[derive(Clone, Copy, PartialEq)] @@ -425,10 +417,19 @@ impl WriteBackendMethods for GccCodegenBackend { type Module = GccContext; type TargetMachine = (); type ModuleBuffer = ModuleBuffer; - type ThinData = ThinData; - type ThinBuffer = ThinBuffer; + type ThinData = (); - fn run_and_optimize_fat_lto( + fn target_machine_factory( + &self, + _sess: &Session, + _opt_level: OptLevel, + _features: &[String], + ) -> TargetMachineFactoryFn { + // TODO(antoyo): set opt level. + Arc::new(|_, _| ()) + } + + fn optimize_and_codegen_fat_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: &SharedEmitter, @@ -437,29 +438,21 @@ impl WriteBackendMethods for GccCodegenBackend { _exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec>, - ) -> ModuleCodegen { + ) -> CompiledModule { back::lto::run_fat(cgcx, prof, shared_emitter, each_linked_rlib_for_lto, modules) } fn run_thin_lto( - cgcx: &CodegenContext, - prof: &SelfProfilerRef, - dcx: DiagCtxtHandle<'_>, + _cgcx: &CodegenContext, + _prof: &SelfProfilerRef, + _dcx: DiagCtxtHandle<'_>, // FIXME(bjorn3): Limit LTO exports to these symbols _exported_symbols_for_lto: &[String], - each_linked_rlib_for_lto: &[PathBuf], - modules: Vec<(String, Self::ThinBuffer)>, - cached_modules: Vec<(SerializedModule, WorkProduct)>, + _each_linked_rlib_for_lto: &[PathBuf], + _modules: Vec<(String, Self::ModuleBuffer)>, + _cached_modules: Vec<(SerializedModule, WorkProduct)>, ) -> (Vec>, Vec) { - back::lto::run_thin(cgcx, prof, dcx, each_linked_rlib_for_lto, modules, cached_modules) - } - - fn print_pass_timings(&self) { - unimplemented!(); - } - - fn print_statistics(&self) { - unimplemented!() + unreachable!() } fn optimize( @@ -472,14 +465,14 @@ impl WriteBackendMethods for GccCodegenBackend { module.module_llvm.context.set_optimization_level(to_gcc_opt_level(config.opt_level)); } - fn optimize_thin( - cgcx: &CodegenContext, + fn optimize_and_codegen_thin( + _cgcx: &CodegenContext, _prof: &SelfProfilerRef, _shared_emitter: &SharedEmitter, _tm_factory: TargetMachineFactoryFn, - thin: ThinModule, - ) -> ModuleCodegen { - back::lto::optimize_thin_module(thin, cgcx) + _thin: ThinModule, + ) -> CompiledModule { + unreachable!() } fn codegen( @@ -489,14 +482,12 @@ impl WriteBackendMethods for GccCodegenBackend { module: ModuleCodegen, config: &ModuleConfig, ) -> CompiledModule { - back::write::codegen(cgcx, prof, shared_emitter, module, config) - } - - fn prepare_thin(module: ModuleCodegen) -> (String, Self::ThinBuffer) { - back::lto::prepare_thin(module) + let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); + let dcx = dcx.handle(); + back::write::codegen(cgcx, prof, dcx, module, config) } - fn serialize_module(_module: ModuleCodegen) -> (String, Self::ModuleBuffer) { + fn serialize_module(_module: Self::Module, _is_thin: bool) -> Self::ModuleBuffer { unimplemented!(); } } diff --git a/src/type_of.rs b/src/type_of.rs index 68fca5a17ad..65f4fc68f05 100644 --- a/src/type_of.rs +++ b/src/type_of.rs @@ -85,7 +85,7 @@ fn uncached_gcc_type<'gcc, 'tcx>( ); } BackendRepr::Memory { .. } => {} - BackendRepr::ScalableVector { .. } => todo!(), + BackendRepr::SimdScalableVector { .. } => todo!(), } let name = match *layout.ty.kind() { @@ -181,7 +181,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { match self.backend_repr { BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => true, // FIXME(rustc_scalable_vector): Not yet implemented in rustc_codegen_gcc. - BackendRepr::ScalableVector { .. } => todo!(), + BackendRepr::SimdScalableVector { .. } => todo!(), BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => false, } } @@ -191,7 +191,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { BackendRepr::ScalarPair(..) => true, BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } - | BackendRepr::ScalableVector { .. } + | BackendRepr::SimdScalableVector { .. } | BackendRepr::Memory { .. } => false, } } @@ -288,7 +288,9 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { Float(f) => cx.type_from_float(f), Pointer(address_space) => { // If we know the alignment, pick something better than i8. - let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) { + let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) + && pointee.align > rustc_abi::Align::ONE + { cx.type_pointee_for_align(pointee.align) } else { cx.type_i8() diff --git a/tests/run/asm.rs b/tests/run/asm.rs index 9b15a28d829..01775c92ffc 100644 --- a/tests/run/asm.rs +++ b/tests/run/asm.rs @@ -213,7 +213,6 @@ fn asm() { core::arch::asm!( "", out("al") _, - out("bl") _, out("cl") _, out("dl") _, out("sil") _,