From badabab01f15f156dbb6ce39df4a339006fbfae1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 30 May 2025 11:55:06 +0000 Subject: Only borrow EncodedMetadata in codegen_crate And move passing it to the linker to the driver code. --- compiler/rustc_codegen_llvm/src/lib.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index fd376ea8d80..0ef2761a66a 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -344,15 +344,13 @@ impl CodegenBackend for LlvmCodegenBackend { fn codegen_crate<'tcx>( &self, tcx: TyCtxt<'tcx>, - metadata: EncodedMetadata, - need_metadata_module: bool, + metadata: Option<&EncodedMetadata>, ) -> Box { Box::new(rustc_codegen_ssa::base::codegen_crate( LlvmCodegenBackend(()), tcx, crate::llvm_util::target_cpu(tcx.sess).to_string(), metadata, - need_metadata_module, )) } @@ -377,14 +375,20 @@ impl CodegenBackend for LlvmCodegenBackend { (codegen_results, work_products) } - fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) { + fn link( + &self, + sess: &Session, + codegen_results: CodegenResults, + metadata: EncodedMetadata, + outputs: &OutputFilenames, + ) { use rustc_codegen_ssa::back::link::link_binary; use crate::back::archive::LlvmArchiveBuilderBuilder; // Run the linker on any artifacts that resulted from the LLVM run. // This should produce either a finished executable or library. - link_binary(sess, &LlvmArchiveBuilderBuilder, codegen_results, outputs); + link_binary(sess, &LlvmArchiveBuilderBuilder, codegen_results, metadata, outputs); } } -- cgit 1.4.1-3-g733a5 From 0bd7aa1116c42a96d1c692065ae500a3d2d75484 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 30 May 2025 12:51:15 +0000 Subject: Move metadata object generation for dylibs to the linker code This deduplicates some code between codegen backends and may in the future allow adding extra metadata that is only known at link time. --- compiler/rustc_codegen_cranelift/src/driver/aot.rs | 46 +------------------- compiler/rustc_codegen_cranelift/src/lib.rs | 5 +-- compiler/rustc_codegen_gcc/src/lib.rs | 6 +-- compiler/rustc_codegen_llvm/src/lib.rs | 7 +-- compiler/rustc_codegen_ssa/messages.ftl | 2 - compiler/rustc_codegen_ssa/src/back/archive.rs | 12 +++++- compiler/rustc_codegen_ssa/src/back/link.rs | 44 +++++++++++++------ compiler/rustc_codegen_ssa/src/back/write.rs | 23 +--------- compiler/rustc_codegen_ssa/src/base.rs | 50 +++------------------- compiler/rustc_codegen_ssa/src/errors.rs | 6 --- compiler/rustc_codegen_ssa/src/lib.rs | 3 +- compiler/rustc_codegen_ssa/src/traits/backend.rs | 6 +-- compiler/rustc_interface/src/passes.rs | 7 +-- compiler/rustc_metadata/src/fs.rs | 46 ++++++++------------ compiler/rustc_middle/src/ty/context.rs | 25 ++++------- compiler/rustc_session/src/session.rs | 7 --- .../codegen-backend/auxiliary/the_backend.rs | 17 ++++---- 17 files changed, 92 insertions(+), 220 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 58a0a380945..442151fe32d 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -11,7 +11,6 @@ use std::thread::JoinHandle; use cranelift_object::{ObjectBuilder, ObjectModule}; use rustc_codegen_ssa::assert_module_sources::CguReuse; use rustc_codegen_ssa::back::link::ensure_removed; -use rustc_codegen_ssa::back::metadata::create_compressed_metadata_file; use rustc_codegen_ssa::base::determine_cgu_reuse; use rustc_codegen_ssa::{ CodegenResults, CompiledModule, CrateInfo, ModuleKind, errors as ssa_errors, @@ -19,7 +18,6 @@ use rustc_codegen_ssa::{ use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{IntoDynSyncSend, par_map}; -use rustc_metadata::EncodedMetadata; use rustc_metadata::fs::copy_to_stdout; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -61,7 +59,6 @@ impl HashStable for OngoingModuleCodegen { pub(crate) struct OngoingCodegen { modules: Vec, allocator_module: Option, - metadata_module: Option, crate_info: CrateInfo, concurrency_limiter: ConcurrencyLimiter, } @@ -133,7 +130,6 @@ impl OngoingCodegen { let codegen_results = CodegenResults { modules, allocator_module: self.allocator_module, - metadata_module: self.metadata_module, crate_info: self.crate_info, }; @@ -644,42 +640,6 @@ fn module_codegen( })) } -fn emit_metadata_module(tcx: TyCtxt<'_>, metadata: &EncodedMetadata) -> CompiledModule { - use rustc_middle::mir::mono::CodegenUnitNameBuilder; - - let _timer = tcx.sess.timer("write compressed metadata"); - - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); - let metadata_cgu_name = cgu_name_builder - .build_cgu_name(LOCAL_CRATE, ["crate"], Some("metadata")) - .as_str() - .to_string(); - - let tmp_file = tcx.output_filenames(()).temp_path_for_cgu( - OutputType::Metadata, - &metadata_cgu_name, - tcx.sess.invocation_temp.as_deref(), - ); - - let symbol_name = rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx); - let obj = create_compressed_metadata_file(tcx.sess, metadata, &symbol_name); - - if let Err(err) = std::fs::write(&tmp_file, obj) { - tcx.dcx().fatal(format!("error writing metadata object file: {}", err)); - } - - CompiledModule { - name: metadata_cgu_name, - kind: ModuleKind::Metadata, - object: Some(tmp_file), - dwarf_object: None, - bytecode: None, - assembly: None, - llvm_ir: None, - links_from_incr_cache: Vec::new(), - } -} - fn emit_allocator_module(tcx: TyCtxt<'_>) -> Option { let mut allocator_module = make_module(tcx.sess, "allocator_shim".to_string()); let created_alloc_shim = crate::allocator::codegen(tcx, &mut allocator_module); @@ -704,7 +664,7 @@ fn emit_allocator_module(tcx: TyCtxt<'_>) -> Option { } } -pub(crate) fn run_aot(tcx: TyCtxt<'_>, metadata: Option<&EncodedMetadata>) -> Box { +pub(crate) fn run_aot(tcx: TyCtxt<'_>) -> Box { // FIXME handle `-Ctarget-cpu=native` let target_cpu = match tcx.sess.opts.cg.target_cpu { Some(ref name) => name, @@ -720,7 +680,6 @@ pub(crate) fn run_aot(tcx: TyCtxt<'_>, metadata: Option<&EncodedMetadata>) -> Bo return Box::new(OngoingCodegen { modules: vec![], allocator_module: None, - metadata_module: None, crate_info: CrateInfo::new(tcx, target_cpu), concurrency_limiter: ConcurrencyLimiter::new(0), }); @@ -780,12 +739,9 @@ pub(crate) fn run_aot(tcx: TyCtxt<'_>, metadata: Option<&EncodedMetadata>) -> Bo let allocator_module = emit_allocator_module(tcx); - let metadata_module = metadata.map(|metadata| emit_metadata_module(tcx, metadata)); - Box::new(OngoingCodegen { modules, allocator_module, - metadata_module, crate_info: CrateInfo::new(tcx, target_cpu), concurrency_limiter: concurrency_limiter.0, }) diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 277d4f16f19..07ea29f3024 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -46,7 +46,6 @@ use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::settings::{self, Configurable}; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::{CodegenResults, TargetConfig}; -use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_session::Session; use rustc_session::config::OutputFilenames; @@ -238,7 +237,7 @@ impl CodegenBackend for CraneliftCodegenBackend { println!("Cranelift version: {}", cranelift_codegen::VERSION); } - fn codegen_crate(&self, tcx: TyCtxt<'_>, metadata: Option<&EncodedMetadata>) -> Box { + fn codegen_crate(&self, tcx: TyCtxt<'_>) -> Box { info!("codegen crate {}", tcx.crate_name(LOCAL_CRATE)); let config = self.config.clone().unwrap_or_else(|| { BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args) @@ -251,7 +250,7 @@ impl CodegenBackend for CraneliftCodegenBackend { #[cfg(not(feature = "jit"))] tcx.dcx().fatal("jit support was disabled when compiling rustc_codegen_cranelift"); } else { - driver::aot::run_aot(tcx, metadata) + driver::aot::run_aot(tcx) } } diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index ec0fc7c8e0c..7329593433a 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -48,7 +48,6 @@ extern crate rustc_index; #[cfg(feature = "master")] extern crate rustc_interface; extern crate rustc_macros; -extern crate rustc_metadata; extern crate rustc_middle; extern crate rustc_session; extern crate rustc_span; @@ -106,7 +105,6 @@ use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetCon use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::IntoDynSyncSend; use rustc_errors::DiagCtxtHandle; -use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; @@ -230,9 +228,9 @@ impl CodegenBackend for GccCodegenBackend { providers.global_backend_features = |tcx, ()| gcc_util::global_gcc_features(tcx.sess, true) } - fn codegen_crate(&self, tcx: TyCtxt<'_>, metadata: Option<&EncodedMetadata>) -> Box { + 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(), metadata); + let res = codegen_crate(self.clone(), tcx, target_cpu.to_string()); Box::new(res) } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 0ef2761a66a..dbce60aa781 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -341,16 +341,11 @@ impl CodegenBackend for LlvmCodegenBackend { target_config(sess) } - fn codegen_crate<'tcx>( - &self, - tcx: TyCtxt<'tcx>, - metadata: Option<&EncodedMetadata>, - ) -> Box { + fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Box { Box::new(rustc_codegen_ssa::base::codegen_crate( LlvmCodegenBackend(()), tcx, crate::llvm_util::target_cpu(tcx.sess).to_string(), - metadata, )) } diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index acb4cbaa13f..871ffb2d733 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -200,8 +200,6 @@ codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status codegen_ssa_malformed_cgu_name = found malformed codegen unit name `{$user_path}`. codegen units names must always start with the name of the crate (`{$crate_name}` in this case). -codegen_ssa_metadata_object_file_write = error writing metadata object file: {$error} - codegen_ssa_missing_cpp_build_tool_component = or a necessary component may be missing from the "C++ build tools" workload codegen_ssa_missing_features = add the missing features in a `target_feature` attribute diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 1e1bdfb5977..84a56f6b0b5 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -14,11 +14,12 @@ use object::read::macho::FatArch; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::memmap::Mmap; use rustc_fs_util::TempDirBuilder; +use rustc_metadata::EncodedMetadata; use rustc_session::Session; use rustc_span::Symbol; use tracing::trace; -use super::metadata::search_for_section; +use super::metadata::{create_compressed_metadata_file, search_for_section}; use crate::common; // Re-exporting for rustc_codegen_llvm::back::archive pub use crate::errors::{ArchiveBuildFailure, ExtractBundledLibsError, UnknownArchiveKind}; @@ -58,6 +59,15 @@ impl From for COFFShortExport { pub trait ArchiveBuilderBuilder { fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box; + fn create_dylib_metadata_wrapper( + &self, + sess: &Session, + metadata: &EncodedMetadata, + symbol_name: &str, + ) -> Vec { + create_compressed_metadata_file(sess, metadata, symbol_name) + } + /// Creates a DLL Import Library . /// and returns the path on disk to that import library. /// This functions doesn't take `self` so that it can be called from diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index b15134397d0..0b6d8a6ae9f 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -167,6 +167,7 @@ pub fn link_binary( crate_type, &out_filename, &codegen_results, + &metadata, path.as_ref(), ); } @@ -230,11 +231,7 @@ pub fn link_binary( let remove_temps_from_module = |module: &CompiledModule| maybe_remove_temps_from_module(false, false, module); - // Otherwise, always remove the metadata and allocator module temporaries. - if let Some(ref metadata_module) = codegen_results.metadata_module { - remove_temps_from_module(metadata_module); - } - + // Otherwise, always remove the allocator module temporaries. if let Some(ref allocator_module) = codegen_results.allocator_module { remove_temps_from_module(allocator_module); } @@ -326,7 +323,7 @@ fn link_rlib<'a>( RlibFlavor::Normal => { let (metadata, metadata_position) = create_wrapper_file(sess, ".rmeta".to_string(), metadata.stub_or_full()); - let metadata = emit_wrapper_file(sess, &metadata, tmpdir, METADATA_FILENAME); + let metadata = emit_wrapper_file(sess, &metadata, tmpdir.as_ref(), METADATA_FILENAME); match metadata_position { MetadataPosition::First => { // Most of the time metadata in rlib files is wrapped in a "dummy" object @@ -394,7 +391,7 @@ fn link_rlib<'a>( let src = read(path) .unwrap_or_else(|e| sess.dcx().emit_fatal(errors::ReadFileError { message: e })); let (data, _) = create_wrapper_file(sess, ".bundled_lib".to_string(), &src); - let wrapper_file = emit_wrapper_file(sess, &data, tmpdir, filename.as_str()); + let wrapper_file = emit_wrapper_file(sess, &data, tmpdir.as_ref(), filename.as_str()); packed_bundled_libs.push(wrapper_file); } else { let path = find_native_static_library(lib.name.as_str(), lib.verbatim, sess); @@ -698,6 +695,7 @@ fn link_natively( crate_type: CrateType, out_filename: &Path, codegen_results: &CodegenResults, + metadata: &EncodedMetadata, tmpdir: &Path, ) { info!("preparing {:?} to {:?}", crate_type, out_filename); @@ -722,6 +720,7 @@ fn link_natively( tmpdir, temp_filename, codegen_results, + metadata, self_contained_components, ); @@ -2098,17 +2097,25 @@ fn add_local_crate_allocator_objects(cmd: &mut dyn Linker, codegen_results: &Cod /// Add object files containing metadata for the current crate. fn add_local_crate_metadata_objects( cmd: &mut dyn Linker, + sess: &Session, + archive_builder_builder: &dyn ArchiveBuilderBuilder, crate_type: CrateType, + tmpdir: &Path, codegen_results: &CodegenResults, + metadata: &EncodedMetadata, ) { // When linking a dynamic library, we put the metadata into a section of the // executable. This metadata is in a separate object file from the main - // object file, so we link that in here. - if matches!(crate_type, CrateType::Dylib | CrateType::ProcMacro) - && let Some(m) = &codegen_results.metadata_module - && let Some(obj) = &m.object - { - cmd.add_object(obj); + // object file, so we create and link it in here. + if matches!(crate_type, CrateType::Dylib | CrateType::ProcMacro) { + let data = archive_builder_builder.create_dylib_metadata_wrapper( + sess, + &metadata, + &codegen_results.crate_info.metadata_symbol, + ); + let obj = emit_wrapper_file(sess, &data, tmpdir, "rmeta.o"); + + cmd.add_object(&obj); } } @@ -2198,6 +2205,7 @@ fn linker_with_args( tmpdir: &Path, out_filename: &Path, codegen_results: &CodegenResults, + metadata: &EncodedMetadata, self_contained_components: LinkSelfContainedComponents, ) -> Command { let self_contained_crt_objects = self_contained_components.is_crt_objects_enabled(); @@ -2272,7 +2280,15 @@ fn linker_with_args( // in this DAG so far because they can only depend on other native libraries // and such dependencies are also required to be specified. add_local_crate_regular_objects(cmd, codegen_results); - add_local_crate_metadata_objects(cmd, crate_type, codegen_results); + add_local_crate_metadata_objects( + cmd, + sess, + archive_builder_builder, + crate_type, + tmpdir, + codegen_results, + metadata, + ); add_local_crate_allocator_objects(cmd, codegen_results); // Avoid linking to dynamic libraries unless they satisfy some undefined symbols diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 6163da104cb..bbf9cceef2a 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -141,7 +141,6 @@ impl ModuleConfig { || match kind { ModuleKind::Regular => sess.opts.output_types.contains_key(&OutputType::Object), ModuleKind::Allocator => false, - ModuleKind::Metadata => sess.opts.output_types.contains_key(&OutputType::Metadata), }; let emit_obj = if !should_emit_obj { @@ -349,7 +348,6 @@ pub struct CodegenContext { pub output_filenames: Arc, pub invocation_temp: Option, pub regular_module_config: Arc, - pub metadata_module_config: Arc, pub allocator_module_config: Arc, pub tm_factory: TargetMachineFactoryFn, pub msvc_imps_needed: bool, @@ -394,7 +392,6 @@ impl CodegenContext { pub fn config(&self, kind: ModuleKind) -> &ModuleConfig { match kind { ModuleKind::Regular => &self.regular_module_config, - ModuleKind::Metadata => &self.metadata_module_config, ModuleKind::Allocator => &self.allocator_module_config, } } @@ -473,7 +470,6 @@ pub(crate) fn start_async_codegen( backend: B, tcx: TyCtxt<'_>, target_cpu: String, - metadata_module: Option, ) -> OngoingCodegen { let (coordinator_send, coordinator_receive) = channel(); @@ -483,7 +479,6 @@ pub(crate) fn start_async_codegen( let crate_info = CrateInfo::new(tcx, target_cpu); let regular_config = ModuleConfig::new(ModuleKind::Regular, tcx, no_builtins); - let metadata_config = ModuleConfig::new(ModuleKind::Metadata, tcx, no_builtins); let allocator_config = ModuleConfig::new(ModuleKind::Allocator, tcx, no_builtins); let (shared_emitter, shared_emitter_main) = SharedEmitter::new(); @@ -497,14 +492,12 @@ pub(crate) fn start_async_codegen( codegen_worker_send, coordinator_receive, Arc::new(regular_config), - Arc::new(metadata_config), Arc::new(allocator_config), coordinator_send.clone(), ); OngoingCodegen { backend, - metadata_module, crate_info, codegen_worker_receive, @@ -840,12 +833,6 @@ pub(crate) fn compute_per_cgu_lto_type( sess_crate_types: &[CrateType], module_kind: ModuleKind, ) -> ComputedLtoType { - // Metadata modules never participate in LTO regardless of the lto - // settings. - if module_kind == ModuleKind::Metadata { - return ComputedLtoType::No; - } - // If the linker does LTO, we don't have to do it. Note that we // keep doing full LTO, if it is requested, as not to break the // assumption that the output will be a single module. @@ -1026,10 +1013,7 @@ fn finish_intra_module_work( let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); - if !cgcx.opts.unstable_opts.combine_cgu - || module.kind == ModuleKind::Metadata - || module.kind == ModuleKind::Allocator - { + if !cgcx.opts.unstable_opts.combine_cgu || module.kind == ModuleKind::Allocator { let module = B::codegen(cgcx, dcx, module, module_config)?; Ok(WorkItemResult::Finished(module)) } else { @@ -1120,7 +1104,6 @@ fn start_executing_work( codegen_worker_send: Sender, coordinator_receive: Receiver>, regular_config: Arc, - metadata_config: Arc, allocator_config: Arc, tx_to_llvm_workers: Sender>, ) -> thread::JoinHandle> { @@ -1213,7 +1196,6 @@ fn start_executing_work( diag_emitter: shared_emitter.clone(), output_filenames: Arc::clone(tcx.output_filenames(())), regular_module_config: regular_config, - metadata_module_config: metadata_config, allocator_module_config: allocator_config, tm_factory: backend.target_machine_factory(tcx.sess, ol, backend_features), msvc_imps_needed: msvc_imps_needed(tcx), @@ -1670,7 +1652,6 @@ fn start_executing_work( assert!(compiled_allocator_module.is_none()); compiled_allocator_module = Some(compiled_module); } - ModuleKind::Metadata => bug!("Should be handled separately"), } } Ok(WorkItemResult::NeedsLink(module)) => { @@ -2052,7 +2033,6 @@ impl Drop for Coordinator { pub struct OngoingCodegen { pub backend: B, - pub metadata_module: Option, pub crate_info: CrateInfo, pub codegen_worker_receive: Receiver, pub shared_emitter_main: SharedEmitterMain, @@ -2096,7 +2076,6 @@ impl OngoingCodegen { modules: compiled_modules.modules, allocator_module: compiled_modules.allocator_module, - metadata_module: self.metadata_module, }, work_products, ) diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index bfad5137140..356f5418d34 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -15,11 +15,10 @@ use rustc_data_structures::unord::UnordMap; use rustc_hir::ItemId; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; -use rustc_metadata::EncodedMetadata; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType}; -use rustc_middle::middle::exported_symbols::SymbolExportKind; -use rustc_middle::middle::{exported_symbols, lang_items}; +use rustc_middle::middle::exported_symbols::{self, SymbolExportKind}; +use rustc_middle::middle::lang_items; use rustc_middle::mir::BinOp; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem, MonoItemPartitions}; @@ -28,7 +27,7 @@ use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::Session; -use rustc_session::config::{self, CrateType, EntryFnType, OutputType}; +use rustc_session::config::{self, CrateType, EntryFnType}; use rustc_span::{DUMMY_SP, Symbol, sym}; use rustc_symbol_mangling::mangle_internal_symbol; use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt}; @@ -37,7 +36,6 @@ use tracing::{debug, info}; use crate::assert_module_sources::CguReuse; use crate::back::link::are_upstream_rust_objects_already_included; -use crate::back::metadata::create_compressed_metadata_file; use crate::back::write::{ ComputedLtoType, OngoingCodegen, compute_per_cgu_lto_type, start_async_codegen, submit_codegened_module_to_llvm, submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, @@ -48,8 +46,7 @@ use crate::mir::operand::OperandValue; use crate::mir::place::PlaceRef; use crate::traits::*; use crate::{ - CachedModuleCodegen, CodegenLintLevels, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind, - errors, meth, mir, + CachedModuleCodegen, CodegenLintLevels, CrateInfo, ModuleCodegen, ModuleKind, errors, meth, mir, }; pub(crate) fn bin_op_to_icmp_predicate(op: BinOp, signed: bool) -> IntPredicate { @@ -669,11 +666,10 @@ pub fn codegen_crate( backend: B, tcx: TyCtxt<'_>, target_cpu: String, - metadata: Option<&EncodedMetadata>, ) -> OngoingCodegen { // Skip crate items and just output metadata in -Z no-codegen mode. if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() { - let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu, None); + let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu); ongoing_codegen.codegen_finished(tcx); @@ -706,40 +702,7 @@ pub fn codegen_crate( } } - let metadata_module = if let Some(metadata) = metadata { - // Emit compressed metadata object. - let metadata_cgu_name = - cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata")).to_string(); - tcx.sess.time("write_compressed_metadata", || { - let file_name = tcx.output_filenames(()).temp_path_for_cgu( - OutputType::Metadata, - &metadata_cgu_name, - tcx.sess.invocation_temp.as_deref(), - ); - let data = create_compressed_metadata_file( - tcx.sess, - metadata, - &exported_symbols::metadata_symbol_name(tcx), - ); - if let Err(error) = std::fs::write(&file_name, data) { - tcx.dcx().emit_fatal(errors::MetadataObjectFileWrite { error }); - } - Some(CompiledModule { - name: metadata_cgu_name, - kind: ModuleKind::Metadata, - object: Some(file_name), - dwarf_object: None, - bytecode: None, - assembly: None, - llvm_ir: None, - links_from_incr_cache: Vec::new(), - }) - }) - } else { - None - }; - - let ongoing_codegen = start_async_codegen(backend.clone(), tcx, target_cpu, metadata_module); + let ongoing_codegen = start_async_codegen(backend.clone(), tcx, target_cpu); // Codegen an allocator shim, if necessary. if let Some(kind) = allocator_kind_for_codegen(tcx) { @@ -1010,6 +973,7 @@ impl CrateInfo { windows_subsystem, natvis_debugger_visualizers: Default::default(), lint_levels: CodegenLintLevels::from_tcx(tcx), + metadata_symbol: exported_symbols::metadata_symbol_name(tcx), }; info.native_libraries.reserve(n_crates); diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 572d7b1e06a..3dae195c42a 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -777,12 +777,6 @@ pub(crate) struct MultipleMainFunctions { pub span: Span, } -#[derive(Diagnostic)] -#[diag(codegen_ssa_metadata_object_file_write)] -pub(crate) struct MetadataObjectFileWrite { - pub error: Error, -} - #[derive(Diagnostic)] #[diag(codegen_ssa_invalid_windows_subsystem)] pub(crate) struct InvalidWindowsSubsystem { diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index ba44944476b..523c9f2ad1c 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -170,7 +170,6 @@ pub(crate) struct CachedModuleCodegen { #[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable)] pub enum ModuleKind { Regular, - Metadata, Allocator, } @@ -234,6 +233,7 @@ pub struct CrateInfo { pub windows_subsystem: Option, pub natvis_debugger_visualizers: BTreeSet, pub lint_levels: CodegenLintLevels, + pub metadata_symbol: String, } /// Target-specific options that get set in `cfg(...)`. @@ -258,7 +258,6 @@ pub struct TargetConfig { pub struct CodegenResults { pub modules: Vec, pub allocator_module: Option, - pub metadata_module: Option, pub crate_info: CrateInfo, } diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 420290f5a39..29ec7eb1da3 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -74,11 +74,7 @@ pub trait CodegenBackend { fn provide(&self, _providers: &mut Providers) {} - fn codegen_crate<'tcx>( - &self, - tcx: TyCtxt<'tcx>, - metadata: Option<&EncodedMetadata>, - ) -> Box; + fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Box; /// This is called on the returned `Box` from [`codegen_crate`](Self::codegen_crate) /// diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 124f92f17dc..d16395eb601 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1136,12 +1136,9 @@ pub(crate) fn start_codegen<'tcx>( info!("Pre-codegen\n{:?}", tcx.debug_stats()); - let (metadata, need_metadata_module) = rustc_metadata::fs::encode_and_write_metadata(tcx); + let metadata = rustc_metadata::fs::encode_and_write_metadata(tcx); - let codegen = tcx.sess.time("codegen_crate", || { - codegen_backend - .codegen_crate(tcx, if need_metadata_module { Some(&metadata) } else { None }) - }); + let codegen = tcx.sess.time("codegen_crate", move || codegen_backend.codegen_crate(tcx)); info!("Post-codegen\n{:?}", tcx.debug_stats()); diff --git a/compiler/rustc_metadata/src/fs.rs b/compiler/rustc_metadata/src/fs.rs index e57534b847e..1eaad26ff8e 100644 --- a/compiler/rustc_metadata/src/fs.rs +++ b/compiler/rustc_metadata/src/fs.rs @@ -4,9 +4,9 @@ use std::{fs, io}; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_fs_util::TempDirBuilder; use rustc_middle::ty::TyCtxt; +use rustc_session::Session; use rustc_session::config::{CrateType, OutFileName, OutputType}; use rustc_session::output::filename_for_metadata; -use rustc_session::{MetadataKind, Session}; use crate::errors::{ BinaryOutputToTty, FailedCopyToStdout, FailedCreateEncodedMetadata, FailedCreateFile, @@ -22,13 +22,8 @@ pub const METADATA_FILENAME: &str = "lib.rmeta"; /// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a /// directory being searched for `extern crate` (observing an incomplete file). /// The returned path is the temporary file containing the complete metadata. -pub fn emit_wrapper_file( - sess: &Session, - data: &[u8], - tmpdir: &MaybeTempDir, - name: &str, -) -> PathBuf { - let out_filename = tmpdir.as_ref().join(name); +pub fn emit_wrapper_file(sess: &Session, data: &[u8], tmpdir: &Path, name: &str) -> PathBuf { + let out_filename = tmpdir.join(name); let result = fs::write(&out_filename, data); if let Err(err) = result { @@ -38,7 +33,7 @@ pub fn emit_wrapper_file( out_filename } -pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) { +pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata { let out_filename = filename_for_metadata(tcx.sess, tcx.output_filenames(())); // To avoid races with another rustc process scanning the output directory, // we need to write the file somewhere else and atomically move it to its @@ -59,25 +54,20 @@ pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) { None }; - // Always create a file at `metadata_filename`, even if we have nothing to write to it. - // This simplifies the creation of the output `out_filename` when requested. - let metadata_kind = tcx.metadata_kind(); - match metadata_kind { - MetadataKind::None => { - std::fs::File::create(&metadata_filename).unwrap_or_else(|err| { - tcx.dcx().emit_fatal(FailedCreateFile { filename: &metadata_filename, err }); + if tcx.needs_metadata() { + encode_metadata(tcx, &metadata_filename, metadata_stub_filename.as_deref()); + } else { + // Always create a file at `metadata_filename`, even if we have nothing to write to it. + // This simplifies the creation of the output `out_filename` when requested. + std::fs::File::create(&metadata_filename).unwrap_or_else(|err| { + tcx.dcx().emit_fatal(FailedCreateFile { filename: &metadata_filename, err }); + }); + if let Some(metadata_stub_filename) = &metadata_stub_filename { + std::fs::File::create(metadata_stub_filename).unwrap_or_else(|err| { + tcx.dcx().emit_fatal(FailedCreateFile { filename: &metadata_stub_filename, err }); }); - if let Some(metadata_stub_filename) = &metadata_stub_filename { - std::fs::File::create(metadata_stub_filename).unwrap_or_else(|err| { - tcx.dcx() - .emit_fatal(FailedCreateFile { filename: &metadata_stub_filename, err }); - }); - } - } - MetadataKind::Uncompressed | MetadataKind::Compressed => { - encode_metadata(tcx, &metadata_filename, metadata_stub_filename.as_deref()) } - }; + } let _prof_timer = tcx.sess.prof.generic_activity("write_crate_metadata"); @@ -118,9 +108,7 @@ pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) { tcx.dcx().emit_fatal(FailedCreateEncodedMetadata { err }); }); - let need_metadata_module = metadata_kind == MetadataKind::Compressed; - - (metadata, need_metadata_module) + metadata } #[cfg(not(target_os = "linux"))] diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 57b20a1bba6..5273f35d4c2 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -47,7 +47,7 @@ use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_session::config::CrateType; use rustc_session::cstore::{CrateStoreDyn, Untracked}; use rustc_session::lint::Lint; -use rustc_session::{Limit, MetadataKind, Session}; +use rustc_session::{Limit, Session}; use rustc_span::def_id::{CRATE_DEF_ID, DefPathHash, StableCrateId}; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use rustc_type_ir::TyKind::*; @@ -1828,23 +1828,14 @@ impl<'tcx> TyCtxt<'tcx> { &self.crate_types } - pub fn metadata_kind(self) -> MetadataKind { - self.crate_types() - .iter() - .map(|ty| match *ty { - CrateType::Executable - | CrateType::Staticlib - | CrateType::Cdylib - | CrateType::Sdylib => MetadataKind::None, - CrateType::Rlib => MetadataKind::Uncompressed, - CrateType::Dylib | CrateType::ProcMacro => MetadataKind::Compressed, - }) - .max() - .unwrap_or(MetadataKind::None) - } - pub fn needs_metadata(self) -> bool { - self.metadata_kind() != MetadataKind::None + self.crate_types().iter().any(|ty| match *ty { + CrateType::Executable + | CrateType::Staticlib + | CrateType::Cdylib + | CrateType::Sdylib => false, + CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro => true, + }) } pub fn needs_crate_hash(self) -> bool { diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 010ae42c280..59513d4f8d6 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -215,13 +215,6 @@ pub struct Session { pub invocation_temp: Option, } -#[derive(PartialEq, Eq, PartialOrd, Ord)] -pub enum MetadataKind { - None, - Uncompressed, - Compressed, -} - #[derive(Clone, Copy)] pub enum CodegenUnits { /// Specified by the user. In this case we try fairly hard to produce the diff --git a/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs b/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs index 656cfca1ed1..8449479287f 100644 --- a/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs +++ b/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs @@ -33,17 +33,10 @@ impl CodegenBackend for TheBackend { "" } - fn codegen_crate<'a, 'tcx>( - &self, - tcx: TyCtxt<'tcx>, - metadata: EncodedMetadata, - _need_metadata_module: bool, - ) -> Box { + fn codegen_crate(&self, tcx: TyCtxt<'_>) -> Box { Box::new(CodegenResults { modules: vec![], allocator_module: None, - metadata_module: None, - metadata, crate_info: CrateInfo::new(tcx, "fake_target_cpu".to_string()), }) } @@ -60,7 +53,13 @@ impl CodegenBackend for TheBackend { (*codegen_results, FxIndexMap::default()) } - fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) { + fn link( + &self, + sess: &Session, + codegen_results: CodegenResults, + _metadata: EncodedMetadata, + outputs: &OutputFilenames, + ) { use std::io::Write; use rustc_session::config::{CrateType, OutFileName}; -- cgit 1.4.1-3-g733a5 From d56fcd968d1334bf0c80205fb805a88999fffb5a Mon Sep 17 00:00:00 2001 From: sayantn Date: Fri, 30 May 2025 21:41:36 +0530 Subject: Simplify implementation of Rust intrinsics by using type parameters in the cache --- compiler/rustc_codegen_gcc/src/builder.rs | 2 +- compiler/rustc_codegen_llvm/src/builder.rs | 183 ++----- compiler/rustc_codegen_llvm/src/context.rs | 462 +++++------------- compiler/rustc_codegen_llvm/src/intrinsic.rs | 591 +++++++++-------------- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 12 + compiler/rustc_codegen_llvm/src/llvm/mod.rs | 45 +- compiler/rustc_codegen_llvm/src/type_.rs | 9 + compiler/rustc_codegen_ssa/src/traits/builder.rs | 4 +- 8 files changed, 479 insertions(+), 829 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index d1fb8d8f9d6..1bd89212100 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -897,7 +897,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn checked_binop( &mut self, oop: OverflowOp, - typ: Ty<'_>, + typ: Ty<'tcx>, lhs: Self::Value, rhs: Self::Value, ) -> (Self::Value, Self::Value) { diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index ec006b59192..09cb74d9dcb 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -14,7 +14,6 @@ use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::*; use rustc_data_structures::small_c_str::SmallCStr; use rustc_hir::def_id::DefId; -use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTypingEnv, LayoutError, LayoutOfHelpers, @@ -484,73 +483,31 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn checked_binop( &mut self, oop: OverflowOp, - ty: Ty<'_>, + ty: Ty<'tcx>, lhs: Self::Value, rhs: Self::Value, ) -> (Self::Value, Self::Value) { - use rustc_middle::ty::IntTy::*; - use rustc_middle::ty::UintTy::*; - use rustc_middle::ty::{Int, Uint}; - - let new_kind = match ty.kind() { - Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)), - Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.pointer_width)), - t @ (Uint(_) | Int(_)) => *t, - _ => panic!("tried to get overflow intrinsic for op applied to non-int type"), + let (size, signed) = ty.int_size_and_signed(self.tcx); + let width = size.bits(); + + if oop == OverflowOp::Sub && !signed { + // Emit sub and icmp instead of llvm.usub.with.overflow. LLVM considers these + // to be the canonical form. It will attempt to reform llvm.usub.with.overflow + // in the backend if profitable. + let sub = self.sub(lhs, rhs); + let cmp = self.icmp(IntPredicate::IntULT, lhs, rhs); + return (sub, cmp); + } + + let oop_str = match oop { + OverflowOp::Add => "add", + OverflowOp::Sub => "sub", + OverflowOp::Mul => "mul", }; - let name = match oop { - OverflowOp::Add => match new_kind { - Int(I8) => "llvm.sadd.with.overflow.i8", - Int(I16) => "llvm.sadd.with.overflow.i16", - Int(I32) => "llvm.sadd.with.overflow.i32", - Int(I64) => "llvm.sadd.with.overflow.i64", - Int(I128) => "llvm.sadd.with.overflow.i128", - - Uint(U8) => "llvm.uadd.with.overflow.i8", - Uint(U16) => "llvm.uadd.with.overflow.i16", - Uint(U32) => "llvm.uadd.with.overflow.i32", - Uint(U64) => "llvm.uadd.with.overflow.i64", - Uint(U128) => "llvm.uadd.with.overflow.i128", - - _ => unreachable!(), - }, - OverflowOp::Sub => match new_kind { - Int(I8) => "llvm.ssub.with.overflow.i8", - Int(I16) => "llvm.ssub.with.overflow.i16", - Int(I32) => "llvm.ssub.with.overflow.i32", - Int(I64) => "llvm.ssub.with.overflow.i64", - Int(I128) => "llvm.ssub.with.overflow.i128", - - Uint(_) => { - // Emit sub and icmp instead of llvm.usub.with.overflow. LLVM considers these - // to be the canonical form. It will attempt to reform llvm.usub.with.overflow - // in the backend if profitable. - let sub = self.sub(lhs, rhs); - let cmp = self.icmp(IntPredicate::IntULT, lhs, rhs); - return (sub, cmp); - } - - _ => unreachable!(), - }, - OverflowOp::Mul => match new_kind { - Int(I8) => "llvm.smul.with.overflow.i8", - Int(I16) => "llvm.smul.with.overflow.i16", - Int(I32) => "llvm.smul.with.overflow.i32", - Int(I64) => "llvm.smul.with.overflow.i64", - Int(I128) => "llvm.smul.with.overflow.i128", - - Uint(U8) => "llvm.umul.with.overflow.i8", - Uint(U16) => "llvm.umul.with.overflow.i16", - Uint(U32) => "llvm.umul.with.overflow.i32", - Uint(U64) => "llvm.umul.with.overflow.i64", - Uint(U128) => "llvm.umul.with.overflow.i128", - - _ => unreachable!(), - }, - }; + let name = format!("llvm.{}{oop_str}.with.overflow", if signed { 's' } else { 'u' }); - let res = self.call_intrinsic(name, &[lhs, rhs]); + let res = self.call_intrinsic(&name, &[self.type_ix(width)], &[lhs, rhs]); (self.extract_value(res, 0), self.extract_value(res, 1)) } @@ -954,11 +911,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn fptoui_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { - self.fptoint_sat(false, val, dest_ty) + self.call_intrinsic("llvm.fptoui.sat", &[dest_ty, self.val_ty(val)], &[val]) } fn fptosi_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { - self.fptoint_sat(true, val, dest_ty) + self.call_intrinsic("llvm.fptosi.sat", &[dest_ty, self.val_ty(val)], &[val]) } fn fptoui(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { @@ -981,15 +938,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { if self.cx.type_kind(src_ty) != TypeKind::Vector { let float_width = self.cx.float_width(src_ty); let int_width = self.cx.int_width(dest_ty); - let name = match (int_width, float_width) { - (32, 32) => Some("llvm.wasm.trunc.unsigned.i32.f32"), - (32, 64) => Some("llvm.wasm.trunc.unsigned.i32.f64"), - (64, 32) => Some("llvm.wasm.trunc.unsigned.i64.f32"), - (64, 64) => Some("llvm.wasm.trunc.unsigned.i64.f64"), - _ => None, - }; - if let Some(name) = name { - return self.call_intrinsic(name, &[val]); + if matches!((int_width, float_width), (32 | 64, 32 | 64)) { + return self.call_intrinsic( + "llvm.wasm.trunc.unsigned", + &[dest_ty, src_ty], + &[val], + ); } } } @@ -1003,15 +957,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { if self.cx.type_kind(src_ty) != TypeKind::Vector { let float_width = self.cx.float_width(src_ty); let int_width = self.cx.int_width(dest_ty); - let name = match (int_width, float_width) { - (32, 32) => Some("llvm.wasm.trunc.signed.i32.f32"), - (32, 64) => Some("llvm.wasm.trunc.signed.i32.f64"), - (64, 32) => Some("llvm.wasm.trunc.signed.i64.f32"), - (64, 64) => Some("llvm.wasm.trunc.signed.i64.f64"), - _ => None, - }; - if let Some(name) = name { - return self.call_intrinsic(name, &[val]); + if matches!((int_width, float_width), (32 | 64, 32 | 64)) { + return self.call_intrinsic( + "llvm.wasm.trunc.signed", + &[dest_ty, src_ty], + &[val], + ); } } } @@ -1084,22 +1035,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { return None; } - let name = match (ty.is_signed(), ty.primitive_size(self.tcx).bits()) { - (true, 8) => "llvm.scmp.i8.i8", - (true, 16) => "llvm.scmp.i8.i16", - (true, 32) => "llvm.scmp.i8.i32", - (true, 64) => "llvm.scmp.i8.i64", - (true, 128) => "llvm.scmp.i8.i128", - - (false, 8) => "llvm.ucmp.i8.i8", - (false, 16) => "llvm.ucmp.i8.i16", - (false, 32) => "llvm.ucmp.i8.i32", - (false, 64) => "llvm.ucmp.i8.i64", - (false, 128) => "llvm.ucmp.i8.i128", + let size = ty.primitive_size(self.tcx); + let name = if ty.is_signed() { "llvm.scmp" } else { "llvm.ucmp" }; - _ => bug!("three-way compare unsupported for type {ty:?}"), - }; - Some(self.call_intrinsic(name, &[lhs, rhs])) + Some(self.call_intrinsic(&name, &[self.type_i8(), self.type_ix(size.bits())], &[lhs, rhs])) } /* Miscellaneous instructions */ @@ -1385,11 +1324,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn lifetime_start(&mut self, ptr: &'ll Value, size: Size) { - self.call_lifetime_intrinsic("llvm.lifetime.start.p0i8", ptr, size); + self.call_lifetime_intrinsic("llvm.lifetime.start", ptr, size); } fn lifetime_end(&mut self, ptr: &'ll Value, size: Size) { - self.call_lifetime_intrinsic("llvm.lifetime.end.p0i8", ptr, size); + self.call_lifetime_intrinsic("llvm.lifetime.end", ptr, size); } fn call( @@ -1454,7 +1393,7 @@ impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> { // Forward to the `get_static` method of `CodegenCx` let global = self.cx().get_static(def_id); if self.cx().tcx.is_thread_local_static(def_id) { - let pointer = self.call_intrinsic("llvm.threadlocal.address", &[global]); + let pointer = self.call_intrinsic("llvm.threadlocal.address", &[], &[global]); // Cast to default address space if globals are in a different addrspace self.pointercast(pointer, self.type_ptr()) } else { @@ -1649,8 +1588,13 @@ impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { } impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { - pub(crate) fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value { - let (ty, f) = self.cx.get_intrinsic(intrinsic); + pub(crate) fn call_intrinsic( + &mut self, + base_name: &str, + type_params: &[&'ll Type], + args: &[&'ll Value], + ) -> &'ll Value { + let (ty, f) = self.cx.get_intrinsic(base_name, type_params); self.call(ty, None, None, f, args, None, None) } @@ -1664,7 +1608,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { return; } - self.call_intrinsic(intrinsic, &[self.cx.const_u64(size), ptr]); + self.call_intrinsic(intrinsic, &[self.type_ptr()], &[self.cx.const_u64(size), ptr]); } } impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { @@ -1689,31 +1633,6 @@ impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { } } impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { - fn fptoint_sat(&mut self, signed: bool, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { - let src_ty = self.cx.val_ty(val); - let (float_ty, int_ty, vector_length) = if self.cx.type_kind(src_ty) == TypeKind::Vector { - assert_eq!(self.cx.vector_length(src_ty), self.cx.vector_length(dest_ty)); - ( - self.cx.element_type(src_ty), - self.cx.element_type(dest_ty), - Some(self.cx.vector_length(src_ty)), - ) - } else { - (src_ty, dest_ty, None) - }; - let float_width = self.cx.float_width(float_ty); - let int_width = self.cx.int_width(int_ty); - - let instr = if signed { "fptosi" } else { "fptoui" }; - let name = if let Some(vector_length) = vector_length { - format!("llvm.{instr}.sat.v{vector_length}i{int_width}.v{vector_length}f{float_width}") - } else { - format!("llvm.{instr}.sat.i{int_width}.f{float_width}") - }; - let f = self.declare_cfn(&name, llvm::UnnamedAddr::No, self.type_func(&[src_ty], dest_ty)); - self.call(self.type_func(&[src_ty], dest_ty), None, None, f, &[val], None, None) - } - pub(crate) fn landing_pad( &mut self, ty: &'ll Type, @@ -1819,7 +1738,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { // llvm.type.test intrinsic. The LowerTypeTests link-time optimization pass replaces // calls to this intrinsic with code to test type membership. let typeid = self.get_metadata_value(typeid_metadata); - let cond = self.call_intrinsic("llvm.type.test", &[llfn, typeid]); + let cond = self.call_intrinsic("llvm.type.test", &[], &[llfn, typeid]); let bb_pass = self.append_sibling_block("type_test.pass"); let bb_fail = self.append_sibling_block("type_test.fail"); self.cond_br(cond, bb_pass, bb_fail); @@ -1887,7 +1806,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { num_counters: &'ll Value, index: &'ll Value, ) { - self.call_intrinsic("llvm.instrprof.increment", &[fn_name, hash, num_counters, index]); + self.call_intrinsic("llvm.instrprof.increment", &[], &[fn_name, hash, num_counters, index]); } /// Emits a call to `llvm.instrprof.mcdc.parameters`. @@ -1906,7 +1825,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { hash: &'ll Value, bitmap_bits: &'ll Value, ) { - self.call_intrinsic("llvm.instrprof.mcdc.parameters", &[fn_name, hash, bitmap_bits]); + self.call_intrinsic("llvm.instrprof.mcdc.parameters", &[], &[fn_name, hash, bitmap_bits]); } #[instrument(level = "debug", skip(self))] @@ -1918,7 +1837,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { mcdc_temp: &'ll Value, ) { let args = &[fn_name, hash, bitmap_index, mcdc_temp]; - self.call_intrinsic("llvm.instrprof.mcdc.tvbitmap.update", args); + self.call_intrinsic("llvm.instrprof.mcdc.tvbitmap.update", &[], args); } #[instrument(level = "debug", skip(self))] diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 8d6e1d8941b..f36f3b2b16b 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -137,7 +137,8 @@ pub(crate) struct FullCx<'ll, 'tcx> { eh_catch_typeinfo: Cell>, pub rust_try_fn: Cell>, - intrinsics: RefCell>, + intrinsics: + RefCell), (&'ll Type, &'ll Value)>>, /// A counter that is used for generating local symbol names local_gen_sym_counter: Cell, @@ -842,17 +843,24 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } impl<'ll> CodegenCx<'ll, '_> { - pub(crate) fn get_intrinsic(&self, key: &str) -> (&'ll Type, &'ll Value) { - if let Some(v) = self.intrinsics.borrow().get(key).cloned() { - return v; + pub(crate) fn get_intrinsic( + &self, + base_name: &str, + type_params: &[&'ll Type], + ) -> (&'ll Type, &'ll Value) { + if let Some(v) = + self.intrinsics.borrow().get(&(base_name, SmallVec::from_slice(type_params))) + { + return *v; } - self.declare_intrinsic(key).unwrap_or_else(|| bug!("unknown intrinsic '{}'", key)) + self.declare_intrinsic(base_name, type_params) } fn insert_intrinsic( &self, - name: &'static str, + base_name: &'static str, + type_params: &[&'ll Type], args: Option<&[&'ll llvm::Type]>, ret: &'ll llvm::Type, ) -> (&'ll llvm::Type, &'ll llvm::Value) { @@ -861,372 +869,153 @@ impl<'ll> CodegenCx<'ll, '_> { } else { self.type_variadic_func(&[], ret) }; - let f = self.declare_cfn(name, llvm::UnnamedAddr::No, fn_ty); - self.intrinsics.borrow_mut().insert(name, (fn_ty, f)); + + let intrinsic = llvm::Intrinsic::lookup(base_name.as_bytes()) + .expect("Unknown LLVM intrinsic `{base_name}`"); + + let full_name = if intrinsic.is_overloaded() { + &intrinsic.overloaded_name(self.llmod, type_params) + } else { + base_name + }; + + let f = self.declare_cfn(full_name, llvm::UnnamedAddr::No, fn_ty); + self.intrinsics + .borrow_mut() + .insert((base_name, SmallVec::from_slice(type_params)), (fn_ty, f)); (fn_ty, f) } - fn declare_intrinsic(&self, key: &str) -> Option<(&'ll Type, &'ll Value)> { + fn declare_intrinsic( + &self, + base_name: &str, + type_params: &[&'ll Type], + ) -> (&'ll Type, &'ll Value) { + macro_rules! param { + ($index:literal) => { + type_params[$index] + }; + ($other:expr) => { + $other + }; + } macro_rules! ifn { - ($name:expr, fn() -> $ret:expr) => ( - if key == $name { - return Some(self.insert_intrinsic($name, Some(&[]), $ret)); - } - ); ($name:expr, fn(...) -> $ret:expr) => ( - if key == $name { - return Some(self.insert_intrinsic($name, None, $ret)); + if base_name == $name { + return self.insert_intrinsic($name, type_params, None, param!($ret)); } ); ($name:expr, fn($($arg:expr),*) -> $ret:expr) => ( - if key == $name { - return Some(self.insert_intrinsic($name, Some(&[$($arg),*]), $ret)); + if base_name == $name { + return self.insert_intrinsic($name, type_params, Some(&[$(param!($arg)),*]), param!($ret)); } ); } macro_rules! mk_struct { - ($($field_ty:expr),*) => (self.type_struct( &[$($field_ty),*], false)) + ($($field_ty:expr),*) => (self.type_struct( &[$(param!($field_ty)),*], false)) } + let same_width_vector = |index, element_ty| { + self.type_vector(element_ty, self.vector_length(type_params[index]) as u64) + }; + let ptr = self.type_ptr(); let void = self.type_void(); let i1 = self.type_i1(); - let t_i8 = self.type_i8(); - let t_i16 = self.type_i16(); let t_i32 = self.type_i32(); let t_i64 = self.type_i64(); - let t_i128 = self.type_i128(); let t_isize = self.type_isize(); - let t_f16 = self.type_f16(); - let t_f32 = self.type_f32(); - let t_f64 = self.type_f64(); - let t_f128 = self.type_f128(); let t_metadata = self.type_metadata(); let t_token = self.type_token(); ifn!("llvm.wasm.get.exception", fn(t_token) -> ptr); ifn!("llvm.wasm.get.ehselector", fn(t_token) -> t_i32); - ifn!("llvm.wasm.trunc.unsigned.i32.f32", fn(t_f32) -> t_i32); - ifn!("llvm.wasm.trunc.unsigned.i32.f64", fn(t_f64) -> t_i32); - ifn!("llvm.wasm.trunc.unsigned.i64.f32", fn(t_f32) -> t_i64); - ifn!("llvm.wasm.trunc.unsigned.i64.f64", fn(t_f64) -> t_i64); - ifn!("llvm.wasm.trunc.signed.i32.f32", fn(t_f32) -> t_i32); - ifn!("llvm.wasm.trunc.signed.i32.f64", fn(t_f64) -> t_i32); - ifn!("llvm.wasm.trunc.signed.i64.f32", fn(t_f32) -> t_i64); - ifn!("llvm.wasm.trunc.signed.i64.f64", fn(t_f64) -> t_i64); - - ifn!("llvm.fptosi.sat.i8.f32", fn(t_f32) -> t_i8); - ifn!("llvm.fptosi.sat.i16.f32", fn(t_f32) -> t_i16); - ifn!("llvm.fptosi.sat.i32.f32", fn(t_f32) -> t_i32); - ifn!("llvm.fptosi.sat.i64.f32", fn(t_f32) -> t_i64); - ifn!("llvm.fptosi.sat.i128.f32", fn(t_f32) -> t_i128); - ifn!("llvm.fptosi.sat.i8.f64", fn(t_f64) -> t_i8); - ifn!("llvm.fptosi.sat.i16.f64", fn(t_f64) -> t_i16); - ifn!("llvm.fptosi.sat.i32.f64", fn(t_f64) -> t_i32); - ifn!("llvm.fptosi.sat.i64.f64", fn(t_f64) -> t_i64); - ifn!("llvm.fptosi.sat.i128.f64", fn(t_f64) -> t_i128); - - ifn!("llvm.fptoui.sat.i8.f32", fn(t_f32) -> t_i8); - ifn!("llvm.fptoui.sat.i16.f32", fn(t_f32) -> t_i16); - ifn!("llvm.fptoui.sat.i32.f32", fn(t_f32) -> t_i32); - ifn!("llvm.fptoui.sat.i64.f32", fn(t_f32) -> t_i64); - ifn!("llvm.fptoui.sat.i128.f32", fn(t_f32) -> t_i128); - ifn!("llvm.fptoui.sat.i8.f64", fn(t_f64) -> t_i8); - ifn!("llvm.fptoui.sat.i16.f64", fn(t_f64) -> t_i16); - ifn!("llvm.fptoui.sat.i32.f64", fn(t_f64) -> t_i32); - ifn!("llvm.fptoui.sat.i64.f64", fn(t_f64) -> t_i64); - ifn!("llvm.fptoui.sat.i128.f64", fn(t_f64) -> t_i128); + ifn!("llvm.wasm.trunc.unsigned", fn(1) -> 0); + ifn!("llvm.wasm.trunc.signed", fn(1) -> 0); + ifn!("llvm.fptosi.sat", fn(1) -> 0); + ifn!("llvm.fptoui.sat", fn(1) -> 0); ifn!("llvm.trap", fn() -> void); ifn!("llvm.debugtrap", fn() -> void); ifn!("llvm.frameaddress", fn(t_i32) -> ptr); - ifn!("llvm.powi.f16.i32", fn(t_f16, t_i32) -> t_f16); - ifn!("llvm.powi.f32.i32", fn(t_f32, t_i32) -> t_f32); - ifn!("llvm.powi.f64.i32", fn(t_f64, t_i32) -> t_f64); - ifn!("llvm.powi.f128.i32", fn(t_f128, t_i32) -> t_f128); - - ifn!("llvm.pow.f16", fn(t_f16, t_f16) -> t_f16); - ifn!("llvm.pow.f32", fn(t_f32, t_f32) -> t_f32); - ifn!("llvm.pow.f64", fn(t_f64, t_f64) -> t_f64); - ifn!("llvm.pow.f128", fn(t_f128, t_f128) -> t_f128); - - ifn!("llvm.sqrt.f16", fn(t_f16) -> t_f16); - ifn!("llvm.sqrt.f32", fn(t_f32) -> t_f32); - ifn!("llvm.sqrt.f64", fn(t_f64) -> t_f64); - ifn!("llvm.sqrt.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.sin.f16", fn(t_f16) -> t_f16); - ifn!("llvm.sin.f32", fn(t_f32) -> t_f32); - ifn!("llvm.sin.f64", fn(t_f64) -> t_f64); - ifn!("llvm.sin.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.cos.f16", fn(t_f16) -> t_f16); - ifn!("llvm.cos.f32", fn(t_f32) -> t_f32); - ifn!("llvm.cos.f64", fn(t_f64) -> t_f64); - ifn!("llvm.cos.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.exp.f16", fn(t_f16) -> t_f16); - ifn!("llvm.exp.f32", fn(t_f32) -> t_f32); - ifn!("llvm.exp.f64", fn(t_f64) -> t_f64); - ifn!("llvm.exp.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.exp2.f16", fn(t_f16) -> t_f16); - ifn!("llvm.exp2.f32", fn(t_f32) -> t_f32); - ifn!("llvm.exp2.f64", fn(t_f64) -> t_f64); - ifn!("llvm.exp2.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.log.f16", fn(t_f16) -> t_f16); - ifn!("llvm.log.f32", fn(t_f32) -> t_f32); - ifn!("llvm.log.f64", fn(t_f64) -> t_f64); - ifn!("llvm.log.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.log10.f16", fn(t_f16) -> t_f16); - ifn!("llvm.log10.f32", fn(t_f32) -> t_f32); - ifn!("llvm.log10.f64", fn(t_f64) -> t_f64); - ifn!("llvm.log10.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.log2.f16", fn(t_f16) -> t_f16); - ifn!("llvm.log2.f32", fn(t_f32) -> t_f32); - ifn!("llvm.log2.f64", fn(t_f64) -> t_f64); - ifn!("llvm.log2.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.fma.f16", fn(t_f16, t_f16, t_f16) -> t_f16); - ifn!("llvm.fma.f32", fn(t_f32, t_f32, t_f32) -> t_f32); - ifn!("llvm.fma.f64", fn(t_f64, t_f64, t_f64) -> t_f64); - ifn!("llvm.fma.f128", fn(t_f128, t_f128, t_f128) -> t_f128); - - ifn!("llvm.fmuladd.f16", fn(t_f16, t_f16, t_f16) -> t_f16); - ifn!("llvm.fmuladd.f32", fn(t_f32, t_f32, t_f32) -> t_f32); - ifn!("llvm.fmuladd.f64", fn(t_f64, t_f64, t_f64) -> t_f64); - ifn!("llvm.fmuladd.f128", fn(t_f128, t_f128, t_f128) -> t_f128); - - ifn!("llvm.fabs.f16", fn(t_f16) -> t_f16); - ifn!("llvm.fabs.f32", fn(t_f32) -> t_f32); - ifn!("llvm.fabs.f64", fn(t_f64) -> t_f64); - ifn!("llvm.fabs.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.minnum.f16", fn(t_f16, t_f16) -> t_f16); - ifn!("llvm.minnum.f32", fn(t_f32, t_f32) -> t_f32); - ifn!("llvm.minnum.f64", fn(t_f64, t_f64) -> t_f64); - ifn!("llvm.minnum.f128", fn(t_f128, t_f128) -> t_f128); - - ifn!("llvm.minimum.f16", fn(t_f16, t_f16) -> t_f16); - ifn!("llvm.minimum.f32", fn(t_f32, t_f32) -> t_f32); - ifn!("llvm.minimum.f64", fn(t_f64, t_f64) -> t_f64); - // There are issues on x86_64 and aarch64 with the f128 variant. - // - https://github.com/llvm/llvm-project/issues/139380 - // - https://github.com/llvm/llvm-project/issues/139381 - // ifn!("llvm.minimum.f128", fn(t_f128, t_f128) -> t_f128); - - ifn!("llvm.maxnum.f16", fn(t_f16, t_f16) -> t_f16); - ifn!("llvm.maxnum.f32", fn(t_f32, t_f32) -> t_f32); - ifn!("llvm.maxnum.f64", fn(t_f64, t_f64) -> t_f64); - ifn!("llvm.maxnum.f128", fn(t_f128, t_f128) -> t_f128); - - ifn!("llvm.maximum.f16", fn(t_f16, t_f16) -> t_f16); - ifn!("llvm.maximum.f32", fn(t_f32, t_f32) -> t_f32); - ifn!("llvm.maximum.f64", fn(t_f64, t_f64) -> t_f64); - // There are issues on x86_64 and aarch64 with the f128 variant. - // - https://github.com/llvm/llvm-project/issues/139380 - // - https://github.com/llvm/llvm-project/issues/139381 - // ifn!("llvm.maximum.f128", fn(t_f128, t_f128) -> t_f128); - - ifn!("llvm.floor.f16", fn(t_f16) -> t_f16); - ifn!("llvm.floor.f32", fn(t_f32) -> t_f32); - ifn!("llvm.floor.f64", fn(t_f64) -> t_f64); - ifn!("llvm.floor.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.ceil.f16", fn(t_f16) -> t_f16); - ifn!("llvm.ceil.f32", fn(t_f32) -> t_f32); - ifn!("llvm.ceil.f64", fn(t_f64) -> t_f64); - ifn!("llvm.ceil.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.trunc.f16", fn(t_f16) -> t_f16); - ifn!("llvm.trunc.f32", fn(t_f32) -> t_f32); - ifn!("llvm.trunc.f64", fn(t_f64) -> t_f64); - ifn!("llvm.trunc.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.copysign.f16", fn(t_f16, t_f16) -> t_f16); - ifn!("llvm.copysign.f32", fn(t_f32, t_f32) -> t_f32); - ifn!("llvm.copysign.f64", fn(t_f64, t_f64) -> t_f64); - ifn!("llvm.copysign.f128", fn(t_f128, t_f128) -> t_f128); - - ifn!("llvm.round.f16", fn(t_f16) -> t_f16); - ifn!("llvm.round.f32", fn(t_f32) -> t_f32); - ifn!("llvm.round.f64", fn(t_f64) -> t_f64); - ifn!("llvm.round.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.roundeven.f16", fn(t_f16) -> t_f16); - ifn!("llvm.roundeven.f32", fn(t_f32) -> t_f32); - ifn!("llvm.roundeven.f64", fn(t_f64) -> t_f64); - ifn!("llvm.roundeven.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.rint.f16", fn(t_f16) -> t_f16); - ifn!("llvm.rint.f32", fn(t_f32) -> t_f32); - ifn!("llvm.rint.f64", fn(t_f64) -> t_f64); - ifn!("llvm.rint.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.nearbyint.f16", fn(t_f16) -> t_f16); - ifn!("llvm.nearbyint.f32", fn(t_f32) -> t_f32); - ifn!("llvm.nearbyint.f64", fn(t_f64) -> t_f64); - ifn!("llvm.nearbyint.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.ctpop.i8", fn(t_i8) -> t_i8); - ifn!("llvm.ctpop.i16", fn(t_i16) -> t_i16); - ifn!("llvm.ctpop.i32", fn(t_i32) -> t_i32); - ifn!("llvm.ctpop.i64", fn(t_i64) -> t_i64); - ifn!("llvm.ctpop.i128", fn(t_i128) -> t_i128); - - ifn!("llvm.ctlz.i8", fn(t_i8, i1) -> t_i8); - ifn!("llvm.ctlz.i16", fn(t_i16, i1) -> t_i16); - ifn!("llvm.ctlz.i32", fn(t_i32, i1) -> t_i32); - ifn!("llvm.ctlz.i64", fn(t_i64, i1) -> t_i64); - ifn!("llvm.ctlz.i128", fn(t_i128, i1) -> t_i128); - - ifn!("llvm.cttz.i8", fn(t_i8, i1) -> t_i8); - ifn!("llvm.cttz.i16", fn(t_i16, i1) -> t_i16); - ifn!("llvm.cttz.i32", fn(t_i32, i1) -> t_i32); - ifn!("llvm.cttz.i64", fn(t_i64, i1) -> t_i64); - ifn!("llvm.cttz.i128", fn(t_i128, i1) -> t_i128); - - ifn!("llvm.bswap.i16", fn(t_i16) -> t_i16); - ifn!("llvm.bswap.i32", fn(t_i32) -> t_i32); - ifn!("llvm.bswap.i64", fn(t_i64) -> t_i64); - ifn!("llvm.bswap.i128", fn(t_i128) -> t_i128); - - ifn!("llvm.bitreverse.i8", fn(t_i8) -> t_i8); - ifn!("llvm.bitreverse.i16", fn(t_i16) -> t_i16); - ifn!("llvm.bitreverse.i32", fn(t_i32) -> t_i32); - ifn!("llvm.bitreverse.i64", fn(t_i64) -> t_i64); - ifn!("llvm.bitreverse.i128", fn(t_i128) -> t_i128); - - ifn!("llvm.fshl.i8", fn(t_i8, t_i8, t_i8) -> t_i8); - ifn!("llvm.fshl.i16", fn(t_i16, t_i16, t_i16) -> t_i16); - ifn!("llvm.fshl.i32", fn(t_i32, t_i32, t_i32) -> t_i32); - ifn!("llvm.fshl.i64", fn(t_i64, t_i64, t_i64) -> t_i64); - ifn!("llvm.fshl.i128", fn(t_i128, t_i128, t_i128) -> t_i128); - - ifn!("llvm.fshr.i8", fn(t_i8, t_i8, t_i8) -> t_i8); - ifn!("llvm.fshr.i16", fn(t_i16, t_i16, t_i16) -> t_i16); - ifn!("llvm.fshr.i32", fn(t_i32, t_i32, t_i32) -> t_i32); - ifn!("llvm.fshr.i64", fn(t_i64, t_i64, t_i64) -> t_i64); - ifn!("llvm.fshr.i128", fn(t_i128, t_i128, t_i128) -> t_i128); - - ifn!("llvm.sadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1}); - ifn!("llvm.sadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1}); - ifn!("llvm.sadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1}); - ifn!("llvm.sadd.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1}); - ifn!("llvm.sadd.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1}); - - ifn!("llvm.uadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1}); - ifn!("llvm.uadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1}); - ifn!("llvm.uadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1}); - ifn!("llvm.uadd.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1}); - ifn!("llvm.uadd.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1}); - - ifn!("llvm.ssub.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1}); - ifn!("llvm.ssub.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1}); - ifn!("llvm.ssub.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1}); - ifn!("llvm.ssub.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1}); - ifn!("llvm.ssub.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1}); - - ifn!("llvm.usub.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1}); - ifn!("llvm.usub.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1}); - ifn!("llvm.usub.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1}); - ifn!("llvm.usub.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1}); - ifn!("llvm.usub.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1}); - - ifn!("llvm.smul.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1}); - ifn!("llvm.smul.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1}); - ifn!("llvm.smul.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1}); - ifn!("llvm.smul.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1}); - ifn!("llvm.smul.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1}); - - ifn!("llvm.umul.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1}); - ifn!("llvm.umul.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1}); - ifn!("llvm.umul.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1}); - ifn!("llvm.umul.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1}); - ifn!("llvm.umul.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1}); - - ifn!("llvm.sadd.sat.i8", fn(t_i8, t_i8) -> t_i8); - ifn!("llvm.sadd.sat.i16", fn(t_i16, t_i16) -> t_i16); - ifn!("llvm.sadd.sat.i32", fn(t_i32, t_i32) -> t_i32); - ifn!("llvm.sadd.sat.i64", fn(t_i64, t_i64) -> t_i64); - ifn!("llvm.sadd.sat.i128", fn(t_i128, t_i128) -> t_i128); - - ifn!("llvm.uadd.sat.i8", fn(t_i8, t_i8) -> t_i8); - ifn!("llvm.uadd.sat.i16", fn(t_i16, t_i16) -> t_i16); - ifn!("llvm.uadd.sat.i32", fn(t_i32, t_i32) -> t_i32); - ifn!("llvm.uadd.sat.i64", fn(t_i64, t_i64) -> t_i64); - ifn!("llvm.uadd.sat.i128", fn(t_i128, t_i128) -> t_i128); - - ifn!("llvm.ssub.sat.i8", fn(t_i8, t_i8) -> t_i8); - ifn!("llvm.ssub.sat.i16", fn(t_i16, t_i16) -> t_i16); - ifn!("llvm.ssub.sat.i32", fn(t_i32, t_i32) -> t_i32); - ifn!("llvm.ssub.sat.i64", fn(t_i64, t_i64) -> t_i64); - ifn!("llvm.ssub.sat.i128", fn(t_i128, t_i128) -> t_i128); - - ifn!("llvm.usub.sat.i8", fn(t_i8, t_i8) -> t_i8); - ifn!("llvm.usub.sat.i16", fn(t_i16, t_i16) -> t_i16); - ifn!("llvm.usub.sat.i32", fn(t_i32, t_i32) -> t_i32); - ifn!("llvm.usub.sat.i64", fn(t_i64, t_i64) -> t_i64); - ifn!("llvm.usub.sat.i128", fn(t_i128, t_i128) -> t_i128); - - ifn!("llvm.scmp.i8.i8", fn(t_i8, t_i8) -> t_i8); - ifn!("llvm.scmp.i8.i16", fn(t_i16, t_i16) -> t_i8); - ifn!("llvm.scmp.i8.i32", fn(t_i32, t_i32) -> t_i8); - ifn!("llvm.scmp.i8.i64", fn(t_i64, t_i64) -> t_i8); - ifn!("llvm.scmp.i8.i128", fn(t_i128, t_i128) -> t_i8); - - ifn!("llvm.ucmp.i8.i8", fn(t_i8, t_i8) -> t_i8); - ifn!("llvm.ucmp.i8.i16", fn(t_i16, t_i16) -> t_i8); - ifn!("llvm.ucmp.i8.i32", fn(t_i32, t_i32) -> t_i8); - ifn!("llvm.ucmp.i8.i64", fn(t_i64, t_i64) -> t_i8); - ifn!("llvm.ucmp.i8.i128", fn(t_i128, t_i128) -> t_i8); - - ifn!("llvm.lifetime.start.p0i8", fn(t_i64, ptr) -> void); - ifn!("llvm.lifetime.end.p0i8", fn(t_i64, ptr) -> void); - - // FIXME: This is an infinitesimally small portion of the types you can - // pass to this intrinsic, if we can ever lazily register intrinsics we - // should register these when they're used, that way any type can be - // passed. - ifn!("llvm.is.constant.i1", fn(i1) -> i1); - ifn!("llvm.is.constant.i8", fn(t_i8) -> i1); - ifn!("llvm.is.constant.i16", fn(t_i16) -> i1); - ifn!("llvm.is.constant.i32", fn(t_i32) -> i1); - ifn!("llvm.is.constant.i64", fn(t_i64) -> i1); - ifn!("llvm.is.constant.i128", fn(t_i128) -> i1); - ifn!("llvm.is.constant.isize", fn(t_isize) -> i1); - ifn!("llvm.is.constant.f16", fn(t_f16) -> i1); - ifn!("llvm.is.constant.f32", fn(t_f32) -> i1); - ifn!("llvm.is.constant.f64", fn(t_f64) -> i1); - ifn!("llvm.is.constant.f128", fn(t_f128) -> i1); - ifn!("llvm.is.constant.ptr", fn(ptr) -> i1); - - ifn!("llvm.expect.i1", fn(i1, i1) -> i1); - ifn!("llvm.eh.typeid.for", fn(ptr) -> t_i32); + ifn!("llvm.powi", fn(0, 1) -> 0); + ifn!("llvm.pow", fn(0, 0) -> 0); + ifn!("llvm.sqrt", fn(0) -> 0); + ifn!("llvm.sin", fn(0) -> 0); + ifn!("llvm.cos", fn(0) -> 0); + ifn!("llvm.exp", fn(0) -> 0); + ifn!("llvm.exp2", fn(0) -> 0); + ifn!("llvm.log", fn(0) -> 0); + ifn!("llvm.log10", fn(0) -> 0); + ifn!("llvm.log2", fn(0) -> 0); + ifn!("llvm.fma", fn(0, 0, 0) -> 0); + ifn!("llvm.fmuladd", fn(0, 0, 0) -> 0); + ifn!("llvm.fabs", fn(0) -> 0); + ifn!("llvm.minnum", fn(0, 0) -> 0); + ifn!("llvm.minimum", fn(0, 0) -> 0); + ifn!("llvm.maxnum", fn(0, 0) -> 0); + ifn!("llvm.maximum", fn(0, 0) -> 0); + ifn!("llvm.floor", fn(0) -> 0); + ifn!("llvm.ceil", fn(0) -> 0); + ifn!("llvm.trunc", fn(0) -> 0); + ifn!("llvm.copysign", fn(0, 0) -> 0); + ifn!("llvm.round", fn(0) -> 0); + ifn!("llvm.rint", fn(0) -> 0); + ifn!("llvm.nearbyint", fn(0) -> 0); + + ifn!("llvm.ctpop", fn(0) -> 0); + ifn!("llvm.ctlz", fn(0, i1) -> 0); + ifn!("llvm.cttz", fn(0, i1) -> 0); + ifn!("llvm.bswap", fn(0) -> 0); + ifn!("llvm.bitreverse", fn(0) -> 0); + ifn!("llvm.fshl", fn(0, 0, 0) -> 0); + ifn!("llvm.fshr", fn(0, 0, 0) -> 0); + + ifn!("llvm.sadd.with.overflow", fn(0, 0) -> mk_struct! {0, i1}); + ifn!("llvm.uadd.with.overflow", fn(0, 0) -> mk_struct! {0, i1}); + ifn!("llvm.ssub.with.overflow", fn(0, 0) -> mk_struct! {0, i1}); + ifn!("llvm.usub.with.overflow", fn(0, 0) -> mk_struct! {0, i1}); + ifn!("llvm.smul.with.overflow", fn(0, 0) -> mk_struct! {0, i1}); + ifn!("llvm.umul.with.overflow", fn(0, 0) -> mk_struct! {0, i1}); + + ifn!("llvm.sadd.sat", fn(0, 0) -> 0); + ifn!("llvm.uadd.sat", fn(0, 0) -> 0); + ifn!("llvm.ssub.sat", fn(0, 0) -> 0); + ifn!("llvm.usub.sat", fn(0, 0) -> 0); + + ifn!("llvm.scmp", fn(1, 1) -> 0); + ifn!("llvm.ucmp", fn(1, 1) -> 0); + + ifn!("llvm.lifetime.start", fn(t_i64, 0) -> void); + ifn!("llvm.lifetime.end", fn(t_i64, 0) -> void); + + ifn!("llvm.is.constant", fn(0) -> i1); + ifn!("llvm.expect", fn(0, 0) -> 0); + + ifn!("llvm.eh.typeid.for", fn(0) -> t_i32); ifn!("llvm.localescape", fn(...) -> void); ifn!("llvm.localrecover", fn(ptr, ptr, t_i32) -> ptr); - ifn!("llvm.x86.seh.recoverfp", fn(ptr, ptr) -> ptr); ifn!("llvm.assume", fn(i1) -> void); - ifn!("llvm.prefetch", fn(ptr, t_i32, t_i32, t_i32) -> void); + ifn!("llvm.prefetch", fn(0, t_i32, t_i32, t_i32) -> void); // This isn't an "LLVM intrinsic", but LLVM's optimization passes // recognize it like one (including turning it into `bcmp` sometimes) // and we use it to implement intrinsics like `raw_eq` and `compare_bytes` - match self.sess().target.arch.as_ref() { - "avr" | "msp430" => ifn!("memcmp", fn(ptr, ptr, t_isize) -> t_i16), - _ => ifn!("memcmp", fn(ptr, ptr, t_isize) -> t_i32), + if base_name == "memcmp" { + let fn_ty = self.type_func(&[ptr, ptr, t_isize], self.type_int()); + let f = self.declare_cfn("memcmp", llvm::UnnamedAddr::No, fn_ty); + self.intrinsics.borrow_mut().insert(("memcmp", SmallVec::new()), (fn_ty, f)); + + return (fn_ty, f); } // variadic intrinsics - ifn!("llvm.va_start", fn(ptr) -> void); - ifn!("llvm.va_end", fn(ptr) -> void); - ifn!("llvm.va_copy", fn(ptr, ptr) -> void); + ifn!("llvm.va_start", fn(0) -> void); + ifn!("llvm.va_end", fn(0) -> void); + ifn!("llvm.va_copy", fn(0, 0) -> void); if self.sess().instrument_coverage() { ifn!("llvm.instrprof.increment", fn(ptr, t_i64, t_i32, t_i32) -> void); @@ -1238,14 +1027,19 @@ impl<'ll> CodegenCx<'ll, '_> { ifn!("llvm.type.checked.load", fn(ptr, t_i32, t_metadata) -> mk_struct! {ptr, i1}); if self.sess().opts.debuginfo != DebugInfo::None { - ifn!("llvm.dbg.declare", fn(t_metadata, t_metadata) -> void); - ifn!("llvm.dbg.value", fn(t_metadata, t_i64, t_metadata) -> void); + ifn!("llvm.dbg.declare", fn(t_metadata, t_metadata, t_metadata) -> void); + ifn!("llvm.dbg.value", fn(t_metadata, t_metadata, t_metadata) -> void); } - ifn!("llvm.ptrmask", fn(ptr, t_isize) -> ptr); + ifn!("llvm.ptrmask", fn(0, 1) -> 0); ifn!("llvm.threadlocal.address", fn(ptr) -> ptr); - None + ifn!("llvm.masked.load", fn(1, t_i32, same_width_vector(0, i1), 0) -> 0); + ifn!("llvm.masked.store", fn(0, 1, t_i32, same_width_vector(0, i1)) -> void); + ifn!("llvm.masked.gather", fn(1, t_i32, same_width_vector(0, i1), 0) -> 0); + ifn!("llvm.masked.scatter", fn(0, 1, t_i32, same_width_vector(0, i1)) -> void); + + bug!("Unknown intrinsic: `{base_name}`") } pub(crate) fn eh_catch_typeinfo(&self) -> &'ll Value { diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 10697b9a71f..497c31706ec 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::{self, GenericArgsRef, Ty}; use rustc_middle::{bug, span_bug}; use rustc_span::{Span, Symbol, sym}; use rustc_symbol_mangling::mangle_internal_symbol; -use rustc_target::spec::{HasTargetSpec, PanicStrategy}; +use rustc_target::spec::PanicStrategy; use tracing::debug; use crate::abi::FnAbiLlvmExt; @@ -27,137 +27,142 @@ use crate::type_of::LayoutLlvmExt; use crate::va_arg::emit_va_arg; use crate::value::Value; -fn get_simple_intrinsic<'ll>( - cx: &CodegenCx<'ll, '_>, +fn call_simple_intrinsic<'ll, 'tcx>( + bx: &mut Builder<'_, 'll, 'tcx>, name: Symbol, -) -> Option<(&'ll Type, &'ll Value)> { - let llvm_name = match name { - sym::sqrtf16 => "llvm.sqrt.f16", - sym::sqrtf32 => "llvm.sqrt.f32", - sym::sqrtf64 => "llvm.sqrt.f64", - sym::sqrtf128 => "llvm.sqrt.f128", - - sym::powif16 => "llvm.powi.f16.i32", - sym::powif32 => "llvm.powi.f32.i32", - sym::powif64 => "llvm.powi.f64.i32", - sym::powif128 => "llvm.powi.f128.i32", - - sym::sinf16 => "llvm.sin.f16", - sym::sinf32 => "llvm.sin.f32", - sym::sinf64 => "llvm.sin.f64", - sym::sinf128 => "llvm.sin.f128", - - sym::cosf16 => "llvm.cos.f16", - sym::cosf32 => "llvm.cos.f32", - sym::cosf64 => "llvm.cos.f64", - sym::cosf128 => "llvm.cos.f128", - - sym::powf16 => "llvm.pow.f16", - sym::powf32 => "llvm.pow.f32", - sym::powf64 => "llvm.pow.f64", - sym::powf128 => "llvm.pow.f128", - - sym::expf16 => "llvm.exp.f16", - sym::expf32 => "llvm.exp.f32", - sym::expf64 => "llvm.exp.f64", - sym::expf128 => "llvm.exp.f128", - - sym::exp2f16 => "llvm.exp2.f16", - sym::exp2f32 => "llvm.exp2.f32", - sym::exp2f64 => "llvm.exp2.f64", - sym::exp2f128 => "llvm.exp2.f128", - - sym::logf16 => "llvm.log.f16", - sym::logf32 => "llvm.log.f32", - sym::logf64 => "llvm.log.f64", - sym::logf128 => "llvm.log.f128", - - sym::log10f16 => "llvm.log10.f16", - sym::log10f32 => "llvm.log10.f32", - sym::log10f64 => "llvm.log10.f64", - sym::log10f128 => "llvm.log10.f128", - - sym::log2f16 => "llvm.log2.f16", - sym::log2f32 => "llvm.log2.f32", - sym::log2f64 => "llvm.log2.f64", - sym::log2f128 => "llvm.log2.f128", - - sym::fmaf16 => "llvm.fma.f16", - sym::fmaf32 => "llvm.fma.f32", - sym::fmaf64 => "llvm.fma.f64", - sym::fmaf128 => "llvm.fma.f128", - - sym::fmuladdf16 => "llvm.fmuladd.f16", - sym::fmuladdf32 => "llvm.fmuladd.f32", - sym::fmuladdf64 => "llvm.fmuladd.f64", - sym::fmuladdf128 => "llvm.fmuladd.f128", - - sym::fabsf16 => "llvm.fabs.f16", - sym::fabsf32 => "llvm.fabs.f32", - sym::fabsf64 => "llvm.fabs.f64", - sym::fabsf128 => "llvm.fabs.f128", - - sym::minnumf16 => "llvm.minnum.f16", - sym::minnumf32 => "llvm.minnum.f32", - sym::minnumf64 => "llvm.minnum.f64", - sym::minnumf128 => "llvm.minnum.f128", - - sym::minimumf16 => "llvm.minimum.f16", - sym::minimumf32 => "llvm.minimum.f32", - sym::minimumf64 => "llvm.minimum.f64", + args: &[OperandRef<'tcx, &'ll Value>], +) -> Option<&'ll Value> { + let (base_name, type_params): (&'static str, &[&'ll Type]) = match name { + sym::sqrtf16 => ("llvm.sqrt", &[bx.type_f16()]), + sym::sqrtf32 => ("llvm.sqrt", &[bx.type_f32()]), + sym::sqrtf64 => ("llvm.sqrt", &[bx.type_f64()]), + sym::sqrtf128 => ("llvm.sqrt", &[bx.type_f128()]), + + sym::powif16 => ("llvm.powi", &[bx.type_f16(), bx.type_i32()]), + sym::powif32 => ("llvm.powi", &[bx.type_f32(), bx.type_i32()]), + sym::powif64 => ("llvm.powi", &[bx.type_f64(), bx.type_i32()]), + sym::powif128 => ("llvm.powi", &[bx.type_f128(), bx.type_i32()]), + + sym::sinf16 => ("llvm.sin", &[bx.type_f16()]), + sym::sinf32 => ("llvm.sin", &[bx.type_f32()]), + sym::sinf64 => ("llvm.sin", &[bx.type_f64()]), + sym::sinf128 => ("llvm.sin", &[bx.type_f128()]), + + sym::cosf16 => ("llvm.cos", &[bx.type_f16()]), + sym::cosf32 => ("llvm.cos", &[bx.type_f32()]), + sym::cosf64 => ("llvm.cos", &[bx.type_f64()]), + sym::cosf128 => ("llvm.cos", &[bx.type_f128()]), + + sym::powf16 => ("llvm.pow", &[bx.type_f16()]), + sym::powf32 => ("llvm.pow", &[bx.type_f32()]), + sym::powf64 => ("llvm.pow", &[bx.type_f64()]), + sym::powf128 => ("llvm.pow", &[bx.type_f128()]), + + sym::expf16 => ("llvm.exp", &[bx.type_f16()]), + sym::expf32 => ("llvm.exp", &[bx.type_f32()]), + sym::expf64 => ("llvm.exp", &[bx.type_f64()]), + sym::expf128 => ("llvm.exp", &[bx.type_f128()]), + + sym::exp2f16 => ("llvm.exp2", &[bx.type_f16()]), + sym::exp2f32 => ("llvm.exp2", &[bx.type_f32()]), + sym::exp2f64 => ("llvm.exp2", &[bx.type_f64()]), + sym::exp2f128 => ("llvm.exp2", &[bx.type_f128()]), + + sym::logf16 => ("llvm.log", &[bx.type_f16()]), + sym::logf32 => ("llvm.log", &[bx.type_f32()]), + sym::logf64 => ("llvm.log", &[bx.type_f64()]), + sym::logf128 => ("llvm.log", &[bx.type_f128()]), + + sym::log10f16 => ("llvm.log10", &[bx.type_f16()]), + sym::log10f32 => ("llvm.log10", &[bx.type_f32()]), + sym::log10f64 => ("llvm.log10", &[bx.type_f64()]), + sym::log10f128 => ("llvm.log10", &[bx.type_f128()]), + + sym::log2f16 => ("llvm.log2", &[bx.type_f16()]), + sym::log2f32 => ("llvm.log2", &[bx.type_f32()]), + sym::log2f64 => ("llvm.log2", &[bx.type_f64()]), + sym::log2f128 => ("llvm.log2", &[bx.type_f128()]), + + sym::fmaf16 => ("llvm.fma", &[bx.type_f16()]), + sym::fmaf32 => ("llvm.fma", &[bx.type_f32()]), + sym::fmaf64 => ("llvm.fma", &[bx.type_f64()]), + sym::fmaf128 => ("llvm.fma", &[bx.type_f128()]), + + sym::fmuladdf16 => ("llvm.fmuladd", &[bx.type_f16()]), + sym::fmuladdf32 => ("llvm.fmuladd", &[bx.type_f32()]), + sym::fmuladdf64 => ("llvm.fmuladd", &[bx.type_f64()]), + sym::fmuladdf128 => ("llvm.fmuladd", &[bx.type_f128()]), + + sym::fabsf16 => ("llvm.fabs", &[bx.type_f16()]), + sym::fabsf32 => ("llvm.fabs", &[bx.type_f32()]), + sym::fabsf64 => ("llvm.fabs", &[bx.type_f64()]), + sym::fabsf128 => ("llvm.fabs", &[bx.type_f128()]), + + sym::minnumf16 => ("llvm.minnum", &[bx.type_f16()]), + sym::minnumf32 => ("llvm.minnum", &[bx.type_f32()]), + sym::minnumf64 => ("llvm.minnum", &[bx.type_f64()]), + sym::minnumf128 => ("llvm.minnum", &[bx.type_f128()]), + + sym::minimumf16 => ("llvm.minimum", &[bx.type_f16()]), + sym::minimumf32 => ("llvm.minimum", &[bx.type_f32()]), + sym::minimumf64 => ("llvm.minimum", &[bx.type_f64()]), // There are issues on x86_64 and aarch64 with the f128 variant, // let's instead use the instrinsic fallback body. - // sym::minimumf128 => "llvm.minimum.f128", - sym::maxnumf16 => "llvm.maxnum.f16", - sym::maxnumf32 => "llvm.maxnum.f32", - sym::maxnumf64 => "llvm.maxnum.f64", - sym::maxnumf128 => "llvm.maxnum.f128", - - sym::maximumf16 => "llvm.maximum.f16", - sym::maximumf32 => "llvm.maximum.f32", - sym::maximumf64 => "llvm.maximum.f64", + // sym::minimumf128 => ("llvm.minimum", &[cx.type_f128()]), + sym::maxnumf16 => ("llvm.maxnum", &[bx.type_f16()]), + sym::maxnumf32 => ("llvm.maxnum", &[bx.type_f32()]), + sym::maxnumf64 => ("llvm.maxnum", &[bx.type_f64()]), + sym::maxnumf128 => ("llvm.maxnum", &[bx.type_f128()]), + + sym::maximumf16 => ("llvm.maximum", &[bx.type_f16()]), + sym::maximumf32 => ("llvm.maximum", &[bx.type_f32()]), + sym::maximumf64 => ("llvm.maximum", &[bx.type_f64()]), // There are issues on x86_64 and aarch64 with the f128 variant, // let's instead use the instrinsic fallback body. - // sym::maximumf128 => "llvm.maximum.f128", - sym::copysignf16 => "llvm.copysign.f16", - sym::copysignf32 => "llvm.copysign.f32", - sym::copysignf64 => "llvm.copysign.f64", - sym::copysignf128 => "llvm.copysign.f128", - - sym::floorf16 => "llvm.floor.f16", - sym::floorf32 => "llvm.floor.f32", - sym::floorf64 => "llvm.floor.f64", - sym::floorf128 => "llvm.floor.f128", - - sym::ceilf16 => "llvm.ceil.f16", - sym::ceilf32 => "llvm.ceil.f32", - sym::ceilf64 => "llvm.ceil.f64", - sym::ceilf128 => "llvm.ceil.f128", - - sym::truncf16 => "llvm.trunc.f16", - sym::truncf32 => "llvm.trunc.f32", - sym::truncf64 => "llvm.trunc.f64", - sym::truncf128 => "llvm.trunc.f128", + // sym::maximumf128 => ("llvm.maximum", &[cx.type_f128()]), + sym::copysignf16 => ("llvm.copysign", &[bx.type_f16()]), + sym::copysignf32 => ("llvm.copysign", &[bx.type_f32()]), + sym::copysignf64 => ("llvm.copysign", &[bx.type_f64()]), + sym::copysignf128 => ("llvm.copysign", &[bx.type_f128()]), + + sym::floorf16 => ("llvm.floor", &[bx.type_f16()]), + sym::floorf32 => ("llvm.floor", &[bx.type_f32()]), + sym::floorf64 => ("llvm.floor", &[bx.type_f64()]), + sym::floorf128 => ("llvm.floor", &[bx.type_f128()]), + + sym::ceilf16 => ("llvm.ceil", &[bx.type_f16()]), + sym::ceilf32 => ("llvm.ceil", &[bx.type_f32()]), + sym::ceilf64 => ("llvm.ceil", &[bx.type_f64()]), + sym::ceilf128 => ("llvm.ceil", &[bx.type_f128()]), + + sym::truncf16 => ("llvm.trunc", &[bx.type_f16()]), + sym::truncf32 => ("llvm.trunc", &[bx.type_f32()]), + sym::truncf64 => ("llvm.trunc", &[bx.type_f64()]), + sym::truncf128 => ("llvm.trunc", &[bx.type_f128()]), // We could use any of `rint`, `nearbyint`, or `roundeven` // for this -- they are all identical in semantics when // assuming the default FP environment. // `rint` is what we used for $forever. - sym::round_ties_even_f16 => "llvm.rint.f16", - sym::round_ties_even_f32 => "llvm.rint.f32", - sym::round_ties_even_f64 => "llvm.rint.f64", - sym::round_ties_even_f128 => "llvm.rint.f128", + sym::round_ties_even_f16 => ("llvm.rint", &[bx.type_f16()]), + sym::round_ties_even_f32 => ("llvm.rint", &[bx.type_f32()]), + sym::round_ties_even_f64 => ("llvm.rint", &[bx.type_f64()]), + sym::round_ties_even_f128 => ("llvm.rint", &[bx.type_f128()]), - sym::roundf16 => "llvm.round.f16", - sym::roundf32 => "llvm.round.f32", - sym::roundf64 => "llvm.round.f64", - sym::roundf128 => "llvm.round.f128", + sym::roundf16 => ("llvm.round", &[bx.type_f16()]), + sym::roundf32 => ("llvm.round", &[bx.type_f32()]), + sym::roundf64 => ("llvm.round", &[bx.type_f64()]), + sym::roundf128 => ("llvm.round", &[bx.type_f128()]), - sym::ptr_mask => "llvm.ptrmask", + sym::ptr_mask => ("llvm.ptrmask", &[bx.type_ptr(), bx.type_isize()]), _ => return None, }; - Some(cx.get_intrinsic(llvm_name)) + Some(bx.call_intrinsic( + base_name, + type_params, + &args.iter().map(|arg| arg.immediate()).collect::>(), + )) } impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { @@ -173,36 +178,16 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { let name = tcx.item_name(instance.def_id()); let fn_args = instance.args; - let simple = get_simple_intrinsic(self, name); + let simple = call_simple_intrinsic(self, name, args); let llval = match name { - _ if simple.is_some() => { - let (simple_ty, simple_fn) = simple.unwrap(); - self.call( - simple_ty, - None, - None, - simple_fn, - &args.iter().map(|arg| arg.immediate()).collect::>(), - None, - Some(instance), - ) - } + _ if simple.is_some() => simple.unwrap(), sym::is_val_statically_known => { - let intrinsic_type = args[0].layout.immediate_llvm_type(self.cx); - let kind = self.type_kind(intrinsic_type); - let intrinsic_name = match kind { - TypeKind::Pointer | TypeKind::Integer => { - Some(format!("llvm.is.constant.{intrinsic_type:?}")) - } - // LLVM float types' intrinsic names differ from their type names. - TypeKind::Half => Some(format!("llvm.is.constant.f16")), - TypeKind::Float => Some(format!("llvm.is.constant.f32")), - TypeKind::Double => Some(format!("llvm.is.constant.f64")), - TypeKind::FP128 => Some(format!("llvm.is.constant.f128")), - _ => None, - }; - if let Some(intrinsic_name) = intrinsic_name { - self.call_intrinsic(&intrinsic_name, &[args[0].immediate()]) + if let OperandValue::Immediate(imm) = args[0].val { + self.call_intrinsic( + "llvm.is.constant", + &[args[0].layout.immediate_llvm_type(self.cx)], + &[imm], + ) } else { self.const_bool(false) } @@ -246,10 +231,12 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { ); return Ok(()); } - sym::breakpoint => self.call_intrinsic("llvm.debugtrap", &[]), - sym::va_copy => { - self.call_intrinsic("llvm.va_copy", &[args[0].immediate(), args[1].immediate()]) - } + sym::breakpoint => self.call_intrinsic("llvm.debugtrap", &[], &[]), + sym::va_copy => self.call_intrinsic( + "llvm.va_copy", + &[self.type_ptr()], + &[args[0].immediate(), args[1].immediate()], + ), sym::va_arg => { match result.layout.backend_repr { BackendRepr::Scalar(scalar) => { @@ -324,6 +311,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { }; self.call_intrinsic( "llvm.prefetch", + &[self.type_ptr()], &[ args[0].immediate(), self.const_i32(rw), @@ -385,11 +373,13 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } let (size, signed) = ty.int_size_and_signed(self.tcx); let width = size.bits(); + let llty = self.type_ix(width); match name { sym::ctlz | sym::cttz => { let y = self.const_bool(false); let ret = self.call_intrinsic( - &format!("llvm.{name}.i{width}"), + &format!("llvm.{name}"), + &[llty], &[args[0].immediate(), y], ); @@ -397,62 +387,54 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } sym::ctlz_nonzero => { let y = self.const_bool(true); - let llvm_name = &format!("llvm.ctlz.i{width}"); - let ret = self.call_intrinsic(llvm_name, &[args[0].immediate(), y]); + let ret = + self.call_intrinsic("llvm.ctlz", &[llty], &[args[0].immediate(), y]); self.intcast(ret, result.layout.llvm_type(self), false) } sym::cttz_nonzero => { let y = self.const_bool(true); - let llvm_name = &format!("llvm.cttz.i{width}"); - let ret = self.call_intrinsic(llvm_name, &[args[0].immediate(), y]); + let ret = + self.call_intrinsic("llvm.cttz", &[llty], &[args[0].immediate(), y]); self.intcast(ret, result.layout.llvm_type(self), false) } sym::ctpop => { - let ret = self.call_intrinsic( - &format!("llvm.ctpop.i{width}"), - &[args[0].immediate()], - ); + let ret = + self.call_intrinsic("llvm.ctpop", &[llty], &[args[0].immediate()]); self.intcast(ret, result.layout.llvm_type(self), false) } sym::bswap => { if width == 8 { args[0].immediate() // byte swap a u8/i8 is just a no-op } else { - self.call_intrinsic( - &format!("llvm.bswap.i{width}"), - &[args[0].immediate()], - ) + self.call_intrinsic("llvm.bswap", &[llty], &[args[0].immediate()]) } } - sym::bitreverse => self.call_intrinsic( - &format!("llvm.bitreverse.i{width}"), - &[args[0].immediate()], - ), + sym::bitreverse => { + self.call_intrinsic("llvm.bitreverse", &[llty], &[args[0].immediate()]) + } sym::rotate_left | sym::rotate_right => { let is_left = name == sym::rotate_left; let val = args[0].immediate(); let raw_shift = args[1].immediate(); // rotate = funnel shift with first two args the same - let llvm_name = - &format!("llvm.fsh{}.i{}", if is_left { 'l' } else { 'r' }, width); + let llvm_name = format!("llvm.fsh{}", if is_left { 'l' } else { 'r' }); // llvm expects shift to be the same type as the values, but rust // always uses `u32`. let raw_shift = self.intcast(raw_shift, self.val_ty(val), false); - self.call_intrinsic(llvm_name, &[val, val, raw_shift]) + self.call_intrinsic(&llvm_name, &[llty], &[val, val, raw_shift]) } sym::saturating_add | sym::saturating_sub => { let is_add = name == sym::saturating_add; let lhs = args[0].immediate(); let rhs = args[1].immediate(); - let llvm_name = &format!( - "llvm.{}{}.sat.i{}", + let llvm_name = format!( + "llvm.{}{}.sat", if signed { 's' } else { 'u' }, if is_add { "add" } else { "sub" }, - width ); - self.call_intrinsic(llvm_name, &[lhs, rhs]) + self.call_intrinsic(&llvm_name, &[llty], &[lhs, rhs]) } _ => bug!(), } @@ -484,11 +466,8 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { self.icmp(IntPredicate::IntEQ, a_val, b_val) } else { let n = self.const_usize(layout.size().bytes()); - let cmp = self.call_intrinsic("memcmp", &[a, b, n]); - match self.cx.sess().target.arch.as_ref() { - "avr" | "msp430" => self.icmp(IntPredicate::IntEQ, cmp, self.const_i16(0)), - _ => self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0)), - } + let cmp = self.call_intrinsic("memcmp", &[], &[a, b, n]); + self.icmp(IntPredicate::IntEQ, cmp, self.const_int(self.type_int(), 0)) } } @@ -496,6 +475,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { // Here we assume that the `memcmp` provided by the target is a NOP for size 0. let cmp = self.call_intrinsic( "memcmp", + &[], &[args[0].immediate(), args[1].immediate(), args[2].immediate()], ); // Some targets have `memcmp` returning `i16`, but the intrinsic is always `i32`. @@ -619,18 +599,22 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } fn abort(&mut self) { - self.call_intrinsic("llvm.trap", &[]); + self.call_intrinsic("llvm.trap", &[], &[]); } fn assume(&mut self, val: Self::Value) { if self.cx.sess().opts.optimize != rustc_session::config::OptLevel::No { - self.call_intrinsic("llvm.assume", &[val]); + self.call_intrinsic("llvm.assume", &[], &[val]); } } fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value { if self.cx.sess().opts.optimize != rustc_session::config::OptLevel::No { - self.call_intrinsic("llvm.expect.i1", &[cond, self.const_bool(expected)]) + self.call_intrinsic( + "llvm.expect", + &[self.type_i1()], + &[cond, self.const_bool(expected)], + ) } else { cond } @@ -644,17 +628,20 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { ) -> Self::Value { let typeid = self.get_metadata_value(typeid); let vtable_byte_offset = self.const_i32(vtable_byte_offset as i32); - let type_checked_load = - self.call_intrinsic("llvm.type.checked.load", &[llvtable, vtable_byte_offset, typeid]); + let type_checked_load = self.call_intrinsic( + "llvm.type.checked.load", + &[], + &[llvtable, vtable_byte_offset, typeid], + ); self.extract_value(type_checked_load, 0) } fn va_start(&mut self, va_list: &'ll Value) -> &'ll Value { - self.call_intrinsic("llvm.va_start", &[va_list]) + self.call_intrinsic("llvm.va_start", &[self.type_ptr()], &[va_list]) } fn va_end(&mut self, va_list: &'ll Value) -> &'ll Value { - self.call_intrinsic("llvm.va_end", &[va_list]) + self.call_intrinsic("llvm.va_end", &[self.type_ptr()], &[va_list]) } } @@ -893,8 +880,8 @@ fn codegen_wasm_try<'ll, 'tcx>( let null = bx.const_null(bx.type_ptr()); let funclet = bx.catch_pad(cs, &[null]); - let ptr = bx.call_intrinsic("llvm.wasm.get.exception", &[funclet.cleanuppad()]); - let _sel = bx.call_intrinsic("llvm.wasm.get.ehselector", &[funclet.cleanuppad()]); + let ptr = bx.call_intrinsic("llvm.wasm.get.exception", &[], &[funclet.cleanuppad()]); + let _sel = bx.call_intrinsic("llvm.wasm.get.ehselector", &[], &[funclet.cleanuppad()]); let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void()); bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet), None); @@ -1031,7 +1018,7 @@ fn codegen_emcc_try<'ll, 'tcx>( let selector = bx.extract_value(vals, 1); // Check if the typeid we got is the one for a Rust panic. - let rust_typeid = bx.call_intrinsic("llvm.eh.typeid.for", &[tydesc]); + let rust_typeid = bx.call_intrinsic("llvm.eh.typeid.for", &[bx.type_ptr()], &[tydesc]); let is_rust_panic = bx.icmp(IntPredicate::IntEQ, selector, rust_typeid); let is_rust_panic = bx.zext(is_rust_panic, bx.type_bool()); @@ -1522,56 +1509,37 @@ fn generic_simd_intrinsic<'ll, 'tcx>( }}; } - let (elem_ty_str, elem_ty) = if let ty::Float(f) = in_elem.kind() { - let elem_ty = bx.cx.type_float_from_ty(*f); - match f.bit_width() { - 16 => ("f16", elem_ty), - 32 => ("f32", elem_ty), - 64 => ("f64", elem_ty), - 128 => ("f128", elem_ty), - _ => return_error!(InvalidMonomorphization::FloatingPointVector { - span, - name, - f_ty: *f, - in_ty, - }), - } + let elem_ty = if let ty::Float(f) = in_elem.kind() { + bx.cx.type_float_from_ty(*f) } else { return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty }); }; let vec_ty = bx.type_vector(elem_ty, in_len); - let (intr_name, fn_ty) = match name { - sym::simd_ceil => ("ceil", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_fabs => ("fabs", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_fcos => ("cos", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_fexp2 => ("exp2", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_fexp => ("exp", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_flog10 => ("log10", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_flog2 => ("log2", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_flog => ("log", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_floor => ("floor", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_fma => ("fma", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)), - sym::simd_relaxed_fma => ("fmuladd", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)), - sym::simd_fsin => ("sin", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_fsqrt => ("sqrt", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_round => ("round", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_trunc => ("trunc", bx.type_func(&[vec_ty], vec_ty)), + let intr_name = match name { + sym::simd_ceil => "llvm.ceil", + sym::simd_fabs => "llvm.fabs", + sym::simd_fcos => "llvm.cos", + sym::simd_fexp2 => "llvm.exp2", + sym::simd_fexp => "llvm.exp", + sym::simd_flog10 => "llvm.log10", + sym::simd_flog2 => "llvm.log2", + sym::simd_flog => "llvm.log", + sym::simd_floor => "llvm.floor", + sym::simd_fma => "llvm.fma", + sym::simd_relaxed_fma => "llvm.fmuladd", + sym::simd_fsin => "llvm.sin", + sym::simd_fsqrt => "llvm.sqrt", + sym::simd_round => "llvm.round", + sym::simd_trunc => "llvm.trunc", _ => return_error!(InvalidMonomorphization::UnrecognizedIntrinsic { span, name }), }; - let llvm_name = &format!("llvm.{intr_name}.v{in_len}{elem_ty_str}"); - let f = bx.declare_cfn(llvm_name, llvm::UnnamedAddr::No, fn_ty); - let c = bx.call( - fn_ty, - None, - None, - f, + Ok(bx.call_intrinsic( + intr_name, + &[vec_ty], &args.iter().map(|arg| arg.immediate()).collect::>(), - None, - None, - ); - Ok(c) + )) } if std::matches!( @@ -1595,29 +1563,6 @@ fn generic_simd_intrinsic<'ll, 'tcx>( return simd_simple_float_intrinsic(name, in_elem, in_ty, in_len, bx, span, args); } - // FIXME: use: - // https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Function.h#L182 - // https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Intrinsics.h#L81 - fn llvm_vector_str(bx: &Builder<'_, '_, '_>, elem_ty: Ty<'_>, vec_len: u64) -> String { - match *elem_ty.kind() { - ty::Int(v) => format!( - "v{}i{}", - vec_len, - // Normalize to prevent crash if v: IntTy::Isize - v.normalize(bx.target_spec().pointer_width).bit_width().unwrap() - ), - ty::Uint(v) => format!( - "v{}i{}", - vec_len, - // Normalize to prevent crash if v: UIntTy::Usize - v.normalize(bx.target_spec().pointer_width).bit_width().unwrap() - ), - ty::Float(v) => format!("v{}f{}", vec_len, v.bit_width()), - ty::RawPtr(_, _) => format!("v{}p0", vec_len), - _ => unreachable!(), - } - } - fn llvm_vector_ty<'ll>(cx: &CodegenCx<'ll, '_>, elem_ty: Ty<'_>, vec_len: u64) -> &'ll Type { let elem_ty = match *elem_ty.kind() { ty::Int(v) => cx.type_int_from_ty(v), @@ -1698,38 +1643,22 @@ fn generic_simd_intrinsic<'ll, 'tcx>( ); // Alignment of T, must be a constant integer value: - let alignment_ty = bx.type_i32(); let alignment = bx.const_i32(bx.align_of(in_elem).bytes() as i32); // Truncate the mask vector to a vector of i1s: let mask = vector_mask_to_bitmask(bx, args[2].immediate(), mask_elem_bitwidth, in_len); - let mask_ty = bx.type_vector(bx.type_i1(), in_len); // Type of the vector of pointers: let llvm_pointer_vec_ty = llvm_vector_ty(bx, element_ty1, in_len); - let llvm_pointer_vec_str = llvm_vector_str(bx, element_ty1, in_len); // Type of the vector of elements: let llvm_elem_vec_ty = llvm_vector_ty(bx, element_ty0, in_len); - let llvm_elem_vec_str = llvm_vector_str(bx, element_ty0, in_len); - let llvm_intrinsic = - format!("llvm.masked.gather.{llvm_elem_vec_str}.{llvm_pointer_vec_str}"); - let fn_ty = bx.type_func( - &[llvm_pointer_vec_ty, alignment_ty, mask_ty, llvm_elem_vec_ty], - llvm_elem_vec_ty, - ); - let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty); - let v = bx.call( - fn_ty, - None, - None, - f, + return Ok(bx.call_intrinsic( + "llvm.masked.gather", + &[llvm_elem_vec_ty, llvm_pointer_vec_ty], &[args[1].immediate(), alignment, mask, args[0].immediate()], - None, - None, - ); - return Ok(v); + )); } if name == sym::simd_masked_load { @@ -1795,32 +1724,20 @@ fn generic_simd_intrinsic<'ll, 'tcx>( ); let mask = vector_mask_to_bitmask(bx, args[0].immediate(), m_elem_bitwidth, mask_len); - let mask_ty = bx.type_vector(bx.type_i1(), mask_len); // Alignment of T, must be a constant integer value: - let alignment_ty = bx.type_i32(); let alignment = bx.const_i32(bx.align_of(values_elem).bytes() as i32); let llvm_pointer = bx.type_ptr(); // Type of the vector of elements: let llvm_elem_vec_ty = llvm_vector_ty(bx, values_elem, values_len); - let llvm_elem_vec_str = llvm_vector_str(bx, values_elem, values_len); - - let llvm_intrinsic = format!("llvm.masked.load.{llvm_elem_vec_str}.p0"); - let fn_ty = bx - .type_func(&[llvm_pointer, alignment_ty, mask_ty, llvm_elem_vec_ty], llvm_elem_vec_ty); - let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty); - let v = bx.call( - fn_ty, - None, - None, - f, + + return Ok(bx.call_intrinsic( + "llvm.masked.load", + &[llvm_elem_vec_ty, llvm_pointer], &[args[1].immediate(), alignment, mask, args[2].immediate()], - None, - None, - ); - return Ok(v); + )); } if name == sym::simd_masked_store { @@ -1880,33 +1797,20 @@ fn generic_simd_intrinsic<'ll, 'tcx>( ); let mask = vector_mask_to_bitmask(bx, args[0].immediate(), m_elem_bitwidth, mask_len); - let mask_ty = bx.type_vector(bx.type_i1(), mask_len); // Alignment of T, must be a constant integer value: - let alignment_ty = bx.type_i32(); let alignment = bx.const_i32(bx.align_of(values_elem).bytes() as i32); - let ret_t = bx.type_void(); - let llvm_pointer = bx.type_ptr(); // Type of the vector of elements: let llvm_elem_vec_ty = llvm_vector_ty(bx, values_elem, values_len); - let llvm_elem_vec_str = llvm_vector_str(bx, values_elem, values_len); - - let llvm_intrinsic = format!("llvm.masked.store.{llvm_elem_vec_str}.p0"); - let fn_ty = bx.type_func(&[llvm_elem_vec_ty, llvm_pointer, alignment_ty, mask_ty], ret_t); - let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty); - let v = bx.call( - fn_ty, - None, - None, - f, + + return Ok(bx.call_intrinsic( + "llvm.masked.store", + &[llvm_elem_vec_ty, llvm_pointer], &[args[2].immediate(), args[1].immediate(), alignment, mask], - None, - None, - ); - return Ok(v); + )); } if name == sym::simd_scatter { @@ -1971,38 +1875,22 @@ fn generic_simd_intrinsic<'ll, 'tcx>( ); // Alignment of T, must be a constant integer value: - let alignment_ty = bx.type_i32(); let alignment = bx.const_i32(bx.align_of(in_elem).bytes() as i32); // Truncate the mask vector to a vector of i1s: let mask = vector_mask_to_bitmask(bx, args[2].immediate(), mask_elem_bitwidth, in_len); - let mask_ty = bx.type_vector(bx.type_i1(), in_len); - - let ret_t = bx.type_void(); // Type of the vector of pointers: let llvm_pointer_vec_ty = llvm_vector_ty(bx, element_ty1, in_len); - let llvm_pointer_vec_str = llvm_vector_str(bx, element_ty1, in_len); // Type of the vector of elements: let llvm_elem_vec_ty = llvm_vector_ty(bx, element_ty0, in_len); - let llvm_elem_vec_str = llvm_vector_str(bx, element_ty0, in_len); - - let llvm_intrinsic = - format!("llvm.masked.scatter.{llvm_elem_vec_str}.{llvm_pointer_vec_str}"); - let fn_ty = - bx.type_func(&[llvm_elem_vec_ty, llvm_pointer_vec_ty, alignment_ty, mask_ty], ret_t); - let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty); - let v = bx.call( - fn_ty, - None, - None, - f, + + return Ok(bx.call_intrinsic( + "llvm.masked.scatter", + &[llvm_elem_vec_ty, llvm_pointer_vec_ty], &[args[0].immediate(), args[1].immediate(), alignment, mask], - None, - None, - ); - return Ok(v); + )); } macro_rules! arith_red { @@ -2431,40 +2319,31 @@ fn generic_simd_intrinsic<'ll, 'tcx>( }, in_len as u64, ); - let intrinsic_name = match name { - sym::simd_bswap => "bswap", - sym::simd_bitreverse => "bitreverse", - sym::simd_ctlz => "ctlz", - sym::simd_ctpop => "ctpop", - sym::simd_cttz => "cttz", + let llvm_intrinsic = match name { + sym::simd_bswap => "llvm.bswap", + sym::simd_bitreverse => "llvm.bitreverse", + sym::simd_ctlz => "llvm.ctlz", + sym::simd_ctpop => "llvm.ctpop", + sym::simd_cttz => "llvm.cttz", _ => unreachable!(), }; let int_size = in_elem.int_size_and_signed(bx.tcx()).0.bits(); - let llvm_intrinsic = &format!("llvm.{}.v{}i{}", intrinsic_name, in_len, int_size,); return match name { // byte swap is no-op for i8/u8 sym::simd_bswap if int_size == 8 => Ok(args[0].immediate()), sym::simd_ctlz | sym::simd_cttz => { // for the (int, i1 immediate) pair, the second arg adds `(0, true) => poison` - let fn_ty = bx.type_func(&[vec_ty, bx.type_i1()], vec_ty); let dont_poison_on_zero = bx.const_int(bx.type_i1(), 0); - let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty); - Ok(bx.call( - fn_ty, - None, - None, - f, + Ok(bx.call_intrinsic( + llvm_intrinsic, + &[vec_ty], &[args[0].immediate(), dont_poison_on_zero], - None, - None, )) } sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctpop => { // simple unary argument cases - let fn_ty = bx.type_func(&[vec_ty], vec_ty); - let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty); - Ok(bx.call(fn_ty, None, None, f, &[args[0].immediate()], None, None)) + Ok(bx.call_intrinsic(llvm_intrinsic, &[vec_ty], &[args[0].immediate()])) } _ => unreachable!(), }; @@ -2495,10 +2374,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>( let lhs = args[0].immediate(); let rhs = args[1].immediate(); let is_add = name == sym::simd_saturating_add; - let ptr_bits = bx.tcx().data_layout.pointer_size.bits() as _; - let (signed, elem_width, elem_ty) = match *in_elem.kind() { - ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_int_from_ty(i)), - ty::Uint(i) => (false, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_uint_from_ty(i)), + let (signed, elem_ty) = match *in_elem.kind() { + ty::Int(i) => (true, bx.cx.type_int_from_ty(i)), + ty::Uint(i) => (false, bx.cx.type_uint_from_ty(i)), _ => { return_error!(InvalidMonomorphization::ExpectedVectorElementType { span, @@ -2508,19 +2386,14 @@ fn generic_simd_intrinsic<'ll, 'tcx>( }); } }; - let llvm_intrinsic = &format!( - "llvm.{}{}.sat.v{}i{}", + let llvm_intrinsic = format!( + "llvm.{}{}.sat", if signed { 's' } else { 'u' }, if is_add { "add" } else { "sub" }, - in_len, - elem_width ); let vec_ty = bx.cx.type_vector(elem_ty, in_len as u64); - let fn_ty = bx.type_func(&[vec_ty, vec_ty], vec_ty); - let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty); - let v = bx.call(fn_ty, None, None, f, &[lhs, rhs], None, None); - return Ok(v); + return Ok(bx.call_intrinsic(&llvm_intrinsic, &[vec_ty], &[lhs, rhs])); } span_bug!(span, "unknown SIMD intrinsic"); diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index e27fbf94f34..59c61db5fcd 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -15,6 +15,7 @@ use std::fmt::Debug; use std::marker::PhantomData; +use std::num::NonZero; use std::ptr; use bitflags::bitflags; @@ -1195,6 +1196,17 @@ unsafe extern "C" { // Operations on functions pub(crate) fn LLVMSetFunctionCallConv(Fn: &Value, CC: c_uint); + // Operations about llvm intrinsics + pub(crate) fn LLVMLookupIntrinsicID(Name: *const c_char, NameLen: size_t) -> c_uint; + pub(crate) fn LLVMIntrinsicIsOverloaded(ID: NonZero) -> Bool; + pub(crate) fn LLVMIntrinsicCopyOverloadedName2<'a>( + Mod: &'a Module, + ID: NonZero, + ParamTypes: *const &'a Type, + ParamCount: size_t, + NameLength: *mut size_t, + ) -> *mut c_char; + // Operations on parameters pub(crate) fn LLVMIsAArgument(Val: &Value) -> Option<&Value>; pub(crate) safe fn LLVMCountParams(Fn: &Value) -> c_uint; diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index ed23f911930..bc3538c768d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -1,9 +1,10 @@ #![allow(non_snake_case)] use std::ffi::{CStr, CString}; -use std::ptr; +use std::num::NonZero; use std::str::FromStr; use std::string::FromUtf8Error; +use std::{ptr, slice}; use libc::c_uint; use rustc_abi::{Align, Size, WrappingRange}; @@ -327,6 +328,48 @@ pub(crate) fn get_value_name(value: &Value) -> &[u8] { } } +#[derive(Debug, Copy, Clone)] +pub(crate) struct Intrinsic { + id: NonZero, +} + +impl Intrinsic { + pub(crate) fn lookup(name: &[u8]) -> Option { + let id = unsafe { LLVMLookupIntrinsicID(name.as_c_char_ptr(), name.len()) }; + NonZero::new(id).map(|id| Self { id }) + } + + pub(crate) fn is_overloaded(self) -> bool { + unsafe { LLVMIntrinsicIsOverloaded(self.id) == True } + } + + pub(crate) fn overloaded_name<'ll>( + self, + llmod: &'ll Module, + type_params: &[&'ll Type], + ) -> String { + let mut len = 0; + let ptr = unsafe { + LLVMIntrinsicCopyOverloadedName2( + llmod, + self.id, + type_params.as_ptr(), + type_params.len(), + &mut len, + ) + }; + + let slice = unsafe { slice::from_raw_parts_mut(ptr.cast(), len) }; + let copied = str::from_utf8(slice).expect("Non-UTF8 intrinsic name").to_string(); + + unsafe { + libc::free(ptr.cast()); + } + + copied + } +} + /// Safe wrapper for `LLVMSetValueName2` from a byte slice pub(crate) fn set_value_name(value: &Value, name: &[u8]) { unsafe { diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 169036f5152..2364ad0c9d2 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -1,4 +1,5 @@ use std::borrow::Borrow; +use std::hash::{Hash, Hasher}; use std::{fmt, ptr}; use libc::{c_char, c_uint}; @@ -25,6 +26,14 @@ impl PartialEq for Type { } } +impl Eq for Type {} + +impl Hash for Type { + fn hash(&self, state: &mut H) { + ptr::hash(self, state); + } +} + impl fmt::Debug for Type { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str( diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 7f78bc75695..f35f551d590 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -23,7 +23,7 @@ use crate::common::{AtomicRmwBinOp, IntPredicate, RealPredicate, Synchronization use crate::mir::operand::{OperandRef, OperandValue}; use crate::mir::place::{PlaceRef, PlaceValue}; -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum OverflowOp { Add, Sub, @@ -215,7 +215,7 @@ pub trait BuilderMethods<'a, 'tcx>: fn checked_binop( &mut self, oop: OverflowOp, - ty: Ty<'_>, + ty: Ty<'tcx>, lhs: Self::Value, rhs: Self::Value, ) -> (Self::Value, Self::Value); -- cgit 1.4.1-3-g733a5 From c49ec838685eb54fbbc5acc55e9cb2947cad315e Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Thu, 12 Jun 2025 17:07:36 +0800 Subject: Add `f16` inline asm support for LoongArch --- compiler/rustc_codegen_llvm/src/asm.rs | 21 +++++++++++++++++++++ compiler/rustc_target/src/asm/loongarch.rs | 8 +++++--- tests/assembly/asm/loongarch-type.rs | 26 +++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 4 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 4185aef8b31..9ddadcf16aa 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -1021,6 +1021,15 @@ fn llvm_fixup_input<'ll, 'tcx>( ) if element.primitive() == Primitive::Float(Float::F16) => { bx.bitcast(value, bx.type_vector(bx.type_i16(), count)) } + (LoongArch(LoongArchInlineAsmRegClass::freg), BackendRepr::Scalar(s)) + if s.primitive() == Primitive::Float(Float::F16) => + { + // Smaller floats are always "NaN-boxed" inside larger floats on LoongArch. + let value = bx.bitcast(value, bx.type_i16()); + let value = bx.zext(value, bx.type_i32()); + let value = bx.or(value, bx.const_u32(0xFFFF_0000)); + bx.bitcast(value, bx.type_f32()) + } (Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics. @@ -1178,6 +1187,13 @@ fn llvm_fixup_output<'ll, 'tcx>( ) if element.primitive() == Primitive::Float(Float::F16) => { bx.bitcast(value, bx.type_vector(bx.type_f16(), count)) } + (LoongArch(LoongArchInlineAsmRegClass::freg), BackendRepr::Scalar(s)) + if s.primitive() == Primitive::Float(Float::F16) => + { + let value = bx.bitcast(value, bx.type_i32()); + let value = bx.trunc(value, bx.type_i16()); + bx.bitcast(value, bx.type_f16()) + } (Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics. @@ -1318,6 +1334,11 @@ fn llvm_fixup_output_type<'ll, 'tcx>( ) if element.primitive() == Primitive::Float(Float::F16) => { cx.type_vector(cx.type_i16(), count) } + (LoongArch(LoongArchInlineAsmRegClass::freg), BackendRepr::Scalar(s)) + if s.primitive() == Primitive::Float(Float::F16) => + { + cx.type_f32() + } (Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics. diff --git a/compiler/rustc_target/src/asm/loongarch.rs b/compiler/rustc_target/src/asm/loongarch.rs index 8783d3953b1..51e7ee8daa4 100644 --- a/compiler/rustc_target/src/asm/loongarch.rs +++ b/compiler/rustc_target/src/asm/loongarch.rs @@ -37,9 +37,11 @@ impl LoongArchInlineAsmRegClass { arch: InlineAsmArch, ) -> &'static [(InlineAsmType, Option)] { match (self, arch) { - (Self::reg, InlineAsmArch::LoongArch64) => types! { _: I8, I16, I32, I64, F32, F64; }, - (Self::reg, InlineAsmArch::LoongArch32) => types! { _: I8, I16, I32, F32; }, - (Self::freg, _) => types! { f: F32; d: F64; }, + (Self::reg, InlineAsmArch::LoongArch64) => { + types! { _: I8, I16, I32, I64, F16, F32, F64; } + } + (Self::reg, InlineAsmArch::LoongArch32) => types! { _: I8, I16, I32, F16, F32; }, + (Self::freg, _) => types! { f: F16, F32; d: F64; }, _ => unreachable!("unsupported register class"), } } diff --git a/tests/assembly/asm/loongarch-type.rs b/tests/assembly/asm/loongarch-type.rs index 86d9e03bc93..c782be19f1d 100644 --- a/tests/assembly/asm/loongarch-type.rs +++ b/tests/assembly/asm/loongarch-type.rs @@ -4,7 +4,7 @@ //@ compile-flags: -Zmerge-functions=disabled //@ needs-llvm-components: loongarch -#![feature(no_core)] +#![feature(no_core, f16)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] @@ -69,6 +69,12 @@ check!(reg_i8, i8, reg, "move"); // CHECK: #NO_APP check!(reg_i16, i16, reg, "move"); +// CHECK-LABEL: reg_f16: +// CHECK: #APP +// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_f16, f16, reg, "move"); + // CHECK-LABEL: reg_i32: // CHECK: #APP // CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} @@ -99,6 +105,12 @@ check!(reg_f64, f64, reg, "move"); // CHECK: #NO_APP check!(reg_ptr, ptr, reg, "move"); +// CHECK-LABEL: freg_f16: +// CHECK: #APP +// CHECK: fmov.s $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(freg_f16, f16, freg, "fmov.s"); + // CHECK-LABEL: freg_f32: // CHECK: #APP // CHECK: fmov.s $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} @@ -123,6 +135,12 @@ check_reg!(r4_i8, i8, "$r4", "move"); // CHECK: #NO_APP check_reg!(r4_i16, i16, "$r4", "move"); +// CHECK-LABEL: r4_f16: +// CHECK: #APP +// CHECK: move $a0, $a0 +// CHECK: #NO_APP +check_reg!(r4_f16, f16, "$r4", "move"); + // CHECK-LABEL: r4_i32: // CHECK: #APP // CHECK: move $a0, $a0 @@ -153,6 +171,12 @@ check_reg!(r4_f64, f64, "$r4", "move"); // CHECK: #NO_APP check_reg!(r4_ptr, ptr, "$r4", "move"); +// CHECK-LABEL: f0_f16: +// CHECK: #APP +// CHECK: fmov.s $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} +// CHECK: #NO_APP +check_reg!(f0_f16, f16, "$f0", "fmov.s"); + // CHECK-LABEL: f0_f32: // CHECK: #APP // CHECK: fmov.s $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} -- cgit 1.4.1-3-g733a5 From 2038405ff7020904c21c73331f9c3a3d27f75470 Mon Sep 17 00:00:00 2001 From: sayantn Date: Thu, 5 Jun 2025 18:12:58 +0530 Subject: Add `simd_funnel_sh{l,r}` and `simd_round_ties_even` --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 17 ++++- compiler/rustc_hir_analysis/src/check/intrinsic.rs | 3 +- compiler/rustc_span/src/symbol.rs | 3 + library/core/src/intrinsics/simd.rs | 42 ++++++++++++ tests/ui/simd/intrinsic/float-math-pass.rs | 3 + tests/ui/simd/intrinsic/generic-arithmetic-2.rs | 12 ++++ .../ui/simd/intrinsic/generic-arithmetic-2.stderr | 74 ++++++++++++++-------- tests/ui/simd/intrinsic/generic-arithmetic-pass.rs | 74 ++++++++++++++++++++++ 8 files changed, 201 insertions(+), 27 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 497c31706ec..fd8b9c4a9d2 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1532,6 +1532,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( sym::simd_fsin => "llvm.sin", sym::simd_fsqrt => "llvm.sqrt", sym::simd_round => "llvm.round", + sym::simd_round_ties_even => "llvm.rint", sym::simd_trunc => "llvm.trunc", _ => return_error!(InvalidMonomorphization::UnrecognizedIntrinsic { span, name }), }; @@ -1558,6 +1559,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( | sym::simd_fsqrt | sym::simd_relaxed_fma | sym::simd_round + | sym::simd_round_ties_even | sym::simd_trunc ) { return simd_simple_float_intrinsic(name, in_elem, in_ty, in_len, bx, span, args); @@ -2304,7 +2306,13 @@ fn generic_simd_intrinsic<'ll, 'tcx>( // Unary integer intrinsics if matches!( name, - sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctlz | sym::simd_ctpop | sym::simd_cttz + sym::simd_bswap + | sym::simd_bitreverse + | sym::simd_ctlz + | sym::simd_ctpop + | sym::simd_cttz + | sym::simd_funnel_shl + | sym::simd_funnel_shr ) { let vec_ty = bx.cx.type_vector( match *in_elem.kind() { @@ -2325,6 +2333,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>( sym::simd_ctlz => "llvm.ctlz", sym::simd_ctpop => "llvm.ctpop", sym::simd_cttz => "llvm.cttz", + sym::simd_funnel_shl => "llvm.fshl", + sym::simd_funnel_shr => "llvm.fshr", _ => unreachable!(), }; let int_size = in_elem.int_size_and_signed(bx.tcx()).0.bits(); @@ -2345,6 +2355,11 @@ fn generic_simd_intrinsic<'ll, 'tcx>( // simple unary argument cases Ok(bx.call_intrinsic(llvm_intrinsic, &[vec_ty], &[args[0].immediate()])) } + sym::simd_funnel_shl | sym::simd_funnel_shr => Ok(bx.call_intrinsic( + llvm_intrinsic, + &[vec_ty], + &[args[0].immediate(), args[1].immediate(), args[2].immediate()], + )), _ => unreachable!(), }; } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 060fc51b7bd..cebf7d1b532 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -594,8 +594,9 @@ pub(crate) fn check_intrinsic_type( | sym::simd_ceil | sym::simd_floor | sym::simd_round + | sym::simd_round_ties_even | sym::simd_trunc => (1, 0, vec![param(0)], param(0)), - sym::simd_fma | sym::simd_relaxed_fma => { + sym::simd_fma | sym::simd_relaxed_fma | sym::simd_funnel_shl | sym::simd_funnel_shr => { (1, 0, vec![param(0), param(0), param(0)], param(0)) } sym::simd_gather => (3, 0, vec![param(0), param(1), param(2)], param(0)), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index cb9ccf4cc3f..eddbc66fe40 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1967,6 +1967,8 @@ symbols! { simd_fmin, simd_fsin, simd_fsqrt, + simd_funnel_shl, + simd_funnel_shr, simd_gather, simd_ge, simd_gt, @@ -1994,6 +1996,7 @@ symbols! { simd_relaxed_fma, simd_rem, simd_round, + simd_round_ties_even, simd_saturating_add, simd_saturating_sub, simd_scatter, diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index 40efc263068..11533ab6aa4 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -126,6 +126,40 @@ pub unsafe fn simd_shl(lhs: T, rhs: T) -> T; #[rustc_nounwind] pub unsafe fn simd_shr(lhs: T, rhs: T) -> T; +/// Funnel Shifts vector left elementwise, with UB on overflow. +/// +/// Concatenates `a` and `b` elementwise (with `a` in the most significant half), +/// creating a vector of the same length, but with each element being twice as +/// wide. Then shift this vector left elementwise by `shift`, shifting in zeros, +/// and extract the most significant half of each of the elements. If `a` and `b` +/// are the same, this is equivalent to an elementwise rotate left operation. +/// +/// `T` must be a vector of integers. +/// +/// # Safety +/// +/// Each element of `shift` must be less than `::BITS`. +#[rustc_intrinsic] +#[rustc_nounwind] +pub unsafe fn simd_funnel_shl(a: T, b: T, shift: T) -> T; + +/// Funnel Shifts vector right elementwise, with UB on overflow. +/// +/// Concatenates `a` and `b` elementwise (with `a` in the most significant half), +/// creating a vector of the same length, but with each element being twice as +/// wide. Then shift this vector right elementwise by `shift`, shifting in zeros, +/// and extract the least significant half of each of the elements. If `a` and `b` +/// are the same, this is equivalent to an elementwise rotate right operation. +/// +/// `T` must be a vector of integers. +/// +/// # Safety +/// +/// Each element of `shift` must be less than `::BITS`. +#[rustc_intrinsic] +#[rustc_nounwind] +pub unsafe fn simd_funnel_shr(a: T, b: T, shift: T) -> T; + /// "Ands" vectors elementwise. /// /// `T` must be a vector of integers. @@ -678,6 +712,14 @@ pub unsafe fn simd_floor(x: T) -> T; #[rustc_nounwind] pub unsafe fn simd_round(x: T) -> T; +/// Rounds each element to the closest integer-valued float. +/// Ties are resolved by rounding to the number with an even least significant digit +/// +/// `T` must be a vector of floats. +#[rustc_intrinsic] +#[rustc_nounwind] +pub unsafe fn simd_round_ties_even(x: T) -> T; + /// Returns the integer part of each element as an integer-valued float. /// In other words, non-integer values are truncated towards zero. /// diff --git a/tests/ui/simd/intrinsic/float-math-pass.rs b/tests/ui/simd/intrinsic/float-math-pass.rs index 4c28568a739..01fed8537d0 100644 --- a/tests/ui/simd/intrinsic/float-math-pass.rs +++ b/tests/ui/simd/intrinsic/float-math-pass.rs @@ -85,6 +85,9 @@ fn main() { let r = simd_round(h); assert_eq!(x, r); + let r = simd_round_ties_even(h); + assert_eq!(z, r); + let r = simd_trunc(h); assert_eq!(z, r); } diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-2.rs b/tests/ui/simd/intrinsic/generic-arithmetic-2.rs index fdf06b7882e..caec607d6fe 100644 --- a/tests/ui/simd/intrinsic/generic-arithmetic-2.rs +++ b/tests/ui/simd/intrinsic/generic-arithmetic-2.rs @@ -43,6 +43,10 @@ fn main() { simd_shl(y, y); simd_shr(x, x); simd_shr(y, y); + simd_funnel_shl(x, x, x); + simd_funnel_shl(y, y, y); + simd_funnel_shr(x, x, x); + simd_funnel_shr(y, y, y); simd_and(x, x); simd_and(y, y); simd_or(x, x); @@ -73,6 +77,10 @@ fn main() { //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_shr(0, 0); //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_funnel_shl(0, 0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_funnel_shr(0, 0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_and(0, 0); //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_or(0, 0); @@ -95,6 +103,10 @@ fn main() { //~^ ERROR unsupported operation on `f32x4` with element `f32` simd_shr(z, z); //~^ ERROR unsupported operation on `f32x4` with element `f32` + simd_funnel_shl(z, z, z); + //~^ ERROR unsupported operation on `f32x4` with element `f32` + simd_funnel_shr(z, z, z); + //~^ ERROR unsupported operation on `f32x4` with element `f32` simd_and(z, z); //~^ ERROR unsupported operation on `f32x4` with element `f32` simd_or(z, z); diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr b/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr index 76db6d5328f..a27a8d721fb 100644 --- a/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr +++ b/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr @@ -1,147 +1,171 @@ error[E0511]: invalid monomorphization of `simd_add` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:64:9 + --> $DIR/generic-arithmetic-2.rs:68:9 | LL | simd_add(0, 0); | ^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_sub` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:66:9 + --> $DIR/generic-arithmetic-2.rs:70:9 | LL | simd_sub(0, 0); | ^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_mul` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:68:9 + --> $DIR/generic-arithmetic-2.rs:72:9 | LL | simd_mul(0, 0); | ^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_div` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:70:9 + --> $DIR/generic-arithmetic-2.rs:74:9 | LL | simd_div(0, 0); | ^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shl` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:72:9 + --> $DIR/generic-arithmetic-2.rs:76:9 | LL | simd_shl(0, 0); | ^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shr` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:74:9 + --> $DIR/generic-arithmetic-2.rs:78:9 | LL | simd_shr(0, 0); | ^^^^^^^^^^^^^^ +error[E0511]: invalid monomorphization of `simd_funnel_shl` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-arithmetic-2.rs:80:9 + | +LL | simd_funnel_shl(0, 0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_funnel_shr` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-arithmetic-2.rs:82:9 + | +LL | simd_funnel_shr(0, 0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0511]: invalid monomorphization of `simd_and` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:76:9 + --> $DIR/generic-arithmetic-2.rs:84:9 | LL | simd_and(0, 0); | ^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_or` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:78:9 + --> $DIR/generic-arithmetic-2.rs:86:9 | LL | simd_or(0, 0); | ^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_xor` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:80:9 + --> $DIR/generic-arithmetic-2.rs:88:9 | LL | simd_xor(0, 0); | ^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_neg` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:83:9 + --> $DIR/generic-arithmetic-2.rs:91:9 | LL | simd_neg(0); | ^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_bswap` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:85:9 + --> $DIR/generic-arithmetic-2.rs:93:9 | LL | simd_bswap(0); | ^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_bitreverse` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:87:9 + --> $DIR/generic-arithmetic-2.rs:95:9 | LL | simd_bitreverse(0); | ^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_ctlz` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:89:9 + --> $DIR/generic-arithmetic-2.rs:97:9 | LL | simd_ctlz(0); | ^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_cttz` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:91:9 + --> $DIR/generic-arithmetic-2.rs:99:9 | LL | simd_cttz(0); | ^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shl` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/generic-arithmetic-2.rs:94:9 + --> $DIR/generic-arithmetic-2.rs:102:9 | LL | simd_shl(z, z); | ^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shr` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/generic-arithmetic-2.rs:96:9 + --> $DIR/generic-arithmetic-2.rs:104:9 | LL | simd_shr(z, z); | ^^^^^^^^^^^^^^ +error[E0511]: invalid monomorphization of `simd_funnel_shl` intrinsic: unsupported operation on `f32x4` with element `f32` + --> $DIR/generic-arithmetic-2.rs:106:9 + | +LL | simd_funnel_shl(z, z, z); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_funnel_shr` intrinsic: unsupported operation on `f32x4` with element `f32` + --> $DIR/generic-arithmetic-2.rs:108:9 + | +LL | simd_funnel_shr(z, z, z); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0511]: invalid monomorphization of `simd_and` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/generic-arithmetic-2.rs:98:9 + --> $DIR/generic-arithmetic-2.rs:110:9 | LL | simd_and(z, z); | ^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_or` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/generic-arithmetic-2.rs:100:9 + --> $DIR/generic-arithmetic-2.rs:112:9 | LL | simd_or(z, z); | ^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_xor` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/generic-arithmetic-2.rs:102:9 + --> $DIR/generic-arithmetic-2.rs:114:9 | LL | simd_xor(z, z); | ^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_bswap` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/generic-arithmetic-2.rs:104:9 + --> $DIR/generic-arithmetic-2.rs:116:9 | LL | simd_bswap(z); | ^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_bitreverse` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/generic-arithmetic-2.rs:106:9 + --> $DIR/generic-arithmetic-2.rs:118:9 | LL | simd_bitreverse(z); | ^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_ctlz` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/generic-arithmetic-2.rs:108:9 + --> $DIR/generic-arithmetic-2.rs:120:9 | LL | simd_ctlz(z); | ^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_ctpop` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/generic-arithmetic-2.rs:110:9 + --> $DIR/generic-arithmetic-2.rs:122:9 | LL | simd_ctpop(z); | ^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_cttz` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/generic-arithmetic-2.rs:112:9 + --> $DIR/generic-arithmetic-2.rs:124:9 | LL | simd_cttz(z); | ^^^^^^^^^^^^ -error: aborting due to 24 previous errors +error: aborting due to 28 previous errors For more information about this error, try `rustc --explain E0511`. diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs index 3f0325d690b..4c97fb2141d 100644 --- a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs +++ b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs @@ -83,6 +83,80 @@ fn main() { all_eq!(simd_shr(simd_shl(y1, y2), y2), y1); all_eq!(simd_shr(simd_shl(y2, y1), y1), y2); + all_eq!( + simd_funnel_shl(x1, x2, x1), + i32x4([ + (1 << 1) | (2 >> 31), + (2 << 2) | (3 >> 30), + (3 << 3) | (4 >> 29), + (4 << 4) | (5 >> 28) + ]) + ); + all_eq!( + simd_funnel_shl(x2, x1, x1), + i32x4([ + (2 << 1) | (1 >> 31), + (3 << 2) | (2 >> 30), + (4 << 3) | (3 >> 29), + (5 << 4) | (4 >> 28) + ]) + ); + all_eq!( + simd_funnel_shl(y1, y2, y1), + U32::<4>([ + (1 << 1) | (2 >> 31), + (2 << 2) | (3 >> 30), + (3 << 3) | (4 >> 29), + (4 << 4) | (5 >> 28) + ]) + ); + all_eq!( + simd_funnel_shl(y2, y1, y1), + U32::<4>([ + (2 << 1) | (1 >> 31), + (3 << 2) | (2 >> 30), + (4 << 3) | (3 >> 29), + (5 << 4) | (4 >> 28) + ]) + ); + + all_eq!( + simd_funnel_shr(x1, x2, x1), + i32x4([ + (1 << 31) | (2 >> 1), + (2 << 30) | (3 >> 2), + (3 << 29) | (4 >> 3), + (4 << 28) | (5 >> 4) + ]) + ); + all_eq!( + simd_funnel_shr(x2, x1, x1), + i32x4([ + (2 << 31) | (1 >> 1), + (3 << 30) | (2 >> 2), + (4 << 29) | (3 >> 3), + (5 << 28) | (4 >> 4) + ]) + ); + all_eq!( + simd_funnel_shr(y1, y2, y1), + U32::<4>([ + (1 << 31) | (2 >> 1), + (2 << 30) | (3 >> 2), + (3 << 29) | (4 >> 3), + (4 << 28) | (5 >> 4) + ]) + ); + all_eq!( + simd_funnel_shr(y2, y1, y1), + U32::<4>([ + (2 << 31) | (1 >> 1), + (3 << 30) | (2 >> 2), + (4 << 29) | (3 >> 3), + (5 << 28) | (4 >> 4) + ]) + ); + // ensure we get logical vs. arithmetic shifts correct let (a, b, c, d) = (-12, -123, -1234, -12345); all_eq!(simd_shr(i32x4([a, b, c, d]), x1), i32x4([a >> 1, b >> 2, c >> 3, d >> 4])); -- cgit 1.4.1-3-g733a5 From 9415f3d8a6ee7314fd5aefeb1f80738850c17355 Mon Sep 17 00:00:00 2001 From: sayantn Date: Sun, 15 Jun 2025 03:57:44 +0530 Subject: Use `LLVMIntrinsicGetDeclaration` to completely remove the hardcoded intrinsics list --- compiler/rustc_codegen_llvm/src/builder.rs | 13 +- compiler/rustc_codegen_llvm/src/context.rs | 192 +++------------------------ compiler/rustc_codegen_llvm/src/intrinsic.rs | 8 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 8 +- compiler/rustc_codegen_llvm/src/llvm/mod.rs | 28 +--- compiler/rustc_codegen_llvm/src/type_.rs | 7 - 6 files changed, 32 insertions(+), 224 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 09cb74d9dcb..5f099d32aa2 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -507,7 +507,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let name = format!("llvm.{}{oop_str}.with.overflow", if signed { 's' } else { 'u' }); - let res = self.call_intrinsic(&name, &[self.type_ix(width)], &[lhs, rhs]); + let res = self.call_intrinsic(name, &[self.type_ix(width)], &[lhs, rhs]); (self.extract_value(res, 0), self.extract_value(res, 1)) } @@ -1038,7 +1038,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let size = ty.primitive_size(self.tcx); let name = if ty.is_signed() { "llvm.scmp" } else { "llvm.ucmp" }; - Some(self.call_intrinsic(&name, &[self.type_i8(), self.type_ix(size.bits())], &[lhs, rhs])) + Some(self.call_intrinsic(name, &[self.type_i8(), self.type_ix(size.bits())], &[lhs, rhs])) } /* Miscellaneous instructions */ @@ -1393,7 +1393,8 @@ impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> { // Forward to the `get_static` method of `CodegenCx` let global = self.cx().get_static(def_id); if self.cx().tcx.is_thread_local_static(def_id) { - let pointer = self.call_intrinsic("llvm.threadlocal.address", &[], &[global]); + let pointer = + self.call_intrinsic("llvm.threadlocal.address", &[self.type_ptr()], &[global]); // Cast to default address space if globals are in a different addrspace self.pointercast(pointer, self.type_ptr()) } else { @@ -1590,15 +1591,15 @@ impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { pub(crate) fn call_intrinsic( &mut self, - base_name: &str, + base_name: impl Into>, type_params: &[&'ll Type], args: &[&'ll Value], ) -> &'ll Value { - let (ty, f) = self.cx.get_intrinsic(base_name, type_params); + let (ty, f) = self.cx.get_intrinsic(base_name.into(), type_params); self.call(ty, None, None, f, args, None, None) } - fn call_lifetime_intrinsic(&mut self, intrinsic: &str, ptr: &'ll Value, size: Size) { + fn call_lifetime_intrinsic(&mut self, intrinsic: &'static str, ptr: &'ll Value, size: Size) { let size = size.bytes(); if size == 0 { return; diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index f36f3b2b16b..bff95ea46fa 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -1,4 +1,4 @@ -use std::borrow::Borrow; +use std::borrow::{Borrow, Cow}; use std::cell::{Cell, RefCell}; use std::ffi::{CStr, c_char, c_uint}; use std::marker::PhantomData; @@ -138,7 +138,7 @@ pub(crate) struct FullCx<'ll, 'tcx> { pub rust_try_fn: Cell>, intrinsics: - RefCell), (&'ll Type, &'ll Value)>>, + RefCell, SmallVec<[&'ll Type; 2]>), (&'ll Type, &'ll Value)>>, /// A counter that is used for generating local symbol names local_gen_sym_counter: Cell, @@ -845,45 +845,16 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { impl<'ll> CodegenCx<'ll, '_> { pub(crate) fn get_intrinsic( &self, - base_name: &str, + base_name: Cow<'static, str>, type_params: &[&'ll Type], ) -> (&'ll Type, &'ll Value) { - if let Some(v) = - self.intrinsics.borrow().get(&(base_name, SmallVec::from_slice(type_params))) - { - return *v; - } - - self.declare_intrinsic(base_name, type_params) - } - - fn insert_intrinsic( - &self, - base_name: &'static str, - type_params: &[&'ll Type], - args: Option<&[&'ll llvm::Type]>, - ret: &'ll llvm::Type, - ) -> (&'ll llvm::Type, &'ll llvm::Value) { - let fn_ty = if let Some(args) = args { - self.type_func(args, ret) - } else { - self.type_variadic_func(&[], ret) - }; - - let intrinsic = llvm::Intrinsic::lookup(base_name.as_bytes()) - .expect("Unknown LLVM intrinsic `{base_name}`"); - - let full_name = if intrinsic.is_overloaded() { - &intrinsic.overloaded_name(self.llmod, type_params) - } else { - base_name - }; - - let f = self.declare_cfn(full_name, llvm::UnnamedAddr::No, fn_ty); - self.intrinsics + *self + .intrinsics .borrow_mut() - .insert((base_name, SmallVec::from_slice(type_params)), (fn_ty, f)); - (fn_ty, f) + .entry((base_name, SmallVec::from_slice(type_params))) + .or_insert_with_key(|(base_name, type_params)| { + self.declare_intrinsic(base_name, type_params) + }) } fn declare_intrinsic( @@ -891,155 +862,22 @@ impl<'ll> CodegenCx<'ll, '_> { base_name: &str, type_params: &[&'ll Type], ) -> (&'ll Type, &'ll Value) { - macro_rules! param { - ($index:literal) => { - type_params[$index] - }; - ($other:expr) => { - $other - }; - } - macro_rules! ifn { - ($name:expr, fn(...) -> $ret:expr) => ( - if base_name == $name { - return self.insert_intrinsic($name, type_params, None, param!($ret)); - } - ); - ($name:expr, fn($($arg:expr),*) -> $ret:expr) => ( - if base_name == $name { - return self.insert_intrinsic($name, type_params, Some(&[$(param!($arg)),*]), param!($ret)); - } - ); - } - macro_rules! mk_struct { - ($($field_ty:expr),*) => (self.type_struct( &[$(param!($field_ty)),*], false)) - } - - let same_width_vector = |index, element_ty| { - self.type_vector(element_ty, self.vector_length(type_params[index]) as u64) - }; - - let ptr = self.type_ptr(); - let void = self.type_void(); - let i1 = self.type_i1(); - let t_i32 = self.type_i32(); - let t_i64 = self.type_i64(); - let t_isize = self.type_isize(); - let t_metadata = self.type_metadata(); - let t_token = self.type_token(); - - ifn!("llvm.wasm.get.exception", fn(t_token) -> ptr); - ifn!("llvm.wasm.get.ehselector", fn(t_token) -> t_i32); - - ifn!("llvm.wasm.trunc.unsigned", fn(1) -> 0); - ifn!("llvm.wasm.trunc.signed", fn(1) -> 0); - ifn!("llvm.fptosi.sat", fn(1) -> 0); - ifn!("llvm.fptoui.sat", fn(1) -> 0); - - ifn!("llvm.trap", fn() -> void); - ifn!("llvm.debugtrap", fn() -> void); - ifn!("llvm.frameaddress", fn(t_i32) -> ptr); - - ifn!("llvm.powi", fn(0, 1) -> 0); - ifn!("llvm.pow", fn(0, 0) -> 0); - ifn!("llvm.sqrt", fn(0) -> 0); - ifn!("llvm.sin", fn(0) -> 0); - ifn!("llvm.cos", fn(0) -> 0); - ifn!("llvm.exp", fn(0) -> 0); - ifn!("llvm.exp2", fn(0) -> 0); - ifn!("llvm.log", fn(0) -> 0); - ifn!("llvm.log10", fn(0) -> 0); - ifn!("llvm.log2", fn(0) -> 0); - ifn!("llvm.fma", fn(0, 0, 0) -> 0); - ifn!("llvm.fmuladd", fn(0, 0, 0) -> 0); - ifn!("llvm.fabs", fn(0) -> 0); - ifn!("llvm.minnum", fn(0, 0) -> 0); - ifn!("llvm.minimum", fn(0, 0) -> 0); - ifn!("llvm.maxnum", fn(0, 0) -> 0); - ifn!("llvm.maximum", fn(0, 0) -> 0); - ifn!("llvm.floor", fn(0) -> 0); - ifn!("llvm.ceil", fn(0) -> 0); - ifn!("llvm.trunc", fn(0) -> 0); - ifn!("llvm.copysign", fn(0, 0) -> 0); - ifn!("llvm.round", fn(0) -> 0); - ifn!("llvm.rint", fn(0) -> 0); - ifn!("llvm.nearbyint", fn(0) -> 0); - - ifn!("llvm.ctpop", fn(0) -> 0); - ifn!("llvm.ctlz", fn(0, i1) -> 0); - ifn!("llvm.cttz", fn(0, i1) -> 0); - ifn!("llvm.bswap", fn(0) -> 0); - ifn!("llvm.bitreverse", fn(0) -> 0); - ifn!("llvm.fshl", fn(0, 0, 0) -> 0); - ifn!("llvm.fshr", fn(0, 0, 0) -> 0); - - ifn!("llvm.sadd.with.overflow", fn(0, 0) -> mk_struct! {0, i1}); - ifn!("llvm.uadd.with.overflow", fn(0, 0) -> mk_struct! {0, i1}); - ifn!("llvm.ssub.with.overflow", fn(0, 0) -> mk_struct! {0, i1}); - ifn!("llvm.usub.with.overflow", fn(0, 0) -> mk_struct! {0, i1}); - ifn!("llvm.smul.with.overflow", fn(0, 0) -> mk_struct! {0, i1}); - ifn!("llvm.umul.with.overflow", fn(0, 0) -> mk_struct! {0, i1}); - - ifn!("llvm.sadd.sat", fn(0, 0) -> 0); - ifn!("llvm.uadd.sat", fn(0, 0) -> 0); - ifn!("llvm.ssub.sat", fn(0, 0) -> 0); - ifn!("llvm.usub.sat", fn(0, 0) -> 0); - - ifn!("llvm.scmp", fn(1, 1) -> 0); - ifn!("llvm.ucmp", fn(1, 1) -> 0); - - ifn!("llvm.lifetime.start", fn(t_i64, 0) -> void); - ifn!("llvm.lifetime.end", fn(t_i64, 0) -> void); - - ifn!("llvm.is.constant", fn(0) -> i1); - ifn!("llvm.expect", fn(0, 0) -> 0); - - ifn!("llvm.eh.typeid.for", fn(0) -> t_i32); - ifn!("llvm.localescape", fn(...) -> void); - ifn!("llvm.localrecover", fn(ptr, ptr, t_i32) -> ptr); - - ifn!("llvm.assume", fn(i1) -> void); - ifn!("llvm.prefetch", fn(0, t_i32, t_i32, t_i32) -> void); - // This isn't an "LLVM intrinsic", but LLVM's optimization passes // recognize it like one (including turning it into `bcmp` sometimes) // and we use it to implement intrinsics like `raw_eq` and `compare_bytes` if base_name == "memcmp" { - let fn_ty = self.type_func(&[ptr, ptr, t_isize], self.type_int()); + let fn_ty = self + .type_func(&[self.type_ptr(), self.type_ptr(), self.type_isize()], self.type_int()); let f = self.declare_cfn("memcmp", llvm::UnnamedAddr::No, fn_ty); - self.intrinsics.borrow_mut().insert(("memcmp", SmallVec::new()), (fn_ty, f)); return (fn_ty, f); } - // variadic intrinsics - ifn!("llvm.va_start", fn(0) -> void); - ifn!("llvm.va_end", fn(0) -> void); - ifn!("llvm.va_copy", fn(0, 0) -> void); - - if self.sess().instrument_coverage() { - ifn!("llvm.instrprof.increment", fn(ptr, t_i64, t_i32, t_i32) -> void); - ifn!("llvm.instrprof.mcdc.parameters", fn(ptr, t_i64, t_i32) -> void); - ifn!("llvm.instrprof.mcdc.tvbitmap.update", fn(ptr, t_i64, t_i32, ptr) -> void); - } - - ifn!("llvm.type.test", fn(ptr, t_metadata) -> i1); - ifn!("llvm.type.checked.load", fn(ptr, t_i32, t_metadata) -> mk_struct! {ptr, i1}); - - if self.sess().opts.debuginfo != DebugInfo::None { - ifn!("llvm.dbg.declare", fn(t_metadata, t_metadata, t_metadata) -> void); - ifn!("llvm.dbg.value", fn(t_metadata, t_metadata, t_metadata) -> void); - } - - ifn!("llvm.ptrmask", fn(0, 1) -> 0); - ifn!("llvm.threadlocal.address", fn(ptr) -> ptr); - - ifn!("llvm.masked.load", fn(1, t_i32, same_width_vector(0, i1), 0) -> 0); - ifn!("llvm.masked.store", fn(0, 1, t_i32, same_width_vector(0, i1)) -> void); - ifn!("llvm.masked.gather", fn(1, t_i32, same_width_vector(0, i1), 0) -> 0); - ifn!("llvm.masked.scatter", fn(0, 1, t_i32, same_width_vector(0, i1)) -> void); + let intrinsic = llvm::Intrinsic::lookup(base_name.as_bytes()) + .unwrap_or_else(|| bug!("Unknown intrinsic: `{base_name}`")); + let f = intrinsic.get_declaration(self.llmod, &type_params); - bug!("Unknown intrinsic: `{base_name}`") + (self.get_type_of_global(f), f) } pub(crate) fn eh_catch_typeinfo(&self) -> &'ll Value { diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 497c31706ec..4e8e5244868 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -378,7 +378,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { sym::ctlz | sym::cttz => { let y = self.const_bool(false); let ret = self.call_intrinsic( - &format!("llvm.{name}"), + format!("llvm.{name}"), &[llty], &[args[0].immediate(), y], ); @@ -423,7 +423,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { // always uses `u32`. let raw_shift = self.intcast(raw_shift, self.val_ty(val), false); - self.call_intrinsic(&llvm_name, &[llty], &[val, val, raw_shift]) + self.call_intrinsic(llvm_name, &[llty], &[val, val, raw_shift]) } sym::saturating_add | sym::saturating_sub => { let is_add = name == sym::saturating_add; @@ -434,7 +434,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { if signed { 's' } else { 'u' }, if is_add { "add" } else { "sub" }, ); - self.call_intrinsic(&llvm_name, &[llty], &[lhs, rhs]) + self.call_intrinsic(llvm_name, &[llty], &[lhs, rhs]) } _ => bug!(), } @@ -2393,7 +2393,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( ); let vec_ty = bx.cx.type_vector(elem_ty, in_len as u64); - return Ok(bx.call_intrinsic(&llvm_intrinsic, &[vec_ty], &[lhs, rhs])); + return Ok(bx.call_intrinsic(llvm_intrinsic, &[vec_ty], &[lhs, rhs])); } span_bug!(span, "unknown SIMD intrinsic"); diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 59c61db5fcd..91ada856d59 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1078,8 +1078,6 @@ unsafe extern "C" { // Operations on other types pub(crate) fn LLVMVoidTypeInContext(C: &Context) -> &Type; - pub(crate) fn LLVMTokenTypeInContext(C: &Context) -> &Type; - pub(crate) fn LLVMMetadataTypeInContext(C: &Context) -> &Type; // Operations on all values pub(crate) fn LLVMTypeOf(Val: &Value) -> &Type; @@ -1198,14 +1196,12 @@ unsafe extern "C" { // Operations about llvm intrinsics pub(crate) fn LLVMLookupIntrinsicID(Name: *const c_char, NameLen: size_t) -> c_uint; - pub(crate) fn LLVMIntrinsicIsOverloaded(ID: NonZero) -> Bool; - pub(crate) fn LLVMIntrinsicCopyOverloadedName2<'a>( + pub(crate) fn LLVMGetIntrinsicDeclaration<'a>( Mod: &'a Module, ID: NonZero, ParamTypes: *const &'a Type, ParamCount: size_t, - NameLength: *mut size_t, - ) -> *mut c_char; + ) -> &'a Value; // Operations on parameters pub(crate) fn LLVMIsAArgument(Val: &Value) -> Option<&Value>; diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index bc3538c768d..661174a80df 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -2,9 +2,9 @@ use std::ffi::{CStr, CString}; use std::num::NonZero; +use std::ptr; use std::str::FromStr; use std::string::FromUtf8Error; -use std::{ptr, slice}; use libc::c_uint; use rustc_abi::{Align, Size, WrappingRange}; @@ -339,34 +339,14 @@ impl Intrinsic { NonZero::new(id).map(|id| Self { id }) } - pub(crate) fn is_overloaded(self) -> bool { - unsafe { LLVMIntrinsicIsOverloaded(self.id) == True } - } - - pub(crate) fn overloaded_name<'ll>( + pub(crate) fn get_declaration<'ll>( self, llmod: &'ll Module, type_params: &[&'ll Type], - ) -> String { - let mut len = 0; - let ptr = unsafe { - LLVMIntrinsicCopyOverloadedName2( - llmod, - self.id, - type_params.as_ptr(), - type_params.len(), - &mut len, - ) - }; - - let slice = unsafe { slice::from_raw_parts_mut(ptr.cast(), len) }; - let copied = str::from_utf8(slice).expect("Non-UTF8 intrinsic name").to_string(); - + ) -> &'ll Value { unsafe { - libc::free(ptr.cast()); + LLVMGetIntrinsicDeclaration(llmod, self.id, type_params.as_ptr(), type_params.len()) } - - copied } } diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 2364ad0c9d2..453eca2bbe1 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -58,13 +58,6 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { pub(crate) fn type_void(&self) -> &'ll Type { unsafe { llvm::LLVMVoidTypeInContext(self.llcx()) } } - pub(crate) fn type_token(&self) -> &'ll Type { - unsafe { llvm::LLVMTokenTypeInContext(self.llcx()) } - } - - pub(crate) fn type_metadata(&self) -> &'ll Type { - unsafe { llvm::LLVMMetadataTypeInContext(self.llcx()) } - } ///x Creates an integer type with the given number of bits, e.g., i24 pub(crate) fn type_ix(&self, num_bits: u64) -> &'ll Type { -- cgit 1.4.1-3-g733a5 From a9500d6b0b1a97513f79ed8e04b07c5a4f4fc258 Mon Sep 17 00:00:00 2001 From: sayantn Date: Sun, 15 Jun 2025 22:13:09 +0530 Subject: Correctly account for different address spaces in LLVM intrinsic invocations --- compiler/rustc_codegen_llvm/src/builder.rs | 4 +-- compiler/rustc_codegen_llvm/src/intrinsic.rs | 39 ++++++++++++++++------------ 2 files changed, 24 insertions(+), 19 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 5f099d32aa2..5e9594dd06b 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1394,7 +1394,7 @@ impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> { let global = self.cx().get_static(def_id); if self.cx().tcx.is_thread_local_static(def_id) { let pointer = - self.call_intrinsic("llvm.threadlocal.address", &[self.type_ptr()], &[global]); + self.call_intrinsic("llvm.threadlocal.address", &[self.val_ty(global)], &[global]); // Cast to default address space if globals are in a different addrspace self.pointercast(pointer, self.type_ptr()) } else { @@ -1609,7 +1609,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { return; } - self.call_intrinsic(intrinsic, &[self.type_ptr()], &[self.cx.const_u64(size), ptr]); + self.call_intrinsic(intrinsic, &[self.val_ty(ptr)], &[self.cx.const_u64(size), ptr]); } } impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 4e8e5244868..f7f062849a8 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -154,8 +154,6 @@ fn call_simple_intrinsic<'ll, 'tcx>( sym::roundf64 => ("llvm.round", &[bx.type_f64()]), sym::roundf128 => ("llvm.round", &[bx.type_f128()]), - sym::ptr_mask => ("llvm.ptrmask", &[bx.type_ptr(), bx.type_isize()]), - _ => return None, }; Some(bx.call_intrinsic( @@ -181,6 +179,14 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { let simple = call_simple_intrinsic(self, name, args); let llval = match name { _ if simple.is_some() => simple.unwrap(), + sym::ptr_mask => { + let ptr = args[0].immediate(); + self.call_intrinsic( + "llvm.ptrmask", + &[self.val_ty(ptr), self.type_isize()], + &[ptr, args[1].immediate()], + ) + } sym::is_val_statically_known => { if let OperandValue::Immediate(imm) = args[0].val { self.call_intrinsic( @@ -232,11 +238,14 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { return Ok(()); } sym::breakpoint => self.call_intrinsic("llvm.debugtrap", &[], &[]), - sym::va_copy => self.call_intrinsic( - "llvm.va_copy", - &[self.type_ptr()], - &[args[0].immediate(), args[1].immediate()], - ), + sym::va_copy => { + let dest = args[0].immediate(); + self.call_intrinsic( + "llvm.va_copy", + &[self.val_ty(dest)], + &[dest, args[1].immediate()], + ) + } sym::va_arg => { match result.layout.backend_repr { BackendRepr::Scalar(scalar) => { @@ -309,15 +318,11 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { sym::prefetch_write_instruction => (1, 0), _ => bug!(), }; + let ptr = args[0].immediate(); self.call_intrinsic( "llvm.prefetch", - &[self.type_ptr()], - &[ - args[0].immediate(), - self.const_i32(rw), - args[1].immediate(), - self.const_i32(cache_type), - ], + &[self.val_ty(ptr)], + &[ptr, self.const_i32(rw), args[1].immediate(), self.const_i32(cache_type)], ) } sym::carrying_mul_add => { @@ -637,11 +642,11 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } fn va_start(&mut self, va_list: &'ll Value) -> &'ll Value { - self.call_intrinsic("llvm.va_start", &[self.type_ptr()], &[va_list]) + self.call_intrinsic("llvm.va_start", &[self.val_ty(va_list)], &[va_list]) } fn va_end(&mut self, va_list: &'ll Value) -> &'ll Value { - self.call_intrinsic("llvm.va_end", &[self.type_ptr()], &[va_list]) + self.call_intrinsic("llvm.va_end", &[self.val_ty(va_list)], &[va_list]) } } @@ -1018,7 +1023,7 @@ fn codegen_emcc_try<'ll, 'tcx>( let selector = bx.extract_value(vals, 1); // Check if the typeid we got is the one for a Rust panic. - let rust_typeid = bx.call_intrinsic("llvm.eh.typeid.for", &[bx.type_ptr()], &[tydesc]); + let rust_typeid = bx.call_intrinsic("llvm.eh.typeid.for", &[bx.val_ty(tydesc)], &[tydesc]); let is_rust_panic = bx.icmp(IntPredicate::IntEQ, selector, rust_typeid); let is_rust_panic = bx.zext(is_rust_panic, bx.type_bool()); -- cgit 1.4.1-3-g733a5 From 5723c9997c41be799fcaec791e591fb8406421ff Mon Sep 17 00:00:00 2001 From: beetrees Date: Thu, 3 Apr 2025 23:53:06 +0100 Subject: Fix RISC-V C function ABI when passing/returning structs containing floats --- .../rustc_codegen_cranelift/src/abi/pass_mode.rs | 66 +++++--- compiler/rustc_codegen_gcc/src/intrinsic/mod.rs | 2 +- compiler/rustc_codegen_llvm/src/abi.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 54 ++++++- compiler/rustc_codegen_ssa/src/mir/mod.rs | 3 +- compiler/rustc_target/src/callconv/mips64.rs | 15 +- compiler/rustc_target/src/callconv/mod.rs | 84 ++++++---- compiler/rustc_target/src/callconv/nvptx64.rs | 25 ++- compiler/rustc_target/src/callconv/riscv.rs | 137 ++++++++++++---- compiler/rustc_target/src/callconv/sparc64.rs | 18 +-- tests/assembly/riscv-float-struct-abi.rs | 177 +++++++++++++++++++++ tests/codegen/riscv-abi/cast-local-large-enough.rs | 44 +++++ tests/ui/abi/numbers-arithmetic/float-struct.rs | 44 +++++ 13 files changed, 537 insertions(+), 134 deletions(-) create mode 100644 tests/assembly/riscv-float-struct-abi.rs create mode 100644 tests/codegen/riscv-abi/cast-local-large-enough.rs create mode 100644 tests/ui/abi/numbers-arithmetic/float-struct.rs (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs index 9a0a5b51039..cd0afee0cfb 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs @@ -40,7 +40,18 @@ fn apply_attrs_to_abi_param(param: AbiParam, arg_attrs: ArgAttributes) -> AbiPar } } -fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[AbiParam; 2]> { +fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[(Size, AbiParam); 2]> { + if let Some(offset_from_start) = cast.rest_offset { + assert!(cast.prefix[1..].iter().all(|p| p.is_none())); + assert_eq!(cast.rest.unit.size, cast.rest.total); + let first = cast.prefix[0].unwrap(); + let second = cast.rest.unit; + return smallvec![ + (Size::ZERO, reg_to_abi_param(first)), + (offset_from_start, reg_to_abi_param(second)) + ]; + } + let (rest_count, rem_bytes) = if cast.rest.unit.size.bytes() == 0 { (0, 0) } else { @@ -55,25 +66,32 @@ fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[AbiParam; 2]> { // different types in Cranelift IR. Instead a single array of primitive types is used. // Create list of fields in the main structure - let mut args = cast + let args = cast .prefix .iter() .flatten() .map(|®| reg_to_abi_param(reg)) - .chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit))) - .collect::>(); + .chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit))); + + let mut res = SmallVec::new(); + let mut offset = Size::ZERO; + + for arg in args { + res.push((offset, arg)); + offset += Size::from_bytes(arg.value_type.bytes()); + } // Append final integer if rem_bytes != 0 { // Only integers can be really split further. assert_eq!(cast.rest.unit.kind, RegKind::Integer); - args.push(reg_to_abi_param(Reg { - kind: RegKind::Integer, - size: Size::from_bytes(rem_bytes), - })); + res.push(( + offset, + reg_to_abi_param(Reg { kind: RegKind::Integer, size: Size::from_bytes(rem_bytes) }), + )); } - args + res } impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { @@ -104,7 +122,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { }, PassMode::Cast { ref cast, pad_i32 } => { assert!(!pad_i32, "padding support not yet implemented"); - cast_target_to_abi_params(cast) + cast_target_to_abi_params(cast).into_iter().map(|(_, param)| param).collect() } PassMode::Indirect { attrs, meta_attrs: None, on_stack } => { if on_stack { @@ -160,9 +178,10 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { } _ => unreachable!("{:?}", self.layout.backend_repr), }, - PassMode::Cast { ref cast, .. } => { - (None, cast_target_to_abi_params(cast).into_iter().collect()) - } + PassMode::Cast { ref cast, .. } => ( + None, + cast_target_to_abi_params(cast).into_iter().map(|(_, param)| param).collect(), + ), PassMode::Indirect { attrs, meta_attrs: None, on_stack } => { assert!(!on_stack); ( @@ -187,12 +206,14 @@ pub(super) fn to_casted_value<'tcx>( ) -> SmallVec<[Value; 2]> { let (ptr, meta) = arg.force_stack(fx); assert!(meta.is_none()); - let mut offset = 0; cast_target_to_abi_params(cast) .into_iter() - .map(|param| { - let val = ptr.offset_i64(fx, offset).load(fx, param.value_type, MemFlags::new()); - offset += i64::from(param.value_type.bytes()); + .map(|(offset, param)| { + let val = ptr.offset_i64(fx, offset.bytes() as i64).load( + fx, + param.value_type, + MemFlags::new(), + ); val }) .collect() @@ -205,7 +226,7 @@ pub(super) fn from_casted_value<'tcx>( cast: &CastTarget, ) -> CValue<'tcx> { let abi_params = cast_target_to_abi_params(cast); - let abi_param_size: u32 = abi_params.iter().map(|param| param.value_type.bytes()).sum(); + let abi_param_size: u32 = abi_params.iter().map(|(_, param)| param.value_type.bytes()).sum(); let layout_size = u32::try_from(layout.size.bytes()).unwrap(); let ptr = fx.create_stack_slot( // Stack slot size may be bigger for example `[u8; 3]` which is packed into an `i32`. @@ -214,16 +235,13 @@ pub(super) fn from_casted_value<'tcx>( std::cmp::max(abi_param_size, layout_size), u32::try_from(layout.align.abi.bytes()).unwrap(), ); - let mut offset = 0; let mut block_params_iter = block_params.iter().copied(); - for param in abi_params { - let val = ptr.offset_i64(fx, offset).store( + for (offset, _) in abi_params { + ptr.offset_i64(fx, offset.bytes() as i64).store( fx, block_params_iter.next().unwrap(), MemFlags::new(), - ); - offset += i64::from(param.value_type.bytes()); - val + ) } assert_eq!(block_params_iter.next(), None, "Leftover block param"); CValue::by_ref(ptr, layout) diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 9e05b8f23aa..c921851b42b 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -626,7 +626,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { bx.lifetime_start(llscratch, scratch_size); // ... where we first store the value... - bx.store(val, llscratch, scratch_align); + rustc_codegen_ssa::mir::store_cast(bx, cast, val, llscratch, scratch_align); // ... and then memcpy it to the intended destination. bx.memcpy( diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index aba63d75f1d..4b07c8aef91 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -229,7 +229,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { let llscratch = bx.alloca(scratch_size, scratch_align); bx.lifetime_start(llscratch, scratch_size); // ...store the value... - bx.store(val, llscratch, scratch_align); + rustc_codegen_ssa::mir::store_cast(bx, cast, val, llscratch, scratch_align); // ... and then memcpy it to the intended destination. bx.memcpy( dst.val.llval, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 43b87171d51..3df97429e09 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1,6 +1,6 @@ use std::cmp; -use rustc_abi::{BackendRepr, ExternAbi, HasDataLayout, Reg, Size, WrappingRange}; +use rustc_abi::{Align, BackendRepr, ExternAbi, HasDataLayout, Reg, Size, WrappingRange}; use rustc_ast as ast; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_data_structures::packed::Pu128; @@ -13,7 +13,7 @@ use rustc_middle::{bug, span_bug}; use rustc_session::config::OptLevel; use rustc_span::Span; use rustc_span::source_map::Spanned; -use rustc_target::callconv::{ArgAbi, FnAbi, PassMode}; +use rustc_target::callconv::{ArgAbi, CastTarget, FnAbi, PassMode}; use tracing::{debug, info}; use super::operand::OperandRef; @@ -558,8 +558,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } ZeroSized => bug!("ZST return value shouldn't be in PassMode::Cast"), }; - let ty = bx.cast_backend_type(cast_ty); - bx.load(ty, llslot, self.fn_abi.ret.layout.align.abi) + load_cast(bx, cast_ty, llslot, self.fn_abi.ret.layout.align.abi) } }; bx.ret(llval); @@ -1618,8 +1617,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { MemFlags::empty(), ); // ...and then load it with the ABI type. - let cast_ty = bx.cast_backend_type(cast); - llval = bx.load(cast_ty, llscratch, scratch_align); + llval = load_cast(bx, cast, llscratch, scratch_align); bx.lifetime_end(llscratch, scratch_size); } else { // We can't use `PlaceRef::load` here because the argument @@ -1969,3 +1967,47 @@ enum ReturnDest<'tcx, V> { /// Store a direct return value to an operand local place. DirectOperand(mir::Local), } + +fn load_cast<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + bx: &mut Bx, + cast: &CastTarget, + ptr: Bx::Value, + align: Align, +) -> Bx::Value { + let cast_ty = bx.cast_backend_type(cast); + if let Some(offset_from_start) = cast.rest_offset { + assert!(cast.prefix[1..].iter().all(|p| p.is_none())); + assert_eq!(cast.rest.unit.size, cast.rest.total); + let first_ty = bx.reg_backend_type(&cast.prefix[0].unwrap()); + let second_ty = bx.reg_backend_type(&cast.rest.unit); + let first = bx.load(first_ty, ptr, align); + let second_ptr = bx.inbounds_ptradd(ptr, bx.const_usize(offset_from_start.bytes())); + let second = bx.load(second_ty, second_ptr, align.restrict_for_offset(offset_from_start)); + let res = bx.cx().const_poison(cast_ty); + let res = bx.insert_value(res, first, 0); + bx.insert_value(res, second, 1) + } else { + bx.load(cast_ty, ptr, align) + } +} + +pub fn store_cast<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + bx: &mut Bx, + cast: &CastTarget, + value: Bx::Value, + ptr: Bx::Value, + align: Align, +) { + if let Some(offset_from_start) = cast.rest_offset { + assert!(cast.prefix[1..].iter().all(|p| p.is_none())); + assert_eq!(cast.rest.unit.size, cast.rest.total); + assert!(cast.prefix[0].is_some()); + let first = bx.extract_value(value, 0); + let second = bx.extract_value(value, 1); + bx.store(first, ptr, align); + let second_ptr = bx.inbounds_ptradd(ptr, bx.const_usize(offset_from_start.bytes())); + bx.store(second, second_ptr, align.restrict_for_offset(offset_from_start)); + } else { + bx.store(value, ptr, align); + }; +} diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 96a04473aba..66c4af4c935 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -26,6 +26,7 @@ pub mod place; mod rvalue; mod statement; +pub use self::block::store_cast; use self::debuginfo::{FunctionDebugContext, PerLocalVarDebugInfo}; use self::operand::{OperandRef, OperandValue}; use self::place::PlaceRef; @@ -259,7 +260,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } PassMode::Cast { ref cast, .. } => { debug!("alloc: {:?} (return place) -> place", local); - let size = cast.size(&start_bx); + let size = cast.size(&start_bx).max(layout.size); return LocalRef::Place(PlaceRef::alloca_size(&mut start_bx, size, layout)); } _ => {} diff --git a/compiler/rustc_target/src/callconv/mips64.rs b/compiler/rustc_target/src/callconv/mips64.rs index 89f324bc313..77c0cf06fc1 100644 --- a/compiler/rustc_target/src/callconv/mips64.rs +++ b/compiler/rustc_target/src/callconv/mips64.rs @@ -2,9 +2,7 @@ use rustc_abi::{ BackendRepr, FieldsShape, Float, HasDataLayout, Primitive, Reg, Size, TyAbiInterface, }; -use crate::callconv::{ - ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, PassMode, Uniform, -}; +use crate::callconv::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Uniform}; fn extend_integer_width_mips(arg: &mut ArgAbi<'_, Ty>, bits: u64) { // Always sign extend u32 values on 64-bit mips @@ -140,16 +138,7 @@ where // Extract first 8 chunks as the prefix let rest_size = size - Size::from_bytes(8) * prefix_index as u64; - arg.cast_to(CastTarget { - prefix, - rest: Uniform::new(Reg::i64(), rest_size), - attrs: ArgAttributes { - regular: ArgAttribute::default(), - arg_ext: ArgExtension::None, - pointee_size: Size::ZERO, - pointee_align: None, - }, - }); + arg.cast_to(CastTarget::prefixed(prefix, Uniform::new(Reg::i64(), rest_size))); } pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 2ff7a71ca82..71cc2a45563 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -197,6 +197,17 @@ impl ArgAttributes { } } +impl From for ArgAttributes { + fn from(value: ArgAttribute) -> Self { + Self { + regular: value, + arg_ext: ArgExtension::None, + pointee_size: Size::ZERO, + pointee_align: None, + } + } +} + /// An argument passed entirely registers with the /// same kind (e.g., HFA / HVA on PPC64 and AArch64). #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)] @@ -251,6 +262,9 @@ impl Uniform { #[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub struct CastTarget { pub prefix: [Option; 8], + /// The offset of `rest` from the start of the value. Currently only implemented for a `Reg` + /// pair created by the `offset_pair` method. + pub rest_offset: Option, pub rest: Uniform, pub attrs: ArgAttributes, } @@ -263,42 +277,45 @@ impl From for CastTarget { impl From for CastTarget { fn from(uniform: Uniform) -> CastTarget { - CastTarget { - prefix: [None; 8], - rest: uniform, - attrs: ArgAttributes { - regular: ArgAttribute::default(), - arg_ext: ArgExtension::None, - pointee_size: Size::ZERO, - pointee_align: None, - }, - } + Self::prefixed([None; 8], uniform) } } impl CastTarget { - pub fn pair(a: Reg, b: Reg) -> CastTarget { - CastTarget { + pub fn prefixed(prefix: [Option; 8], rest: Uniform) -> Self { + Self { prefix, rest_offset: None, rest, attrs: ArgAttributes::new() } + } + + pub fn offset_pair(a: Reg, offset_from_start: Size, b: Reg) -> Self { + Self { prefix: [Some(a), None, None, None, None, None, None, None], - rest: Uniform::from(b), - attrs: ArgAttributes { - regular: ArgAttribute::default(), - arg_ext: ArgExtension::None, - pointee_size: Size::ZERO, - pointee_align: None, - }, + rest_offset: Some(offset_from_start), + rest: b.into(), + attrs: ArgAttributes::new(), } } + pub fn with_attrs(mut self, attrs: ArgAttributes) -> Self { + self.attrs = attrs; + self + } + + pub fn pair(a: Reg, b: Reg) -> CastTarget { + Self::prefixed([Some(a), None, None, None, None, None, None, None], Uniform::from(b)) + } + /// When you only access the range containing valid data, you can use this unaligned size; /// otherwise, use the safer `size` method. pub fn unaligned_size(&self, _cx: &C) -> Size { // Prefix arguments are passed in specific designated registers - let prefix_size = self - .prefix - .iter() - .filter_map(|x| x.map(|reg| reg.size)) - .fold(Size::ZERO, |acc, size| acc + size); + let prefix_size = if let Some(offset_from_start) = self.rest_offset { + offset_from_start + } else { + self.prefix + .iter() + .filter_map(|x| x.map(|reg| reg.size)) + .fold(Size::ZERO, |acc, size| acc + size) + }; // Remaining arguments are passed in chunks of the unit size let rest_size = self.rest.unit.size * self.rest.total.bytes().div_ceil(self.rest.unit.size.bytes()); @@ -322,9 +339,22 @@ impl CastTarget { /// Checks if these two `CastTarget` are equal enough to be considered "the same for all /// function call ABIs". pub fn eq_abi(&self, other: &Self) -> bool { - let CastTarget { prefix: prefix_l, rest: rest_l, attrs: attrs_l } = self; - let CastTarget { prefix: prefix_r, rest: rest_r, attrs: attrs_r } = other; - prefix_l == prefix_r && rest_l == rest_r && attrs_l.eq_abi(attrs_r) + let CastTarget { + prefix: prefix_l, + rest_offset: rest_offset_l, + rest: rest_l, + attrs: attrs_l, + } = self; + let CastTarget { + prefix: prefix_r, + rest_offset: rest_offset_r, + rest: rest_r, + attrs: attrs_r, + } = other; + prefix_l == prefix_r + && rest_offset_l == rest_offset_r + && rest_l == rest_r + && attrs_l.eq_abi(attrs_r) } } diff --git a/compiler/rustc_target/src/callconv/nvptx64.rs b/compiler/rustc_target/src/callconv/nvptx64.rs index a26e7dac5ba..44977de7fcb 100644 --- a/compiler/rustc_target/src/callconv/nvptx64.rs +++ b/compiler/rustc_target/src/callconv/nvptx64.rs @@ -1,6 +1,6 @@ use rustc_abi::{HasDataLayout, Reg, Size, TyAbiInterface}; -use super::{ArgAttribute, ArgAttributes, ArgExtension, CastTarget}; +use super::CastTarget; use crate::callconv::{ArgAbi, FnAbi, Uniform}; fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { @@ -34,16 +34,10 @@ fn classify_aggregate(arg: &mut ArgAbi<'_, Ty>) { }; if align_bytes == size.bytes() { - arg.cast_to(CastTarget { - prefix: [Some(reg), None, None, None, None, None, None, None], - rest: Uniform::new(Reg::i8(), Size::from_bytes(0)), - attrs: ArgAttributes { - regular: ArgAttribute::default(), - arg_ext: ArgExtension::None, - pointee_size: Size::ZERO, - pointee_align: None, - }, - }); + arg.cast_to(CastTarget::prefixed( + [Some(reg), None, None, None, None, None, None, None], + Uniform::new(Reg::i8(), Size::ZERO), + )); } else { arg.cast_to(Uniform::new(reg, size)); } @@ -78,11 +72,10 @@ where }; if arg.layout.size.bytes() / align_bytes == 1 { // Make sure we pass the struct as array at the LLVM IR level and not as a single integer. - arg.cast_to(CastTarget { - prefix: [Some(unit), None, None, None, None, None, None, None], - rest: Uniform::new(unit, Size::ZERO), - attrs: ArgAttributes::new(), - }); + arg.cast_to(CastTarget::prefixed( + [Some(unit), None, None, None, None, None, None, None], + Uniform::new(unit, Size::ZERO), + )); } else { arg.cast_to(Uniform::new(unit, arg.layout.size)); } diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs index cd1d3cd1eee..6a2038f9381 100644 --- a/compiler/rustc_target/src/callconv/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs @@ -14,16 +14,16 @@ use crate::spec::HasTargetSpec; #[derive(Copy, Clone)] enum RegPassKind { - Float(Reg), - Integer(Reg), + Float { offset_from_start: Size, ty: Reg }, + Integer { offset_from_start: Size, ty: Reg }, Unknown, } #[derive(Copy, Clone)] enum FloatConv { - FloatPair(Reg, Reg), + FloatPair { first_ty: Reg, second_ty_offset_from_start: Size, second_ty: Reg }, Float(Reg), - MixedPair(Reg, Reg), + MixedPair { first_ty: Reg, second_ty_offset_from_start: Size, second_ty: Reg }, } #[derive(Copy, Clone)] @@ -43,6 +43,7 @@ fn should_use_fp_conv_helper<'a, Ty, C>( flen: u64, field1_kind: &mut RegPassKind, field2_kind: &mut RegPassKind, + offset_from_start: Size, ) -> Result<(), CannotUseFpConv> where Ty: TyAbiInterface<'a, C> + Copy, @@ -55,16 +56,16 @@ where } match (*field1_kind, *field2_kind) { (RegPassKind::Unknown, _) => { - *field1_kind = RegPassKind::Integer(Reg { - kind: RegKind::Integer, - size: arg_layout.size, - }); + *field1_kind = RegPassKind::Integer { + offset_from_start, + ty: Reg { kind: RegKind::Integer, size: arg_layout.size }, + }; } - (RegPassKind::Float(_), RegPassKind::Unknown) => { - *field2_kind = RegPassKind::Integer(Reg { - kind: RegKind::Integer, - size: arg_layout.size, - }); + (RegPassKind::Float { .. }, RegPassKind::Unknown) => { + *field2_kind = RegPassKind::Integer { + offset_from_start, + ty: Reg { kind: RegKind::Integer, size: arg_layout.size }, + }; } _ => return Err(CannotUseFpConv), } @@ -75,12 +76,16 @@ where } match (*field1_kind, *field2_kind) { (RegPassKind::Unknown, _) => { - *field1_kind = - RegPassKind::Float(Reg { kind: RegKind::Float, size: arg_layout.size }); + *field1_kind = RegPassKind::Float { + offset_from_start, + ty: Reg { kind: RegKind::Float, size: arg_layout.size }, + }; } (_, RegPassKind::Unknown) => { - *field2_kind = - RegPassKind::Float(Reg { kind: RegKind::Float, size: arg_layout.size }); + *field2_kind = RegPassKind::Float { + offset_from_start, + ty: Reg { kind: RegKind::Float, size: arg_layout.size }, + }; } _ => return Err(CannotUseFpConv), } @@ -102,13 +107,14 @@ where flen, field1_kind, field2_kind, + offset_from_start, ); } return Err(CannotUseFpConv); } } FieldsShape::Array { count, .. } => { - for _ in 0..count { + for i in 0..count { let elem_layout = arg_layout.field(cx, 0); should_use_fp_conv_helper( cx, @@ -117,6 +123,7 @@ where flen, field1_kind, field2_kind, + offset_from_start + elem_layout.size * i, )?; } } @@ -127,7 +134,15 @@ where } for i in arg_layout.fields.index_by_increasing_offset() { let field = arg_layout.field(cx, i); - should_use_fp_conv_helper(cx, &field, xlen, flen, field1_kind, field2_kind)?; + should_use_fp_conv_helper( + cx, + &field, + xlen, + flen, + field1_kind, + field2_kind, + offset_from_start + arg_layout.fields.offset(i), + )?; } } }, @@ -146,14 +161,52 @@ where { let mut field1_kind = RegPassKind::Unknown; let mut field2_kind = RegPassKind::Unknown; - if should_use_fp_conv_helper(cx, arg, xlen, flen, &mut field1_kind, &mut field2_kind).is_err() { + if should_use_fp_conv_helper( + cx, + arg, + xlen, + flen, + &mut field1_kind, + &mut field2_kind, + Size::ZERO, + ) + .is_err() + { return None; } match (field1_kind, field2_kind) { - (RegPassKind::Integer(l), RegPassKind::Float(r)) => Some(FloatConv::MixedPair(l, r)), - (RegPassKind::Float(l), RegPassKind::Integer(r)) => Some(FloatConv::MixedPair(l, r)), - (RegPassKind::Float(l), RegPassKind::Float(r)) => Some(FloatConv::FloatPair(l, r)), - (RegPassKind::Float(f), RegPassKind::Unknown) => Some(FloatConv::Float(f)), + ( + RegPassKind::Integer { offset_from_start, .. } + | RegPassKind::Float { offset_from_start, .. }, + _, + ) if offset_from_start != Size::ZERO => { + panic!("type {:?} has a first field with non-zero offset {offset_from_start:?}", arg.ty) + } + ( + RegPassKind::Integer { ty: first_ty, .. }, + RegPassKind::Float { offset_from_start, ty: second_ty }, + ) => Some(FloatConv::MixedPair { + first_ty, + second_ty_offset_from_start: offset_from_start, + second_ty, + }), + ( + RegPassKind::Float { ty: first_ty, .. }, + RegPassKind::Integer { offset_from_start, ty: second_ty }, + ) => Some(FloatConv::MixedPair { + first_ty, + second_ty_offset_from_start: offset_from_start, + second_ty, + }), + ( + RegPassKind::Float { ty: first_ty, .. }, + RegPassKind::Float { offset_from_start, ty: second_ty }, + ) => Some(FloatConv::FloatPair { + first_ty, + second_ty_offset_from_start: offset_from_start, + second_ty, + }), + (RegPassKind::Float { ty, .. }, RegPassKind::Unknown) => Some(FloatConv::Float(ty)), _ => None, } } @@ -171,11 +224,19 @@ where FloatConv::Float(f) => { arg.cast_to(f); } - FloatConv::FloatPair(l, r) => { - arg.cast_to(CastTarget::pair(l, r)); + FloatConv::FloatPair { first_ty, second_ty_offset_from_start, second_ty } => { + arg.cast_to(CastTarget::offset_pair( + first_ty, + second_ty_offset_from_start, + second_ty, + )); } - FloatConv::MixedPair(l, r) => { - arg.cast_to(CastTarget::pair(l, r)); + FloatConv::MixedPair { first_ty, second_ty_offset_from_start, second_ty } => { + arg.cast_to(CastTarget::offset_pair( + first_ty, + second_ty_offset_from_start, + second_ty, + )); } } return false; @@ -239,15 +300,27 @@ fn classify_arg<'a, Ty, C>( arg.cast_to(f); return; } - Some(FloatConv::FloatPair(l, r)) if *avail_fprs >= 2 => { + Some(FloatConv::FloatPair { first_ty, second_ty_offset_from_start, second_ty }) + if *avail_fprs >= 2 => + { *avail_fprs -= 2; - arg.cast_to(CastTarget::pair(l, r)); + arg.cast_to(CastTarget::offset_pair( + first_ty, + second_ty_offset_from_start, + second_ty, + )); return; } - Some(FloatConv::MixedPair(l, r)) if *avail_fprs >= 1 && *avail_gprs >= 1 => { + Some(FloatConv::MixedPair { first_ty, second_ty_offset_from_start, second_ty }) + if *avail_fprs >= 1 && *avail_gprs >= 1 => + { *avail_gprs -= 1; *avail_fprs -= 1; - arg.cast_to(CastTarget::pair(l, r)); + arg.cast_to(CastTarget::offset_pair( + first_ty, + second_ty_offset_from_start, + second_ty, + )); return; } _ => (), diff --git a/compiler/rustc_target/src/callconv/sparc64.rs b/compiler/rustc_target/src/callconv/sparc64.rs index 7ca0031fc59..186826c08fc 100644 --- a/compiler/rustc_target/src/callconv/sparc64.rs +++ b/compiler/rustc_target/src/callconv/sparc64.rs @@ -5,9 +5,7 @@ use rustc_abi::{ TyAndLayout, }; -use crate::callconv::{ - ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, Uniform, -}; +use crate::callconv::{ArgAbi, ArgAttribute, CastTarget, FnAbi, Uniform}; use crate::spec::HasTargetSpec; #[derive(Clone, Debug)] @@ -197,16 +195,10 @@ where rest_size = rest_size - Reg::i32().size; } - arg.cast_to(CastTarget { - prefix: data.prefix, - rest: Uniform::new(Reg::i64(), rest_size), - attrs: ArgAttributes { - regular: data.arg_attribute, - arg_ext: ArgExtension::None, - pointee_size: Size::ZERO, - pointee_align: None, - }, - }); + arg.cast_to( + CastTarget::prefixed(data.prefix, Uniform::new(Reg::i64(), rest_size)) + .with_attrs(data.arg_attribute.into()), + ); return; } } diff --git a/tests/assembly/riscv-float-struct-abi.rs b/tests/assembly/riscv-float-struct-abi.rs new file mode 100644 index 00000000000..5d9ac9d70b8 --- /dev/null +++ b/tests/assembly/riscv-float-struct-abi.rs @@ -0,0 +1,177 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ compile-flags: -Copt-level=3 --target riscv64gc-unknown-linux-gnu +//@ needs-llvm-components: riscv + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +#[repr(C, align(64))] +struct Aligned(f64); + +#[repr(C)] +struct Padded(u8, Aligned); + +#[repr(C, packed)] +struct Packed(u8, f32); + +impl Copy for Aligned {} +impl Copy for Padded {} +impl Copy for Packed {} + +extern "C" { + fn take_padded(x: Padded); + fn get_padded() -> Padded; + fn take_packed(x: Packed); + fn get_packed() -> Packed; +} + +// CHECK-LABEL: pass_padded +#[unsafe(no_mangle)] +extern "C" fn pass_padded(out: &mut Padded, x: Padded) { + // CHECK: sb a1, 0(a0) + // CHECK-NEXT: fsd fa0, 64(a0) + // CHECK-NEXT: ret + *out = x; +} + +// CHECK-LABEL: ret_padded +#[unsafe(no_mangle)] +extern "C" fn ret_padded(x: &Padded) -> Padded { + // CHECK: fld fa0, 64(a0) + // CHECK-NEXT: lbu a0, 0(a0) + // CHECK-NEXT: ret + *x +} + +#[unsafe(no_mangle)] +extern "C" fn call_padded(x: &Padded) { + // CHECK: fld fa0, 64(a0) + // CHECK-NEXT: lbu a0, 0(a0) + // CHECK-NEXT: tail take_padded + unsafe { + take_padded(*x); + } +} + +#[unsafe(no_mangle)] +extern "C" fn receive_padded(out: &mut Padded) { + // CHECK: addi sp, sp, -16 + // CHECK-NEXT: .cfi_def_cfa_offset 16 + // CHECK-NEXT: sd ra, [[#%d,RA_SPILL:]](sp) + // CHECK-NEXT: sd [[TEMP:.*]], [[#%d,TEMP_SPILL:]](sp) + // CHECK-NEXT: .cfi_offset ra, [[#%d,RA_SPILL - 16]] + // CHECK-NEXT: .cfi_offset [[TEMP]], [[#%d,TEMP_SPILL - 16]] + // CHECK-NEXT: mv [[TEMP]], a0 + // CHECK-NEXT: call get_padded + // CHECK-NEXT: sb a0, 0([[TEMP]]) + // CHECK-NEXT: fsd fa0, 64([[TEMP]]) + // CHECK-NEXT: ld ra, [[#%d,RA_SPILL]](sp) + // CHECK-NEXT: ld [[TEMP]], [[#%d,TEMP_SPILL]](sp) + // CHECK: addi sp, sp, 16 + // CHECK: ret + unsafe { + *out = get_padded(); + } +} + +// CHECK-LABEL: pass_packed +#[unsafe(no_mangle)] +extern "C" fn pass_packed(out: &mut Packed, x: Packed) { + // CHECK: addi sp, sp, -16 + // CHECK-NEXT: .cfi_def_cfa_offset 16 + // CHECK-NEXT: sb a1, 0(a0) + // CHECK-NEXT: fsw fa0, 8(sp) + // CHECK-NEXT: lw [[VALUE:.*]], 8(sp) + // CHECK-DAG: srli [[BYTE4:.*]], [[VALUE]], 24 + // CHECK-DAG: srli [[BYTE3:.*]], [[VALUE]], 16 + // CHECK-DAG: srli [[BYTE2:.*]], [[VALUE]], 8 + // CHECK-DAG: sb [[VALUE]], 1(a0) + // CHECK-DAG: sb [[BYTE2]], 2(a0) + // CHECK-DAG: sb [[BYTE3]], 3(a0) + // CHECK-DAG: sb [[BYTE4]], 4(a0) + // CHECK-NEXT: addi sp, sp, 16 + // CHECK: ret + *out = x; +} + +// CHECK-LABEL: ret_packed +#[unsafe(no_mangle)] +extern "C" fn ret_packed(x: &Packed) -> Packed { + // CHECK: addi sp, sp, -16 + // CHECK-NEXT: .cfi_def_cfa_offset 16 + // CHECK-NEXT: lbu [[BYTE2:.*]], 2(a0) + // CHECK-NEXT: lbu [[BYTE1:.*]], 1(a0) + // CHECK-NEXT: lbu [[BYTE3:.*]], 3(a0) + // CHECK-NEXT: lbu [[BYTE4:.*]], 4(a0) + // CHECK-NEXT: slli [[SHIFTED2:.*]], [[BYTE2]], 8 + // CHECK-NEXT: or [[BYTE12:.*]], [[SHIFTED2]], [[BYTE1]] + // CHECK-NEXT: slli [[SHIFTED3:.*]], [[BYTE3]], 16 + // CHECK-NEXT: slli [[SHIFTED4:.*]], [[BYTE4]], 24 + // CHECK-NEXT: or [[BYTE34:.*]], [[SHIFTED3]], [[SHIFTED4]] + // CHECK-NEXT: or [[VALUE:.*]], [[BYTE12]], [[BYTE34]] + // CHECK-NEXT: sw [[VALUE]], 8(sp) + // CHECK-NEXT: flw fa0, 8(sp) + // CHECK-NEXT: lbu a0, 0(a0) + // CHECK-NEXT: addi sp, sp, 16 + // CHECK: ret + *x +} + +#[unsafe(no_mangle)] +extern "C" fn call_packed(x: &Packed) { + // CHECK: addi sp, sp, -16 + // CHECK-NEXT: .cfi_def_cfa_offset 16 + // CHECK-NEXT: lbu [[BYTE2:.*]], 2(a0) + // CHECK-NEXT: lbu [[BYTE1:.*]], 1(a0) + // CHECK-NEXT: lbu [[BYTE3:.*]], 3(a0) + // CHECK-NEXT: lbu [[BYTE4:.*]], 4(a0) + // CHECK-NEXT: slli [[SHIFTED2:.*]], [[BYTE2]], 8 + // CHECK-NEXT: or [[BYTE12:.*]], [[SHIFTED2]], [[BYTE1]] + // CHECK-NEXT: slli [[SHIFTED3:.*]], [[BYTE3]], 16 + // CHECK-NEXT: slli [[SHIFTED4:.*]], [[BYTE4]], 24 + // CHECK-NEXT: or [[BYTE34:.*]], [[SHIFTED3]], [[SHIFTED4]] + // CHECK-NEXT: or [[VALUE:.*]], [[BYTE12]], [[BYTE34]] + // CHECK-NEXT: sw [[VALUE]], 8(sp) + // CHECK-NEXT: flw fa0, 8(sp) + // CHECK-NEXT: lbu a0, 0(a0) + // CHECK-NEXT: addi sp, sp, 16 + // CHECK: tail take_packed + unsafe { + take_packed(*x); + } +} + +#[unsafe(no_mangle)] +extern "C" fn receive_packed(out: &mut Packed) { + // CHECK: addi sp, sp, -32 + // CHECK-NEXT: .cfi_def_cfa_offset 32 + // CHECK-NEXT: sd ra, [[#%d,RA_SPILL:]](sp) + // CHECK-NEXT: sd [[TEMP:.*]], [[#%d,TEMP_SPILL:]](sp) + // CHECK-NEXT: .cfi_offset ra, [[#%d,RA_SPILL - 32]] + // CHECK-NEXT: .cfi_offset [[TEMP]], [[#%d,TEMP_SPILL - 32]] + // CHECK-NEXT: mv [[TEMP]], a0 + // CHECK-NEXT: call get_packed + // CHECK-NEXT: sb a0, 0([[TEMP]]) + // CHECK-NEXT: fsw fa0, [[FLOAT_SPILL:.*]](sp) + // CHECK-NEXT: lw [[VALUE:.*]], [[FLOAT_SPILL]](sp) + // CHECK-DAG: srli [[BYTE4:.*]], [[VALUE]], 24 + // CHECK-DAG: srli [[BYTE3:.*]], [[VALUE]], 16 + // CHECK-DAG: srli [[BYTE2:.*]], [[VALUE]], 8 + // CHECK-DAG: sb [[VALUE]], 1([[TEMP]]) + // CHECK-DAG: sb [[BYTE2]], 2([[TEMP]]) + // CHECK-DAG: sb [[BYTE3]], 3([[TEMP]]) + // CHECK-DAG: sb [[BYTE4]], 4([[TEMP]]) + // CHECK-NEXT: ld ra, [[#%d,RA_SPILL]](sp) + // CHECK-NEXT: ld [[TEMP]], [[#%d,TEMP_SPILL]](sp) + // CHECK: addi sp, sp, 32 + // CHECK: ret + unsafe { + *out = get_packed(); + } +} diff --git a/tests/codegen/riscv-abi/cast-local-large-enough.rs b/tests/codegen/riscv-abi/cast-local-large-enough.rs new file mode 100644 index 00000000000..9d21d73b459 --- /dev/null +++ b/tests/codegen/riscv-abi/cast-local-large-enough.rs @@ -0,0 +1,44 @@ +//@ add-core-stubs +//@ compile-flags: -Copt-level=0 -Cdebuginfo=0 --target riscv64gc-unknown-linux-gnu +//@ needs-llvm-components: riscv + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +#[repr(C, align(64))] +struct Aligned(f64); + +#[repr(C, align(64))] +struct AlignedPair(f32, f64); + +impl Copy for Aligned {} +impl Copy for AlignedPair {} + +// CHECK-LABEL: define double @read_aligned +#[unsafe(no_mangle)] +pub extern "C" fn read_aligned(x: &Aligned) -> Aligned { + // CHECK: %[[TEMP:.*]] = alloca [64 x i8], align 64 + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 64 %[[TEMP]], ptr align 64 %[[PTR:.*]], i64 64, i1 false) + // CHECK-NEXT: %[[RES:.*]] = load double, ptr %[[TEMP]], align 64 + // CHECK-NEXT: ret double %[[RES]] + *x +} + +// CHECK-LABEL: define { float, double } @read_aligned_pair +#[unsafe(no_mangle)] +pub extern "C" fn read_aligned_pair(x: &AlignedPair) -> AlignedPair { + // CHECK: %[[TEMP:.*]] = alloca [64 x i8], align 64 + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 64 %[[TEMP]], ptr align 64 %[[PTR:.*]], i64 64, i1 false) + // CHECK-NEXT: %[[FIRST:.*]] = load float, ptr %[[TEMP]], align 64 + // CHECK-NEXT: %[[SECOND_PTR:.*]] = getelementptr inbounds i8, ptr %[[TEMP]], i64 8 + // CHECK-NEXT: %[[SECOND:.*]] = load double, ptr %[[SECOND_PTR]], align 8 + // CHECK-NEXT: %[[RES1:.*]] = insertvalue { float, double } poison, float %[[FIRST]], 0 + // CHECK-NEXT: %[[RES2:.*]] = insertvalue { float, double } %[[RES1]], double %[[SECOND]], 1 + // CHECK-NEXT: ret { float, double } %[[RES2]] + *x +} diff --git a/tests/ui/abi/numbers-arithmetic/float-struct.rs b/tests/ui/abi/numbers-arithmetic/float-struct.rs new file mode 100644 index 00000000000..a958dc27272 --- /dev/null +++ b/tests/ui/abi/numbers-arithmetic/float-struct.rs @@ -0,0 +1,44 @@ +//@ run-pass + +use std::fmt::Debug; +use std::hint::black_box; + +#[repr(C)] +#[derive(Copy, Clone, PartialEq, Debug, Default)] +struct Regular(f32, f64); + +#[repr(C, packed)] +#[derive(Copy, Clone, PartialEq, Debug, Default)] +struct Packed(f32, f64); + +#[repr(C, align(64))] +#[derive(Copy, Clone, PartialEq, Debug, Default)] +struct AlignedF32(f32); + +#[repr(C)] +#[derive(Copy, Clone, PartialEq, Debug, Default)] +struct Aligned(f64, AlignedF32); + +#[inline(never)] +extern "C" fn read(x: &T) -> T { + *black_box(x) +} + +#[inline(never)] +extern "C" fn write(x: T, dest: &mut T) { + *dest = black_box(x) +} + +#[track_caller] +fn check(x: T) { + assert_eq!(read(&x), x); + let mut out = T::default(); + write(x, &mut out); + assert_eq!(out, x); +} + +fn main() { + check(Regular(1.0, 2.0)); + check(Packed(3.0, 4.0)); + check(Aligned(5.0, AlignedF32(6.0))); +} -- cgit 1.4.1-3-g733a5 From 7d3a1d49ab6bba49eae6536c77fc52152c9e3768 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Mon, 16 Jun 2025 10:36:15 -0700 Subject: make more CodegenCx function generic --- compiler/rustc_codegen_llvm/src/common.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 3cfa96393e9..ae5add59322 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -99,14 +99,14 @@ impl<'ll, CX: Borrow>> BackendTypes for GenericCx<'ll, CX> { type DIVariable = &'ll llvm::debuginfo::DIVariable; } -impl<'ll> CodegenCx<'ll, '_> { +impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { pub(crate) fn const_array(&self, ty: &'ll Type, elts: &[&'ll Value]) -> &'ll Value { let len = u64::try_from(elts.len()).expect("LLVMConstArray2 elements len overflow"); unsafe { llvm::LLVMConstArray2(ty, elts.as_ptr(), len) } } pub(crate) fn const_bytes(&self, bytes: &[u8]) -> &'ll Value { - bytes_in_context(self.llcx, bytes) + bytes_in_context(self.llcx(), bytes) } pub(crate) fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value { -- cgit 1.4.1-3-g733a5 From 6906b44e1c667705ce04626901a75d51f4910de3 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Thu, 15 May 2025 16:38:46 -0700 Subject: Change __rust_no_alloc_shim_is_unstable to be a function --- compiler/rustc_ast/src/expand/allocator.rs | 2 +- compiler/rustc_codegen_cranelift/src/allocator.rs | 40 +++++++---- compiler/rustc_codegen_gcc/src/allocator.rs | 78 ++++++++++++---------- compiler/rustc_codegen_llvm/src/allocator.rs | 74 +++++++++++--------- .../rustc_codegen_ssa/src/back/symbol_export.rs | 14 +--- compiler/rustc_symbol_mangling/src/v0.rs | 4 -- library/alloc/src/alloc.rs | 7 +- src/tools/miri/src/shims/extern_static.rs | 4 -- src/tools/miri/src/shims/foreign_items.rs | 4 ++ src/tools/miri/tests/pass/alloc-access-tracking.rs | 4 +- tests/codegen/alloc-optimisation.rs | 3 +- tests/codegen/unwind-landingpad-inline.rs | 6 +- tests/codegen/vec-iter-collect-len.rs | 6 +- tests/codegen/vec-optimizes-away.rs | 3 +- tests/run-make/no-alloc-shim/foo.rs | 6 +- tests/run-make/no-alloc-shim/rmake.rs | 22 ++++-- tests/run-make/symbols-all-mangled/rmake.rs | 8 --- tests/ui/sanitizer/dataflow-abilist.txt | 1 + 18 files changed, 155 insertions(+), 131 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_ast/src/expand/allocator.rs b/compiler/rustc_ast/src/expand/allocator.rs index dd8d5ae624a..7dee2ed17b4 100644 --- a/compiler/rustc_ast/src/expand/allocator.rs +++ b/compiler/rustc_ast/src/expand/allocator.rs @@ -22,7 +22,7 @@ pub fn alloc_error_handler_name(alloc_error_handler_kind: AllocatorKind) -> &'st } } -pub const NO_ALLOC_SHIM_IS_UNSTABLE: &str = "__rust_no_alloc_shim_is_unstable"; +pub const NO_ALLOC_SHIM_IS_UNSTABLE: &str = "__rust_no_alloc_shim_is_unstable_v2"; pub enum AllocatorTy { Layout, diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs index 9cff8a84db3..ffb932a3c38 100644 --- a/compiler/rustc_codegen_cranelift/src/allocator.rs +++ b/compiler/rustc_codegen_cranelift/src/allocator.rs @@ -1,6 +1,7 @@ //! Allocator shim // Adapted from rustc +use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use rustc_ast::expand::allocator::{ ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, alloc_error_handler_name, default_fn_name, global_fn_name, @@ -97,16 +98,31 @@ fn codegen_inner( data.define(Box::new([val])); module.define_data(data_id, &data).unwrap(); - let data_id = module - .declare_data( - &mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), - Linkage::Export, - false, - false, - ) - .unwrap(); - let mut data = DataDescription::new(); - data.set_align(1); - data.define(Box::new([0])); - module.define_data(data_id, &data).unwrap(); + { + let sig = Signature { + call_conv: module.target_config().default_call_conv, + params: vec![], + returns: vec![], + }; + let func_id = module + .declare_function( + &mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), + Linkage::Export, + &sig, + ) + .unwrap(); + + let mut ctx = Context::new(); + ctx.func.signature = sig; + let mut func_ctx = FunctionBuilderContext::new(); + let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); + + let block = bcx.create_block(); + bcx.switch_to_block(block); + bcx.ins().return_(&[]); + bcx.seal_all_blocks(); + bcx.finalize(); + + module.define_function(func_id, &mut ctx).unwrap(); + } } diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs index f4ebd42ee2d..cf8aa500c77 100644 --- a/compiler/rustc_codegen_gcc/src/allocator.rs +++ b/compiler/rustc_codegen_gcc/src/allocator.rs @@ -57,7 +57,7 @@ pub(crate) unsafe fn codegen( let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name)); let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name)); - create_wrapper_function(tcx, context, &from_name, &to_name, &types, output); + create_wrapper_function(tcx, context, &from_name, Some(&to_name), &types, output); } } @@ -66,7 +66,7 @@ pub(crate) unsafe fn codegen( tcx, context, &mangle_internal_symbol(tcx, "__rust_alloc_error_handler"), - &mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind)), + Some(&mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind))), &[usize, usize], None, ); @@ -81,21 +81,21 @@ pub(crate) unsafe fn codegen( let value = context.new_rvalue_from_int(i8, value as i32); global.global_set_initializer_rvalue(value); - let name = mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE); - let global = context.new_global(None, GlobalKind::Exported, i8, name); - #[cfg(feature = "master")] - global.add_attribute(VarAttribute::Visibility(symbol_visibility_to_gcc( - tcx.sess.default_visibility(), - ))); - let value = context.new_rvalue_from_int(i8, 0); - global.global_set_initializer_rvalue(value); + create_wrapper_function( + tcx, + context, + &mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), + None, + &[], + None, + ); } fn create_wrapper_function( tcx: TyCtxt<'_>, context: &Context<'_>, from_name: &str, - to_name: &str, + to_name: Option<&str>, types: &[Type<'_>], output: Option>, ) { @@ -124,34 +124,40 @@ fn create_wrapper_function( // TODO(antoyo): emit unwind tables. } - let args: Vec<_> = types - .iter() - .enumerate() - .map(|(index, typ)| context.new_parameter(None, *typ, format!("param{}", index))) - .collect(); - let callee = context.new_function( - None, - FunctionType::Extern, - output.unwrap_or(void), - &args, - to_name, - false, - ); - #[cfg(feature = "master")] - callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); - let block = func.new_block("entry"); - let args = args - .iter() - .enumerate() - .map(|(i, _)| func.get_param(i as i32).to_rvalue()) - .collect::>(); - let ret = context.new_call(None, callee, &args); - //llvm::LLVMSetTailCall(ret, True); - if output.is_some() { - block.end_with_return(None, ret); + if let Some(to_name) = to_name { + let args: Vec<_> = types + .iter() + .enumerate() + .map(|(index, typ)| context.new_parameter(None, *typ, format!("param{}", index))) + .collect(); + let callee = context.new_function( + None, + FunctionType::Extern, + output.unwrap_or(void), + &args, + to_name, + false, + ); + #[cfg(feature = "master")] + callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); + + let args = args + .iter() + .enumerate() + .map(|(i, _)| func.get_param(i as i32).to_rvalue()) + .collect::>(); + let ret = context.new_call(None, callee, &args); + //llvm::LLVMSetTailCall(ret, True); + if output.is_some() { + block.end_with_return(None, ret); + } else { + block.add_eval(None, ret); + block.end_with_void_return(None); + } } else { + assert!(output.is_none()); block.end_with_void_return(None); } diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 4a78e694979..9dca63cfc8d 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -57,7 +57,7 @@ pub(crate) unsafe fn codegen( let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name)); let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name)); - create_wrapper_function(tcx, &cx, &from_name, &to_name, &args, output, false); + create_wrapper_function(tcx, &cx, &from_name, Some(&to_name), &args, output, false); } } @@ -66,7 +66,7 @@ pub(crate) unsafe fn codegen( tcx, &cx, &mangle_internal_symbol(tcx, "__rust_alloc_error_handler"), - &mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind)), + Some(&mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind))), &[usize, usize], // size, align None, true, @@ -81,11 +81,16 @@ pub(crate) unsafe fn codegen( let llval = llvm::LLVMConstInt(i8, val as u64, False); llvm::set_initializer(ll_g, llval); - let name = mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE); - let ll_g = cx.declare_global(&name, i8); - llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility())); - let llval = llvm::LLVMConstInt(i8, 0, False); - llvm::set_initializer(ll_g, llval); + // __rust_no_alloc_shim_is_unstable_v2 + create_wrapper_function( + tcx, + &cx, + &mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), + None, + &[], + None, + false, + ); } if tcx.sess.opts.debuginfo != DebugInfo::None { @@ -99,7 +104,7 @@ fn create_wrapper_function( tcx: TyCtxt<'_>, cx: &SimpleCx<'_>, from_name: &str, - to_name: &str, + to_name: Option<&str>, args: &[&Type], output: Option<&Type>, no_return: bool, @@ -128,33 +133,38 @@ fn create_wrapper_function( attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]); } - let callee = declare_simple_fn( - &cx, - to_name, - llvm::CallConv::CCallConv, - llvm::UnnamedAddr::Global, - llvm::Visibility::Hidden, - ty, - ); - if let Some(no_return) = no_return { - // -> ! DIFlagNoReturn - attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]); - } - llvm::set_visibility(callee, llvm::Visibility::Hidden); - let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(cx.llcx, llfn, c"entry".as_ptr()) }; - let mut bx = SBuilder::build(&cx, llbb); - let args = args - .iter() - .enumerate() - .map(|(i, _)| llvm::get_param(llfn, i as c_uint)) - .collect::>(); - let ret = bx.call(ty, callee, &args, None); - llvm::LLVMSetTailCall(ret, True); - if output.is_some() { - bx.ret(ret); + + if let Some(to_name) = to_name { + let callee = declare_simple_fn( + &cx, + to_name, + llvm::CallConv::CCallConv, + llvm::UnnamedAddr::Global, + llvm::Visibility::Hidden, + ty, + ); + if let Some(no_return) = no_return { + // -> ! DIFlagNoReturn + attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]); + } + llvm::set_visibility(callee, llvm::Visibility::Hidden); + + let args = args + .iter() + .enumerate() + .map(|(i, _)| llvm::get_param(llfn, i as c_uint)) + .collect::>(); + let ret = bx.call(ty, callee, &args, None); + llvm::LLVMSetTailCall(ret, True); + if output.is_some() { + bx.ret(ret); + } else { + bx.ret_void() + } } else { + assert!(output.is_none()); bx.ret_void() } } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 92b9b6e132e..d0b6c7470fb 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -219,6 +219,7 @@ fn exported_symbols_provider_local<'tcx>( .chain([ mangle_internal_symbol(tcx, "__rust_alloc_error_handler"), mangle_internal_symbol(tcx, OomStrategy::SYMBOL), + mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), ]) { let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name)); @@ -232,19 +233,6 @@ fn exported_symbols_provider_local<'tcx>( }, )); } - - let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new( - tcx, - &mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), - )); - symbols.push(( - exported_symbol, - SymbolExportInfo { - level: SymbolExportLevel::Rust, - kind: SymbolExportKind::Data, - used: false, - }, - )) } if tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled() { diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 49a5e20d7cf..1db8ad72b32 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -85,10 +85,6 @@ pub fn mangle_internal_symbol<'tcx>(tcx: TyCtxt<'tcx>, item_name: &str) -> Strin if item_name == "rust_eh_personality" { // rust_eh_personality must not be renamed as LLVM hard-codes the name return "rust_eh_personality".to_owned(); - } else if item_name == "__rust_no_alloc_shim_is_unstable" { - // Temporary back compat hack to give people the chance to migrate to - // include #[rustc_std_internal_symbol]. - return "__rust_no_alloc_shim_is_unstable".to_owned(); } let prefix = "_R"; diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index e1cc4ba25c4..b4176e9c1f4 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -31,8 +31,9 @@ unsafe extern "Rust" { #[rustc_std_internal_symbol] fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; + #[rustc_nounwind] #[rustc_std_internal_symbol] - static __rust_no_alloc_shim_is_unstable: u8; + fn __rust_no_alloc_shim_is_unstable_v2(); } /// The global memory allocator. @@ -88,7 +89,7 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 { unsafe { // Make sure we don't accidentally allow omitting the allocator shim in // stable code until it is actually stabilized. - core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable); + __rust_no_alloc_shim_is_unstable_v2(); __rust_alloc(layout.size(), layout.align()) } @@ -171,7 +172,7 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { unsafe { // Make sure we don't accidentally allow omitting the allocator shim in // stable code until it is actually stabilized. - core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable); + __rust_no_alloc_shim_is_unstable_v2(); __rust_alloc_zeroed(layout.size(), layout.align()) } diff --git a/src/tools/miri/src/shims/extern_static.rs b/src/tools/miri/src/shims/extern_static.rs index 2feed5a8352..a2ea3dbd88b 100644 --- a/src/tools/miri/src/shims/extern_static.rs +++ b/src/tools/miri/src/shims/extern_static.rs @@ -45,10 +45,6 @@ impl<'tcx> MiriMachine<'tcx> { /// Sets up the "extern statics" for this machine. pub fn init_extern_statics(ecx: &mut MiriInterpCx<'tcx>) -> InterpResult<'tcx> { - // "__rust_no_alloc_shim_is_unstable" - let val = ImmTy::from_int(0, ecx.machine.layouts.u8); // always 0, value does not matter - Self::alloc_extern_static(ecx, "__rust_no_alloc_shim_is_unstable", val)?; - // "__rust_alloc_error_handler_should_panic" let val = ecx.tcx.sess.opts.unstable_opts.oom.should_panic(); let val = ImmTy::from_int(val, ecx.machine.layouts.u8); diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 39b930fdeb9..416cb1ab55e 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -611,6 +611,10 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(new_ptr, dest) }); } + name if name == this.mangle_internal_symbol("__rust_no_alloc_shim_is_unstable_v2") => { + // This is a no-op shim that only exists to prevent making the allocator shims instantly stable. + let [] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?; + } // C memory handling functions "memcmp" => { diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.rs b/src/tools/miri/tests/pass/alloc-access-tracking.rs index 0e88951dc43..9eba0ca171b 100644 --- a/src/tools/miri/tests/pass/alloc-access-tracking.rs +++ b/src/tools/miri/tests/pass/alloc-access-tracking.rs @@ -1,7 +1,7 @@ #![no_std] #![no_main] -//@compile-flags: -Zmiri-track-alloc-id=20 -Zmiri-track-alloc-accesses -Cpanic=abort -//@normalize-stderr-test: "id 20" -> "id $$ALLOC" +//@compile-flags: -Zmiri-track-alloc-id=19 -Zmiri-track-alloc-accesses -Cpanic=abort +//@normalize-stderr-test: "id 19" -> "id $$ALLOC" //@only-target: linux # alloc IDs differ between OSes (due to extern static allocations) extern "Rust" { diff --git a/tests/codegen/alloc-optimisation.rs b/tests/codegen/alloc-optimisation.rs index 19f14647c1d..3735860d510 100644 --- a/tests/codegen/alloc-optimisation.rs +++ b/tests/codegen/alloc-optimisation.rs @@ -5,7 +5,8 @@ pub fn alloc_test(data: u32) { // CHECK-LABEL: @alloc_test // CHECK-NEXT: start: - // CHECK-NEXT: {{.*}} load volatile i8, ptr @{{.*}}__rust_no_alloc_shim_is_unstable, align 1 + // CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 + // CHECK-NEXT: tail call void @_R{{.+}}__rust_no_alloc_shim_is_unstable_v2() // CHECK-NEXT: ret void let x = Box::new(data); drop(x); diff --git a/tests/codegen/unwind-landingpad-inline.rs b/tests/codegen/unwind-landingpad-inline.rs index 920774b3402..1cf606279e6 100644 --- a/tests/codegen/unwind-landingpad-inline.rs +++ b/tests/codegen/unwind-landingpad-inline.rs @@ -10,8 +10,10 @@ // See https://github.com/rust-lang/rust/issues/46515 // CHECK-LABEL: @check_no_escape_in_landingpad // CHECK: start: -// CHECK-NEXT: __rust_no_alloc_shim_is_unstable -// CHECK-NEXT: __rust_no_alloc_shim_is_unstable +// CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 +// CHECK-NEXT: tail call void @[[NO_ALLOC_SHIM:_R.+__rust_no_alloc_shim_is_unstable_v2]]() +// CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 +// CHECK-NEXT: tail call void @[[NO_ALLOC_SHIM]]() // CHECK-NEXT: ret void #[no_mangle] pub fn check_no_escape_in_landingpad(f: fn()) { diff --git a/tests/codegen/vec-iter-collect-len.rs b/tests/codegen/vec-iter-collect-len.rs index a88573522d4..807548ef883 100644 --- a/tests/codegen/vec-iter-collect-len.rs +++ b/tests/codegen/vec-iter-collect-len.rs @@ -4,7 +4,9 @@ #[no_mangle] pub fn get_len() -> usize { // CHECK-LABEL: @get_len - // CHECK-NOT: call - // CHECK-NOT: invoke + // CHECK-NEXT: start: + // CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 + // CHECK-NEXT: tail call void @_R{{.+}}__rust_no_alloc_shim_is_unstable_v2() + // CHECK-NEXT: ret i{{[0-9]+}} 3 [1, 2, 3].iter().collect::>().len() } diff --git a/tests/codegen/vec-optimizes-away.rs b/tests/codegen/vec-optimizes-away.rs index f6ed2898bda..93b55454b10 100644 --- a/tests/codegen/vec-optimizes-away.rs +++ b/tests/codegen/vec-optimizes-away.rs @@ -5,7 +5,8 @@ pub fn sum_me() -> i32 { // CHECK-LABEL: @sum_me // CHECK-NEXT: {{^.*:$}} - // CHECK-NEXT: {{.*}} load volatile i8, ptr @{{.*}}__rust_no_alloc_shim_is_unstable, align 1 + // CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 + // CHECK-NEXT: tail call void @_R{{.+}}__rust_no_alloc_shim_is_unstable_v2() // CHECK-NEXT: ret i32 6 vec![1, 2, 3].iter().sum::() } diff --git a/tests/run-make/no-alloc-shim/foo.rs b/tests/run-make/no-alloc-shim/foo.rs index 42606961f8b..b5d0d394d2b 100644 --- a/tests/run-make/no-alloc-shim/foo.rs +++ b/tests/run-make/no-alloc-shim/foo.rs @@ -1,4 +1,4 @@ -#![feature(default_alloc_error_handler)] +#![feature(rustc_attrs)] #![no_std] #![no_main] @@ -31,8 +31,8 @@ unsafe impl GlobalAlloc for Alloc { } #[cfg(not(check_feature_gate))] -#[no_mangle] -static __rust_no_alloc_shim_is_unstable: u8 = 0; +#[rustc_std_internal_symbol] +fn __rust_no_alloc_shim_is_unstable_v2() {} #[no_mangle] extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const i8) -> i32 { diff --git a/tests/run-make/no-alloc-shim/rmake.rs b/tests/run-make/no-alloc-shim/rmake.rs index d61ef5de8c5..47cabfc208c 100644 --- a/tests/run-make/no-alloc-shim/rmake.rs +++ b/tests/run-make/no-alloc-shim/rmake.rs @@ -7,12 +7,6 @@ //@ ignore-cross-compile // Reason: the compiled binary is executed -//@ ignore-msvc -//FIXME(Oneirical): Getting this to work on MSVC requires passing libcmt.lib to CC, -// which is not trivial to do. -// Tracking issue: https://github.com/rust-lang/rust/issues/128602 -// Discussion: https://github.com/rust-lang/rust/pull/128407#discussion_r1702439172 - use run_make_support::{cc, has_extension, has_prefix, run, rustc, shallow_find_files}; fn main() { @@ -30,15 +24,28 @@ fn main() { has_prefix(path, "libcompiler_builtins") && has_extension(path, "rlib") }); + #[allow(unused_mut)] + let mut platform_args = Vec::::new(); + #[cfg(target_env = "msvc")] + { + platform_args.push("-MD".to_string()); + + // `/link` tells MSVC that the remaining arguments are linker options. + platform_args.push("/link".to_string()); + platform_args.push("vcruntime.lib".to_string()); + platform_args.push("msvcrt.lib".to_string()); + } + cc().input("foo.o") .out_exe("foo") + .args(&platform_args) .args(&alloc_libs) .args(&core_libs) .args(&compiler_builtins_libs) .run(); run("foo"); - // Check that linking without __rust_no_alloc_shim_is_unstable defined fails + // Check that linking without __rust_no_alloc_shim_is_unstable_v2 defined fails rustc() .input("foo.rs") .crate_type("bin") @@ -48,6 +55,7 @@ fn main() { .run(); cc().input("foo.o") .out_exe("foo") + .args(&platform_args) .args(&alloc_libs) .args(&core_libs) .args(&compiler_builtins_libs) diff --git a/tests/run-make/symbols-all-mangled/rmake.rs b/tests/run-make/symbols-all-mangled/rmake.rs index 79ddd06bb94..2cf57975800 100644 --- a/tests/run-make/symbols-all-mangled/rmake.rs +++ b/tests/run-make/symbols-all-mangled/rmake.rs @@ -35,10 +35,6 @@ fn symbols_check_archive(path: &str) { continue; // All compiler-builtins symbols must remain unmangled } - if name == "__rust_no_alloc_shim_is_unstable" { - continue; // FIXME remove exception once we mangle this symbol - } - if name.contains("rust_eh_personality") { continue; // Unfortunately LLVM doesn't allow us to mangle this symbol } @@ -75,10 +71,6 @@ fn symbols_check(path: &str) { continue; } - if name == "__rust_no_alloc_shim_is_unstable" { - continue; // FIXME remove exception once we mangle this symbol - } - if name.contains("rust_eh_personality") { continue; // Unfortunately LLVM doesn't allow us to mangle this symbol } diff --git a/tests/ui/sanitizer/dataflow-abilist.txt b/tests/ui/sanitizer/dataflow-abilist.txt index fe04838f549..3d32397a175 100644 --- a/tests/ui/sanitizer/dataflow-abilist.txt +++ b/tests/ui/sanitizer/dataflow-abilist.txt @@ -503,3 +503,4 @@ fun:__rust_realloc=uninstrumented fun:_ZN4core*=uninstrumented fun:_ZN3std*=uninstrumented fun:rust_eh_personality=uninstrumented +fun:_R*__rustc*=uninstrumented -- cgit 1.4.1-3-g733a5 From 6359123d25e8ff38c6fbf280559d5f829bec691f Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Mon, 16 Jun 2025 14:23:06 -0700 Subject: add and use generic get_const_int function --- compiler/rustc_codegen_llvm/src/builder/autodiff.rs | 4 ++-- compiler/rustc_codegen_llvm/src/context.rs | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index c5c13ac097a..b07d9a5cfca 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -114,7 +114,7 @@ fn match_args_from_caller_to_enzyme<'ll>( let mul = unsafe { llvm::LLVMBuildMul( builder.llbuilder, - cx.get_const_i64(elem_bytes_size), + cx.get_const_int(cx.type_i64(), elem_bytes_size), next_outer_arg, UNNAMED, ) @@ -385,7 +385,7 @@ fn generate_enzyme_call<'ll>( if attrs.width > 1 { let enzyme_width = cx.create_metadata("enzyme_width".to_string()).unwrap(); args.push(cx.get_metadata_value(enzyme_width)); - args.push(cx.get_const_i64(attrs.width as u64)); + args.push(cx.get_const_int(cx.type_i64(), attrs.width as u64)); } let has_sret = has_sret(outer_fn); diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 8d6e1d8941b..0684c69ec00 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -678,11 +678,8 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { llvm::LLVMMetadataAsValue(self.llcx(), metadata) } - // FIXME(autodiff): We should split `ConstCodegenMethods` to pull the reusable parts - // onto a trait that is also implemented for GenericCx. - pub(crate) fn get_const_i64(&self, n: u64) -> &'ll Value { - let ty = unsafe { llvm::LLVMInt64TypeInContext(self.llcx()) }; - unsafe { llvm::LLVMConstInt(ty, n, llvm::False) } + pub(crate) fn get_const_int(&self, ty: &'ll Type, val: u64) -> &'ll Value { + unsafe { llvm::LLVMConstInt(ty, val, llvm::False) } } pub(crate) fn get_function(&self, name: &str) -> Option<&'ll Value> { -- cgit 1.4.1-3-g733a5 From d70ec32ea7e03e3a082a45eeba6c8aa4c653efb4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 May 2025 22:53:38 +0200 Subject: move cfg(target_feature) computation into shared place --- compiler/rustc_codegen_gcc/src/lib.rs | 59 +++++--------- compiler/rustc_codegen_llvm/src/llvm_util.rs | 87 ++------------------ compiler/rustc_codegen_ssa/src/target_features.rs | 99 ++++++++++++++++++++++- 3 files changed, 126 insertions(+), 119 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index aa57655921d..f5ad28681c7 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -103,7 +103,9 @@ use rustc_codegen_ssa::back::write::{ }; use rustc_codegen_ssa::base::codegen_crate; use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBackendMethods}; -use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetConfig}; +use rustc_codegen_ssa::{ + CodegenResults, CompiledModule, ModuleCodegen, TargetConfig, target_features, +}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::IntoDynSyncSend; use rustc_errors::DiagCtxtHandle; @@ -476,42 +478,25 @@ fn to_gcc_opt_level(optlevel: Option) -> OptimizationLevel { /// Returns the features that should be set in `cfg(target_feature)`. fn target_config(sess: &Session, target_info: &LockedTargetInfo) -> TargetConfig { - // TODO(antoyo): use global_gcc_features. - let f = |allow_unstable| { - sess.target - .rust_target_features() - .iter() - .filter_map(|&(feature, gate, _)| { - if allow_unstable - || (gate.in_cfg() - && (sess.is_nightly_build() || gate.requires_nightly().is_none())) - { - Some(feature) - } else { - None - } - }) - .filter(|feature| { - // TODO: we disable Neon for now since we don't support the LLVM intrinsics for it. - if *feature == "neon" { - return false; - } - target_info.cpu_supports(feature) - // cSpell:disable - /* - adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma, - avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq, - bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm, - sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves - */ - // cSpell:enable - }) - .map(Symbol::intern) - .collect() - }; - - let target_features = f(false); - let unstable_target_features = f(true); + let (unstable_target_features, target_features) = target_features::cfg_target_feature( + sess, + /* FIXME: we ignore `-Ctarget-feature` */ "", + |feature| { + // TODO: we disable Neon for now since we don't support the LLVM intrinsics for it. + if feature == "neon" { + return false; + } + target_info.cpu_supports(feature) + // cSpell:disable + /* + adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma, + avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq, + bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm, + sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves + */ + // cSpell:enable + }, + ); let has_reliable_f16 = target_info.supports_target_dependent_type(CType::Float16); let has_reliable_f128 = target_info.supports_target_dependent_type(CType::Float128); diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 0e77bc43df8..f9ebf861634 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -6,9 +6,9 @@ use std::sync::Once; use std::{ptr, slice, str}; use libc::c_int; -use rustc_codegen_ssa::TargetConfig; use rustc_codegen_ssa::base::wants_wasm_eh; use rustc_codegen_ssa::codegen_attrs::check_tied_features; +use rustc_codegen_ssa::{TargetConfig, target_features}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::small_c_str::SmallCStr; use rustc_data_structures::unord::UnordSet; @@ -17,9 +17,8 @@ use rustc_middle::bug; use rustc_session::Session; use rustc_session::config::{PrintKind, PrintRequest}; use rustc_session::features::{StabilityExt, retpoline_features_by_flags}; -use rustc_span::Symbol; use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport}; -use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES}; +use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES; use smallvec::{SmallVec, smallvec}; use crate::back::write::create_informational_target_machine; @@ -343,18 +342,11 @@ pub(crate) fn target_config(sess: &Session) -> TargetConfig { // the target CPU, that is still expanded to target features (with all their implied features) // by LLVM. let target_machine = create_informational_target_machine(sess, true); - // Compute which of the known target features are enabled in the 'base' target machine. We only - // consider "supported" features; "forbidden" features are not reflected in `cfg` as of now. - let mut features: FxHashSet = sess - .target - .rust_target_features() - .iter() - .filter(|(feature, _, _)| { - // skip checking special features, as LLVM may not understand them - if RUSTC_SPECIAL_FEATURES.contains(feature) { - return true; - } + + let (unstable_target_features, target_features) = + target_features::cfg_target_feature(sess, &sess.opts.cg.target_feature, |feature| { if let Some(feat) = to_llvm_features(sess, feature) { + // All the LLVM features this expands to must be enabled. for llvm_feature in feat { let cstr = SmallCStr::new(llvm_feature); // `LLVMRustHasFeature` is moderately expensive. On targets with many @@ -368,73 +360,8 @@ pub(crate) fn target_config(sess: &Session) -> TargetConfig { } else { false } - }) - .map(|(feature, _, _)| Symbol::intern(feature)) - .collect(); - - // Add enabled and remove disabled features. - for (enabled, feature) in - sess.opts.cg.target_feature.split(',').filter_map(|s| match s.chars().next() { - Some('+') => Some((true, Symbol::intern(&s[1..]))), - Some('-') => Some((false, Symbol::intern(&s[1..]))), - _ => None, - }) - { - if enabled { - // Also add all transitively implied features. - - // We don't care about the order in `features` since the only thing we use it for is the - // `features.contains` below. - #[allow(rustc::potential_query_instability)] - features.extend( - sess.target - .implied_target_features(feature.as_str()) - .iter() - .map(|s| Symbol::intern(s)), - ); - } else { - // Remove transitively reverse-implied features. - - // We don't care about the order in `features` since the only thing we use it for is the - // `features.contains` below. - #[allow(rustc::potential_query_instability)] - features.retain(|f| { - if sess.target.implied_target_features(f.as_str()).contains(&feature.as_str()) { - // If `f` if implies `feature`, then `!feature` implies `!f`, so we have to - // remove `f`. (This is the standard logical contraposition principle.) - false - } else { - // We can keep `f`. - true - } - }); - } - } - - // Filter enabled features based on feature gates. - let f = |allow_unstable| { - sess.target - .rust_target_features() - .iter() - .filter_map(|(feature, gate, _)| { - // The `allow_unstable` set is used by rustc internally to determined which target - // features are truly available, so we want to return even perma-unstable - // "forbidden" features. - if allow_unstable - || (gate.in_cfg() - && (sess.is_nightly_build() || gate.requires_nightly().is_none())) - { - Some(Symbol::intern(feature)) - } else { - None - } - }) - .filter(|feature| features.contains(&feature)) - .collect() - }; + }); - let target_features = f(false); - let unstable_target_features = f(true); let mut cfg = TargetConfig { target_features, unstable_target_features, diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 640d197c219..476671d6855 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -1,5 +1,5 @@ use rustc_attr_data_structures::InstructionSetAttr; -use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -8,11 +8,12 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_middle::middle::codegen_fn_attrs::TargetFeature; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; +use rustc_session::Session; use rustc_session::features::StabilityExt; use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; -use rustc_target::target_features::{self, Stability}; +use rustc_target::target_features::{self, RUSTC_SPECIAL_FEATURES, Stability}; use crate::errors; @@ -156,6 +157,100 @@ pub(crate) fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, } } +/// Utility function for a codegen backend to compute `cfg(target_feature)`, or more specifically, +/// to populate `sess.unstable_target_features` and `sess.target_features` (these are the first and +/// 2nd component of the return value, respectively). +/// +/// `target_feature_flag` is the value of `-Ctarget-feature` (giving the caller a chance to override it). +/// `target_base_has_feature` should check whether the given feature (a Rust feature name!) is enabled +/// in the "base" target machine, i.e., without applying `-Ctarget-feature`. +/// +/// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled elsewhere. +pub fn cfg_target_feature( + sess: &Session, + target_feature_flag: &str, + mut is_feature_enabled: impl FnMut(&str) -> bool, +) -> (Vec, Vec) { + // Compute which of the known target features are enabled in the 'base' target machine. We only + // consider "supported" features; "forbidden" features are not reflected in `cfg` as of now. + let mut features: FxHashSet = sess + .target + .rust_target_features() + .iter() + .filter(|(feature, _, _)| { + // Skip checking special features, those are not known to the backend. + if RUSTC_SPECIAL_FEATURES.contains(feature) { + return true; + } + is_feature_enabled(feature) + }) + .map(|(feature, _, _)| Symbol::intern(feature)) + .collect(); + + // Add enabled and remove disabled features. + for (enabled, feature) in + target_feature_flag.split(',').filter_map(|s| match s.chars().next() { + Some('+') => Some((true, Symbol::intern(&s[1..]))), + Some('-') => Some((false, Symbol::intern(&s[1..]))), + _ => None, + }) + { + if enabled { + // Also add all transitively implied features. + + // We don't care about the order in `features` since the only thing we use it for is the + // `features.contains` below. + #[allow(rustc::potential_query_instability)] + features.extend( + sess.target + .implied_target_features(feature.as_str()) + .iter() + .map(|s| Symbol::intern(s)), + ); + } else { + // Remove transitively reverse-implied features. + + // We don't care about the order in `features` since the only thing we use it for is the + // `features.contains` below. + #[allow(rustc::potential_query_instability)] + features.retain(|f| { + if sess.target.implied_target_features(f.as_str()).contains(&feature.as_str()) { + // If `f` if implies `feature`, then `!feature` implies `!f`, so we have to + // remove `f`. (This is the standard logical contraposition principle.) + false + } else { + // We can keep `f`. + true + } + }); + } + } + + // Filter enabled features based on feature gates. + let f = |allow_unstable| { + sess.target + .rust_target_features() + .iter() + .filter_map(|(feature, gate, _)| { + // The `allow_unstable` set is used by rustc internally to determine which target + // features are truly available, so we want to return even perma-unstable + // "forbidden" features. + if allow_unstable + || (gate.in_cfg() + && (sess.is_nightly_build() || gate.requires_nightly().is_none())) + { + Some(Symbol::intern(feature)) + } else { + None + } + }) + .filter(|feature| features.contains(&feature)) + .collect() + }; + + (f(true), f(false)) +} + pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { rust_target_features: |tcx, cnum| { -- cgit 1.4.1-3-g733a5 From cd08652faa37a9119c2cf535b927129b1c4438b7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 23 May 2025 08:07:42 +0200 Subject: move -Ctarget-feature handling into shared code --- compiler/rustc_codegen_gcc/messages.ftl | 16 --- compiler/rustc_codegen_gcc/src/errors.rs | 26 +--- compiler/rustc_codegen_gcc/src/gcc_util.rs | 124 ++++------------- compiler/rustc_codegen_llvm/messages.ftl | 10 -- compiler/rustc_codegen_llvm/src/errors.rs | 26 +--- compiler/rustc_codegen_llvm/src/llvm_util.rs | 160 ++++++--------------- compiler/rustc_codegen_ssa/messages.ftl | 19 +++ compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 26 +--- compiler/rustc_codegen_ssa/src/errors.rs | 89 ++++++++---- compiler/rustc_codegen_ssa/src/target_features.rs | 161 +++++++++++++++++++++- compiler/rustc_session/messages.ftl | 8 -- compiler/rustc_session/src/errors.rs | 17 --- compiler/rustc_session/src/features.rs | 59 -------- compiler/rustc_session/src/lib.rs | 1 - compiler/rustc_session/src/options.rs | 8 -- compiler/rustc_target/src/target_features.rs | 30 ++-- src/librustdoc/json/mod.rs | 5 +- tests/ui/check-cfg/target_feature.stderr | 3 - 18 files changed, 326 insertions(+), 462 deletions(-) delete mode 100644 compiler/rustc_session/src/features.rs (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_gcc/messages.ftl b/compiler/rustc_codegen_gcc/messages.ftl index 18a8a5a1e04..55a28bc9493 100644 --- a/compiler/rustc_codegen_gcc/messages.ftl +++ b/compiler/rustc_codegen_gcc/messages.ftl @@ -1,7 +1,3 @@ -codegen_gcc_unknown_ctarget_feature_prefix = - unknown feature specified for `-Ctarget-feature`: `{$feature}` - .note = features must begin with a `+` to enable or `-` to disable it - codegen_gcc_unwinding_inline_asm = GCC backend does not support unwinding from inline asm @@ -16,15 +12,3 @@ codegen_gcc_lto_disallowed = lto can only be run for executables, cdylibs and st codegen_gcc_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdylib-lto` codegen_gcc_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$gcc_err}) - -codegen_gcc_unknown_ctarget_feature = - unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}` - .note = it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future - .possible_feature = you might have meant: `{$rust_feature}` - .consider_filing_feature_request = consider filing a feature request - -codegen_gcc_missing_features = - add the missing features in a `target_feature` attribute - -codegen_gcc_target_feature_disable_or_enable = - the target features {$features} must all be either enabled or disabled together diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs index 7786be9ae5d..b7e7343460f 100644 --- a/compiler/rustc_codegen_gcc/src/errors.rs +++ b/compiler/rustc_codegen_gcc/src/errors.rs @@ -1,30 +1,6 @@ -use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_macros::Diagnostic; use rustc_span::Span; -#[derive(Diagnostic)] -#[diag(codegen_gcc_unknown_ctarget_feature_prefix)] -#[note] -pub(crate) struct UnknownCTargetFeaturePrefix<'a> { - pub feature: &'a str, -} - -#[derive(Diagnostic)] -#[diag(codegen_gcc_unknown_ctarget_feature)] -#[note] -pub(crate) struct UnknownCTargetFeature<'a> { - pub feature: &'a str, - #[subdiagnostic] - pub rust_feature: PossibleFeature<'a>, -} - -#[derive(Subdiagnostic)] -pub(crate) enum PossibleFeature<'a> { - #[help(codegen_gcc_possible_feature)] - Some { rust_feature: &'a str }, - #[help(codegen_gcc_consider_filing_feature_request)] - None, -} - #[derive(Diagnostic)] #[diag(codegen_gcc_unwinding_inline_asm)] pub(crate) struct UnwindingInlineAsm { diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs index 2e00d5fcb61..562f4124882 100644 --- a/compiler/rustc_codegen_gcc/src/gcc_util.rs +++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs @@ -1,20 +1,11 @@ #[cfg(feature = "master")] use gccjit::Context; -use rustc_codegen_ssa::codegen_attrs::check_tied_features; -use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::unord::UnordSet; +use rustc_codegen_ssa::target_features; use rustc_session::Session; -use rustc_session::features::{StabilityExt, retpoline_features_by_flags}; -use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES; use smallvec::{SmallVec, smallvec}; -use crate::errors::{PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix}; - -fn gcc_features_by_flags(sess: &Session) -> Vec<&str> { - let mut features: Vec<&str> = Vec::new(); - retpoline_features_by_flags(sess, &mut features); - features +fn gcc_features_by_flags(sess: &Session, features: &mut Vec) { + target_features::retpoline_features_by_flags(sess, features); } /// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, @@ -44,98 +35,31 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec. - all_rust_features.push((false, feature)); - } else if !feature.is_empty() && diagnostics { - sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature }); - } - } - // Remove features that are meant for rustc, not codegen. - all_rust_features.retain(|&(_, feature)| { - // Retain if it is not a rustc feature - !RUSTC_SPECIFIC_FEATURES.contains(&feature) - }); - - // Check feature validity. - if diagnostics { - for &(enable, feature) in &all_rust_features { - let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature); - match feature_state { - None => { - let rust_feature = known_features.iter().find_map(|&(rust_feature, _, _)| { - let gcc_features = to_gcc_features(sess, rust_feature); - if gcc_features.contains(&feature) && !gcc_features.contains(&rust_feature) - { - Some(rust_feature) - } else { - None - } - }); - let unknown_feature = if let Some(rust_feature) = rust_feature { - UnknownCTargetFeature { - feature, - rust_feature: PossibleFeature::Some { rust_feature }, - } - } else { - UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None } - }; - sess.dcx().emit_warn(unknown_feature); - } - Some(&(_, stability, _)) => { - stability.verify_feature_enabled_by_flag(sess, enable, feature); - } - } - - // FIXME(nagisa): figure out how to not allocate a full hashset here. - featsmap.insert(feature, enable); - } - } - - // Translate this into GCC features. - let feats = - all_rust_features.iter().flat_map(|&(enable, feature)| { - let enable_disable = if enable { '+' } else { '-' }; + target_features::flag_to_backend_features( + sess, + diagnostics, + |feature| to_gcc_features(sess, feature), + |feature, enable| { // We run through `to_gcc_features` when // passing requests down to GCC. This means that all in-language // features also work on the command line instead of having two // different names when the GCC name and the Rust name differ. - to_gcc_features(sess, feature) - .iter() - .flat_map(|feat| to_gcc_features(sess, feat).into_iter()) - .map(|feature| { - if enable_disable == '-' { - format!("-{}", feature) - } else { - feature.to_string() - } - }) - .collect::>() - }); - features.extend(feats); - - if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) { - sess.dcx().emit_err(TargetFeatureDisableOrEnable { - features: f, - span: None, - missing_features: None, - }); - } + features.extend( + to_gcc_features(sess, feature) + .iter() + .flat_map(|feat| to_gcc_features(sess, feat).into_iter()) + .map( + |feature| { + if !enable { format!("-{}", feature) } else { feature.to_string() } + }, + ), + ); + }, + ); + + gcc_features_by_flags(sess, &mut features); + + // FIXME: LLVM also sets +reserve-x18 here under some conditions. features } diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index 3faeb9b3b22..3885f18271f 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -59,16 +59,6 @@ codegen_llvm_symbol_already_defined = codegen_llvm_target_machine = could not create LLVM TargetMachine for triple: {$triple} codegen_llvm_target_machine_with_llvm_err = could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err} -codegen_llvm_unknown_ctarget_feature = - unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}` - .note = it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future - .possible_feature = you might have meant: `{$rust_feature}` - .consider_filing_feature_request = consider filing a feature request - -codegen_llvm_unknown_ctarget_feature_prefix = - unknown feature specified for `-Ctarget-feature`: `{$feature}` - .note = features must begin with a `+` to enable or `-` to disable it - codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err} diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index 8bc74fbec7e..d50ad8a1a9c 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -3,35 +3,11 @@ use std::path::Path; use rustc_data_structures::small_c_str::SmallCStr; use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level}; -use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_macros::Diagnostic; use rustc_span::Span; use crate::fluent_generated as fluent; -#[derive(Diagnostic)] -#[diag(codegen_llvm_unknown_ctarget_feature_prefix)] -#[note] -pub(crate) struct UnknownCTargetFeaturePrefix<'a> { - pub feature: &'a str, -} - -#[derive(Diagnostic)] -#[diag(codegen_llvm_unknown_ctarget_feature)] -#[note] -pub(crate) struct UnknownCTargetFeature<'a> { - pub feature: &'a str, - #[subdiagnostic] - pub rust_feature: PossibleFeature<'a>, -} - -#[derive(Subdiagnostic)] -pub(crate) enum PossibleFeature<'a> { - #[help(codegen_llvm_possible_feature)] - Some { rust_feature: &'a str }, - #[help(codegen_llvm_consider_filing_feature_request)] - None, -} - #[derive(Diagnostic)] #[diag(codegen_llvm_symbol_already_defined)] pub(crate) struct SymbolAlreadyDefined<'a> { diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index f9ebf861634..ee78c310b0d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -7,25 +7,18 @@ use std::{ptr, slice, str}; use libc::c_int; use rustc_codegen_ssa::base::wants_wasm_eh; -use rustc_codegen_ssa::codegen_attrs::check_tied_features; use rustc_codegen_ssa::{TargetConfig, target_features}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::small_c_str::SmallCStr; -use rustc_data_structures::unord::UnordSet; use rustc_fs_util::path_to_c_string; use rustc_middle::bug; use rustc_session::Session; use rustc_session::config::{PrintKind, PrintRequest}; -use rustc_session::features::{StabilityExt, retpoline_features_by_flags}; use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport}; -use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES; use smallvec::{SmallVec, smallvec}; use crate::back::write::create_informational_target_machine; -use crate::errors::{ - FixedX18InvalidArch, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix, -}; -use crate::llvm; +use crate::{errors, llvm}; static INIT: Once = Once::new(); @@ -194,15 +187,6 @@ impl<'a> LLVMFeature<'a> { ) -> Self { Self { llvm_feature_name, dependencies } } - - fn contains(&'a self, feat: &str) -> bool { - self.iter().any(|dep| dep == feat) - } - - fn iter(&'a self) -> impl Iterator { - let dependencies = self.dependencies.iter().map(|feat| feat.as_str()); - std::iter::once(self.llvm_feature_name).chain(dependencies) - } } impl<'a> IntoIterator for LLVMFeature<'a> { @@ -215,18 +199,22 @@ impl<'a> IntoIterator for LLVMFeature<'a> { } } -// WARNING: the features after applying `to_llvm_features` must be known -// to LLVM or the feature detection code will walk past the end of the feature -// array, leading to crashes. -// -// To find a list of LLVM's names, see llvm-project/llvm/lib/Target/{ARCH}/*.td -// where `{ARCH}` is the architecture name. Look for instances of `SubtargetFeature`. -// -// Check the current rustc fork of LLVM in the repo at https://github.com/rust-lang/llvm-project/. -// The commit in use can be found via the `llvm-project` submodule in -// https://github.com/rust-lang/rust/tree/master/src Though note that Rust can also be build with -// an external precompiled version of LLVM which might lead to failures if the oldest tested / -// supported LLVM version doesn't yet support the relevant intrinsics. +/// Convert a Rust feature name to an LLVM feature name. Returning `None` means the +/// feature should be skipped, usually because it is not supported by the current +/// LLVM version. +/// +/// WARNING: the features after applying `to_llvm_features` must be known +/// to LLVM or the feature detection code will walk past the end of the feature +/// array, leading to crashes. +/// +/// To find a list of LLVM's names, see llvm-project/llvm/lib/Target/{ARCH}/*.td +/// where `{ARCH}` is the architecture name. Look for instances of `SubtargetFeature`. +/// +/// Check the current rustc fork of LLVM in the repo at . +/// The commit in use can be found via the `llvm-project` submodule in +/// Though note that Rust can also be build with +/// an external precompiled version of LLVM which might lead to failures if the oldest tested / +/// supported LLVM version doesn't yet support the relevant intrinsics. pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option> { let arch = if sess.target.arch == "x86_64" { "x86" @@ -634,10 +622,9 @@ pub(crate) fn target_cpu(sess: &Session) -> &str { handle_native(cpu_name) } -fn llvm_features_by_flags(sess: &Session) -> Vec<&str> { - let mut features: Vec<&str> = Vec::new(); - retpoline_features_by_flags(sess, &mut features); - features +/// The target features for compiler flags other than `-Ctarget-features`. +fn llvm_features_by_flags(sess: &Session, features: &mut Vec) { + target_features::retpoline_features_by_flags(sess, features); } /// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, @@ -704,6 +691,8 @@ pub(crate) fn global_llvm_features( .split(',') .filter(|v| !v.is_empty()) // Drop +v8plus feature introduced in LLVM 20. + // (Hard-coded target features do not go through `to_llvm_feature` since they already + // are LLVM feature names, hence we need a special case here.) .filter(|v| *v != "+v8plus" || get_version() >= (20, 0, 0)) .map(String::from), ); @@ -714,86 +703,23 @@ pub(crate) fn global_llvm_features( // -Ctarget-features if !only_base_features { - let known_features = sess.target.rust_target_features(); - // Will only be filled when `diagnostics` is set! - let mut featsmap = FxHashMap::default(); - - // Compute implied features - let mut all_rust_features = vec![]; - for feature in sess.opts.cg.target_feature.split(',').chain(llvm_features_by_flags(sess)) { - if let Some(feature) = feature.strip_prefix('+') { - all_rust_features.extend( - UnordSet::from(sess.target.implied_target_features(feature)) - .to_sorted_stable_ord() - .iter() - .map(|&&s| (true, s)), - ) - } else if let Some(feature) = feature.strip_prefix('-') { - // FIXME: Why do we not remove implied features on "-" here? - // We do the equivalent above in `target_config`. - // See . - all_rust_features.push((false, feature)); - } else if !feature.is_empty() { - if diagnostics { - sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature }); - } - } - } - // Remove features that are meant for rustc, not LLVM. - all_rust_features.retain(|(_, feature)| { - // Retain if it is not a rustc feature - !RUSTC_SPECIFIC_FEATURES.contains(feature) - }); - - // Check feature validity. - if diagnostics { - for &(enable, feature) in &all_rust_features { - let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature); - match feature_state { - None => { - let rust_feature = - known_features.iter().find_map(|&(rust_feature, _, _)| { - let llvm_features = to_llvm_features(sess, rust_feature)?; - if llvm_features.contains(feature) - && !llvm_features.contains(rust_feature) - { - Some(rust_feature) - } else { - None - } - }); - let unknown_feature = if let Some(rust_feature) = rust_feature { - UnknownCTargetFeature { - feature, - rust_feature: PossibleFeature::Some { rust_feature }, - } - } else { - UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None } - }; - sess.dcx().emit_warn(unknown_feature); - } - Some((_, stability, _)) => { - stability.verify_feature_enabled_by_flag(sess, enable, feature); - } - } - - // FIXME(nagisa): figure out how to not allocate a full hashset here. - featsmap.insert(feature, enable); - } - } - - // Translate this into LLVM features. - let feats = all_rust_features - .iter() - .filter_map(|&(enable, feature)| { + target_features::flag_to_backend_features( + sess, + diagnostics, + |feature| { + to_llvm_features(sess, feature) + .map(|f| SmallVec::<[&str; 2]>::from_iter(f.into_iter())) + .unwrap_or_default() + }, + |feature, enable| { let enable_disable = if enable { '+' } else { '-' }; // We run through `to_llvm_features` when // passing requests down to LLVM. This means that all in-language // features also work on the command line instead of having two // different names when the LLVM name and the Rust name differ. - let llvm_feature = to_llvm_features(sess, feature)?; + let Some(llvm_feature) = to_llvm_features(sess, feature) else { return }; - Some( + features.extend( std::iter::once(format!( "{}{}", enable_disable, llvm_feature.llvm_feature_name @@ -808,23 +734,17 @@ pub(crate) fn global_llvm_features( }, )), ) - }) - .flatten(); - features.extend(feats); - - if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) { - sess.dcx().emit_err(rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable { - features: f, - span: None, - missing_features: None, - }); - } + }, + ); + + llvm_features_by_flags(sess, &mut features); } // -Zfixed-x18 + // FIXME: merge with `llvm_features_by_flags`. if sess.opts.unstable_opts.fixed_x18 { if sess.target.arch != "aarch64" { - sess.dcx().emit_fatal(FixedX18InvalidArch { arch: &sess.target.arch }); + sess.dcx().emit_fatal(errors::FixedX18InvalidArch { arch: &sess.target.arch }); } else { features.push("+reserve-x18".into()); } diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 5322fe58cf3..ffcce8b2ff4 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -68,6 +68,11 @@ codegen_ssa_failed_to_write = failed to write {$path}: {$error} codegen_ssa_field_associated_value_expected = associated value expected for `{$name}` +codegen_ssa_forbidden_ctarget_feature = + target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason} + .note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +codegen_ssa_forbidden_ctarget_feature_issue = for more information, see issue #116344 + codegen_ssa_forbidden_target_feature_attr = target feature `{$feature}` cannot be enabled with `#[target_feature]`: {$reason} @@ -368,8 +373,22 @@ codegen_ssa_unexpected_parameter_name = unexpected parameter name codegen_ssa_unknown_archive_kind = Don't know how to build archive of type: {$kind} +codegen_ssa_unknown_ctarget_feature = + unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}` + .note = it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future + .possible_feature = you might have meant: `{$rust_feature}` + .consider_filing_feature_request = consider filing a feature request + +codegen_ssa_unknown_ctarget_feature_prefix = + unknown feature specified for `-Ctarget-feature`: `{$feature}` + .note = features must begin with a `+` to enable or `-` to disable it + codegen_ssa_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified +codegen_ssa_unstable_ctarget_feature = + unstable feature specified for `-Ctarget-feature`: `{$feature}` + .note = this feature is not stably supported; its behavior can change in the future + codegen_ssa_unsupported_instruction_set = target does not support `#[instruction_set]` codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 188a9a98ce7..78c8264eeb0 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -7,7 +7,6 @@ use rustc_attr_data_structures::ReprAttr::ReprAlign; use rustc_attr_data_structures::{ AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, find_attr, }; -use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS; @@ -19,13 +18,15 @@ use rustc_middle::mir::mono::Linkage; use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::{self as ty, TyCtxt}; +use rustc_session::lint; use rustc_session::parse::feature_err; -use rustc_session::{Session, lint}; use rustc_span::{Ident, Span, sym}; use rustc_target::spec::SanitizerSet; use crate::errors; -use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature_attr}; +use crate::target_features::{ + check_target_feature_trait_unsafe, check_tied_features, from_target_feature_attr, +}; fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage { use rustc_middle::mir::mono::Linkage::*; @@ -625,25 +626,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { codegen_fn_attrs } -/// Given a map from target_features to whether they are enabled or disabled, ensure only valid -/// combinations are allowed. -pub fn check_tied_features( - sess: &Session, - features: &FxHashMap<&str, bool>, -) -> Option<&'static [&'static str]> { - if !features.is_empty() { - for tied in sess.target.tied_target_features() { - // Tied features must be set to the same value, or not set at all - let mut tied_iter = tied.iter(); - let enabled = features.get(tied_iter.next().unwrap()); - if tied_iter.any(|f| enabled != features.get(f)) { - return Some(tied); - } - } - } - None -} - /// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller /// applied to the method prototype. fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool { diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 5387b2a7f81..7c5d615aaff 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1217,30 +1217,6 @@ pub(crate) struct ErrorCreatingImportLibrary<'a> { pub error: String, } -pub struct TargetFeatureDisableOrEnable<'a> { - pub features: &'a [&'a str], - pub span: Option, - pub missing_features: Option, -} - -#[derive(Subdiagnostic)] -#[help(codegen_ssa_missing_features)] -pub struct MissingFeatures; - -impl Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> { - fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { - let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_target_feature_disable_or_enable); - if let Some(span) = self.span { - diag.span(span); - }; - if let Some(missing_features) = self.missing_features { - diag.subdiagnostic(missing_features); - } - diag.arg("features", self.features.join(", ")); - diag - } -} - #[derive(Diagnostic)] #[diag(codegen_ssa_aix_strip_not_used)] pub(crate) struct AixStripNotUsed; @@ -1283,3 +1259,68 @@ pub(crate) struct XcrunSdkPathWarning { #[derive(LintDiagnostic)] #[diag(codegen_ssa_aarch64_softfloat_neon)] pub(crate) struct Aarch64SoftfloatNeon; + +#[derive(Diagnostic)] +#[diag(codegen_ssa_unknown_ctarget_feature_prefix)] +#[note] +pub(crate) struct UnknownCTargetFeaturePrefix<'a> { + pub feature: &'a str, +} + +#[derive(Subdiagnostic)] +pub(crate) enum PossibleFeature<'a> { + #[help(codegen_ssa_possible_feature)] + Some { rust_feature: &'a str }, + #[help(codegen_ssa_consider_filing_feature_request)] + None, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_unknown_ctarget_feature)] +#[note] +pub(crate) struct UnknownCTargetFeature<'a> { + pub feature: &'a str, + #[subdiagnostic] + pub rust_feature: PossibleFeature<'a>, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_unstable_ctarget_feature)] +#[note] +pub(crate) struct UnstableCTargetFeature<'a> { + pub feature: &'a str, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_forbidden_ctarget_feature)] +#[note] +#[note(codegen_ssa_forbidden_ctarget_feature_issue)] +pub(crate) struct ForbiddenCTargetFeature<'a> { + pub feature: &'a str, + pub enabled: &'a str, + pub reason: &'a str, +} + +pub struct TargetFeatureDisableOrEnable<'a> { + pub features: &'a [&'a str], + pub span: Option, + pub missing_features: Option, +} + +#[derive(Subdiagnostic)] +#[help(codegen_ssa_missing_features)] +pub struct MissingFeatures; + +impl Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { + let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_target_feature_disable_or_enable); + if let Some(span) = self.span { + diag.span(span); + }; + if let Some(missing_features) = self.missing_features { + diag.subdiagnostic(missing_features); + } + diag.arg("features", self.features.join(", ")); + diag + } +} diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 476671d6855..9cca6a3c72b 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -1,5 +1,5 @@ use rustc_attr_data_structures::InstructionSetAttr; -use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -9,11 +9,13 @@ use rustc_middle::middle::codegen_fn_attrs::TargetFeature; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_session::features::StabilityExt; use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; -use rustc_target::target_features::{self, RUSTC_SPECIAL_FEATURES, Stability}; +use rustc_target::target_features::{ + self, RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES, Stability, +}; +use smallvec::SmallVec; use crate::errors; @@ -68,7 +70,7 @@ pub(crate) fn from_target_feature_attr( // Only allow target features whose feature gates have been enabled // and which are permitted to be toggled. - if let Err(reason) = stability.is_toggle_permitted(tcx.sess) { + if let Err(reason) = stability.toggle_allowed() { tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr { span: item.span(), feature, @@ -89,7 +91,7 @@ pub(crate) fn from_target_feature_attr( let feature_sym = Symbol::intern(feature); for &name in tcx.implied_target_features(feature_sym) { // But ensure the ABI does not forbid enabling this. - // Here we do assume that LLVM doesn't add even more implied features + // Here we do assume that the backend doesn't add even more implied features // we don't know about, at least no features that would have ABI effects! // We skip this logic in rustdoc, where we want to allow all target features of // all targets, so we can't check their ABI compatibility and anyway we are not @@ -251,6 +253,155 @@ pub fn cfg_target_feature( (f(true), f(false)) } +/// Given a map from target_features to whether they are enabled or disabled, ensure only valid +/// combinations are allowed. +pub fn check_tied_features( + sess: &Session, + features: &FxHashMap<&str, bool>, +) -> Option<&'static [&'static str]> { + if !features.is_empty() { + for tied in sess.target.tied_target_features() { + // Tied features must be set to the same value, or not set at all + let mut tied_iter = tied.iter(); + let enabled = features.get(tied_iter.next().unwrap()); + if tied_iter.any(|f| enabled != features.get(f)) { + return Some(tied); + } + } + } + None +} + +/// Translates the `-Ctarget-feature` flag into a backend target feature list. +/// +/// `to_backend_features` converts a Rust feature name into a list of backend feature names; this is +/// used for diagnostic purposes only. +/// +/// `extend_backend_features` extends the set of backend features (assumed to be in mutable state +/// accessible by that closure) to enable/disable the given Rust feature name. +pub fn flag_to_backend_features<'a, const N: usize>( + sess: &'a Session, + diagnostics: bool, + to_backend_features: impl Fn(&'a str) -> SmallVec<[&'a str; N]>, + mut extend_backend_features: impl FnMut(&'a str, /* enable */ bool), +) { + let known_features = sess.target.rust_target_features(); + + // Compute implied features + let mut rust_features = vec![]; + for feature in sess.opts.cg.target_feature.split(',') { + if let Some(feature) = feature.strip_prefix('+') { + rust_features.extend( + UnordSet::from(sess.target.implied_target_features(feature)) + .to_sorted_stable_ord() + .iter() + .map(|&&s| (true, s)), + ) + } else if let Some(feature) = feature.strip_prefix('-') { + // FIXME: Why do we not remove implied features on "-" here? + // We do the equivalent above in `target_config`. + // See . + rust_features.push((false, feature)); + } else if !feature.is_empty() { + if diagnostics { + sess.dcx().emit_warn(errors::UnknownCTargetFeaturePrefix { feature }); + } + } + } + // Remove features that are meant for rustc, not the backend. + rust_features.retain(|(_, feature)| { + // Retain if it is not a rustc feature + !RUSTC_SPECIFIC_FEATURES.contains(feature) + }); + + // Check feature validity. + if diagnostics { + let mut featsmap = FxHashMap::default(); + + for &(enable, feature) in &rust_features { + let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature); + match feature_state { + None => { + // This is definitely not a valid Rust feature name. Maybe it is a backend feature name? + // If so, give a better error message. + let rust_feature = known_features.iter().find_map(|&(rust_feature, _, _)| { + let backend_features = to_backend_features(rust_feature); + if backend_features.contains(&feature) + && !backend_features.contains(&rust_feature) + { + Some(rust_feature) + } else { + None + } + }); + let unknown_feature = if let Some(rust_feature) = rust_feature { + errors::UnknownCTargetFeature { + feature, + rust_feature: errors::PossibleFeature::Some { rust_feature }, + } + } else { + errors::UnknownCTargetFeature { + feature, + rust_feature: errors::PossibleFeature::None, + } + }; + sess.dcx().emit_warn(unknown_feature); + } + Some((_, stability, _)) => { + if let Err(reason) = stability.toggle_allowed() { + sess.dcx().emit_warn(errors::ForbiddenCTargetFeature { + feature, + enabled: if enable { "enabled" } else { "disabled" }, + reason, + }); + } else if stability.requires_nightly().is_some() { + // An unstable feature. Warn about using it. It makes little sense + // to hard-error here since we just warn about fully unknown + // features above. + sess.dcx().emit_warn(errors::UnstableCTargetFeature { feature }); + } + } + } + + // FIXME(nagisa): figure out how to not allocate a full hashset here. + featsmap.insert(feature, enable); + } + + if let Some(f) = check_tied_features(sess, &featsmap) { + sess.dcx().emit_err(errors::TargetFeatureDisableOrEnable { + features: f, + span: None, + missing_features: None, + }); + } + } + + // Add this to the backend features. + for (enable, feature) in rust_features { + extend_backend_features(feature, enable); + } +} + +/// Computes the backend target features to be added to account for retpoline flags. +/// Used by both LLVM and GCC since their target features are, conveniently, the same. +pub fn retpoline_features_by_flags(sess: &Session, features: &mut Vec) { + // -Zretpoline without -Zretpoline-external-thunk enables + // retpoline-indirect-branches and retpoline-indirect-calls target features + let unstable_opts = &sess.opts.unstable_opts; + if unstable_opts.retpoline && !unstable_opts.retpoline_external_thunk { + features.push("+retpoline-indirect-branches".into()); + features.push("+retpoline-indirect-calls".into()); + } + // -Zretpoline-external-thunk (maybe, with -Zretpoline too) enables + // retpoline-external-thunk, retpoline-indirect-branches and + // retpoline-indirect-calls target features + if unstable_opts.retpoline_external_thunk { + features.push("+retpoline-external-thunk".into()); + features.push("+retpoline-indirect-branches".into()); + features.push("+retpoline-indirect-calls".into()); + } +} + pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { rust_target_features: |tcx, cnum| { diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index 61953614c77..528c52eace7 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -40,11 +40,6 @@ session_file_is_not_writeable = output file {$file} is not writeable -- check it session_file_write_fail = failed to write `{$path}` due to error `{$err}` -session_forbidden_ctarget_feature = - target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason} - .note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -session_forbidden_ctarget_feature_issue = for more information, see issue #116344 - session_function_return_requires_x86_or_x86_64 = `-Zfunction-return` (except `keep`) is only supported on x86 and x86_64 session_function_return_thunk_extern_requires_non_large_code_model = `-Zfunction-return=thunk-extern` is only supported on non-large code models @@ -137,9 +132,6 @@ session_target_stack_protector_not_supported = `-Z stack-protector={$stack_prote session_unleashed_feature_help_named = skipping check for `{$gate}` feature session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate -session_unstable_ctarget_feature = - unstable feature specified for `-Ctarget-feature`: `{$feature}` - .note = this feature is not stably supported; its behavior can change in the future session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto` session_unsupported_crate_type_for_target = diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 9c591dcf619..bf95014843d 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -501,20 +501,3 @@ pub(crate) struct SoftFloatIgnored; #[note] #[note(session_soft_float_deprecated_issue)] pub(crate) struct SoftFloatDeprecated; - -#[derive(Diagnostic)] -#[diag(session_forbidden_ctarget_feature)] -#[note] -#[note(session_forbidden_ctarget_feature_issue)] -pub(crate) struct ForbiddenCTargetFeature<'a> { - pub feature: &'a str, - pub enabled: &'a str, - pub reason: &'a str, -} - -#[derive(Diagnostic)] -#[diag(session_unstable_ctarget_feature)] -#[note] -pub(crate) struct UnstableCTargetFeature<'a> { - pub feature: &'a str, -} diff --git a/compiler/rustc_session/src/features.rs b/compiler/rustc_session/src/features.rs deleted file mode 100644 index 70a088a236f..00000000000 --- a/compiler/rustc_session/src/features.rs +++ /dev/null @@ -1,59 +0,0 @@ -use rustc_target::target_features::Stability; - -use crate::Session; -use crate::errors::{ForbiddenCTargetFeature, UnstableCTargetFeature}; - -pub trait StabilityExt { - /// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`. - /// Otherwise, some features also may only be enabled by flag (target modifier). - /// (It might still be nightly-only even if this returns `true`, so make sure to also check - /// `requires_nightly`.) - fn is_toggle_permitted(&self, sess: &Session) -> Result<(), &'static str>; - - /// Check that feature is correctly enabled/disabled by command line flag (emits warnings) - fn verify_feature_enabled_by_flag(&self, sess: &Session, enable: bool, feature: &str); -} - -impl StabilityExt for Stability { - fn is_toggle_permitted(&self, sess: &Session) -> Result<(), &'static str> { - match self { - Stability::Forbidden { reason } => Err(reason), - Stability::TargetModifierOnly { reason, flag } => { - if !sess.opts.target_feature_flag_enabled(*flag) { Err(reason) } else { Ok(()) } - } - _ => Ok(()), - } - } - fn verify_feature_enabled_by_flag(&self, sess: &Session, enable: bool, feature: &str) { - if let Err(reason) = self.is_toggle_permitted(sess) { - sess.dcx().emit_warn(ForbiddenCTargetFeature { - feature, - enabled: if enable { "enabled" } else { "disabled" }, - reason, - }); - } else if self.requires_nightly().is_some() { - // An unstable feature. Warn about using it. It makes little sense - // to hard-error here since we just warn about fully unknown - // features above. - sess.dcx().emit_warn(UnstableCTargetFeature { feature }); - } - } -} - -pub fn retpoline_features_by_flags(sess: &Session, features: &mut Vec<&str>) { - // -Zretpoline without -Zretpoline-external-thunk enables - // retpoline-indirect-branches and retpoline-indirect-calls target features - let unstable_opts = &sess.opts.unstable_opts; - if unstable_opts.retpoline && !unstable_opts.retpoline_external_thunk { - features.push("+retpoline-indirect-branches"); - features.push("+retpoline-indirect-calls"); - } - // -Zretpoline-external-thunk (maybe, with -Zretpoline too) enables - // retpoline-external-thunk, retpoline-indirect-branches and - // retpoline-indirect-calls target features - if unstable_opts.retpoline_external_thunk { - features.push("+retpoline-external-thunk"); - features.push("+retpoline-indirect-branches"); - features.push("+retpoline-indirect-calls"); - } -} diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 4added19e56..5e5872ee068 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -29,7 +29,6 @@ pub use session::*; pub mod output; pub use getopts; -pub mod features; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 31b4237d3b2..7fef942525b 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -290,14 +290,6 @@ macro_rules! top_level_options { mods.sort_by(|a, b| a.opt.cmp(&b.opt)); mods } - - pub fn target_feature_flag_enabled(&self, flag: &str) -> bool { - match flag { - "retpoline" => self.unstable_opts.retpoline, - "retpoline-external-thunk" => self.unstable_opts.retpoline_external_thunk, - _ => false, - } - } } ); } diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index a1eac1fba25..c18a2c1ebef 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -34,9 +34,6 @@ pub enum Stability { /// particular for features are actually ABI configuration flags (not all targets are as nice as /// RISC-V and have an explicit way to set the ABI separate from target features). Forbidden { reason: &'static str }, - /// This feature can not be set via `-Ctarget-feature` or `#[target_feature]`, it can only be set - /// by target modifier flag. Target modifier flags are tracked to be consistent in linked modules. - TargetModifierOnly { reason: &'static str, flag: &'static str }, } use Stability::*; @@ -52,7 +49,6 @@ impl HashStable for Stability { Stability::Forbidden { reason } => { reason.hash_stable(hcx, hasher); } - Stability::TargetModifierOnly { .. } => {} } } } @@ -62,7 +58,7 @@ impl Stability { /// (It might still be nightly-only even if this returns `true`, so make sure to also check /// `requires_nightly`.) pub fn in_cfg(&self) -> bool { - !matches!(self, Stability::Forbidden { .. }) + matches!(self, Stability::Stable | Stability::Unstable { .. }) } /// Returns the nightly feature that is required to toggle this target feature via @@ -78,7 +74,16 @@ impl Stability { Stability::Unstable(nightly_feature) => Some(nightly_feature), Stability::Stable { .. } => None, Stability::Forbidden { .. } => panic!("forbidden features should not reach this far"), - Stability::TargetModifierOnly { .. } => None, + } + } + + /// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`. + /// (It might still be nightly-only even if this returns `true`, so make sure to also check + /// `requires_nightly`.) + pub fn toggle_allowed(&self) -> Result<(), &'static str> { + match self { + Stability::Unstable(_) | Stability::Stable { .. } => Ok(()), + Stability::Forbidden { reason } => Err(reason), } } } @@ -450,26 +455,19 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("rdseed", Stable, &[]), ( "retpoline-external-thunk", - Stability::TargetModifierOnly { + Stability::Forbidden { reason: "use `retpoline-external-thunk` target modifier flag instead", - flag: "retpoline-external-thunk", }, &[], ), ( "retpoline-indirect-branches", - Stability::TargetModifierOnly { - reason: "use `retpoline` target modifier flag instead", - flag: "retpoline", - }, + Stability::Forbidden { reason: "use `retpoline` target modifier flag instead" }, &[], ), ( "retpoline-indirect-calls", - Stability::TargetModifierOnly { - reason: "use `retpoline` target modifier flag instead", - flag: "retpoline", - }, + Stability::Forbidden { reason: "use `retpoline` target modifier flag instead" }, &[], ), ("rtm", Unstable(sym::rtm_target_feature), &[]), diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 2feadce26d0..29c63a391e2 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -18,7 +18,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_session::features::StabilityExt; use rustc_span::def_id::LOCAL_CRATE; use rustdoc_json_types as types; // It's important to use the FxHashMap from rustdoc_json_types here, instead of @@ -148,7 +147,7 @@ fn target(sess: &rustc_session::Session) -> types::Target { .copied() .filter(|(_, stability, _)| { // Describe only target features which the user can toggle - stability.is_toggle_permitted(sess).is_ok() + stability.toggle_allowed().is_ok() }) .map(|(name, stability, implied_features)| { types::TargetFeature { @@ -164,7 +163,7 @@ fn target(sess: &rustc_session::Session) -> types::Target { // Imply only target features which the user can toggle feature_stability .get(name) - .map(|stability| stability.is_toggle_permitted(sess).is_ok()) + .map(|stability| stability.toggle_allowed().is_ok()) .unwrap_or(false) }) .map(String::from) diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index f29a41d6a8e..ec81ba2e3d8 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -212,9 +212,6 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `relax` `relaxed-simd` `reserve-x18` -`retpoline-external-thunk` -`retpoline-indirect-branches` -`retpoline-indirect-calls` `rtm` `sb` `scq` -- cgit 1.4.1-3-g733a5 From 8bec5bb5adaa1f5a0bc3683fee5f77a5fdac539b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 May 2025 12:50:48 +0200 Subject: cg_gcc: properly populate cfg(target_features) with -Ctarget-features --- compiler/rustc_codegen_gcc/src/lib.rs | 39 ++++++++++------------- compiler/rustc_codegen_llvm/src/llvm_util.rs | 32 +++++++++---------- compiler/rustc_codegen_ssa/src/target_features.rs | 13 +++----- 3 files changed, 37 insertions(+), 47 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index f5ad28681c7..a912678ef2a 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -102,10 +102,9 @@ use rustc_codegen_ssa::back::write::{ CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn, }; 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, target_features, -}; +use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetConfig}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::IntoDynSyncSend; use rustc_errors::DiagCtxtHandle; @@ -478,25 +477,21 @@ fn to_gcc_opt_level(optlevel: Option) -> OptimizationLevel { /// Returns the features that should be set in `cfg(target_feature)`. fn target_config(sess: &Session, target_info: &LockedTargetInfo) -> TargetConfig { - let (unstable_target_features, target_features) = target_features::cfg_target_feature( - sess, - /* FIXME: we ignore `-Ctarget-feature` */ "", - |feature| { - // TODO: we disable Neon for now since we don't support the LLVM intrinsics for it. - if feature == "neon" { - return false; - } - target_info.cpu_supports(feature) - // cSpell:disable - /* - adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma, - avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq, - bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm, - sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves - */ - // cSpell:enable - }, - ); + let (unstable_target_features, target_features) = cfg_target_feature(sess, |feature| { + // TODO: we disable Neon for now since we don't support the LLVM intrinsics for it. + if feature == "neon" { + return false; + } + target_info.cpu_supports(feature) + // cSpell:disable + /* + adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma, + avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq, + bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm, + sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves + */ + // cSpell:enable + }); let has_reliable_f16 = target_info.supports_target_dependent_type(CType::Float16); let has_reliable_f128 = target_info.supports_target_dependent_type(CType::Float128); diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index ee78c310b0d..bc2165fa829 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -7,6 +7,7 @@ use std::{ptr, slice, str}; use libc::c_int; use rustc_codegen_ssa::base::wants_wasm_eh; +use rustc_codegen_ssa::target_features::cfg_target_feature; use rustc_codegen_ssa::{TargetConfig, target_features}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::small_c_str::SmallCStr; @@ -331,24 +332,23 @@ pub(crate) fn target_config(sess: &Session) -> TargetConfig { // by LLVM. let target_machine = create_informational_target_machine(sess, true); - let (unstable_target_features, target_features) = - target_features::cfg_target_feature(sess, &sess.opts.cg.target_feature, |feature| { - if let Some(feat) = to_llvm_features(sess, feature) { - // All the LLVM features this expands to must be enabled. - for llvm_feature in feat { - let cstr = SmallCStr::new(llvm_feature); - // `LLVMRustHasFeature` is moderately expensive. On targets with many - // features (e.g. x86) these calls take a non-trivial fraction of runtime - // when compiling very small programs. - if !unsafe { llvm::LLVMRustHasFeature(target_machine.raw(), cstr.as_ptr()) } { - return false; - } + let (unstable_target_features, target_features) = cfg_target_feature(sess, |feature| { + if let Some(feat) = to_llvm_features(sess, feature) { + // All the LLVM features this expands to must be enabled. + for llvm_feature in feat { + let cstr = SmallCStr::new(llvm_feature); + // `LLVMRustHasFeature` is moderately expensive. On targets with many + // features (e.g. x86) these calls take a non-trivial fraction of runtime + // when compiling very small programs. + if !unsafe { llvm::LLVMRustHasFeature(target_machine.raw(), cstr.as_ptr()) } { + return false; } - true - } else { - false } - }); + true + } else { + false + } + }); let mut cfg = TargetConfig { target_features, diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 41d8b8d8cbf..e29cdbb968e 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -163,8 +163,7 @@ pub(crate) fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, /// and call the closure for each (expanded) Rust feature. If the list contains /// a syntactically invalid item (not starting with `+`/`-`), the error callback is invoked. fn parse_rust_feature_flag<'a>( - sess: &Session, - target_feature_flag: &'a str, + sess: &'a Session, err_callback: impl Fn(&'a str), mut callback: impl FnMut( /* base_feature */ &'a str, @@ -175,7 +174,7 @@ fn parse_rust_feature_flag<'a>( // A cache for the backwards implication map. let mut inverse_implied_features: Option>> = None; - for feature in target_feature_flag.split(',') { + for feature in sess.opts.cg.target_feature.split(',') { if let Some(base_feature) = feature.strip_prefix('+') { callback(base_feature, sess.target.implied_target_features(base_feature), true) } else if let Some(base_feature) = feature.strip_prefix('-') { @@ -215,15 +214,13 @@ fn parse_rust_feature_flag<'a>( /// to populate `sess.unstable_target_features` and `sess.target_features` (these are the first and /// 2nd component of the return value, respectively). /// -/// `target_feature_flag` is the value of `-Ctarget-feature` (giving the caller a chance to override it). /// `target_base_has_feature` should check whether the given feature (a Rust feature name!) is enabled /// in the "base" target machine, i.e., without applying `-Ctarget-feature`. /// /// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled elsewhere. pub fn cfg_target_feature( sess: &Session, - target_feature_flag: &str, - mut is_feature_enabled: impl FnMut(&str) -> bool, + mut target_base_has_feature: impl FnMut(&str) -> bool, ) -> (Vec, Vec) { // Compute which of the known target features are enabled in the 'base' target machine. We only // consider "supported" features; "forbidden" features are not reflected in `cfg` as of now. @@ -236,7 +233,7 @@ pub fn cfg_target_feature( if RUSTC_SPECIAL_FEATURES.contains(feature) { return true; } - is_feature_enabled(feature) + target_base_has_feature(feature) }) .map(|(feature, _, _)| Symbol::intern(feature)) .collect(); @@ -244,7 +241,6 @@ pub fn cfg_target_feature( // Add enabled and remove disabled features. parse_rust_feature_flag( sess, - target_feature_flag, /* err_callback */ |_| {}, |_base_feature, new_features, enabled| { // Iteration order is irrelevant since this only influences an `UnordSet`. @@ -323,7 +319,6 @@ pub fn flag_to_backend_features<'a, const N: usize>( let mut rust_features = vec![]; parse_rust_feature_flag( sess, - &sess.opts.cg.target_feature, /* err_callback */ |feature| { if diagnostics { -- cgit 1.4.1-3-g733a5 From 0c4b0f57268b1e866eb7eb720caf815efcb85aeb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Jun 2025 14:04:39 +0200 Subject: line-wrap and extend comments, typos --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 10 ++++----- compiler/rustc_codegen_ssa/src/target_features.rs | 25 +++++++++++++++-------- compiler/rustc_target/src/target_features.rs | 1 + 3 files changed, 22 insertions(+), 14 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index bc2165fa829..676890b36eb 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -211,11 +211,11 @@ impl<'a> IntoIterator for LLVMFeature<'a> { /// To find a list of LLVM's names, see llvm-project/llvm/lib/Target/{ARCH}/*.td /// where `{ARCH}` is the architecture name. Look for instances of `SubtargetFeature`. /// -/// Check the current rustc fork of LLVM in the repo at . -/// The commit in use can be found via the `llvm-project` submodule in -/// Though note that Rust can also be build with -/// an external precompiled version of LLVM which might lead to failures if the oldest tested / -/// supported LLVM version doesn't yet support the relevant intrinsics. +/// Check the current rustc fork of LLVM in the repo at +/// . The commit in use can be found via the +/// `llvm-project` submodule in Though note that +/// Rust can also be build with an external precompiled version of LLVM which might lead to failures +/// if the oldest tested / supported LLVM version doesn't yet support the relevant intrinsics. pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option> { let arch = if sess.target.arch == "x86_64" { "x86" diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index e29cdbb968e..f4f03c1a16b 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -178,8 +178,9 @@ fn parse_rust_feature_flag<'a>( if let Some(base_feature) = feature.strip_prefix('+') { callback(base_feature, sess.target.implied_target_features(base_feature), true) } else if let Some(base_feature) = feature.strip_prefix('-') { - // If `f1` implies `f2`, then `!f2` implies `!f1` -- this is standard logical contraposition. - // So we have to find all the reverse implications of `base_feature` and disable them, too. + // If `f1` implies `f2`, then `!f2` implies `!f1` -- this is standard logical + // contraposition. So we have to find all the reverse implications of `base_feature` and + // disable them, too. let inverse_implied_features = inverse_implied_features.get_or_insert_with(|| { let mut set: FxHashMap<&str, FxHashSet<&str>> = FxHashMap::default(); @@ -191,7 +192,7 @@ fn parse_rust_feature_flag<'a>( set }); - // Inverse mplied target features have their own inverse implied target features, so we + // Inverse implied target features have their own inverse implied target features, so we // traverse the map until there are no more features to add. let mut features = FxHashSet::default(); let mut new_features = vec![base_feature]; @@ -214,8 +215,8 @@ fn parse_rust_feature_flag<'a>( /// to populate `sess.unstable_target_features` and `sess.target_features` (these are the first and /// 2nd component of the return value, respectively). /// -/// `target_base_has_feature` should check whether the given feature (a Rust feature name!) is enabled -/// in the "base" target machine, i.e., without applying `-Ctarget-feature`. +/// `target_base_has_feature` should check whether the given feature (a Rust feature name!) is +/// enabled in the "base" target machine, i.e., without applying `-Ctarget-feature`. /// /// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled elsewhere. pub fn cfg_target_feature( @@ -231,6 +232,8 @@ pub fn cfg_target_feature( .filter(|(feature, _, _)| { // Skip checking special features, those are not known to the backend. if RUSTC_SPECIAL_FEATURES.contains(feature) { + // FIXME: `true` here means we'll always think the feature is enabled. + // Does that really make sense? return true; } target_base_has_feature(feature) @@ -241,7 +244,10 @@ pub fn cfg_target_feature( // Add enabled and remove disabled features. parse_rust_feature_flag( sess, - /* err_callback */ |_| {}, + /* err_callback */ + |_| { + // Errors are already emitted in `flag_to_backend_features`; avoid duplicates. + }, |_base_feature, new_features, enabled| { // Iteration order is irrelevant since this only influences an `UnordSet`. #[allow(rustc::potential_query_instability)] @@ -339,8 +345,8 @@ pub fn flag_to_backend_features<'a, const N: usize>( let feature_state = known_features.iter().find(|&&(v, _, _)| v == base_feature); match feature_state { None => { - // This is definitely not a valid Rust feature name. Maybe it is a backend feature name? - // If so, give a better error message. + // This is definitely not a valid Rust feature name. Maybe it is a backend + // feature name? If so, give a better error message. let rust_feature = known_features.iter().find_map(|&(rust_feature, _, _)| { let backend_features = to_backend_features(rust_feature); @@ -452,7 +458,8 @@ pub(crate) fn provide(providers: &mut Providers) { Stability::Unstable { .. } | Stability::Forbidden { .. }, ) | (Stability::Forbidden { .. }, Stability::Forbidden { .. }) => { - // The stability in the entry is at least as good as the new one, just keep it. + // The stability in the entry is at least as good as the new + // one, just keep it. } _ => { // Overwrite stabilite. diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index c18a2c1ebef..f7582f8a344 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -730,6 +730,7 @@ static LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ #[rustfmt::skip] const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start + // For "backchain", https://github.com/rust-lang/rust/issues/142412 is a stabilization blocker ("backchain", Unstable(sym::s390x_target_feature), &[]), ("concurrent-functions", Unstable(sym::s390x_target_feature), &[]), ("deflate-conversion", Unstable(sym::s390x_target_feature), &[]), -- cgit 1.4.1-3-g733a5 From a50a3b8e318594c41783294e440d864763e412ef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 14 Jun 2025 14:11:00 +0200 Subject: various minor target feature cleanups --- compiler/rustc_codegen_gcc/src/gcc_util.rs | 3 +-- compiler/rustc_codegen_llvm/src/llvm_util.rs | 22 ++++++++-------- compiler/rustc_codegen_ssa/src/target_features.rs | 29 +++++++++------------- compiler/rustc_target/src/target_features.rs | 20 +++------------ tests/assembly/s390x-backchain-toggle.rs | 5 +++- tests/ui/check-cfg/target_feature.stderr | 1 - ...etpoline-target-feature-flag.by_feature1.stderr | 2 +- ...etpoline-target-feature-flag.by_feature2.stderr | 2 +- ...etpoline-target-feature-flag.by_feature3.stderr | 2 +- .../retpoline-target-feature-flag.rs | 6 ++--- 10 files changed, 38 insertions(+), 54 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs index 562f4124882..42ba40692b7 100644 --- a/compiler/rustc_codegen_gcc/src/gcc_util.rs +++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs @@ -6,6 +6,7 @@ use smallvec::{SmallVec, smallvec}; fn gcc_features_by_flags(sess: &Session, features: &mut Vec) { target_features::retpoline_features_by_flags(sess, features); + // FIXME: LLVM also sets +reserve-x18 here under some conditions. } /// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, @@ -59,8 +60,6 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec &str { /// The target features for compiler flags other than `-Ctarget-features`. fn llvm_features_by_flags(sess: &Session, features: &mut Vec) { target_features::retpoline_features_by_flags(sess, features); + + // -Zfixed-x18 + if sess.opts.unstable_opts.fixed_x18 { + if sess.target.arch != "aarch64" { + sess.dcx().emit_fatal(errors::FixedX18InvalidArch { arch: &sess.target.arch }); + } else { + features.push("+reserve-x18".into()); + } + } } /// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, @@ -736,19 +745,10 @@ pub(crate) fn global_llvm_features( ) }, ); - - llvm_features_by_flags(sess, &mut features); } - // -Zfixed-x18 - // FIXME: merge with `llvm_features_by_flags`. - if sess.opts.unstable_opts.fixed_x18 { - if sess.target.arch != "aarch64" { - sess.dcx().emit_fatal(errors::FixedX18InvalidArch { arch: &sess.target.arch }); - } else { - features.push("+reserve-x18".into()); - } - } + // We add this in the "base target" so that these show up in `sess.unstable_target_features`. + llvm_features_by_flags(sess, &mut features); features } diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index f4f03c1a16b..67ac619091b 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -12,9 +12,7 @@ use rustc_session::Session; use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; -use rustc_target::target_features::{ - self, RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES, Stability, -}; +use rustc_target::target_features::{self, RUSTC_SPECIFIC_FEATURES, Stability}; use smallvec::SmallVec; use crate::errors; @@ -176,8 +174,18 @@ fn parse_rust_feature_flag<'a>( for feature in sess.opts.cg.target_feature.split(',') { if let Some(base_feature) = feature.strip_prefix('+') { + // Skip features that are not target features, but rustc features. + if RUSTC_SPECIFIC_FEATURES.contains(&base_feature) { + return; + } + callback(base_feature, sess.target.implied_target_features(base_feature), true) } else if let Some(base_feature) = feature.strip_prefix('-') { + // Skip features that are not target features, but rustc features. + if RUSTC_SPECIFIC_FEATURES.contains(&base_feature) { + return; + } + // If `f1` implies `f2`, then `!f2` implies `!f1` -- this is standard logical // contraposition. So we have to find all the reverse implications of `base_feature` and // disable them, too. @@ -229,15 +237,7 @@ pub fn cfg_target_feature( .target .rust_target_features() .iter() - .filter(|(feature, _, _)| { - // Skip checking special features, those are not known to the backend. - if RUSTC_SPECIAL_FEATURES.contains(feature) { - // FIXME: `true` here means we'll always think the feature is enabled. - // Does that really make sense? - return true; - } - target_base_has_feature(feature) - }) + .filter(|(feature, _, _)| target_base_has_feature(feature)) .map(|(feature, _, _)| Symbol::intern(feature)) .collect(); @@ -332,11 +332,6 @@ pub fn flag_to_backend_features<'a, const N: usize>( } }, |base_feature, new_features, enable| { - // Skip features that are meant for rustc, not the backend. - if RUSTC_SPECIFIC_FEATURES.contains(&base_feature) { - return; - } - rust_features.extend( UnordSet::from(new_features).to_sorted_stable_ord().iter().map(|&&s| (enable, s)), ); diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index f7582f8a344..3eea1e070a6 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -11,11 +11,6 @@ use crate::spec::{FloatAbi, RustcAbi, Target}; /// These exist globally and are not in the target-specific lists below. pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"]; -/// Features that require special handling when passing to LLVM: -/// these are target-specific (i.e., must also be listed in the target-specific list below) -/// but do not correspond to an LLVM target feature. -pub const RUSTC_SPECIAL_FEATURES: &[&str] = &["backchain"]; - /// Stability information for target features. #[derive(Debug, Copy, Clone)] pub enum Stability { @@ -275,12 +270,7 @@ static AARCH64_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("rcpc3", Unstable(sym::aarch64_unstable_target_feature), &["rcpc2"]), // FEAT_RDM ("rdm", Stable, &["neon"]), - // This is needed for inline assembly, but shouldn't be stabilized as-is - // since it should be enabled globally using -Zfixed-x18, not - // #[target_feature]. - // Note that cfg(target_feature = "reserve-x18") is currently not set for - // targets that reserve x18 by default. - ("reserve-x18", Unstable(sym::aarch64_unstable_target_feature), &[]), + ("reserve-x18", Forbidden { reason: "use `-Zfixed-x18` compiler flag instead" }, &[]), // FEAT_SB ("sb", Stable, &[]), // FEAT_SHA1 & FEAT_SHA256 @@ -455,19 +445,17 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("rdseed", Stable, &[]), ( "retpoline-external-thunk", - Stability::Forbidden { - reason: "use `retpoline-external-thunk` target modifier flag instead", - }, + Stability::Forbidden { reason: "use `-Zretpoline-external-thunk` compiler flag instead" }, &[], ), ( "retpoline-indirect-branches", - Stability::Forbidden { reason: "use `retpoline` target modifier flag instead" }, + Stability::Forbidden { reason: "use `-Zretpoline` compiler flag instead" }, &[], ), ( "retpoline-indirect-calls", - Stability::Forbidden { reason: "use `retpoline` target modifier flag instead" }, + Stability::Forbidden { reason: "use `-Zretpoline` compiler flag instead" }, &[], ), ("rtm", Unstable(sym::rtm_target_feature), &[]), diff --git a/tests/assembly/s390x-backchain-toggle.rs b/tests/assembly/s390x-backchain-toggle.rs index 83c7b82d0d4..9bae15b7d11 100644 --- a/tests/assembly/s390x-backchain-toggle.rs +++ b/tests/assembly/s390x-backchain-toggle.rs @@ -1,5 +1,5 @@ //@ add-core-stubs -//@ revisions: enable-backchain disable-backchain +//@ revisions: enable-backchain disable-backchain default-backchain //@ assembly-output: emit-asm //@ compile-flags: -Copt-level=3 --crate-type=lib --target=s390x-unknown-linux-gnu //@ needs-llvm-components: systemz @@ -26,6 +26,8 @@ extern "C" fn test_backchain() -> i32 { // enable-backchain: stg [[REG1]], 0(%r15) // disable-backchain: aghi %r15, -160 // disable-backchain-NOT: stg %r{{.*}}, 0(%r15) + // default-backchain: aghi %r15, -160 + // default-backchain-NOT: stg %r{{.*}}, 0(%r15) unsafe { extern_func(); } @@ -35,6 +37,7 @@ extern "C" fn test_backchain() -> i32 { // Make sure that the expected return value is written into %r2 (return register): // enable-backchain-NEXT: lghi %r2, 1 // disable-backchain: lghi %r2, 0 + // default-backchain: lghi %r2, 0 #[cfg(target_feature = "backchain")] { 1 diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index ec81ba2e3d8..f422919983b 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -211,7 +211,6 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `reference-types` `relax` `relaxed-simd` -`reserve-x18` `rtm` `sb` `scq` diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr index 2a0f5f01aef..79e89823c51 100644 --- a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr +++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr @@ -1,4 +1,4 @@ -warning: target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `retpoline-external-thunk` target modifier flag instead +warning: target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `-Zretpoline-external-thunk` compiler flag instead | = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #116344 diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr index f7b6cb16447..f5ff15df632 100644 --- a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr +++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr @@ -1,4 +1,4 @@ -warning: target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead +warning: target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `-Zretpoline` compiler flag instead | = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #116344 diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr index 4f2cd1d1a52..158cca08a76 100644 --- a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr +++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr @@ -1,4 +1,4 @@ -warning: target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead +warning: target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `-Zretpoline` compiler flag instead | = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #116344 diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.rs b/tests/ui/target-feature/retpoline-target-feature-flag.rs index de3c44c3ed0..05c85860385 100644 --- a/tests/ui/target-feature/retpoline-target-feature-flag.rs +++ b/tests/ui/target-feature/retpoline-target-feature-flag.rs @@ -16,6 +16,6 @@ #![no_core] extern crate minicore; -//[by_feature1]~? WARN target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `retpoline-external-thunk` target modifier flag instead -//[by_feature2]~? WARN target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead -//[by_feature3]~? WARN target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead +//[by_feature1]~? WARN target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature` +//[by_feature2]~? WARN target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature` +//[by_feature3]~? WARN target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature` -- cgit 1.4.1-3-g733a5 From a123a36a1f52fa8ac85bfa1ba4cef7062058db7b Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 22 Jun 2025 00:47:10 +0200 Subject: centralize `-Zmin-function-alignment` logic --- compiler/rustc_codegen_llvm/src/attributes.rs | 6 +----- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 6 ++++++ compiler/rustc_codegen_ssa/src/mir/naked_asm.rs | 8 ++------ compiler/rustc_const_eval/src/interpret/memory.rs | 7 +------ 4 files changed, 10 insertions(+), 17 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 27fd09745ff..adb53e0b66c 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -491,11 +491,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx); attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]); } - // function alignment can be set globally with the `-Zmin-function-alignment=` flag; - // the alignment from a `#[repr(align())]` is used if it specifies a higher alignment. - if let Some(align) = - Ord::max(cx.tcx.sess.opts.unstable_opts.min_function_alignment, codegen_fn_attrs.alignment) - { + if let Some(align) = codegen_fn_attrs.alignment { llvm::set_alignment(llfn, align); } if let Some(backchain) = backchain_attr(cx) { diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 39818be5bde..ce83bd62ddd 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -126,6 +126,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } + // Apply the minimum function alignment here, so that individual backends don't have to. + codegen_fn_attrs.alignment = Ord::max( + codegen_fn_attrs.alignment, + tcx.sess.opts.unstable_opts.min_function_alignment, + ); + let Some(Ident { name, .. }) = attr.ident() else { continue; }; diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index 9f66457a740..9da4b8cc8fd 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -131,12 +131,8 @@ fn prefix_and_suffix<'tcx>( let attrs = tcx.codegen_fn_attrs(instance.def_id()); let link_section = attrs.link_section.map(|symbol| symbol.as_str().to_string()); - // function alignment can be set globally with the `-Zmin-function-alignment=` flag; - // the alignment from a `#[repr(align())]` is used if it specifies a higher alignment. - // if no alignment is specified, an alignment of 4 bytes is used. - let min_function_alignment = tcx.sess.opts.unstable_opts.min_function_alignment; - let align_bytes = - Ord::max(min_function_alignment, attrs.alignment).map(|a| a.bytes()).unwrap_or(4); + // If no alignment is specified, an alignment of 4 bytes is used. + let align_bytes = attrs.alignment.map(|a| a.bytes()).unwrap_or(4); // In particular, `.arm` can also be written `.code 32` and `.thumb` as `.code 16`. let (arch_prefix, arch_suffix) = if is_arm { diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 36d1a413598..57bf867e389 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -877,12 +877,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if let Some(fn_val) = self.get_fn_alloc(id) { let align = match fn_val { FnVal::Instance(instance) => { - // Function alignment can be set globally with the `-Zmin-function-alignment=` flag; - // the alignment from a `#[repr(align())]` is used if it specifies a higher alignment. - let fn_align = self.tcx.codegen_fn_attrs(instance.def_id()).alignment; - let global_align = self.tcx.sess.opts.unstable_opts.min_function_alignment; - - Ord::max(global_align, fn_align).unwrap_or(Align::ONE) + self.tcx.codegen_fn_attrs(instance.def_id()).alignment.unwrap_or(Align::ONE) } // Machine-specific extra functions currently do not support alignment restrictions. FnVal::Other(_) => Align::ONE, -- cgit 1.4.1-3-g733a5 From a46ef2d01ed9006097b0b71348d633bfb116acaa Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 22 Jun 2025 11:38:25 -0400 Subject: Remove dead instructions in terminate blocks --- compiler/rustc_codegen_gcc/src/builder.rs | 4 ++-- compiler/rustc_codegen_llvm/src/builder.rs | 3 +-- compiler/rustc_codegen_ssa/src/traits/builder.rs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index a2e34d1f8fb..7852aebe0c2 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -1591,9 +1591,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { (value1, value2) } - fn filter_landing_pad(&mut self, pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { + fn filter_landing_pad(&mut self, pers_fn: RValue<'gcc>) { // TODO(antoyo): generate the correct landing pad - self.cleanup_landing_pad(pers_fn) + self.cleanup_landing_pad(pers_fn); } #[cfg(feature = "master")] diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 5e9594dd06b..d0aa7320b4b 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1166,11 +1166,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { (self.extract_value(landing_pad, 0), self.extract_value(landing_pad, 1)) } - fn filter_landing_pad(&mut self, pers_fn: &'ll Value) -> (&'ll Value, &'ll Value) { + fn filter_landing_pad(&mut self, pers_fn: &'ll Value) { let ty = self.type_struct(&[self.type_ptr(), self.type_i32()], false); let landing_pad = self.landing_pad(ty, pers_fn, 1); self.add_clause(landing_pad, self.const_array(self.type_ptr(), &[])); - (self.extract_value(landing_pad, 0), self.extract_value(landing_pad, 1)) } fn resume(&mut self, exn0: &'ll Value, exn1: &'ll Value) { diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index f35f551d590..d19de6f5d26 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -516,7 +516,7 @@ pub trait BuilderMethods<'a, 'tcx>: // These are used by everyone except msvc fn cleanup_landing_pad(&mut self, pers_fn: Self::Function) -> (Self::Value, Self::Value); - fn filter_landing_pad(&mut self, pers_fn: Self::Function) -> (Self::Value, Self::Value); + fn filter_landing_pad(&mut self, pers_fn: Self::Function); fn resume(&mut self, exn0: Self::Value, exn1: Self::Value); // These are used only by msvc -- cgit 1.4.1-3-g733a5 From 7b1c89f2b58515bba671de38ba974edb58429973 Mon Sep 17 00:00:00 2001 From: Karan Janthe Date: Wed, 25 Jun 2025 02:06:53 +0000 Subject: added PrintTAFn flag for autodiff Signed-off-by: Karan Janthe --- compiler/rustc_codegen_llvm/src/back/lto.rs | 6 +++++- compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 17 +++++++++++++++++ compiler/rustc_session/src/config.rs | 4 +++- compiler/rustc_session/src/options.rs | 17 +++++++++++++++-- src/doc/rustc-dev-guide/src/autodiff/flags.md | 1 + src/doc/unstable-book/src/compiler-flags/autodiff.md | 1 + 6 files changed, 42 insertions(+), 4 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index ee46b49a094..9c62244f3c9 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -587,7 +587,7 @@ fn thin_lto( } fn enable_autodiff_settings(ad: &[config::AutoDiff]) { - for &val in ad { + for val in ad { // We intentionally don't use a wildcard, to not forget handling anything new. match val { config::AutoDiff::PrintPerf => { @@ -599,6 +599,10 @@ fn enable_autodiff_settings(ad: &[config::AutoDiff]) { config::AutoDiff::PrintTA => { llvm::set_print_type(true); } + config::AutoDiff::PrintTAFn(fun) => { + llvm::set_print_type(true); // Enable general type printing + llvm::set_print_type_fun(&fun); // Set specific function to analyze + } config::AutoDiff::Inline => { llvm::set_inline(true); } diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index 2ad39fc8538..b94716b89d6 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -57,14 +57,19 @@ pub(crate) use self::Enzyme_AD::*; #[cfg(llvm_enzyme)] pub(crate) mod Enzyme_AD { + use std::ffi::{CString, c_char}; + use libc::c_void; + unsafe extern "C" { pub(crate) fn EnzymeSetCLBool(arg1: *mut ::std::os::raw::c_void, arg2: u8); + pub(crate) fn EnzymeSetCLString(arg1: *mut ::std::os::raw::c_void, arg2: *const c_char); } unsafe extern "C" { static mut EnzymePrintPerf: c_void; static mut EnzymePrintActivity: c_void; static mut EnzymePrintType: c_void; + static mut EnzymeFunctionToAnalyze: c_void; static mut EnzymePrint: c_void; static mut EnzymeStrictAliasing: c_void; static mut looseTypeAnalysis: c_void; @@ -86,6 +91,15 @@ pub(crate) mod Enzyme_AD { EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymePrintType), print as u8); } } + pub(crate) fn set_print_type_fun(fun_name: &str) { + let c_fun_name = CString::new(fun_name).unwrap(); + unsafe { + EnzymeSetCLString( + std::ptr::addr_of_mut!(EnzymeFunctionToAnalyze), + c_fun_name.as_ptr() as *const c_char, + ); + } + } pub(crate) fn set_print(print: bool) { unsafe { EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymePrint), print as u8); @@ -132,6 +146,9 @@ pub(crate) mod Fallback_AD { pub(crate) fn set_print_type(print: bool) { unimplemented!() } + pub(crate) fn set_print_type_fun(fun_name: &str) { + unimplemented!() + } pub(crate) fn set_print(print: bool) { unimplemented!() } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 60e1b465ba9..0f3e53d03d6 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -227,13 +227,15 @@ pub enum CoverageLevel { } /// The different settings that the `-Z autodiff` flag can have. -#[derive(Clone, Copy, PartialEq, Hash, Debug)] +#[derive(Clone, PartialEq, Hash, Debug)] pub enum AutoDiff { /// Enable the autodiff opt pipeline Enable, /// Print TypeAnalysis information PrintTA, + /// Print TypeAnalysis information for a specific function + PrintTAFn(String), /// Print ActivityAnalysis Information PrintAA, /// Print Performance Warnings from Enzyme diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 12fa05118ca..513a006e790 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -711,7 +711,7 @@ mod desc { pub(crate) const parse_list: &str = "a space-separated list of strings"; pub(crate) const parse_list_with_polarity: &str = "a comma-separated list of strings, with elements beginning with + or -"; - pub(crate) const parse_autodiff: &str = "a comma separated list of settings: `Enable`, `PrintSteps`, `PrintTA`, `PrintAA`, `PrintPerf`, `PrintModBefore`, `PrintModAfter`, `PrintModFinal`, `PrintPasses`, `NoPostopt`, `LooseTypes`, `Inline`"; + pub(crate) const parse_autodiff: &str = "a comma separated list of settings: `Enable`, `PrintSteps`, `PrintTA`, `PrintTAFn`, `PrintAA`, `PrintPerf`, `PrintModBefore`, `PrintModAfter`, `PrintModFinal`, `PrintPasses`, `NoPostopt`, `LooseTypes`, `Inline`"; pub(crate) const parse_comma_list: &str = "a comma-separated list of strings"; pub(crate) const parse_opt_comma_list: &str = parse_comma_list; pub(crate) const parse_number: &str = "a number"; @@ -1351,9 +1351,22 @@ pub mod parse { let mut v: Vec<&str> = v.split(",").collect(); v.sort_unstable(); for &val in v.iter() { - let variant = match val { + // Split each entry on '=' if it has an argument + let (key, arg) = match val.split_once('=') { + Some((k, a)) => (k, Some(a)), + None => (val, None), + }; + + let variant = match key { "Enable" => AutoDiff::Enable, "PrintTA" => AutoDiff::PrintTA, + "PrintTAFn" => { + if let Some(fun) = arg { + AutoDiff::PrintTAFn(fun.to_string()) + } else { + return false; + } + } "PrintAA" => AutoDiff::PrintAA, "PrintPerf" => AutoDiff::PrintPerf, "PrintSteps" => AutoDiff::PrintSteps, diff --git a/src/doc/rustc-dev-guide/src/autodiff/flags.md b/src/doc/rustc-dev-guide/src/autodiff/flags.md index 65287d9ba4c..efbb9ea3497 100644 --- a/src/doc/rustc-dev-guide/src/autodiff/flags.md +++ b/src/doc/rustc-dev-guide/src/autodiff/flags.md @@ -6,6 +6,7 @@ To support you while debugging or profiling, we have added support for an experi ```text PrintTA // Print TypeAnalysis information +PrintTAFn // Print TypeAnalysis information for a specific function PrintAA // Print ActivityAnalysis information Print // Print differentiated functions while they are being generated and optimized PrintPerf // Print AD related Performance warnings diff --git a/src/doc/unstable-book/src/compiler-flags/autodiff.md b/src/doc/unstable-book/src/compiler-flags/autodiff.md index 95c188d1f3b..28d2ece1468 100644 --- a/src/doc/unstable-book/src/compiler-flags/autodiff.md +++ b/src/doc/unstable-book/src/compiler-flags/autodiff.md @@ -10,6 +10,7 @@ Multiple options can be separated with a comma. Valid options are: `Enable` - Required flag to enable autodiff `PrintTA` - print Type Analysis Information +`PrintTAFn` - print Type Analysis Information for a specific function `PrintAA` - print Activity Analysis Information `PrintPerf` - print Performance Warnings from Enzyme `PrintSteps` - prints all intermediate transformations -- cgit 1.4.1-3-g733a5 From 58dce8ca86e2825ab2610fd9d70050f78a8d16d5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Jun 2025 15:20:33 +0200 Subject: give Pointer::into_parts a more scary name and offer a safer alternative --- compiler/rustc_codegen_cranelift/src/constant.rs | 2 +- compiler/rustc_codegen_gcc/src/common.rs | 2 +- compiler/rustc_codegen_llvm/src/common.rs | 2 +- .../rustc_const_eval/src/const_eval/eval_queries.rs | 13 +++++++------ compiler/rustc_const_eval/src/interpret/machine.rs | 3 +-- compiler/rustc_const_eval/src/interpret/memory.rs | 3 ++- compiler/rustc_const_eval/src/interpret/validity.rs | 8 +++++--- compiler/rustc_middle/src/mir/consts.rs | 5 +++-- .../rustc_middle/src/mir/interpret/allocation.rs | 4 ++-- compiler/rustc_middle/src/mir/interpret/pointer.rs | 21 ++++++++++++++------- compiler/rustc_middle/src/mir/interpret/value.rs | 4 ++-- compiler/rustc_middle/src/ty/print/pretty.rs | 2 +- compiler/rustc_mir_transform/src/gvn.rs | 2 +- src/tools/miri/src/alloc_addresses/mod.rs | 4 ++-- src/tools/miri/src/machine.rs | 2 +- src/tools/miri/src/provenance_gc.rs | 6 ++---- src/tools/miri/src/shims/foreign_items.rs | 2 +- 17 files changed, 47 insertions(+), 38 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 3a62cd52a9d..ee43eb736e6 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -133,7 +133,7 @@ pub(crate) fn codegen_const_value<'tcx>( } } Scalar::Ptr(ptr, _size) => { - let (prov, offset) = ptr.into_parts(); // we know the `offset` is relative + let (prov, offset) = ptr.prov_and_relative_offset(); let alloc_id = prov.alloc_id(); let base_addr = match fx.tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => { diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 58ff2f1f8f0..cc077059dba 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -261,7 +261,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { } } Scalar::Ptr(ptr, _size) => { - let (prov, offset) = ptr.into_parts(); // we know the `offset` is relative + let (prov, offset) = ptr.prov_and_relative_offset(); let alloc_id = prov.alloc_id(); let base_addr = match self.tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => { diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index ae5add59322..7cfab25bc50 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -268,7 +268,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { } } Scalar::Ptr(ptr, _size) => { - let (prov, offset) = ptr.into_parts(); + let (prov, offset) = ptr.prov_and_relative_offset(); let global_alloc = self.tcx.global_alloc(prov.alloc_id()); let base_addr = match global_alloc { GlobalAlloc::Memory(alloc) => { diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 569a07c3a01..38c7563f66c 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -209,9 +209,9 @@ pub(super) fn op_to_const<'tcx>( match immediate { Left(ref mplace) => { - // We know `offset` is relative to the allocation, so we can use `into_parts`. - let (prov, offset) = mplace.ptr().into_parts(); - let alloc_id = prov.expect("cannot have `fake` place for non-ZST type").alloc_id(); + let (prov, offset) = + mplace.ptr().into_pointer_or_addr().unwrap().prov_and_relative_offset(); + let alloc_id = prov.alloc_id(); ConstValue::Indirect { alloc_id, offset } } // see comment on `let force_as_immediate` above @@ -232,9 +232,10 @@ pub(super) fn op_to_const<'tcx>( imm.layout.ty, ); let msg = "`op_to_const` on an immediate scalar pair must only be used on slice references to the beginning of an actual allocation"; - // We know `offset` is relative to the allocation, so we can use `into_parts`. - let (prov, offset) = a.to_pointer(ecx).expect(msg).into_parts(); - let alloc_id = prov.expect(msg).alloc_id(); + let ptr = a.to_pointer(ecx).expect(msg); + let (prov, offset) = + ptr.into_pointer_or_addr().expect(msg).prov_and_relative_offset(); + let alloc_id = prov.alloc_id(); let data = ecx.tcx.global_alloc(alloc_id).unwrap_memory(); assert!(offset == abi::Size::ZERO, "{}", msg); let meta = b.to_target_usize(ecx).expect(msg); diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index d6d230fbd17..49b911e60d7 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -756,8 +756,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { ptr: Pointer, _size: i64, ) -> Option<(AllocId, Size, Self::ProvenanceExtra)> { - // We know `offset` is relative to the allocation, so we can use `into_parts`. - let (prov, offset) = ptr.into_parts(); + let (prov, offset) = ptr.prov_and_relative_offset(); Some((prov.alloc_id(), offset, prov.immutable())) } diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 69fceb02ff9..3b36bb85985 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -1596,7 +1596,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Some((alloc_id, offset, extra)) => Ok((alloc_id, offset, extra)), None => { assert!(M::Provenance::OFFSET_IS_ADDR); - let (_, addr) = ptr.into_parts(); + // Offset is absolute, as we just asserted. + let (_, addr) = ptr.into_raw_parts(); Err(addr.bytes()) } }, diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 998ef3729ea..c39a486627e 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -868,7 +868,9 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { fn add_data_range(&mut self, ptr: Pointer>, size: Size) { if let Some(data_bytes) = self.data_bytes.as_mut() { // We only have to store the offset, the rest is the same for all pointers here. - let (_prov, offset) = ptr.into_parts(); + // The logic is agnostic to wether the offset is relative or absolute as long as + // it is consistent. + let (_prov, offset) = ptr.into_raw_parts(); // Add this. data_bytes.add_range(offset, size); }; @@ -894,7 +896,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { .as_mplace_or_imm() .expect_left("place must be in memory") .ptr(); - let (_prov, offset) = ptr.into_parts(); + let (_prov, offset) = ptr.into_raw_parts(); offset } @@ -903,7 +905,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { // Our value must be in memory, otherwise we would not have set up `data_bytes`. let mplace = self.ecx.force_allocation(place)?; // Determine starting offset and size. - let (_prov, start_offset) = mplace.ptr().into_parts(); + let (_prov, start_offset) = mplace.ptr().into_raw_parts(); let (size, _align) = self .ecx .size_and_align_of_val(&mplace)? diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 2b2ffa71628..16edc240544 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -168,8 +168,9 @@ impl<'tcx> ConstValue<'tcx> { return Some(&[]); } // Non-empty slice, must have memory. We know this is a relative pointer. - let (inner_prov, offset) = ptr.into_parts(); - let data = tcx.global_alloc(inner_prov?.alloc_id()).unwrap_memory(); + let (inner_prov, offset) = + ptr.into_pointer_or_addr().ok()?.prov_and_relative_offset(); + let data = tcx.global_alloc(inner_prov.alloc_id()).unwrap_memory(); (data, offset.bytes(), offset.bytes() + len) } }; diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index dd55d039794..4198b198ab1 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -526,7 +526,7 @@ impl Allocation { let ptr_bytes = &mut bytes[idx..idx + ptr_size]; let bits = read_target_uint(endian, ptr_bytes).unwrap(); let (ptr_prov, ptr_offset) = - adjust_ptr(Pointer::new(alloc_id, Size::from_bytes(bits)))?.into_parts(); + adjust_ptr(Pointer::new(alloc_id, Size::from_bytes(bits)))?.into_raw_parts(); write_target_uint(endian, ptr_bytes, ptr_offset.bytes().into()).unwrap(); new_provenance.push((offset, ptr_prov)); } @@ -769,7 +769,7 @@ impl Allocation // as-is into memory. This also double-checks that `val.size()` matches `range.size`. let (bytes, provenance) = match val.to_bits_or_ptr_internal(range.size)? { Right(ptr) => { - let (provenance, offset) = ptr.into_parts(); + let (provenance, offset) = ptr.into_raw_parts(); (u128::from(offset.bytes()), Some(provenance)) } Left(data) => (data, None), diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index 25c7c26ddd9..2be3dd6fb7e 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -288,7 +288,7 @@ impl From for Pointer { impl From> for Pointer> { #[inline(always)] fn from(ptr: Pointer) -> Self { - let (prov, offset) = ptr.into_parts(); + let (prov, offset) = ptr.into_raw_parts(); Pointer::new(Some(prov), offset) } } @@ -314,9 +314,7 @@ impl Pointer> { assert!(Prov::OFFSET_IS_ADDR); self.offset } -} -impl Pointer> { /// Creates a pointer to the given address, with invalid provenance (i.e., cannot be used for /// any memory access). #[inline(always)] @@ -336,11 +334,11 @@ impl Pointer { Pointer { provenance, offset } } - /// Obtain the constituents of this pointer. Not that the meaning of the offset depends on the type `Prov`! - /// This function must only be used in the implementation of `Machine::ptr_get_alloc`, - /// and when a `Pointer` is taken apart to be stored efficiently in an `Allocation`. + /// Obtain the constituents of this pointer. Note that the meaning of the offset depends on the + /// type `Prov`! This is a low-level function that should only be used when absolutely + /// necessary. Prefer `prov_and_relative_offset` if possible. #[inline(always)] - pub fn into_parts(self) -> (Prov, Size) { + pub fn into_raw_parts(self) -> (Prov, Size) { (self.provenance, self.offset) } @@ -361,3 +359,12 @@ impl Pointer { self.wrapping_offset(Size::from_bytes(i as u64), cx) } } + +impl Pointer { + /// Return the provenance and relative offset stored in this pointer. Safer alternative to + /// `into_raw_parts` since the type ensures that the offset is indeed relative. + #[inline(always)] + pub fn prov_and_relative_offset(self) -> (CtfeProvenance, Size) { + (self.provenance, self.offset) + } +} diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 7ba0e5b5e07..af37361c059 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -109,7 +109,7 @@ impl Scalar { /// Create a Scalar from a pointer with an `Option<_>` provenance (where `None` represents a /// plain integer / "invalid" pointer). pub fn from_maybe_pointer(ptr: Pointer>, cx: &impl HasDataLayout) -> Self { - match ptr.into_parts() { + match ptr.into_raw_parts() { (Some(prov), offset) => Scalar::from_pointer(Pointer::new(prov, offset), cx), (None, offset) => { Scalar::Int(ScalarInt::try_from_uint(offset.bytes(), cx.pointer_size()).unwrap()) @@ -299,7 +299,7 @@ impl<'tcx, Prov: Provenance> Scalar { Ok(ScalarInt::try_from_uint(ptr.offset.bytes(), Size::from_bytes(sz)).unwrap()) } else { // We know `offset` is relative, since `OFFSET_IS_ADDR == false`. - let (prov, offset) = ptr.into_parts(); + let (prov, offset) = ptr.into_raw_parts(); // Because `OFFSET_IS_ADDR == false`, this unwrap can never fail. Err(Scalar::Ptr(Pointer::new(prov.get_alloc_id().unwrap(), offset), sz)) } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 1392d1d08fc..bee490b3648 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1755,7 +1755,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ) -> Result<(), PrintError> { define_scoped_cx!(self); - let (prov, offset) = ptr.into_parts(); + let (prov, offset) = ptr.prov_and_relative_offset(); match ty.kind() { // Byte strings (&[u8; N]) ty::Ref(_, inner, _) => { diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index b17b7f45000..335354c23b6 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1636,7 +1636,7 @@ fn op_to_prop_const<'tcx>( } let pointer = mplace.ptr().into_pointer_or_addr().ok()?; - let (prov, offset) = pointer.into_parts(); + let (prov, offset) = pointer.prov_and_relative_offset(); let alloc_id = prov.alloc_id(); intern_const_alloc_for_constprop(ecx, alloc_id).discard_err()?; diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 4a038fe6487..1796120cf8a 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -390,7 +390,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, interpret::Pointer> { let this = self.eval_context_ref(); - let (prov, offset) = ptr.into_parts(); // offset is relative (AllocId provenance) + let (prov, offset) = ptr.prov_and_relative_offset(); let alloc_id = prov.alloc_id(); // Get a pointer to the beginning of this allocation. @@ -447,7 +447,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> Option<(AllocId, Size)> { let this = self.eval_context_ref(); - let (tag, addr) = ptr.into_parts(); // addr is absolute (Tag provenance) + let (tag, addr) = ptr.into_raw_parts(); // addr is absolute (Miri provenance) let alloc_id = if let Provenance::Concrete { alloc_id, .. } = tag { alloc_id diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index b4d7db34efa..0bf849fe2b9 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -285,7 +285,7 @@ impl interpret::Provenance for Provenance { } fn fmt(ptr: &interpret::Pointer, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let (prov, addr) = ptr.into_parts(); // address is absolute + let (prov, addr) = ptr.into_raw_parts(); // offset is absolute address write!(f, "{:#x}", addr.bytes())?; if f.alternate() { write!(f, "{prov:#?}")?; diff --git a/src/tools/miri/src/provenance_gc.rs b/src/tools/miri/src/provenance_gc.rs index b3d715db9cd..6adf1448648 100644 --- a/src/tools/miri/src/provenance_gc.rs +++ b/src/tools/miri/src/provenance_gc.rs @@ -68,15 +68,13 @@ impl VisitProvenance for Provenance { impl VisitProvenance for StrictPointer { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { - let (prov, _offset) = self.into_parts(); - prov.visit_provenance(visit); + self.provenance.visit_provenance(visit); } } impl VisitProvenance for Pointer { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { - let (prov, _offset) = self.into_parts(); - prov.visit_provenance(visit); + self.provenance.visit_provenance(visit); } } diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 416cb1ab55e..97070eb742f 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -411,7 +411,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { AlignFromBytesError::TooLarge(_) => Align::MAX, } }); - let (_, addr) = ptr.into_parts(); // we know the offset is absolute + let addr = ptr.addr(); // Cannot panic since `align` is a power of 2 and hence non-zero. if addr.bytes().strict_rem(align.bytes()) != 0 { throw_unsup_format!( -- cgit 1.4.1-3-g733a5 From 4fd37c719824a49c639803c6d4be4ca401a43abd Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 27 Jun 2025 20:24:01 -0500 Subject: Disable f16 on Aarch64 without neon for llvm < 20.1.1 This check was added unconditionally in c51b229140 ("Disable f16 on Aarch64 without `neon`") and reverted in 4a8d35709e ("Revert "Disable `f16` on Aarch64 without `neon`"") since it did not fail in Rust's build. However, it is still possible to hit this crash if using LLVM 19 built with assertions, so disable the type conditionally based on version here. Note that for these builds, a similar patch is needed in the build script for `compiler-builtins` since it does not yet use `cfg(target_has_reliable_f16)` (hopefully to be resolved in the near future). Report: https://www.github.com/rust-lang/rust/pull/139276#issuecomment-3014781652 Original LLVM issue: https://www.github.com/llvm/llvm-project/issues/129394 --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 6fd07d562af..0fb987bdf82 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -370,10 +370,18 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) { let target_env = sess.target.options.env.as_ref(); let target_abi = sess.target.options.abi.as_ref(); let target_pointer_width = sess.target.pointer_width; + let version = get_version(); cfg.has_reliable_f16 = match (target_arch, target_os) { // Selection failure ("s390x", _) => false, + // LLVM crash without neon (now fixed) + ("aarch64", _) + if !cfg.target_features.iter().any(|f| f.as_str() == "neon") + && version < (20, 1, 1) => + { + false + } // Unsupported ("arm64ec", _) => false, // MinGW ABI bugs -- cgit 1.4.1-3-g733a5 From c76d032f0144b650a438ee1efba89c475e0b115b Mon Sep 17 00:00:00 2001 From: klensy Date: Sat, 7 Dec 2024 13:51:08 +0300 Subject: setup CI and tidy to use typos for spellchecking and fix few typos --- .github/workflows/spellcheck.yml | 23 +++++++ REUSE.toml | 1 + compiler/rustc_ast/src/ast.rs | 2 +- compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_passes/messages.ftl | 2 +- compiler/rustc_attr_parsing/src/attributes/cfg.rs | 2 +- compiler/rustc_attr_parsing/src/context.rs | 2 +- compiler/rustc_builtin_macros/src/autodiff.rs | 4 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 4 +- compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 2 +- compiler/rustc_codegen_llvm/src/va_arg.rs | 2 +- compiler/rustc_codegen_ssa/messages.ftl | 2 +- compiler/rustc_codegen_ssa/src/back/link.rs | 6 +- compiler/rustc_codegen_ssa/src/back/metadata.rs | 2 +- compiler/rustc_codegen_ssa/src/target_features.rs | 2 +- compiler/rustc_codegen_ssa/src/traits/builder.rs | 2 +- compiler/rustc_const_eval/src/interpret/place.rs | 2 +- .../rustc_const_eval/src/interpret/validity.rs | 2 +- .../src/util/check_validity_requirement.rs | 2 +- compiler/rustc_data_structures/src/vec_cache.rs | 2 +- compiler/rustc_errors/src/markdown/parse.rs | 2 +- compiler/rustc_expand/src/proc_macro_server.rs | 2 +- compiler/rustc_hir/src/hir.rs | 8 +-- .../rustc_hir_analysis/src/hir_ty_lowering/mod.rs | 2 +- compiler/rustc_hir_typeck/src/coercion.rs | 2 +- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 4 +- compiler/rustc_hir_typeck/src/method/confirm.rs | 2 +- compiler/rustc_hir_typeck/src/method/mod.rs | 2 +- compiler/rustc_hir_typeck/src/pat.rs | 2 +- compiler/rustc_lexer/src/lib.rs | 2 +- compiler/rustc_lint/src/autorefs.rs | 2 +- .../rustc_lint/src/default_could_be_derived.rs | 2 +- compiler/rustc_lint/src/if_let_rescope.rs | 2 +- compiler/rustc_lint/src/reference_casting.rs | 2 +- compiler/rustc_lint_defs/src/builtin.rs | 2 +- compiler/rustc_macros/src/lib.rs | 2 +- compiler/rustc_macros/src/query.rs | 4 +- compiler/rustc_metadata/src/locator.rs | 4 +- compiler/rustc_middle/src/mir/interpret/error.rs | 2 +- compiler/rustc_middle/src/mir/mod.rs | 2 +- compiler/rustc_middle/src/mir/syntax.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/instance.rs | 6 +- .../rustc_middle/src/ty/significant_drop_order.rs | 2 +- compiler/rustc_middle/src/ty/sty.rs | 2 +- .../src/thir/pattern/const_to_pat.rs | 4 +- compiler/rustc_mir_transform/src/check_enums.rs | 4 +- compiler/rustc_mir_transform/src/gvn.rs | 2 +- .../src/lint_tail_expr_drop_order.rs | 2 +- compiler/rustc_mir_transform/src/ref_prop.rs | 20 +++--- compiler/rustc_mir_transform/src/shim.rs | 2 +- compiler/rustc_monomorphize/src/collector.rs | 2 +- compiler/rustc_monomorphize/src/partitioning.rs | 2 +- .../src/solve/effect_goals.rs | 2 +- .../src/solve/eval_ctxt/canonical.rs | 2 +- .../src/solve/normalizes_to/inherent.rs | 2 +- .../src/solve/trait_goals.rs | 2 +- compiler/rustc_passes/messages.ftl | 2 +- compiler/rustc_passes/src/dead.rs | 2 +- compiler/rustc_passes/src/errors.rs | 2 +- compiler/rustc_pattern_analysis/src/usefulness.rs | 4 +- compiler/rustc_query_system/src/dep_graph/graph.rs | 2 +- compiler/rustc_resolve/src/errors.rs | 10 +-- compiler/rustc_resolve/src/late.rs | 8 +-- compiler/rustc_resolve/src/rustdoc.rs | 2 +- compiler/rustc_serialize/src/serialize.rs | 2 +- compiler/rustc_session/src/config.rs | 2 +- compiler/rustc_session/src/session.rs | 2 +- compiler/rustc_smir/src/stable_mir/ty.rs | 2 +- compiler/rustc_span/src/lib.rs | 2 +- compiler/rustc_span/src/symbol.rs | 2 +- compiler/rustc_target/src/callconv/s390x.rs | 2 +- .../src/error_reporting/traits/suggestions.rs | 2 +- compiler/rustc_trait_selection/src/errors.rs | 2 +- .../src/traits/dyn_compatibility.rs | 2 +- .../rustc_trait_selection/src/traits/effects.rs | 4 +- compiler/rustc_trait_selection/src/traits/mod.rs | 2 +- .../src/traits/select/confirmation.rs | 2 +- compiler/rustc_ty_utils/src/opaque_types.rs | 2 +- compiler/rustc_type_ir/src/infer_ctxt.rs | 2 +- compiler/rustc_type_ir/src/search_graph/mod.rs | 6 +- library/core/src/fmt/num.rs | 2 +- library/core/src/intrinsics/mod.rs | 6 +- library/core/src/intrinsics/simd.rs | 4 +- library/core/src/io/borrowed_buf.rs | 2 +- library/core/src/lib.rs | 2 +- library/core/src/num/dec2flt/float.rs | 6 +- library/core/src/pin.rs | 2 +- library/core/src/ptr/const_ptr.rs | 4 +- library/core/src/ptr/mut_ptr.rs | 2 +- library/core/src/ptr/non_null.rs | 2 +- library/coretests/tests/num/dec2flt/float.rs | 4 +- library/std/src/fs.rs | 2 +- library/std/src/os/unix/process.rs | 2 +- .../std/src/sys/net/connection/socket/wasip2.rs | 2 +- library/std/src/sys/pal/uefi/helpers.rs | 6 +- library/std/src/sys/path/cygwin.rs | 2 +- library/std/src/sys/random/linux.rs | 4 +- library/std/src/sys/random/unsupported.rs | 2 +- library/std/src/thread/spawnhook.rs | 2 +- library/std/src/time.rs | 6 +- library/std/tests/thread_local/tests.rs | 2 +- src/bootstrap/src/core/build_steps/format.rs | 2 +- src/bootstrap/src/core/config/flags.rs | 2 +- src/bootstrap/src/utils/change_tracker.rs | 4 +- src/etc/completions/x.py.fish | 2 +- src/etc/completions/x.py.ps1 | 2 +- src/etc/completions/x.py.zsh | 2 +- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/doctest.rs | 2 +- src/librustdoc/doctest/extracted.rs | 2 +- src/librustdoc/html/markdown/footnotes.rs | 4 +- src/librustdoc/html/render/mod.rs | 2 +- src/librustdoc/html/render/write_shared.rs | 2 +- src/librustdoc/html/static/js/main.js | 2 +- src/librustdoc/html/static/js/rustdoc.d.ts | 2 +- src/librustdoc/passes/strip_aliased_non_local.rs | 2 +- src/librustdoc/passes/strip_hidden.rs | 2 +- src/tools/miri/src/shims/backtrace.rs | 2 +- src/tools/tidy/src/ext_tool_checks.rs | 53 ++++++++++++++++ tests/ui/abi/bad-custom.stderr | 2 +- tests/ui/abi/cannot-be-coroutine.avr.stderr | 2 +- tests/ui/abi/cannot-be-coroutine.i686.stderr | 2 +- tests/ui/abi/cannot-be-coroutine.msp430.stderr | 2 +- tests/ui/abi/cannot-be-coroutine.riscv32.stderr | 4 +- tests/ui/abi/cannot-be-coroutine.riscv64.stderr | 4 +- tests/ui/abi/cannot-be-coroutine.x64.stderr | 2 +- tests/ui/abi/cannot-be-coroutine.x64_win.stderr | 2 +- typos.toml | 74 ++++++++++++++++++++++ 129 files changed, 326 insertions(+), 175 deletions(-) create mode 100644 .github/workflows/spellcheck.yml create mode 100644 typos.toml (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/spellcheck.yml new file mode 100644 index 00000000000..7e21bb1b7ff --- /dev/null +++ b/.github/workflows/spellcheck.yml @@ -0,0 +1,23 @@ +# This workflow runs spellcheck job + +name: Spellcheck +on: + pull_request: + branches: + - "**" + +jobs: + spellcheck: + name: run spellchecker + runs-on: ubuntu-latest + steps: + - name: Checkout the source code + uses: actions/checkout@v4 + + - name: check typos + # sync version with src/tools/tidy/src/ext_tool_checks.rs in spellcheck_runner + uses: crate-ci/typos@v1.34.0 + with: + # sync target files with src/tools/tidy/src/ext_tool_checks.rs in check_impl + files: ./compiler ./library ./src/bootstrap ./src/librustdoc + config: ./typos.toml diff --git a/REUSE.toml b/REUSE.toml index 816c6d730c8..027b4ccbe25 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -36,6 +36,7 @@ path = [ "rustfmt.toml", "rust-bors.toml", "triagebot.toml", + "typos.toml", "x", "x.ps1", "x.py", diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 286bbfb5ae8..86f4497bfde 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1344,7 +1344,7 @@ impl Expr { } } - /// Returns an expression with (when possible) *one* outter brace removed + /// Returns an expression with (when possible) *one* outer brace removed pub fn maybe_unwrap_block(&self) -> &Expr { if let ExprKind::Block(block, None) = &self.kind && let [stmt] = block.stmts.as_slice() diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index d0c2b2bf68b..f9076f1f53d 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -142,7 +142,7 @@ macro_rules! common_visitor_and_walkers { )? // Methods in this trait have one of three forms, with the last two forms - // only occuring on `MutVisitor`: + // only occurring on `MutVisitor`: // // fn visit_t(&mut self, t: &mut T); // common // fn flat_map_t(&mut self, t: T) -> SmallVec<[T; 1]>; // rare diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 4290f7b7ede..d58c140c696 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -1,6 +1,6 @@ ast_passes_abi_cannot_be_coroutine = functions with the {$abi} ABI cannot be `{$coroutine_kind_str}` - .suggestion = remove the `{$coroutine_kind_str}` keyword from this definiton + .suggestion = remove the `{$coroutine_kind_str}` keyword from this definition ast_passes_abi_custom_safe_foreign_function = foreign functions with the "custom" ABI cannot be safe diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index f4d23012af7..a8d9229cbc3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -14,7 +14,7 @@ use crate::{fluent_generated, parse_version}; /// Emitter of a builtin lint from `cfg_matches`. /// -/// Used to support emiting a lint (currently on check-cfg), either: +/// Used to support emitting a lint (currently on check-cfg), either: /// - as an early buffered lint (in `rustc`) /// - or has a "normal" lint from HIR (in `rustdoc`) pub trait CfgMatchesLintEmitter { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index cfba0650932..940a2996851 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -187,7 +187,7 @@ impl Stage for Late { } } -/// used when parsing attributes for miscelaneous things *before* ast lowering +/// used when parsing attributes for miscellaneous things *before* ast lowering pub struct Early; /// used when parsing attributes during ast lowering pub struct Late; diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index df1b1eb60e1..c7844778332 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -562,7 +562,7 @@ mod llvm_enzyme { /// so instead we manually build something that should pass the type checker. /// We also add a inline_asm line, as one more barrier for rustc to prevent inlining /// or const propagation. inline_asm will also triggers an Enzyme crash if due to another - /// bug would ever try to accidentially differentiate this placeholder function body. + /// bug would ever try to accidentally differentiate this placeholder function body. /// Finally, we also add back_box usages of all input arguments, to prevent rustc /// from optimizing any arguments away. fn gen_enzyme_body( @@ -606,7 +606,7 @@ mod llvm_enzyme { return body; } - // Everything from here onwards just tries to fullfil the return type. Fun! + // Everything from here onwards just tries to fulfil the return type. Fun! // having an active-only return means we'll drop the original return type. // So that can be treated identical to not having one in the first place. diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 9930eae3fe7..776658b9cca 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -107,7 +107,7 @@ fn call_simple_intrinsic<'ll, 'tcx>( sym::minimumf32 => ("llvm.minimum", &[bx.type_f32()]), sym::minimumf64 => ("llvm.minimum", &[bx.type_f64()]), // There are issues on x86_64 and aarch64 with the f128 variant, - // let's instead use the instrinsic fallback body. + // let's instead use the intrinsic fallback body. // sym::minimumf128 => ("llvm.minimum", &[cx.type_f128()]), sym::maxnumf16 => ("llvm.maxnum", &[bx.type_f16()]), sym::maxnumf32 => ("llvm.maxnum", &[bx.type_f32()]), @@ -118,7 +118,7 @@ fn call_simple_intrinsic<'ll, 'tcx>( sym::maximumf32 => ("llvm.maximum", &[bx.type_f32()]), sym::maximumf64 => ("llvm.maximum", &[bx.type_f64()]), // There are issues on x86_64 and aarch64 with the f128 variant, - // let's instead use the instrinsic fallback body. + // let's instead use the intrinsic fallback body. // sym::maximumf128 => ("llvm.maximum", &[cx.type_f128()]), sym::copysignf16 => ("llvm.copysign", &[bx.type_f16()]), sym::copysignf32 => ("llvm.copysign", &[bx.type_f32()]), diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index b94716b89d6..7b00b2da6ba 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -40,7 +40,7 @@ unsafe extern "C" { pub(crate) fn LLVMDumpValue(V: &Value); pub(crate) fn LLVMGetFunctionCallConv(F: &Value) -> c_uint; pub(crate) fn LLVMGetReturnType(T: &Type) -> &Type; - pub(crate) fn LLVMGetParams(Fnc: &Value, parms: *mut &Value); + pub(crate) fn LLVMGetParams(Fnc: &Value, params: *mut &Value); pub(crate) fn LLVMGetNamedFunction(M: &Module, Name: *const c_char) -> Option<&Value>; } diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 236568590be..4fe4c9bcbf2 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -861,7 +861,7 @@ fn emit_xtensa_va_arg<'ll, 'tcx>( // On big-endian, for values smaller than the slot size we'd have to align the read to the end // of the slot rather than the start. While the ISA and GCC support big-endian, all the Xtensa - // targets supported by rustc are litte-endian so don't worry about it. + // targets supported by rustc are little-endian so don't worry about it. // if from_regsave { // unsafe { *regsave_value_ptr } diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 84d63819343..63f47b9b7de 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -289,7 +289,7 @@ codegen_ssa_thorin_missing_referenced_unit = unit {$unit} referenced by executab codegen_ssa_thorin_missing_required_section = input object missing required section `{$section}` -codegen_ssa_thorin_mixed_input_encodings = input objects haved mixed encodings +codegen_ssa_thorin_mixed_input_encodings = input objects have mixed encodings codegen_ssa_thorin_multiple_debug_info_section = multiple `.debug_info.dwo` sections diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 4a2425967e4..343cb0eeca9 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2767,7 +2767,7 @@ fn add_upstream_rust_crates( if sess.target.is_like_aix { // Unlike ELF linkers, AIX doesn't feature `DT_SONAME` to override - // the dependency name when outputing a shared library. Thus, `ld` will + // the dependency name when outputting a shared library. Thus, `ld` will // use the full path to shared libraries as the dependency if passed it // by default unless `noipath` is passed. // https://www.ibm.com/docs/en/aix/7.3?topic=l-ld-command. @@ -3051,7 +3051,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo // Supported architecture names can be found in the source: // https://github.com/apple-oss-distributions/ld64/blob/ld64-951.9/src/abstraction/MachOFileAbstraction.hpp#L578-L648 // - // Intentially verbose to ensure that the list always matches correctly + // Intentionally verbose to ensure that the list always matches correctly // with the list in the source above. let ld64_arch = match llvm_arch { "armv7k" => "armv7k", @@ -3118,7 +3118,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo // We do not currently know the actual SDK version though, so we have a few options: // 1. Use the minimum version supported by rustc. // 2. Use the same as the deployment target. - // 3. Use an arbitary recent version. + // 3. Use an arbitrary recent version. // 4. Omit the version. // // The first option is too low / too conservative, and means that users will not get the diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index d091c46d9c1..bf38c02e908 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -301,7 +301,7 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 { "n32" if !is_32bit => e_flags |= elf::EF_MIPS_ABI2, "n64" if !is_32bit => {} "" if is_32bit => e_flags |= elf::EF_MIPS_ABI_O32, - "" => sess.dcx().fatal("LLVM ABI must be specifed for 64-bit MIPS targets"), + "" => sess.dcx().fatal("LLVM ABI must be specified for 64-bit MIPS targets"), s if is_32bit => { sess.dcx().fatal(format!("invalid LLVM ABI `{}` for 32-bit MIPS target", s)) } diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 67ac619091b..faa278cc766 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -457,7 +457,7 @@ pub(crate) fn provide(providers: &mut Providers) { // one, just keep it. } _ => { - // Overwrite stabilite. + // Overwrite stability. occupied_entry.insert(stability); } } diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index d19de6f5d26..9d367748c2a 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -87,7 +87,7 @@ pub trait BuilderMethods<'a, 'tcx>: // // This function is opt-in for back ends. // - // The default implementation calls `self.expect()` before emiting the branch + // The default implementation calls `self.expect()` before emitting the branch // by calling `self.cond_br()` fn cond_br_with_expect( &mut self, diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index a3cd35ff0bb..e2284729efd 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -572,7 +572,7 @@ where Right((local, offset, locals_addr, layout)) => { if offset.is_some() { // This has been projected to a part of this local, or had the type changed. - // FIMXE: there are cases where we could still avoid allocating an mplace. + // FIXME: there are cases where we could still avoid allocating an mplace. Left(place.force_mplace(self)?) } else { debug_assert_eq!(locals_addr, self.frame().locals_addr()); diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index e26cf0a4900..fc4d13af8c4 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -865,7 +865,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { fn add_data_range(&mut self, ptr: Pointer>, size: Size) { if let Some(data_bytes) = self.data_bytes.as_mut() { // We only have to store the offset, the rest is the same for all pointers here. - // The logic is agnostic to wether the offset is relative or absolute as long as + // The logic is agnostic to whether the offset is relative or absolute as long as // it is consistent. let (_prov, offset) = ptr.into_raw_parts(); // Add this. diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index d7e97f32bae..4ca39bbc68e 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -69,7 +69,7 @@ fn check_validity_requirement_strict<'tcx>( // require dereferenceability also require non-null, we don't actually get any false negatives // due to this. // The value we are validating is temporary and discarded at the end of this function, so - // there is no point in reseting provenance and padding. + // there is no point in resetting provenance and padding. cx.validate_operand( &allocated.into(), /*recursive*/ false, diff --git a/compiler/rustc_data_structures/src/vec_cache.rs b/compiler/rustc_data_structures/src/vec_cache.rs index 3b448c056b7..0ffa6b3205f 100644 --- a/compiler/rustc_data_structures/src/vec_cache.rs +++ b/compiler/rustc_data_structures/src/vec_cache.rs @@ -257,7 +257,7 @@ unsafe impl Drop for VecCache { // we are also guaranteed to just need to deallocate any large arrays (not iterate over // contents). // - // Confirm no need to deallocate invidual entries. Note that `V: Copy` is asserted on + // Confirm no need to deallocate individual entries. Note that `V: Copy` is asserted on // insert/lookup but not necessarily construction, primarily to avoid annoyingly propagating // the bounds into struct definitions everywhere. assert!(!std::mem::needs_drop::()); diff --git a/compiler/rustc_errors/src/markdown/parse.rs b/compiler/rustc_errors/src/markdown/parse.rs index f02387d8335..e1b1b32cd3e 100644 --- a/compiler/rustc_errors/src/markdown/parse.rs +++ b/compiler/rustc_errors/src/markdown/parse.rs @@ -352,7 +352,7 @@ fn normalize<'a>(MdStream(stream): MdStream<'a>, linkdefs: &mut Vec>) let new_defs = stream.iter().filter(|tt| matches!(tt, MdTree::LinkDef { .. })); linkdefs.extend(new_defs.cloned()); - // Run plaintest expansions on types that need it, call this function on nested types + // Run plaintext expansions on types that need it, call this function on nested types for item in stream { match item { MdTree::PlainText(txt) => expand_plaintext(txt, &mut new_stream, MdTree::PlainText), diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index af91c8b8f00..fd71f2ce948 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -681,7 +681,7 @@ impl server::Span for Rustc<'_, '_> { .lookup_char_pos(span.lo()) .file .name - .prefer_remapped_unconditionaly() + .prefer_remapped_unconditionally() .to_string() } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index c90cd93ff07..ca6405ea209 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -439,7 +439,7 @@ impl<'hir> ConstArg<'hir, AmbigArg> { } impl<'hir> ConstArg<'hir> { - /// Converts a `ConstArg` in an unambigous position to one in an ambiguous position. This is + /// Converts a `ConstArg` in an unambiguous position to one in an ambiguous position. This is /// fallible as the [`ConstArgKind::Infer`] variant is not present in ambiguous positions. /// /// Functions accepting ambiguous consts will not handle the [`ConstArgKind::Infer`] variant, if @@ -508,7 +508,7 @@ pub enum GenericArg<'hir> { Lifetime(&'hir Lifetime), Type(&'hir Ty<'hir, AmbigArg>), Const(&'hir ConstArg<'hir, AmbigArg>), - /// Inference variables in [`GenericArg`] are always represnted by + /// Inference variables in [`GenericArg`] are always represented by /// `GenericArg::Infer` instead of the `Infer` variants on [`TyKind`] and /// [`ConstArgKind`] as it is not clear until hir ty lowering whether a /// `_` argument is a type or const argument. @@ -3323,7 +3323,7 @@ impl<'hir> Ty<'hir, AmbigArg> { } impl<'hir> Ty<'hir> { - /// Converts a `Ty` in an unambigous position to one in an ambiguous position. This is + /// Converts a `Ty` in an unambiguous position to one in an ambiguous position. This is /// fallible as the [`TyKind::Infer`] variant is not present in ambiguous positions. /// /// Functions accepting ambiguous types will not handle the [`TyKind::Infer`] variant, if @@ -4224,7 +4224,7 @@ impl fmt::Display for Constness { } } -/// The actualy safety specified in syntax. We may treat +/// The actual safety specified in syntax. We may treat /// its safety different within the type system to create a /// "sound by default" system that needs checking this enum /// explicitly to allow unsafe operations. diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 6b2854d96af..f335c0e2f40 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1088,7 +1088,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // FIXME(#97583): Print associated item bindings properly (i.e., not as equality // predicates!). - // FIXME: Turn this into a structured, translateable & more actionable suggestion. + // FIXME: Turn this into a structured, translatable & more actionable suggestion. let mut where_bounds = vec![]; for bound in [bound, bound2].into_iter().chain(matching_candidates) { let bound_id = bound.def_id(); diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 3ca04ba330b..b2a229ad651 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -726,7 +726,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Err(SelectionError::TraitDynIncompatible(_)) => { // Dyn compatibility errors in coercion will *always* be due to the // fact that the RHS of the coercion is a non-dyn compatible `dyn Trait` - // writen in source somewhere (otherwise we will never have lowered + // written in source somewhere (otherwise we will never have lowered // the dyn trait from HIR to middle). // // There's no reason to emit yet another dyn compatibility error, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 3c53a060f7f..eeb8d33ef65 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -121,7 +121,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => {} } - // We want to emit an error if the const is not structurally resolveable + // We want to emit an error if the const is not structurally resolvable // as otherwise we can wind up conservatively proving `Copy` which may // infer the repeat expr count to something that never required `Copy` in // the first place. @@ -2461,7 +2461,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { spans.push_span_label(param.param.span(), ""); } } - // Highligh each parameter being depended on for a generic type. + // Highlight each parameter being depended on for a generic type. for ((&(_, param), deps), &(_, expected_ty)) in params_with_generics.iter().zip(&dependants).zip(formal_and_expected_inputs) { diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 9563cf734f6..4c343bb7c22 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -588,7 +588,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { let def_id = pick.item.def_id; let method_predicates = self.tcx.predicates_of(def_id).instantiate(self.tcx, all_args); - debug!("method_predicates after instantitation = {:?}", method_predicates); + debug!("method_predicates after instantiation = {:?}", method_predicates); let sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, all_args); debug!("type scheme instantiated, sig={:?}", sig); diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 085e7a2f5df..8380c3710e6 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -375,7 +375,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // type parameters or early-bound regions. let tcx = self.tcx; // We use `Ident::with_dummy_span` since no built-in operator methods have - // any macro-specific hygeine, so the span's context doesn't really matter. + // any macro-specific hygiene, so the span's context doesn't really matter. let Some(method_item) = self.associated_value(trait_def_id, Ident::with_dummy_span(method_name)) else { diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 349e72090d3..43475521a0f 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -723,7 +723,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This is maximally flexible, allowing e.g., `Some(mut x) | &Some(mut x)`. // In that example, `Some(mut x)` results in `Peel` whereas `&Some(mut x)` in `Reset`. | PatKind::Or(_) - // Like or-patterns, guard patterns just propogate to their subpatterns. + // Like or-patterns, guard patterns just propagate to their subpatterns. | PatKind::Guard(..) => AdjustMode::Pass, } } diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index b2bd5e188ef..e30dbe80248 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -566,7 +566,7 @@ impl Cursor<'_> { } if !found { - // recovery strategy: a closing statement might have precending whitespace/newline + // recovery strategy: a closing statement might have preceding whitespace/newline // but not have enough dashes to properly close. In this case, we eat until there, // and report a mismatch in the parser. let mut rest = self.as_str(); diff --git a/compiler/rustc_lint/src/autorefs.rs b/compiler/rustc_lint/src/autorefs.rs index 845a1f1b81f..5490a3aac9b 100644 --- a/compiler/rustc_lint/src/autorefs.rs +++ b/compiler/rustc_lint/src/autorefs.rs @@ -41,7 +41,7 @@ declare_lint! { /// } /// ``` /// - /// Otherwise try to find an alternative way to achive your goals using only raw pointers: + /// Otherwise try to find an alternative way to achieve your goals using only raw pointers: /// /// ```rust /// use std::ptr; diff --git a/compiler/rustc_lint/src/default_could_be_derived.rs b/compiler/rustc_lint/src/default_could_be_derived.rs index 7734f441df2..0bc772d081f 100644 --- a/compiler/rustc_lint/src/default_could_be_derived.rs +++ b/compiler/rustc_lint/src/default_could_be_derived.rs @@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived { // } // } // where `something()` would have to be a call or path. - // We have nothing meaninful to do with this. + // We have nothing meaningful to do with this. return; } diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index a9b04511c6b..263ea6fa070 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -230,7 +230,7 @@ impl IfLetRescope { } } } - // At this point, any `if let` fragment in the cascade is definitely preceeded by `else`, + // At this point, any `if let` fragment in the cascade is definitely preceded by `else`, // so a opening bracket is mandatory before each `match`. add_bracket_to_match_head = true; if let Some(alt) = alt { diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs index 1d4d380cb68..6ef9d4e9769 100644 --- a/compiler/rustc_lint/src/reference_casting.rs +++ b/compiler/rustc_lint/src/reference_casting.rs @@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting { let init = cx.expr_or_init(e); let orig_cast = if init.span != e.span { Some(init.span) } else { None }; - // small cache to avoid recomputing needlesly computing peel_casts of init + // small cache to avoid recomputing needlessly computing peel_casts of init let mut peel_casts = { let mut peel_casts_cache = None; move || *peel_casts_cache.get_or_insert_with(|| peel_casts(cx, init)) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 10ac14a2fbf..b37548b281c 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1224,7 +1224,7 @@ declare_lint! { /// /// ### Explanation /// - /// A public `use` declaration should not be used to publicly re-export a + /// A public `use` declaration should not be used to publically re-export a /// private `extern crate`. `pub extern crate` should be used instead. /// /// This was historically allowed, but is not the intended behavior diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 42d006ef301..1006ea3ba10 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -177,7 +177,7 @@ decl_derive! { [PrintAttribute] => /// Derives `PrintAttribute` for `AttributeKind`. /// This macro is pretty specific to `rustc_attr_data_structures` and likely not that useful in - /// other places. It's deriving something close to `Debug` without printing some extraenous + /// other places. It's deriving something close to `Debug` without printing some extraneous /// things like spans. print_attribute::print_attribute } diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 2196f71299a..c21ab3ab56f 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -273,8 +273,8 @@ fn add_query_desc_cached_impl( // macro producing a higher order macro that has all its token in the macro declaration we lose // any meaningful spans, resulting in rust-analyzer being unable to make the connection between // the query name and the corresponding providers field. The trick to fix this is to have - // `rustc_queries` emit a field access with the given name's span which allows it to succesfully - // show references / go to definition to the correspondig provider assignment which is usually + // `rustc_queries` emit a field access with the given name's span which allows it to successfully + // show references / go to definition to the corresponding provider assignment which is usually // the more interesting place. let ra_hint = quote! { let crate::query::Providers { #name: _, .. }; diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 941f16bd960..82254f0a381 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -437,8 +437,8 @@ impl<'a> CrateLocator<'a> { let (rlibs, rmetas, dylibs, interfaces) = candidates.entry(hash).or_default(); { - // As a perforamnce optimisation we canonicalize the path and skip - // ones we've already seeen. This allows us to ignore crates + // As a performance optimisation we canonicalize the path and skip + // ones we've already seen. This allows us to ignore crates // we know are exactual equal to ones we've already found. // Going to the same crate through different symlinks does not change the result. let path = try_canonicalize(&spf.path) diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 41a166083d0..8acb8fa9f80 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -116,7 +116,7 @@ impl<'tcx> From for ValTreeCreationError<'tcx> { impl<'tcx> From> for ValTreeCreationError<'tcx> { fn from(err: InterpErrorInfo<'tcx>) -> Self { - // An error ocurred outside the const-eval query, as part of constructing the valtree. We + // An error occurred outside the const-eval query, as part of constructing the valtree. We // don't currently preserve the details of this error, since `InterpErrorInfo` cannot be put // into a query result and it can only be access of some mutable or external memory. let (_kind, backtrace) = err.into_parts(); diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 33e97766a02..e819aa2d8f8 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -262,7 +262,7 @@ pub struct Body<'tcx> { /// us to see the difference and forego optimization on the inlined promoted items. pub phase: MirPhase, - /// How many passses we have executed since starting the current phase. Used for debug output. + /// How many passes we have executed since starting the current phase. Used for debug output. pub pass_count: usize, pub source: MirSource<'tcx>, diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 92eefd89848..6039a03aa29 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -381,7 +381,7 @@ pub enum StatementKind<'tcx> { /// computing these locals. /// /// If the local is already allocated, calling `StorageLive` again will implicitly free the - /// local and then allocate fresh uninitilized memory. If a local is already deallocated, + /// local and then allocate fresh uninitialized memory. If a local is already deallocated, /// calling `StorageDead` again is a NOP. StorageLive(Local), diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 3e68f0f784e..eb981177fa2 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -355,7 +355,7 @@ rustc_queries! { /// Returns whether the type alias given by `DefId` is lazy. /// /// I.e., if the type alias expands / ought to expand to a [free] [alias type] - /// instead of the underyling aliased type. + /// instead of the underlying aliased type. /// /// Relevant for features `lazy_type_alias` and `type_alias_impl_trait`. /// diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 68adfb3cdb3..21b7500e46f 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -71,7 +71,7 @@ pub enum InstanceKind<'tcx> { /// - coroutines Item(DefId), - /// An intrinsic `fn` item (with`#[rustc_instrinsic]`). + /// An intrinsic `fn` item (with`#[rustc_intrinsic]`). /// /// Alongside `Virtual`, this is the only `InstanceKind` that does not have its own callable MIR. /// Instead, codegen and const eval "magically" evaluate calls to intrinsics purely in the @@ -445,10 +445,10 @@ impl<'tcx> fmt::Display for Instance<'tcx> { } } -// async_drop_in_place::coroutine.poll, when T is a standart coroutine, +// async_drop_in_place::coroutine.poll, when T is a standard coroutine, // should be resolved to this coroutine's future_drop_poll (through FutureDropPollShim proxy). // async_drop_in_place::coroutine>::coroutine.poll, -// when T is a standart coroutine, should be resolved to this coroutine's future_drop_poll. +// when T is a standard coroutine, should be resolved to this coroutine's future_drop_poll. // async_drop_in_place::coroutine>::coroutine.poll, // when T is not a coroutine, should be resolved to the innermost // async_drop_in_place::coroutine's poll function (through FutureDropPollShim proxy) diff --git a/compiler/rustc_middle/src/ty/significant_drop_order.rs b/compiler/rustc_middle/src/ty/significant_drop_order.rs index 561f84192b4..5ada9ecc80c 100644 --- a/compiler/rustc_middle/src/ty/significant_drop_order.rs +++ b/compiler/rustc_middle/src/ty/significant_drop_order.rs @@ -70,7 +70,7 @@ fn true_significant_drop_ty<'tcx>( } } -/// Returns the list of types with a "potentially sigificant" that may be dropped +/// Returns the list of types with a "potentially significant" that may be dropped /// by dropping a value of type `ty`. #[instrument(level = "trace", skip(tcx, typing_env))] pub fn extract_component_raw<'tcx>( diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 399a6d6ebc5..7a1890226c9 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1676,7 +1676,7 @@ impl<'tcx> Ty<'tcx> { /// This is particularly useful for getting the type of the result of /// [`UnOp::PtrMetadata`](crate::mir::UnOp::PtrMetadata). /// - /// Panics if `self` is not dereferencable. + /// Panics if `self` is not dereferenceable. #[track_caller] pub fn pointee_metadata_ty_or_projection(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { let Some(pointee_ty) = self.builtin_deref(true) else { diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 003ad170861..6d617d43c2a 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -365,11 +365,11 @@ fn extend_type_not_partial_eq<'tcx>( struct UsedParamsNeedInstantiationVisitor<'tcx> { tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, - /// The user has written `impl PartialEq for Ty` which means it's non-structual. + /// The user has written `impl PartialEq for Ty` which means it's non-structural. adts_with_manual_partialeq: FxHashSet, /// The type has no `PartialEq` implementation, neither manual or derived. adts_without_partialeq: FxHashSet, - /// The user has written `impl PartialEq for Ty` which means it's non-structual, + /// The user has written `impl PartialEq for Ty` which means it's non-structural, /// but we don't have a span to point at, so we'll just add them as a `note`. manual: FxHashSet>, /// The type has no `PartialEq` implementation, neither manual or derived, but diff --git a/compiler/rustc_mir_transform/src/check_enums.rs b/compiler/rustc_mir_transform/src/check_enums.rs index 240da87ab27..d1d1dc97307 100644 --- a/compiler/rustc_mir_transform/src/check_enums.rs +++ b/compiler/rustc_mir_transform/src/check_enums.rs @@ -310,7 +310,7 @@ fn insert_discr_cast_to_u128<'tcx>( StatementKind::Assign(Box::new((discr_in_discr_ty, rvalue))), )); - // Cast the discriminant to a u128 (base for comparisions of enum discriminants). + // Cast the discriminant to a u128 (base for comparisons of enum discriminants). let const_u128 = Ty::new_uint(tcx, ty::UintTy::U128); let rvalue = Rvalue::Cast(CastKind::IntToInt, Operand::Copy(discr_in_discr_ty), const_u128); let discr = local_decls.push(LocalDecl::with_source_info(const_u128, source_info)).into(); @@ -445,7 +445,7 @@ fn insert_niche_check<'tcx>( source_info, ); - // Compare the discriminant agains the valid_range. + // Compare the discriminant against the valid_range. let start_const = Operand::Constant(Box::new(ConstOperand { span: source_info.span, user_ty: None, diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 335354c23b6..6b11706d2b5 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -29,7 +29,7 @@ //! _b = some other value // also has VnIndex i //! ``` //! -//! We consider it to be replacable by: +//! We consider it to be replaceable by: //! ```ignore (MIR) //! _a = some value // has VnIndex i //! // some MIR diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index 1bd770a8526..2f0edf31162 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -516,7 +516,7 @@ struct LocalLabel<'a> { /// A custom `Subdiagnostic` implementation so that the notes are delivered in a specific order impl Subdiagnostic for LocalLabel<'_> { fn add_to_diag(self, diag: &mut rustc_errors::Diag<'_, G>) { - // Becuase parent uses this field , we need to remove it delay before adding it. + // Because parent uses this field , we need to remove it delay before adding it. diag.remove_arg("name"); diag.arg("name", self.name); diag.remove_arg("is_generated_name"); diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs index 368d5340ac3..d1c2d6b508f 100644 --- a/compiler/rustc_mir_transform/src/ref_prop.rs +++ b/compiler/rustc_mir_transform/src/ref_prop.rs @@ -138,7 +138,7 @@ fn compute_replacement<'tcx>( // reborrowed references. let mut storage_to_remove = DenseBitSet::new_empty(body.local_decls.len()); - let fully_replacable_locals = fully_replacable_locals(ssa); + let fully_replaceable_locals = fully_replaceable_locals(ssa); // Returns true iff we can use `place` as a pointee. // @@ -204,7 +204,7 @@ fn compute_replacement<'tcx>( let needs_unique = ty.is_mutable_ptr(); // If this a mutable reference that we cannot fully replace, mark it as unknown. - if needs_unique && !fully_replacable_locals.contains(local) { + if needs_unique && !fully_replaceable_locals.contains(local) { debug!("not fully replaceable"); continue; } @@ -303,7 +303,7 @@ fn compute_replacement<'tcx>( // This a reborrow chain, recursively allow the replacement. // - // This also allows to detect cases where `target.local` is not replacable, + // This also allows to detect cases where `target.local` is not replaceable, // and mark it as such. if let &[PlaceElem::Deref] = &target.projection[..] { assert!(perform_opt); @@ -313,7 +313,7 @@ fn compute_replacement<'tcx>( } else if perform_opt { self.allowed_replacements.insert((target.local, loc)); } else if needs_unique { - // This mutable reference is not fully replacable, so drop it. + // This mutable reference is not fully replaceable, so drop it. self.targets[place.local] = Value::Unknown; } } @@ -326,22 +326,22 @@ fn compute_replacement<'tcx>( /// Compute the set of locals that can be fully replaced. /// -/// We consider a local to be replacable iff it's only used in a `Deref` projection `*_local` or +/// We consider a local to be replaceable iff it's only used in a `Deref` projection `*_local` or /// non-use position (like storage statements and debuginfo). -fn fully_replacable_locals(ssa: &SsaLocals) -> DenseBitSet { - let mut replacable = DenseBitSet::new_empty(ssa.num_locals()); +fn fully_replaceable_locals(ssa: &SsaLocals) -> DenseBitSet { + let mut replaceable = DenseBitSet::new_empty(ssa.num_locals()); // First pass: for each local, whether its uses can be fully replaced. for local in ssa.locals() { if ssa.num_direct_uses(local) == 0 { - replacable.insert(local); + replaceable.insert(local); } } // Second pass: a local can only be fully replaced if all its copies can. - ssa.meet_copy_equivalence(&mut replacable); + ssa.meet_copy_equivalence(&mut replaceable); - replacable + replaceable } /// Utility to help performing substitution of `*pattern` by `target`. diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 4083038cbb6..cdbc74cdfa8 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -31,7 +31,7 @@ pub(super) fn provide(providers: &mut Providers) { providers.mir_shims = make_shim; } -// Replace Pin<&mut ImplCoroutine> accesses (_1.0) into Pin<&mut ProxyCoroutine> acceses +// Replace Pin<&mut ImplCoroutine> accesses (_1.0) into Pin<&mut ProxyCoroutine> accesses struct FixProxyFutureDropVisitor<'tcx> { tcx: TyCtxt<'tcx>, replace_to: Local, diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 91e371d697d..131064f9832 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -532,7 +532,7 @@ fn collect_items_rec<'tcx>( }); } // Only updating `usage_map` for used items as otherwise we may be inserting the same item - // multiple times (if it is first 'mentioned' and then later actuall used), and the usage map + // multiple times (if it is first 'mentioned' and then later actually used), and the usage map // logic does not like that. // This is part of the output of collection and hence only relevant for "used" items. // ("Mentioned" items are only considered internally during collection.) diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 49025673bbd..69851511fb1 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -893,7 +893,7 @@ fn mono_item_visibility<'tcx>( // * First is weak lang items. These are basically mechanisms for // libcore to forward-reference symbols defined later in crates like // the standard library or `#[panic_handler]` definitions. The - // definition of these weak lang items needs to be referencable by + // definition of these weak lang items needs to be referenceable by // libcore, so we're no longer a candidate for internalization. // Removal of these functions can't be done by LLVM but rather must be // done by the linker as it's a non-local decision. diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 42264f58bcd..61f3f9367f0 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -73,7 +73,7 @@ where /// Register additional assumptions for aliases corresponding to `[const]` item bounds. /// /// Unlike item bounds, they are not simply implied by the well-formedness of the alias. - /// Instead, they only hold if the const conditons on the alias also hold. This is why + /// Instead, they only hold if the const conditions on the alias also hold. This is why /// we also register the const conditions of the alias after matching the goal against /// the assumption. fn consider_additional_alias_assumptions( diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index cb7c498b94e..5ed316aa6b1 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -88,7 +88,7 @@ where /// This takes the `shallow_certainty` which represents whether we're confident /// that the final result of the current goal only depends on the nested goals. /// - /// In case this is `Certainy::Maybe`, there may still be additional nested goals + /// In case this is `Certainty::Maybe`, there may still be additional nested goals /// or inference constraints required for this candidate to be hold. The candidate /// always requires all already added constraints and nested goals. #[instrument(level = "trace", skip(self), ret)] diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs index 26443c54e18..2bb1ac8f742 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs @@ -42,7 +42,7 @@ where // Right now this includes both the impl and the assoc item where bounds, // and I don't think the assoc item where-bounds are allowed to be coinductive. // - // Projecting to the IAT also "steps out the impl contructor", so we would have + // Projecting to the IAT also "steps out the impl constructor", so we would have // to be very careful when changing the impl where-clauses to be productive. self.add_goals( GoalSource::Misc, diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 6c9fb63b579..098dc9dbaf0 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -1301,7 +1301,7 @@ where D: SolverDelegate, I: Interner, { - /// FIXME(#57893): For backwards compatability with the old trait solver implementation, + /// FIXME(#57893): For backwards compatibility with the old trait solver implementation, /// we need to handle overlap between builtin and user-written impls for trait objects. /// /// This overlap is unsound in general and something which we intend to fix separately. diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 9a60c151034..5a94d01e088 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -537,7 +537,7 @@ passes_no_sanitize = `#[no_sanitize({$attr_str})]` should be applied to {$accepted_kind} .label = not {$accepted_kind} -passes_non_exaustive_with_default_field_values = +passes_non_exhaustive_with_default_field_values = `#[non_exhaustive]` can't be used to annotate items with default field values .label = this struct has default field values diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index ce43b2c281d..cdfd1a2b07e 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -1199,7 +1199,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { let def_kind = tcx.def_kind(item.owner_id); let mut dead_codes = Vec::new(); - // Only diagnose unused assoc items in inherient impl and used trait, + // Only diagnose unused assoc items in inherent impl and used trait, // for unused assoc items in impls of trait, // we have diagnosed them in the trait if they are unused, // for unused assoc items in unused trait, diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index d4988277073..3ede3c889c8 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -157,7 +157,7 @@ pub(crate) struct NonExhaustiveWrongLocation { } #[derive(Diagnostic)] -#[diag(passes_non_exaustive_with_default_field_values)] +#[diag(passes_non_exhaustive_with_default_field_values)] pub(crate) struct NonExhaustiveWithDefaultFieldValues { #[primary_span] pub attr_span: Span, diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 53638f2a57d..c348cd508f9 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -70,7 +70,7 @@ //! # Constructors and fields //! //! In the value `Pair(Some(0), true)`, `Pair` is called the constructor of the value, and `Some(0)` -//! and `true` are its fields. Every matcheable value can be decomposed in this way. Examples of +//! and `true` are its fields. Every matchable value can be decomposed in this way. Examples of //! constructors are: `Some`, `None`, `(,)` (the 2-tuple constructor), `Foo {..}` (the constructor //! for a struct `Foo`), and `2` (the constructor for the number `2`). //! @@ -102,7 +102,7 @@ //! [`Constructor::is_covered_by`]. //! //! Note 1: variable bindings (like the `x` in `Some(x)`) match anything, so we treat them as wildcards. -//! Note 2: this only applies to matcheable values. For example a value of type `Rc` can't be +//! Note 2: this only applies to matchable values. For example a value of type `Rc` can't be //! deconstructed that way. //! //! diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index d4217e0aa54..04fc32a9b50 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -1342,7 +1342,7 @@ impl DepNodeColorMap { /// This tries to atomically mark a node green and assign `index` as the new /// index. This returns `Ok` if `index` gets assigned, otherwise it returns - /// the alreadly allocated index in `Err`. + /// the already allocated index in `Err`. #[inline] pub(super) fn try_mark_green( &self, diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 6d3752c0c83..509907435d6 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -878,12 +878,12 @@ pub(crate) struct MacroExpandedExternCrateCannotShadowExternArguments { #[derive(Diagnostic)] #[diag(resolve_elided_anonymous_lifetime_report_error, code = E0637)] -pub(crate) struct ElidedAnonymousLivetimeReportError { +pub(crate) struct ElidedAnonymousLifetimeReportError { #[primary_span] #[label] pub(crate) span: Span, #[subdiagnostic] - pub(crate) suggestion: Option, + pub(crate) suggestion: Option, } #[derive(Diagnostic)] @@ -897,7 +897,7 @@ pub(crate) struct LendingIteratorReportError { #[derive(Diagnostic)] #[diag(resolve_anonymous_lifetime_non_gat_report_error)] -pub(crate) struct AnonymousLivetimeNonGatReportError { +pub(crate) struct AnonymousLifetimeNonGatReportError { #[primary_span] #[label] pub(crate) lifetime: Span, @@ -908,7 +908,7 @@ pub(crate) struct AnonymousLivetimeNonGatReportError { resolve_elided_anonymous_lifetime_report_error_suggestion, applicability = "machine-applicable" )] -pub(crate) struct ElidedAnonymousLivetimeReportErrorSuggestion { +pub(crate) struct ElidedAnonymousLifetimeReportErrorSuggestion { #[suggestion_part(code = "for<'a> ")] pub(crate) lo: Span, #[suggestion_part(code = "'a ")] @@ -917,7 +917,7 @@ pub(crate) struct ElidedAnonymousLivetimeReportErrorSuggestion { #[derive(Diagnostic)] #[diag(resolve_explicit_anonymous_lifetime_report_error, code = E0637)] -pub(crate) struct ExplicitAnonymousLivetimeReportError { +pub(crate) struct ExplicitAnonymousLifetimeReportError { #[primary_span] #[label] pub(crate) span: Span, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index ac7bdda4195..c2bea4e0fdc 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1892,7 +1892,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { .. } = rib.kind { - Some(errors::ElidedAnonymousLivetimeReportErrorSuggestion { + Some(errors::ElidedAnonymousLifetimeReportErrorSuggestion { lo: span.shrink_to_lo(), hi: lifetime.ident.span.shrink_to_hi(), }) @@ -1918,18 +1918,18 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ty: ty.span, }); } else { - self.r.dcx().emit_err(errors::AnonymousLivetimeNonGatReportError { + self.r.dcx().emit_err(errors::AnonymousLifetimeNonGatReportError { lifetime: lifetime.ident.span, }); } } else { - self.r.dcx().emit_err(errors::ElidedAnonymousLivetimeReportError { + self.r.dcx().emit_err(errors::ElidedAnonymousLifetimeReportError { span: lifetime.ident.span, suggestion, }); } } else { - self.r.dcx().emit_err(errors::ExplicitAnonymousLivetimeReportError { + self.r.dcx().emit_err(errors::ExplicitAnonymousLifetimeReportError { span: lifetime.ident.span, }); }; diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 3fe5db8ca54..f61cd1f0adf 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -627,7 +627,7 @@ pub fn source_span_for_markdown_range_inner( let fragment = &fragments[i]; let sp = fragment.span; // we need to calculate the span start, - // then use that in our calulations for the span end + // then use that in our calculations for the span end let lo = sp.lo() + BytePos(match_start as u32); return Some(( sp.with_lo(lo).with_hi(lo + BytePos((md_range.end - md_range.start) as u32)), diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs index 6ea70600626..1cb09e8a1ee 100644 --- a/compiler/rustc_serialize/src/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -21,7 +21,7 @@ use thin_vec::ThinVec; /// [utf8]: https://en.wikipedia.org/w/index.php?title=UTF-8&oldid=1058865525#Codepage_layout const STR_SENTINEL: u8 = 0xC1; -/// For byte strings there are no bytes that canot occur. Just use this value +/// For byte strings there are no bytes that cannot occur. Just use this value /// as a best-effort sentinel. There is no validation skipped so the potential /// for badness is lower than in the `STR_SENTINEL` case. const BYTE_STR_SENTINEL: u8 = 0xC2; diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 73bb0471c22..74e766a1e95 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -190,7 +190,7 @@ pub struct CoverageOptions { /// to keep supporting this flag, remove it. pub no_mir_spans: bool, - /// `-Zcoverage-options=discard-all-spans-in-codegen`: During codgen, + /// `-Zcoverage-options=discard-all-spans-in-codegen`: During codegen, /// discard all coverage spans as though they were invalid. Needed by /// regression tests for #133606, because we don't have an easy way to /// reproduce it from actual source code. diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index bad2581ae31..8386fe8dab0 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1545,7 +1545,7 @@ impl RemapFileNameExt for rustc_span::FileName { "one and only one scope should be passed to for_scope" ); if sess.opts.unstable_opts.remap_path_scope.contains(scope) { - self.prefer_remapped_unconditionaly() + self.prefer_remapped_unconditionally() } else { self.prefer_local() } diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 4ea2bb04c5d..398738d1c38 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -1600,7 +1600,7 @@ pub struct VariantIdx(usize); index_impl!(VariantIdx); crate_def! { - /// Hold infomation about an Opaque definition, particularly useful in `RPITIT`. + /// Hold information about an Opaque definition, particularly useful in `RPITIT`. #[derive(Serialize)] pub OpaqueDef; } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index c18ff285c4e..9b0e009b2cd 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -418,7 +418,7 @@ impl FileName { } } - pub fn prefer_remapped_unconditionaly(&self) -> FileNameDisplay<'_> { + pub fn prefer_remapped_unconditionally(&self) -> FileNameDisplay<'_> { FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Remapped } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 34869a38bb4..93c39f3ec8b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2398,7 +2398,7 @@ pub const STDLIB_STABLE_CRATES: &[Symbol] = &[sym::std, sym::core, sym::alloc, s #[derive(Copy, Clone, Eq, HashStable_Generic, Encodable, Decodable)] pub struct Ident { // `name` should never be the empty symbol. If you are considering that, - // you are probably conflating "empty identifer with "no identifier" and + // you are probably conflating "empty identifier with "no identifier" and // you should use `Option` instead. pub name: Symbol, pub span: Span, diff --git a/compiler/rustc_target/src/callconv/s390x.rs b/compiler/rustc_target/src/callconv/s390x.rs index 1ba792c5acc..d2ae404b23b 100644 --- a/compiler/rustc_target/src/callconv/s390x.rs +++ b/compiler/rustc_target/src/callconv/s390x.rs @@ -46,7 +46,7 @@ where } if arg.layout.is_single_vector_element(cx, size) { - // pass non-transparant wrappers around a vector as `PassMode::Cast` + // pass non-transparent wrappers around a vector as `PassMode::Cast` arg.cast_to(Reg { kind: RegKind::Vector, size }); return; } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 2bbf90ed3ed..362052e9fdb 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -4432,7 +4432,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { candidate_impls: &[ImplCandidate<'tcx>], span: Span, ) { - // We can only suggest the slice coersion for function and binary operation arguments, + // We can only suggest the slice coercion for function and binary operation arguments, // since the suggestion would make no sense in turbofish or call let (ObligationCauseCode::BinOp { .. } | ObligationCauseCode::FunctionArg { .. }) = obligation.cause.code() diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 7bf49056e29..90cdf75265d 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -643,7 +643,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { // Do not suggest constraining the `&self` param, but rather the return type. // If that is wrong (because it is not sufficient), a follow up error will tell the // user to fix it. This way we lower the chances of *over* constraining, but still - // get the cake of "correctly" contrained in two steps. + // get the cake of "correctly" constrained in two steps. visitor.visit_ty_unambig(self.ty_sup); } visitor.visit_ty_unambig(self.ty_sub); diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 8d049fedf23..9a4f3887bbb 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -31,7 +31,7 @@ use crate::traits::{ /// /// Currently that is `Self` in supertraits. This is needed /// because `dyn_compatibility_violations` can't be used during -/// type collection, as type collection is needed for `dyn_compatiblity_violations` itself. +/// type collection, as type collection is needed for `dyn_compatibility_violations` itself. #[instrument(level = "debug", skip(tcx), ret)] pub fn hir_ty_lowering_dyn_compatibility_violations( tcx: TyCtxt<'_>, diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index fc95e42d67f..d3ead0d61b3 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -56,7 +56,7 @@ pub fn evaluate_host_effect_obligation<'tcx>( Err(EvaluationFailure::NoSolution) => {} } - match evaluate_host_effect_from_selection_candiate(selcx, obligation) { + match evaluate_host_effect_from_selection_candidate(selcx, obligation) { Ok(result) => return Ok(result), Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous), Err(EvaluationFailure::NoSolution) => {} @@ -333,7 +333,7 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( .collect()) } -fn evaluate_host_effect_from_selection_candiate<'tcx>( +fn evaluate_host_effect_from_selection_candidate<'tcx>( selcx: &mut SelectionContext<'_, 'tcx>, obligation: &HostEffectObligation<'tcx>, ) -> Result>, EvaluationFailure> { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 43806d3977b..91c41544f78 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -481,7 +481,7 @@ pub enum EvaluateConstErr { /// some unevaluated constant with either generic parameters or inference variables in its /// generic arguments. HasGenericsOrInfers, - /// The type this constant evalauted to is not valid for use in const generics. This should + /// The type this constant evaluated to is not valid for use in const generics. This should /// always result in an error when checking the constant is correctly typed for the parameter /// it is an argument to, so a bug is delayed when encountering this. InvalidConstParamTy(ErrorGuaranteed), diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 3eca77b43a8..3a369f13e79 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -904,7 +904,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let goal_kind = self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()).unwrap(); - // If we have not yet determiend the `ClosureKind` of the closure or coroutine-closure, + // If we have not yet determined the `ClosureKind` of the closure or coroutine-closure, // then additionally register an `AsyncFnKindHelper` goal which will fail if the kind // is constrained to an insufficient type later on. if let Some(closure_kind) = self.infcx.shallow_resolve(kind_ty).to_opt_closure_kind() { diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 3b4482146d4..3b313edea6f 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -179,7 +179,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { } } - /// Checks the `#[define_opaque]` attributes on items and collectes opaques to define + /// Checks the `#[define_opaque]` attributes on items and collects opaques to define /// from the referenced types. #[instrument(level = "trace", skip(self))] fn collect_taits_from_defines_attr(&mut self) { diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 8ba9e7105d6..6c77a90250a 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -13,7 +13,7 @@ use crate::{self as ty, Interner}; /// slightly different typing rules depending on the current context. See the /// doc comment for each variant for how and why they are used. /// -/// In most cases you can get the correct typing mode automically via: +/// In most cases you can get the correct typing mode automatically via: /// - `mir::Body::typing_mode` /// - `rustc_lint::LateContext::typing_mode` /// diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 8941360d2d0..7433c215e6f 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -390,8 +390,8 @@ impl PathsToNested { /// /// They are used when checking whether reevaluating a global cache /// would encounter a cycle or use a provisional cache entry given the -/// currentl search graph state. We need to disable the global cache -/// in this case as it could otherwise result in behaviorial differences. +/// current search graph state. We need to disable the global cache +/// in this case as it could otherwise result in behavioral differences. /// Cycles can impact behavior. The cycle ABA may have different final /// results from a the cycle BAB depending on the cycle root. /// @@ -513,7 +513,7 @@ pub struct SearchGraph, X: Cx = ::Cx> { /// /// `nested_goals` are only used when checking whether global cache entries /// are applicable. This only cares about whether a goal is actually accessed. -/// Given that the usage of the provisional cache is fully determinstic, we +/// Given that the usage of the provisional cache is fully deterministic, we /// don't need to track the nested goals used while computing a provisional /// cache entry. enum UpdateParentGoalCtxt<'a, X: Cx> { diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index 42af595ae41..80f462263a5 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -589,7 +589,7 @@ impl fmt::Display for i128 { } impl u128 { - /// Format optimized for u128. Computation of 128 bits is limited by proccessing + /// Format optimized for u128. Computation of 128 bits is limited by processing /// in batches of 16 decimals at a time. #[doc(hidden)] #[unstable( diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 4250de9fb2b..15d4f14038a 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -459,7 +459,7 @@ pub const fn unlikely(b: bool) -> bool { /// Therefore, implementations must not require the user to uphold /// any safety invariants. /// -/// The public form of this instrinsic is [`core::hint::select_unpredictable`]. +/// The public form of this intrinsic is [`core::hint::select_unpredictable`]. /// However unlike the public form, the intrinsic will not drop the value that /// is not selected. #[unstable(feature = "core_intrinsics", issue = "none")] @@ -2290,7 +2290,7 @@ where /// used inside the `if const`. /// Note that the two arms of this `if` really each become their own function, which is why the /// macro supports setting attributes for those functions. The runtime function is always -/// markes as `#[inline]`. +/// marked as `#[inline]`. /// /// See [`const_eval_select()`] for the rules and requirements around that intrinsic. pub(crate) macro const_eval_select { @@ -2530,7 +2530,7 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) /// Returns whether we should perform contract-checking at runtime. /// /// This is meant to be similar to the ub_checks intrinsic, in terms -/// of not prematurely commiting at compile-time to whether contract +/// of not prematurely committing at compile-time to whether contract /// checking is turned on, so that we can specify contracts in libstd /// and let an end user opt into turning them on. #[rustc_const_unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index 11533ab6aa4..19488082cc3 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -160,7 +160,7 @@ pub unsafe fn simd_funnel_shl(a: T, b: T, shift: T) -> T; #[rustc_nounwind] pub unsafe fn simd_funnel_shr(a: T, b: T, shift: T) -> T; -/// "Ands" vectors elementwise. +/// "And"s vectors elementwise. /// /// `T` must be a vector of integers. #[rustc_intrinsic] @@ -522,7 +522,7 @@ pub unsafe fn simd_reduce_max(x: T) -> U; #[rustc_nounwind] pub unsafe fn simd_reduce_min(x: T) -> U; -/// Logical "ands" all elements together. +/// Logical "and"s all elements together. /// /// `T` must be a vector of integers or floats. /// diff --git a/library/core/src/io/borrowed_buf.rs b/library/core/src/io/borrowed_buf.rs index 6bd9c18e00b..854e03cf182 100644 --- a/library/core/src/io/borrowed_buf.rs +++ b/library/core/src/io/borrowed_buf.rs @@ -281,7 +281,7 @@ impl<'a> BorrowedCursor<'a> { /// Panics if there are less than `n` bytes initialized. #[inline] pub fn advance(&mut self, n: usize) -> &mut Self { - // The substraction cannot underflow by invariant of this type. + // The subtraction cannot underflow by invariant of this type. assert!(n <= self.buf.init - self.buf.filled); self.buf.filled += n; diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 6e160eddecb..2f701171505 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -89,7 +89,7 @@ #![allow(internal_features)] #![deny(ffi_unwind_calls)] #![warn(unreachable_pub)] -// Do not check link redundancy on bootstraping phase +// Do not check link redundancy on bootstrapping phase #![allow(rustdoc::redundant_explicit_links)] #![warn(rustdoc::unescaped_backticks)] // diff --git a/library/core/src/num/dec2flt/float.rs b/library/core/src/num/dec2flt/float.rs index 5bf0faf0bc9..21aabdc8add 100644 --- a/library/core/src/num/dec2flt/float.rs +++ b/library/core/src/num/dec2flt/float.rs @@ -109,7 +109,7 @@ pub trait RawFloat: /// Round-to-even only happens for negative values of q /// when q ≥ −4 in the 64-bit case and when q ≥ −17 in - /// the 32-bitcase. + /// the 32-bit case. /// /// When q ≥ 0,we have that 5^q ≤ 2m+1. In the 64-bit case,we /// have 5^q ≤ 2m+1 ≤ 2^54 or q ≤ 23. In the 32-bit case,we have @@ -119,7 +119,7 @@ pub trait RawFloat: /// so (2m+1)×5^−q < 2^64. We have that 2m+1 > 2^53 (64-bit case) /// or 2m+1 > 2^24 (32-bit case). Hence,we must have 2^53×5^−q < 2^64 /// (64-bit) and 2^24×5^−q < 2^64 (32-bit). Hence we have 5^−q < 2^11 - /// or q ≥ −4 (64-bit case) and 5^−q < 2^40 or q ≥ −17 (32-bitcase). + /// or q ≥ −4 (64-bit case) and 5^−q < 2^40 or q ≥ −17 (32-bit case). /// /// Thus we have that we only need to round ties to even when /// we have that q ∈ [−4,23](in the 64-bit case) or q∈[−17,10] @@ -143,7 +143,7 @@ pub trait RawFloat: /// smaller than `10^SMALLEST_POWER_OF_TEN`, which will round to zero. /// /// The smallest power of ten is represented by `⌊log10(2^-n / (2^64 - 1))⌋`, where `n` is - /// the smallest power of two. The `2^64 - 1)` denomenator comes from the number of values + /// the smallest power of two. The `2^64 - 1)` denominator comes from the number of values /// that are representable by the intermediate storage format. I don't actually know _why_ /// the storage format is relevant here. /// diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index b6d5f848ef0..3ca6feb679b 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -792,7 +792,7 @@ //! //! 1. *Structural [`Unpin`].* A struct can be [`Unpin`] only if all of its //! structurally-pinned fields are, too. This is [`Unpin`]'s behavior by default. -//! However, as a libray author, it is your responsibility not to write something like +//! However, as a library author, it is your responsibility not to write something like //! impl\ [Unpin] for Struct\ {} and then offer a method that provides //! structural pinning to an inner field of `T`, which may not be [`Unpin`]! (Adding *any* //! projection operation requires unsafe code, so the fact that [`Unpin`] is a safe trait does diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 800eb74babb..27b0c6830db 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -29,7 +29,7 @@ impl *const T { if const #[rustc_allow_const_fn_unstable(const_raw_ptr_comparison)] { match (ptr).guaranteed_eq(null_mut()) { Some(res) => res, - // To remain maximally convervative, we stop execution when we don't + // To remain maximally conservative, we stop execution when we don't // know whether the pointer is null or not. // We can *not* return `false` here, that would be unsound in `NonNull::new`! None => panic!("null-ness of this pointer cannot be determined in const context"), @@ -49,7 +49,7 @@ impl *const T { self as _ } - /// Try to cast to a pointer of another type by checking aligment. + /// Try to cast to a pointer of another type by checking alignment. /// /// If the pointer is properly aligned to the target type, it will be /// cast to the target type. Otherwise, `None` is returned. diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 6b436184f20..73efdf04454 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -32,7 +32,7 @@ impl *mut T { self as _ } - /// Try to cast to a pointer of another type by checking aligment. + /// Try to cast to a pointer of another type by checking alignment. /// /// If the pointer is properly aligned to the target type, it will be /// cast to the target type. Otherwise, `None` is returned. diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index ea650b810b7..c26c3a32ef3 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -497,7 +497,7 @@ impl NonNull { unsafe { NonNull { pointer: self.as_ptr() as *mut U } } } - /// Try to cast to a pointer of another type by checking aligment. + /// Try to cast to a pointer of another type by checking alignment. /// /// If the pointer is properly aligned to the target type, it will be /// cast to the target type. Otherwise, `None` is returned. diff --git a/library/coretests/tests/num/dec2flt/float.rs b/library/coretests/tests/num/dec2flt/float.rs index 2407ba50ca3..193d5887749 100644 --- a/library/coretests/tests/num/dec2flt/float.rs +++ b/library/coretests/tests/num/dec2flt/float.rs @@ -23,7 +23,7 @@ fn test_f16_integer_decode() { fn test_f32_integer_decode() { assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1)); assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1)); - // Set 2^100 directly instead of using powf, because it doesn't guarentee precision + // Set 2^100 directly instead of using powf, because it doesn't guarantee precision assert_eq!(1.2676506e30_f32.integer_decode(), (8388608, 77, 1)); assert_eq!(0f32.integer_decode(), (0, -150, 1)); assert_eq!((-0f32).integer_decode(), (0, -150, -1)); @@ -40,7 +40,7 @@ fn test_f32_integer_decode() { fn test_f64_integer_decode() { assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1)); assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1)); - // Set 2^100 directly instead of using powf, because it doesn't guarentee precision + // Set 2^100 directly instead of using powf, because it doesn't guarantee precision assert_eq!(1.2676506002282294e30_f64.integer_decode(), (4503599627370496, 48, 1)); assert_eq!(0f64.integer_decode(), (0, -1075, 1)); assert_eq!((-0f64).integer_decode(), (0, -1075, -1)); diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index d9902d41928..7ae8e700ff6 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -3091,7 +3091,7 @@ pub fn read_dir>(path: P) -> io::Result { /// On UNIX-like systems, this function will update the permission bits /// of the file pointed to by the symlink. /// -/// Note that this behavior can lead to privalage escalation vulnerabilites, +/// Note that this behavior can lead to privalage escalation vulnerabilities, /// where the ability to create a symlink in one directory allows you to /// cause the permissions of another file or directory to be modified. /// diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index 3f4fe2e56ec..466b134d8fa 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -385,7 +385,7 @@ pub trait ChildExt: Sealed { /// # Errors /// /// This function will return an error if the signal is invalid. The integer values associated - /// with signals are implemenation-specific, so it's encouraged to use a crate that provides + /// with signals are implementation-specific, so it's encouraged to use a crate that provides /// posix bindings. /// /// # Examples diff --git a/library/std/src/sys/net/connection/socket/wasip2.rs b/library/std/src/sys/net/connection/socket/wasip2.rs index 73c25831872..c77c50fece1 100644 --- a/library/std/src/sys/net/connection/socket/wasip2.rs +++ b/library/std/src/sys/net/connection/socket/wasip2.rs @@ -140,7 +140,7 @@ impl Socket { 0 => {} _ => { // WASI poll does not return POLLHUP or POLLERR in revents. Check if the - // connnection actually succeeded and return ok only when the socket is + // connection actually succeeded and return ok only when the socket is // ready and no errors were found. if let Some(e) = self.take_error()? { return Err(e); diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index e47263348db..420481648a7 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -487,7 +487,7 @@ impl OwnedProtocol { let protocol: *mut T = Box::into_raw(Box::new(protocol)); let mut handle: r_efi::efi::Handle = crate::ptr::null_mut(); - // FIXME: Move into r-efi once extended_varargs_abi_support is stablized + // FIXME: Move into r-efi once extended_varargs_abi_support is stabilized let func: BootInstallMultipleProtocolInterfaces = unsafe { crate::mem::transmute((*bt.as_ptr()).install_multiple_protocol_interfaces) }; @@ -521,7 +521,7 @@ impl Drop for OwnedProtocol { // Do not deallocate a runtime protocol if let Some(bt) = boot_services() { let bt: NonNull = bt.cast(); - // FIXME: Move into r-efi once extended_varargs_abi_support is stablized + // FIXME: Move into r-efi once extended_varargs_abi_support is stabilized let func: BootUninstallMultipleProtocolInterfaces = unsafe { crate::mem::transmute((*bt.as_ptr()).uninstall_multiple_protocol_interfaces) }; @@ -645,7 +645,7 @@ pub(crate) fn get_device_path_from_map(map: &Path) -> io::Result, diff --git a/library/std/src/sys/path/cygwin.rs b/library/std/src/sys/path/cygwin.rs index e90372805bb..da0982384b0 100644 --- a/library/std/src/sys/path/cygwin.rs +++ b/library/std/src/sys/path/cygwin.rs @@ -10,7 +10,7 @@ pub fn is_sep_byte(b: u8) -> bool { b == b'/' || b == b'\\' } -/// Cygwin allways prefers `/` over `\`, and it always converts all `/` to `\` +/// Cygwin always prefers `/` over `\`, and it always converts all `/` to `\` /// internally when calling Win32 APIs. Therefore, the server component of path /// `\\?\UNC\localhost/share` is `localhost/share` on Win32, but `localhost` /// on Cygwin. diff --git a/library/std/src/sys/random/linux.rs b/library/std/src/sys/random/linux.rs index 18196fae28b..53e2f1da675 100644 --- a/library/std/src/sys/random/linux.rs +++ b/library/std/src/sys/random/linux.rs @@ -15,7 +15,7 @@ //! bytes, while the non-blocking pool, once initialized using the blocking //! pool, uses a CPRNG to return an unlimited number of random bytes. With a //! strong enough CPRNG however, the entropy estimation didn't contribute that -//! much towards security while being an excellent vector for DoS attacs. Thus, +//! much towards security while being an excellent vector for DoS attacks. Thus, //! the blocking pool was removed in kernel version 5.6.[^2] That patch did not //! magically increase the quality of the non-blocking pool, however, so we can //! safely consider it strong enough even in older kernel versions and use it @@ -30,7 +30,7 @@ //! data the system has available at the time. //! //! So in conclusion, we always want the output of the non-blocking pool, but -//! may need to wait until it is initalized. The default behavior of `getrandom` +//! may need to wait until it is initialized. The default behavior of `getrandom` //! is to wait until the non-blocking pool is initialized and then draw from there, //! so if `getrandom` is available, we use its default to generate the bytes. For //! `HashMap`, however, we need to specify the `GRND_INSECURE` flags, but that diff --git a/library/std/src/sys/random/unsupported.rs b/library/std/src/sys/random/unsupported.rs index d68ce4a9e87..894409b395a 100644 --- a/library/std/src/sys/random/unsupported.rs +++ b/library/std/src/sys/random/unsupported.rs @@ -6,7 +6,7 @@ pub fn fill_bytes(_: &mut [u8]) { pub fn hashmap_random_keys() -> (u64, u64) { // Use allocation addresses for a bit of randomness. This isn't - // particularily secure, but there isn't really an alternative. + // particularly secure, but there isn't really an alternative. let stack = 0u8; let heap = Box::new(0u8); let k1 = ptr::from_ref(&stack).addr() as u64; diff --git a/library/std/src/thread/spawnhook.rs b/library/std/src/thread/spawnhook.rs index 98f471ad54b..c8a7bcf55c1 100644 --- a/library/std/src/thread/spawnhook.rs +++ b/library/std/src/thread/spawnhook.rs @@ -6,7 +6,7 @@ use crate::thread::Thread; crate::thread_local! { /// A thread local linked list of spawn hooks. /// - /// It is a linked list of Arcs, such that it can very cheaply be inhereted by spawned threads. + /// It is a linked list of Arcs, such that it can very cheaply be inherited by spawned threads. /// /// (That technically makes it a set of linked lists with shared tails, so a linked tree.) static SPAWN_HOOKS: Cell = const { Cell::new(SpawnHooks { first: None }) }; diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 03af35e809c..393426be087 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -95,10 +95,10 @@ use crate::sys_common::{FromInner, IntoInner}; /// let now = Instant::now(); /// let days_per_10_millennia = 365_2425; /// let solar_seconds_per_day = 60 * 60 * 24; -/// let millenium_in_solar_seconds = 31_556_952_000; -/// assert_eq!(millenium_in_solar_seconds, days_per_10_millennia * solar_seconds_per_day / 10); +/// let millennium_in_solar_seconds = 31_556_952_000; +/// assert_eq!(millennium_in_solar_seconds, days_per_10_millennia * solar_seconds_per_day / 10); /// -/// let duration = Duration::new(millenium_in_solar_seconds, 0); +/// let duration = Duration::new(millennium_in_solar_seconds, 0); /// println!("{:?}", now + duration); /// ``` /// diff --git a/library/std/tests/thread_local/tests.rs b/library/std/tests/thread_local/tests.rs index e8278361d93..5df1a0e25ee 100644 --- a/library/std/tests/thread_local/tests.rs +++ b/library/std/tests/thread_local/tests.rs @@ -348,7 +348,7 @@ fn join_orders_after_tls_destructors() { // // The test won't currently work without target_thread_local, aka with slow tls. // The runtime tries very hard to drop last the TLS variable that keeps the information about the -// current thread, by using several tricks like deffering the drop to a later round of TLS destruction. +// current thread, by using several tricks like deferring the drop to a later round of TLS destruction. // However, this only seems to work with fast tls. // // With slow TLS, it seems that multiple libc implementations will just set the value to null the first diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 61268df7336..d487995e98a 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -346,6 +346,6 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { // since last merge. // // NOTE: Because of the exit above, this is only reachable if formatting / format checking - // succeeded. So we are not commiting the version if formatting was not good. + // succeeded. So we are not committing the version if formatting was not good. update_rustfmt_version(build); } diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index bb21d033458..79275db6486 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -382,7 +382,7 @@ pub enum Subcommand { bless: bool, #[arg(long)] /// comma-separated list of other files types to check (accepts py, py:lint, - /// py:fmt, shell) + /// py:fmt, shell, shell:lint, cpp, cpp:fmt, spellcheck, spellcheck:fix) extra_checks: Option, #[arg(long)] /// rerun tests even if the inputs are unchanged diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index f873c62588b..b208ae5249d 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -149,7 +149,7 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ ChangeInfo { change_id: 121976, severity: ChangeSeverity::Info, - summary: "A new `boostrap-cache-path` option has been introduced which can be utilized to modify the cache path for bootstrap.", + summary: "A new `bootstrap-cache-path` option has been introduced which can be utilized to modify the cache path for bootstrap.", }, ChangeInfo { change_id: 122108, @@ -404,7 +404,7 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ ChangeInfo { change_id: 140438, severity: ChangeSeverity::Info, - summary: "Added a new option `rust.debug-assertions-tools` to control debug asssertions for tools.", + summary: "Added a new option `rust.debug-assertions-tools` to control debug assertions for tools.", }, ChangeInfo { change_id: 140732, diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish index 64734d5bcaa..e982cde634f 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -293,7 +293,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand doc" -l skip-std-check-if-no-d complete -c x.py -n "__fish_x.py_using_subcommand doc" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand test" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r complete -c x.py -n "__fish_x.py_using_subcommand test" -l compiletest-rustc-args -d 'extra options to pass the compiler when running compiletest tests' -r -complete -c x.py -n "__fish_x.py_using_subcommand test" -l extra-checks -d 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell)' -r +complete -c x.py -n "__fish_x.py_using_subcommand test" -l extra-checks -d 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell, shell:lint, cpp, cpp:fmt, spellcheck, spellcheck:fix)' -r complete -c x.py -n "__fish_x.py_using_subcommand test" -l compare-mode -d 'mode describing what file the actual ui output will be compared to' -r complete -c x.py -n "__fish_x.py_using_subcommand test" -l pass -d 'force {check,build,run}-pass tests to this mode' -r complete -c x.py -n "__fish_x.py_using_subcommand test" -l run -d 'whether to execute run-* tests' -r diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index 154f4f95eb5..f4b26fac0bc 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -339,7 +339,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { 'x.py;test' { [CompletionResult]::new('--test-args', '--test-args', [CompletionResultType]::ParameterName, 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)') [CompletionResult]::new('--compiletest-rustc-args', '--compiletest-rustc-args', [CompletionResultType]::ParameterName, 'extra options to pass the compiler when running compiletest tests') - [CompletionResult]::new('--extra-checks', '--extra-checks', [CompletionResultType]::ParameterName, 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell)') + [CompletionResult]::new('--extra-checks', '--extra-checks', [CompletionResultType]::ParameterName, 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell, shell:lint, cpp, cpp:fmt, spellcheck, spellcheck:fix)') [CompletionResult]::new('--compare-mode', '--compare-mode', [CompletionResultType]::ParameterName, 'mode describing what file the actual ui output will be compared to') [CompletionResult]::new('--pass', '--pass', [CompletionResultType]::ParameterName, 'force {check,build,run}-pass tests to this mode') [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests') diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh index 177d60f9738..8fc4f052252 100644 --- a/src/etc/completions/x.py.zsh +++ b/src/etc/completions/x.py.zsh @@ -338,7 +338,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '*--test-args=[extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)]:ARGS:_default' \ '*--compiletest-rustc-args=[extra options to pass the compiler when running compiletest tests]:ARGS:_default' \ -'--extra-checks=[comma-separated list of other files types to check (accepts py, py\:lint, py\:fmt, shell)]:EXTRA_CHECKS:_default' \ +'--extra-checks=[comma-separated list of other files types to check (accepts py, py\:lint, py\:fmt, shell, shell\:lint, cpp, cpp\:fmt, spellcheck, spellcheck\:fix)]:EXTRA_CHECKS:_default' \ '--compare-mode=[mode describing what file the actual ui output will be compared to]:COMPARE MODE:_default' \ '--pass=[force {check,build,run}-pass tests to this mode]:check | build | run:_default' \ '--run=[whether to execute run-* tests]:auto | always | never:_default' \ diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3d027db2622..744da14748d 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1171,7 +1171,7 @@ fn clean_poly_fn_sig<'tcx>( // If this comes from a fn item, let's not perpetuate anon params from Rust 2015; use `_` for them. // If this comes from a fn ptr ty, we just keep params unnamed since it's more conventional stylistically. // Since the param name is not part of the semantic type, these params never bear a name unlike - // in the HIR case, thus we can't peform any fancy fallback logic unlike `clean_bare_fn_ty`. + // in the HIR case, thus we can't perform any fancy fallback logic unlike `clean_bare_fn_ty`. let fallback = did.map(|_| kw::Underscore); let params = sig diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 1b5c9fd4664..9b4d2533954 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -858,7 +858,7 @@ impl ScrapedDocTest { item_path.push(' '); } let name = - format!("{} - {item_path}(line {line})", filename.prefer_remapped_unconditionaly()); + format!("{} - {item_path}(line {line})", filename.prefer_remapped_unconditionally()); Self { filename, line, langstr, text, name, span, global_crate_attrs } } diff --git a/src/librustdoc/doctest/extracted.rs b/src/librustdoc/doctest/extracted.rs index 925fb6fee2c..3d046ec1835 100644 --- a/src/librustdoc/doctest/extracted.rs +++ b/src/librustdoc/doctest/extracted.rs @@ -62,7 +62,7 @@ impl ExtractedDocTests { Some(&opts.crate_name), ); self.doctests.push(ExtractedDocTest { - file: filename.prefer_remapped_unconditionaly().to_string(), + file: filename.prefer_remapped_unconditionally().to_string(), line, doctest_attributes: langstr.into(), doctest_code: match wrapped { diff --git a/src/librustdoc/html/markdown/footnotes.rs b/src/librustdoc/html/markdown/footnotes.rs index ded0585ddcc..7ee012c4da2 100644 --- a/src/librustdoc/html/markdown/footnotes.rs +++ b/src/librustdoc/html/markdown/footnotes.rs @@ -38,7 +38,7 @@ impl<'a, I: Iterator>> Footnotes<'a, I> { let key = key.to_owned(); let FootnoteDef { content, id } = self.footnotes.entry(key).or_insert(FootnoteDef { content: Vec::new(), id: new_id }); - // Don't allow changing the ID of existing entrys, but allow changing the contents. + // Don't allow changing the ID of existing entries, but allow changing the contents. (content, *id) } @@ -82,7 +82,7 @@ impl<'a, I: Iterator>> Iterator for Footnotes<'a, I> { return Some((self.handle_footnote_reference(reference), range)); } Some((Event::Start(Tag::FootnoteDefinition(def)), _)) => { - // When we see a footnote definition, collect the assocated content, and store + // When we see a footnote definition, collect the associated content, and store // that for rendering later. let content = self.collect_footnote_def(); let (entry_content, _) = self.get_entry(&def); diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index ed58bae70bd..2d20a45d182 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1947,7 +1947,7 @@ fn render_impl( // 3. Functions // // This order is because you can have associated constants used in associated types (like array - // length), and both in associcated functions. So with this order, when reading from top to + // length), and both in associated functions. So with this order, when reading from top to // bottom, you should see items definitions before they're actually used most of the time. let mut assoc_types = Vec::new(); let mut methods = Vec::new(); diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 606a9113908..41c3f03b91b 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -443,7 +443,7 @@ impl CratesIndexPart { .expect("Object Replacement Character (U+FFFC) should not appear in the --index-page") } - /// Might return parts that are duplicate with ones in prexisting index.html + /// Might return parts that are duplicate with ones in preexisting index.html fn get(crate_name: &str, external_crates: &[String]) -> Result, Error> { let mut ret = PartsAndLocations::default(); let path = Path::new("index.html"); diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 2de8f836da3..3c4af0dc612 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1719,7 +1719,7 @@ function preLoadCss(cssUrl) { // 300px, and the RUSTDOC_MOBILE_BREAKPOINT is 700px, so BODY_MIN must be // at most 400px. Otherwise, it would start out at the default size, then // grabbing the resize handle would suddenly cause it to jank to - // its contraint-generated maximum. + // its constraint-generated maximum. const RUSTDOC_MOBILE_BREAKPOINT = 700; const BODY_MIN = 400; // At half-way past the minimum size, vanish the sidebar entirely diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index bbcd96040be..ca2512e5ab6 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -464,7 +464,7 @@ declare namespace rustdoc { /** * Maps from crate names to trait implementation data. - * Provied by generated `trait.impl` files. + * Provided by generated `trait.impl` files. */ type Implementors = { [key: string]: Array<[string, number, Array]> diff --git a/src/librustdoc/passes/strip_aliased_non_local.rs b/src/librustdoc/passes/strip_aliased_non_local.rs index 7f5c7da3634..b53e3b4e3d7 100644 --- a/src/librustdoc/passes/strip_aliased_non_local.rs +++ b/src/librustdoc/passes/strip_aliased_non_local.rs @@ -42,7 +42,7 @@ struct NonLocalStripper<'tcx> { impl DocFolder for NonLocalStripper<'_> { fn fold_item(&mut self, i: Item) -> Option { // If not local, we want to respect the original visibility of - // the field and not the one given by the user for the currrent crate. + // the field and not the one given by the user for the current crate. // // FIXME(#125009): Not-local should probably consider same Cargo workspace if let Some(def_id) = i.def_id() diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index 692ce21d6cf..3388ae46f05 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -168,7 +168,7 @@ impl DocFolder for Stripper<'_, '_> { self.update_retained = old; if ret.item_id == clean::ItemId::DefId(CRATE_DEF_ID.into()) { // We don't strip the current crate, even if it has `#[doc(hidden)]`. - debug!("strip_hidden: Not strippping local crate"); + debug!("strip_hidden: Not stripping local crate"); Some(ret) } else { Some(strip_item(ret)) diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index dd00b270b38..18d60915d20 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -104,7 +104,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.tcx.sess.source_map().lookup_char_pos(BytePos(offset.bytes().try_into().unwrap())); let name = fn_instance.to_string(); - let filename = lo.file.name.prefer_remapped_unconditionaly().to_string(); + let filename = lo.file.name.prefer_remapped_unconditionally().to_string(); interp_ok((fn_instance, lo, name, filename)) } diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs index 4f9a20fa9e2..2904908fd43 100644 --- a/src/tools/tidy/src/ext_tool_checks.rs +++ b/src/tools/tidy/src/ext_tool_checks.rs @@ -72,6 +72,8 @@ fn check_impl( let shell_lint = lint_args.contains(&"shell:lint") || shell_all; let cpp_all = lint_args.contains(&"cpp"); let cpp_fmt = lint_args.contains(&"cpp:fmt") || cpp_all; + let spellcheck_all = lint_args.contains(&"spellcheck"); + let spellcheck_fix = lint_args.contains(&"spellcheck:fix"); let mut py_path = None; @@ -224,6 +226,27 @@ fn check_impl( shellcheck_runner(&merge_args(&cfg_args, &file_args_shc))?; } + if spellcheck_all || spellcheck_fix { + let config_path = root_path.join("typos.toml"); + // sync target files with .github/workflows/spellcheck.yml + let mut args = vec![ + "-c", + config_path.as_os_str().to_str().unwrap(), + "./compiler", + "./library", + "./src/bootstrap", + "./src/librustdoc", + ]; + + if spellcheck_all { + eprintln!("spellcheck files"); + } else if spellcheck_fix { + eprintln!("spellcheck files and fix"); + args.push("--write-changes"); + } + spellcheck_runner(&args)?; + } + Ok(()) } @@ -491,6 +514,36 @@ fn shellcheck_runner(args: &[&OsStr]) -> Result<(), Error> { if status.success() { Ok(()) } else { Err(Error::FailedCheck("shellcheck")) } } +/// Check that spellchecker is installed then run it at the given path +fn spellcheck_runner(args: &[&str]) -> Result<(), Error> { + // sync version with .github/workflows/spellcheck.yml + let expected_version = "typos-cli 1.34.0"; + match Command::new("typos").arg("--version").output() { + Ok(o) => { + let stdout = String::from_utf8_lossy(&o.stdout); + if stdout.trim() != expected_version { + return Err(Error::Version { + program: "typos", + required: expected_version, + installed: stdout.trim().to_string(), + }); + } + } + Err(e) if e.kind() == io::ErrorKind::NotFound => { + return Err(Error::MissingReq( + "typos", + "spellcheck file checks", + // sync version with .github/workflows/spellcheck.yml + Some("install tool via `cargo install typos-cli@1.34.0`".to_owned()), + )); + } + Err(e) => return Err(e.into()), + } + + let status = Command::new("typos").args(args).status()?; + if status.success() { Ok(()) } else { Err(Error::FailedCheck("typos")) } +} + /// Check git for tracked files matching an extension fn find_with_extension( root_path: &Path, diff --git a/tests/ui/abi/bad-custom.stderr b/tests/ui/abi/bad-custom.stderr index 893382875a2..372ef71375c 100644 --- a/tests/ui/abi/bad-custom.stderr +++ b/tests/ui/abi/bad-custom.stderr @@ -166,7 +166,7 @@ error: functions with the "custom" ABI cannot be `async` LL | async unsafe extern "custom" fn no_async_fn() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: remove the `async` keyword from this definiton +help: remove the `async` keyword from this definition | LL - async unsafe extern "custom" fn no_async_fn() { LL + unsafe extern "custom" fn no_async_fn() { diff --git a/tests/ui/abi/cannot-be-coroutine.avr.stderr b/tests/ui/abi/cannot-be-coroutine.avr.stderr index b06da0f3352..027f98c95c4 100644 --- a/tests/ui/abi/cannot-be-coroutine.avr.stderr +++ b/tests/ui/abi/cannot-be-coroutine.avr.stderr @@ -4,7 +4,7 @@ error: functions with the "avr-interrupt" ABI cannot be `async` LL | async extern "avr-interrupt" fn avr() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: remove the `async` keyword from this definiton +help: remove the `async` keyword from this definition | LL - async extern "avr-interrupt" fn avr() { LL + extern "avr-interrupt" fn avr() { diff --git a/tests/ui/abi/cannot-be-coroutine.i686.stderr b/tests/ui/abi/cannot-be-coroutine.i686.stderr index cbbddd087c8..8c9292b6a32 100644 --- a/tests/ui/abi/cannot-be-coroutine.i686.stderr +++ b/tests/ui/abi/cannot-be-coroutine.i686.stderr @@ -4,7 +4,7 @@ error: functions with the "x86-interrupt" ABI cannot be `async` LL | async extern "x86-interrupt" fn x86() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: remove the `async` keyword from this definiton +help: remove the `async` keyword from this definition | LL - async extern "x86-interrupt" fn x86() { LL + extern "x86-interrupt" fn x86() { diff --git a/tests/ui/abi/cannot-be-coroutine.msp430.stderr b/tests/ui/abi/cannot-be-coroutine.msp430.stderr index 951ce13b605..4b639cea9c1 100644 --- a/tests/ui/abi/cannot-be-coroutine.msp430.stderr +++ b/tests/ui/abi/cannot-be-coroutine.msp430.stderr @@ -4,7 +4,7 @@ error: functions with the "msp430-interrupt" ABI cannot be `async` LL | async extern "msp430-interrupt" fn msp430() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: remove the `async` keyword from this definiton +help: remove the `async` keyword from this definition | LL - async extern "msp430-interrupt" fn msp430() { LL + extern "msp430-interrupt" fn msp430() { diff --git a/tests/ui/abi/cannot-be-coroutine.riscv32.stderr b/tests/ui/abi/cannot-be-coroutine.riscv32.stderr index 8e3b3a2940a..1b18bc51f83 100644 --- a/tests/ui/abi/cannot-be-coroutine.riscv32.stderr +++ b/tests/ui/abi/cannot-be-coroutine.riscv32.stderr @@ -4,7 +4,7 @@ error: functions with the "riscv-interrupt-m" ABI cannot be `async` LL | async extern "riscv-interrupt-m" fn riscv_m() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: remove the `async` keyword from this definiton +help: remove the `async` keyword from this definition | LL - async extern "riscv-interrupt-m" fn riscv_m() { LL + extern "riscv-interrupt-m" fn riscv_m() { @@ -16,7 +16,7 @@ error: functions with the "riscv-interrupt-s" ABI cannot be `async` LL | async extern "riscv-interrupt-s" fn riscv_s() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: remove the `async` keyword from this definiton +help: remove the `async` keyword from this definition | LL - async extern "riscv-interrupt-s" fn riscv_s() { LL + extern "riscv-interrupt-s" fn riscv_s() { diff --git a/tests/ui/abi/cannot-be-coroutine.riscv64.stderr b/tests/ui/abi/cannot-be-coroutine.riscv64.stderr index 8e3b3a2940a..1b18bc51f83 100644 --- a/tests/ui/abi/cannot-be-coroutine.riscv64.stderr +++ b/tests/ui/abi/cannot-be-coroutine.riscv64.stderr @@ -4,7 +4,7 @@ error: functions with the "riscv-interrupt-m" ABI cannot be `async` LL | async extern "riscv-interrupt-m" fn riscv_m() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: remove the `async` keyword from this definiton +help: remove the `async` keyword from this definition | LL - async extern "riscv-interrupt-m" fn riscv_m() { LL + extern "riscv-interrupt-m" fn riscv_m() { @@ -16,7 +16,7 @@ error: functions with the "riscv-interrupt-s" ABI cannot be `async` LL | async extern "riscv-interrupt-s" fn riscv_s() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: remove the `async` keyword from this definiton +help: remove the `async` keyword from this definition | LL - async extern "riscv-interrupt-s" fn riscv_s() { LL + extern "riscv-interrupt-s" fn riscv_s() { diff --git a/tests/ui/abi/cannot-be-coroutine.x64.stderr b/tests/ui/abi/cannot-be-coroutine.x64.stderr index cbbddd087c8..8c9292b6a32 100644 --- a/tests/ui/abi/cannot-be-coroutine.x64.stderr +++ b/tests/ui/abi/cannot-be-coroutine.x64.stderr @@ -4,7 +4,7 @@ error: functions with the "x86-interrupt" ABI cannot be `async` LL | async extern "x86-interrupt" fn x86() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: remove the `async` keyword from this definiton +help: remove the `async` keyword from this definition | LL - async extern "x86-interrupt" fn x86() { LL + extern "x86-interrupt" fn x86() { diff --git a/tests/ui/abi/cannot-be-coroutine.x64_win.stderr b/tests/ui/abi/cannot-be-coroutine.x64_win.stderr index cbbddd087c8..8c9292b6a32 100644 --- a/tests/ui/abi/cannot-be-coroutine.x64_win.stderr +++ b/tests/ui/abi/cannot-be-coroutine.x64_win.stderr @@ -4,7 +4,7 @@ error: functions with the "x86-interrupt" ABI cannot be `async` LL | async extern "x86-interrupt" fn x86() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: remove the `async` keyword from this definiton +help: remove the `async` keyword from this definition | LL - async extern "x86-interrupt" fn x86() { LL + extern "x86-interrupt" fn x86() { diff --git a/typos.toml b/typos.toml new file mode 100644 index 00000000000..4035f206a46 --- /dev/null +++ b/typos.toml @@ -0,0 +1,74 @@ +[files] +extend-exclude = [ + # exclude git (sub)modules and generated content + "compiler/rustc_codegen_gcc", + "compiler/rustc_codegen_cranelift", + "compiler/rustc_baked_icu_data", + "library/compiler-builtins", + "library/backtrace", + "library/stdarch", + # generated lorem ipsum texts + "library/alloctests/benches/str.rs", + "library/alloctests/tests/str.rs", +] + +[default.extend-words] +# Add exclusions here, lines should be like `x = "x"`, where `x` is excluded word. +# +# Also see docs: https://github.com/crate-ci/typos/blob/v1.28.2/docs/reference.md +rplace = "rplace" +arange = "arange" +unstalled = "unstalled" +taits = "taits" +Datas = "Datas" +splitted = "splitted" +leafs = "leafs" +makro = "makro" +optin = "optin" +unparseable = "unparseable" +smove = "smove" +childs = "childs" +filetimes = "filetimes" +misformed = "misformed" +targetting = "targetting" +publically = "publically" +clonable = "clonable" + +# this can be valid word, depends on dictionary edition +#matcheable = "matcheable" + +[default.extend-identifiers] +# An entry goes here if the typo is part of some existing ident +# where you want to keep it, but don't want to allow +# such typos everywhere. +# +# I.e. you don't want (or can't) fix some constant name, like +# `DNS_ERROR_INVAILD_VIRTUALIZATION_INSTANCE_NAME` but actually +# want to see `INVAILD` typo fixed in other places. +ERROR_FILENAME_EXCED_RANGE = "ERROR_FILENAME_EXCED_RANGE" +DNS_ERROR_INVAILD_VIRTUALIZATION_INSTANCE_NAME = "DNS_ERROR_INVAILD_VIRTUALIZATION_INSTANCE_NAME" +ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS = "ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS" +ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC = "ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC" +ERROR_MCA_OCCURED = "ERROR_MCA_OCCURED" +ERRNO_ACCES = "ERRNO_ACCES" +tolen = "tolen" +numer = "numer" + +[default] +extend-ignore-words-re = [ + # words with length <= 4 chars is likely noise + "^[a-zA-Z]{1,4}$", +] + +extend-ignore-re = [ + # ignore these intentional typo examples + "/// 1 \\| #\\[cfg\\(widnows\\)\\]", + "/// warning: unexpected `cfg` condition name: `widnows`", + "/// #\\[cfg\\(widnows\\)\\]", + "\\.arg\\(\"Oh no, a tpyo!\"\\)", + # string used in benches + "\"core::iter::adapters::Copie\"", + "-Ccontrol-flow-guard", + "concat!\\(\"CURRENT_RUSTC_VERSIO\", \"N\"\\)", + "\\*\\*v\\*\\*ariable" +] -- cgit 1.4.1-3-g733a5 From 653bb64c7530c86d00b875e1ef14ac75455d2d80 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Jul 2025 14:24:58 +0000 Subject: Remove LtoModuleCodegen Most uses of it either contain a fat or thin lto module. Only WorkItem::LTO could contain both, but splitting that enum variant doesn't complicate things much. --- compiler/rustc_codegen_gcc/src/back/lto.rs | 15 +++---- compiler/rustc_codegen_gcc/src/lib.rs | 6 +-- compiler/rustc_codegen_llvm/src/back/lto.rs | 17 +++----- compiler/rustc_codegen_llvm/src/lib.rs | 6 +-- compiler/rustc_codegen_ssa/src/back/lto.rs | 60 -------------------------- compiler/rustc_codegen_ssa/src/back/write.rs | 48 +++++++++++++++------ compiler/rustc_codegen_ssa/src/traits/write.rs | 6 +-- 7 files changed, 58 insertions(+), 100 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs index 10fce860b77..e554dd2500b 100644 --- a/compiler/rustc_codegen_gcc/src/back/lto.rs +++ b/compiler/rustc_codegen_gcc/src/back/lto.rs @@ -24,7 +24,7 @@ use std::sync::Arc; use gccjit::{Context, OutputKind}; use object::read::archive::ArchiveFile; -use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared}; +use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared}; use rustc_codegen_ssa::back::symbol_export; use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput}; use rustc_codegen_ssa::traits::*; @@ -176,7 +176,7 @@ pub(crate) fn run_fat( cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, -) -> Result, FatalError> { +) -> Result, FatalError> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); let lto_data = prepare_lto(cgcx, dcx)?; @@ -201,7 +201,7 @@ fn fat_lto( mut serialized_modules: Vec<(SerializedModule, CString)>, tmp_path: TempDir, //symbols_below_threshold: &[String], -) -> Result, FatalError> { +) -> Result, FatalError> { let _timer = cgcx.prof.generic_activity("GCC_fat_lto_build_monolithic_module"); info!("going for a fat lto"); @@ -334,7 +334,7 @@ fn fat_lto( // of now. module.module_llvm.temp_dir = Some(tmp_path); - Ok(LtoModuleCodegen::Fat(module)) + Ok(module) } pub struct ModuleBuffer(PathBuf); @@ -358,7 +358,7 @@ pub(crate) fn run_thin( cgcx: &CodegenContext, modules: Vec<(String, ThinBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, -) -> Result<(Vec>, Vec), FatalError> { +) -> Result<(Vec>, Vec), FatalError> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); let lto_data = prepare_lto(cgcx, dcx)?; @@ -427,7 +427,7 @@ fn thin_lto( tmp_path: TempDir, cached_modules: Vec<(SerializedModule, WorkProduct)>, //_symbols_below_threshold: &[String], -) -> Result<(Vec>, Vec), FatalError> { +) -> Result<(Vec>, Vec), FatalError> { let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_global_analysis"); info!("going for that thin, thin LTO"); @@ -573,8 +573,7 @@ fn thin_lto( }*/ info!(" - {}: re-compiled", module_name); - opt_jobs - .push(LtoModuleCodegen::Thin(ThinModule { shared: shared.clone(), idx: module_index })); + opt_jobs.push(ThinModule { shared: shared.clone(), idx: module_index }); } // Save the current ThinLTO import information for the next compilation diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index a912678ef2a..a151a0ab755 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -97,7 +97,7 @@ use gccjit::{CType, Context, OptimizationLevel}; use gccjit::{TargetInfo, Version}; use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::expand::autodiff_attrs::AutoDiffItem; -use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; +use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule}; use rustc_codegen_ssa::back::write::{ CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn, }; @@ -361,7 +361,7 @@ impl WriteBackendMethods for GccCodegenBackend { cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, - ) -> Result, FatalError> { + ) -> Result, FatalError> { back::lto::run_fat(cgcx, modules, cached_modules) } @@ -369,7 +369,7 @@ impl WriteBackendMethods for GccCodegenBackend { cgcx: &CodegenContext, modules: Vec<(String, Self::ThinBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, - ) -> Result<(Vec>, Vec), FatalError> { + ) -> Result<(Vec>, Vec), FatalError> { back::lto::run_thin(cgcx, modules, cached_modules) } diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 9c62244f3c9..0198b9f0cf0 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -7,7 +7,7 @@ use std::sync::Arc; use std::{io, iter, slice}; use object::read::archive::ArchiveFile; -use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared}; +use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared}; use rustc_codegen_ssa::back::symbol_export; use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput}; use rustc_codegen_ssa::traits::*; @@ -201,7 +201,7 @@ pub(crate) fn run_fat( cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, -) -> Result, FatalError> { +) -> Result, FatalError> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, dcx)?; @@ -217,7 +217,7 @@ pub(crate) fn run_thin( cgcx: &CodegenContext, modules: Vec<(String, ThinBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, -) -> Result<(Vec>, Vec), FatalError> { +) -> Result<(Vec>, Vec), FatalError> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, dcx)?; @@ -248,7 +248,7 @@ fn fat_lto( cached_modules: Vec<(SerializedModule, WorkProduct)>, mut serialized_modules: Vec<(SerializedModule, CString)>, symbols_below_threshold: &[*const libc::c_char], -) -> Result, FatalError> { +) -> Result, FatalError> { let _timer = cgcx.prof.generic_activity("LLVM_fat_lto_build_monolithic_module"); info!("going for a fat lto"); @@ -366,7 +366,7 @@ fn fat_lto( save_temp_bitcode(cgcx, &module, "lto.after-restriction"); } - Ok(LtoModuleCodegen::Fat(module)) + Ok(module) } pub(crate) struct Linker<'a>(&'a mut llvm::Linker<'a>); @@ -436,7 +436,7 @@ fn thin_lto( serialized_modules: Vec<(SerializedModule, CString)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, symbols_below_threshold: &[*const libc::c_char], -) -> Result<(Vec>, Vec), FatalError> { +) -> Result<(Vec>, Vec), FatalError> { let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_global_analysis"); unsafe { info!("going for that thin, thin LTO"); @@ -568,10 +568,7 @@ fn thin_lto( } info!(" - {}: re-compiled", module_name); - opt_jobs.push(LtoModuleCodegen::Thin(ThinModule { - shared: Arc::clone(&shared), - idx: module_index, - })); + opt_jobs.push(ThinModule { shared: Arc::clone(&shared), idx: module_index }); } // Save the current ThinLTO import information for the next compilation diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index cdfffbe47bf..57b37959e0d 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -30,7 +30,7 @@ use errors::{AutoDiffWithoutLTO, ParseTargetMachineConfig}; use llvm_util::target_config; use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::expand::autodiff_attrs::AutoDiffItem; -use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; +use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule}; use rustc_codegen_ssa::back::write::{ CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn, }; @@ -178,14 +178,14 @@ impl WriteBackendMethods for LlvmCodegenBackend { cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, - ) -> Result, FatalError> { + ) -> Result, FatalError> { back::lto::run_fat(cgcx, modules, cached_modules) } fn run_thin_lto( cgcx: &CodegenContext, modules: Vec<(String, Self::ThinBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, - ) -> Result<(Vec>, Vec), FatalError> { + ) -> Result<(Vec>, Vec), FatalError> { back::lto::run_thin(cgcx, modules, cached_modules) } fn optimize( diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs index ce6fe8a191b..b49b6783bbd 100644 --- a/compiler/rustc_codegen_ssa/src/back/lto.rs +++ b/compiler/rustc_codegen_ssa/src/back/lto.rs @@ -1,13 +1,8 @@ use std::ffi::CString; use std::sync::Arc; -use rustc_ast::expand::autodiff_attrs::AutoDiffItem; use rustc_data_structures::memmap::Mmap; -use rustc_errors::FatalError; -use super::write::CodegenContext; -use crate::ModuleCodegen; -use crate::back::write::ModuleConfig; use crate::traits::*; pub struct ThinModule { @@ -42,61 +37,6 @@ pub struct ThinShared { pub module_names: Vec, } -pub enum LtoModuleCodegen { - Fat(ModuleCodegen), - Thin(ThinModule), -} - -impl LtoModuleCodegen { - pub fn name(&self) -> &str { - match *self { - LtoModuleCodegen::Fat(_) => "everything", - LtoModuleCodegen::Thin(ref m) => m.name(), - } - } - - /// Optimize this module within the given codegen context. - pub fn optimize( - self, - cgcx: &CodegenContext, - ) -> Result, FatalError> { - match self { - LtoModuleCodegen::Fat(mut module) => { - B::optimize_fat(cgcx, &mut module)?; - Ok(module) - } - LtoModuleCodegen::Thin(thin) => B::optimize_thin(cgcx, thin), - } - } - - /// A "gauge" of how costly it is to optimize this module, used to sort - /// biggest modules first. - pub fn cost(&self) -> u64 { - match *self { - // Only one module with fat LTO, so the cost doesn't matter. - LtoModuleCodegen::Fat(_) => 0, - LtoModuleCodegen::Thin(ref m) => m.cost(), - } - } - - /// Run autodiff on Fat LTO module - pub fn autodiff( - self, - cgcx: &CodegenContext, - diff_fncs: Vec, - config: &ModuleConfig, - ) -> Result, FatalError> { - match &self { - LtoModuleCodegen::Fat(module) => { - B::autodiff(cgcx, &module, diff_fncs, config)?; - } - _ => panic!("autodiff called with non-fat LTO module"), - } - - Ok(self) - } -} - pub enum SerializedModule { Local(M), FromRlib(Vec), diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 8330e4f7af0..5395b55092b 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -408,14 +408,16 @@ fn generate_lto_work( if !needs_fat_lto.is_empty() { assert!(needs_thin_lto.is_empty()); - let mut module = + let module = B::run_fat_lto(cgcx, needs_fat_lto, import_only_modules).unwrap_or_else(|e| e.raise()); if cgcx.lto == Lto::Fat && !autodiff.is_empty() { let config = cgcx.config(ModuleKind::Regular); - module = module.autodiff(cgcx, autodiff, config).unwrap_or_else(|e| e.raise()); + if let Err(err) = B::autodiff(cgcx, &module, autodiff, config) { + err.raise(); + } } // We are adding a single work item, so the cost doesn't matter. - vec![(WorkItem::LTO(module), 0)] + vec![(WorkItem::FatLto(module), 0)] } else { if !autodiff.is_empty() { let dcx = cgcx.create_dcx(); @@ -428,7 +430,7 @@ fn generate_lto_work( .into_iter() .map(|module| { let cost = module.cost(); - (WorkItem::LTO(module), cost) + (WorkItem::ThinLto(module), cost) }) .chain(copy_jobs.into_iter().map(|wp| { ( @@ -736,15 +738,19 @@ pub(crate) enum WorkItem { /// Copy the post-LTO artifacts from the incremental cache to the output /// directory. CopyPostLtoArtifacts(CachedModuleCodegen), - /// Performs (Thin)LTO on the given module. - LTO(lto::LtoModuleCodegen), + /// Performs fat LTO on the given module. + FatLto(ModuleCodegen), + /// Performs thin-LTO on the given module. + ThinLto(lto::ThinModule), } impl WorkItem { fn module_kind(&self) -> ModuleKind { match *self { WorkItem::Optimize(ref m) => m.kind, - WorkItem::CopyPostLtoArtifacts(_) | WorkItem::LTO(_) => ModuleKind::Regular, + WorkItem::CopyPostLtoArtifacts(_) | WorkItem::FatLto(_) | WorkItem::ThinLto(_) => { + ModuleKind::Regular + } } } @@ -792,7 +798,8 @@ impl WorkItem { match self { WorkItem::Optimize(m) => desc("opt", "optimize module", &m.name), WorkItem::CopyPostLtoArtifacts(m) => desc("cpy", "copy LTO artifacts for", &m.name), - WorkItem::LTO(m) => desc("lto", "LTO module", m.name()), + WorkItem::FatLto(_) => desc("lto", "fat LTO module", "everything"), + WorkItem::ThinLto(m) => desc("lto", "thin-LTO module", m.name()), } } } @@ -996,12 +1003,21 @@ fn execute_copy_from_cache_work_item( }) } -fn execute_lto_work_item( +fn execute_fat_lto_work_item( + cgcx: &CodegenContext, + mut module: ModuleCodegen, + module_config: &ModuleConfig, +) -> Result, FatalError> { + B::optimize_fat(cgcx, &mut module)?; + finish_intra_module_work(cgcx, module, module_config) +} + +fn execute_thin_lto_work_item( cgcx: &CodegenContext, - module: lto::LtoModuleCodegen, + module: lto::ThinModule, module_config: &ModuleConfig, ) -> Result, FatalError> { - let module = module.optimize(cgcx)?; + let module = B::optimize_thin(cgcx, module)?; finish_intra_module_work(cgcx, module, module_config) } @@ -1842,10 +1858,16 @@ fn spawn_work<'a, B: ExtraBackendMethods>( ); Ok(execute_copy_from_cache_work_item(&cgcx, m, module_config)) } - WorkItem::LTO(m) => { + WorkItem::FatLto(m) => { + let _timer = cgcx + .prof + .generic_activity_with_arg("codegen_module_perform_lto", "everything"); + execute_fat_lto_work_item(&cgcx, m, module_config) + } + WorkItem::ThinLto(m) => { let _timer = cgcx.prof.generic_activity_with_arg("codegen_module_perform_lto", m.name()); - execute_lto_work_item(&cgcx, m, module_config) + execute_thin_lto_work_item(&cgcx, m, module_config) } }) }; diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index 07a0609fda1..78380973ffc 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -2,7 +2,7 @@ use rustc_ast::expand::autodiff_attrs::AutoDiffItem; use rustc_errors::{DiagCtxtHandle, FatalError}; use rustc_middle::dep_graph::WorkProduct; -use crate::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; +use crate::back::lto::{SerializedModule, ThinModule}; use crate::back::write::{CodegenContext, FatLtoInput, ModuleConfig}; use crate::{CompiledModule, ModuleCodegen}; @@ -26,7 +26,7 @@ pub trait WriteBackendMethods: Clone + 'static { cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, - ) -> Result, FatalError>; + ) -> Result, FatalError>; /// 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. @@ -34,7 +34,7 @@ pub trait WriteBackendMethods: Clone + 'static { cgcx: &CodegenContext, modules: Vec<(String, Self::ThinBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, - ) -> Result<(Vec>, Vec), FatalError>; + ) -> Result<(Vec>, Vec), FatalError>; fn print_pass_timings(&self); fn print_statistics(&self); fn optimize( -- cgit 1.4.1-3-g733a5 From 7fd78df3463c761a693ea79265a6a1faaf2ed51b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Jul 2025 14:43:09 +0000 Subject: Move dcx creation into WriteBackendMethods::codegen --- compiler/rustc_codegen_gcc/src/back/write.rs | 4 +++- compiler/rustc_codegen_gcc/src/lib.rs | 3 +-- compiler/rustc_codegen_llvm/src/back/write.rs | 4 +++- compiler/rustc_codegen_llvm/src/lib.rs | 3 +-- compiler/rustc_codegen_ssa/src/back/write.rs | 7 ++----- compiler/rustc_codegen_ssa/src/traits/write.rs | 1 - 6 files changed, 10 insertions(+), 12 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs index d03d063bdac..113abe70805 100644 --- a/compiler/rustc_codegen_gcc/src/back/write.rs +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -16,10 +16,12 @@ use crate::{GccCodegenBackend, GccContext}; pub(crate) fn codegen( cgcx: &CodegenContext, - dcx: DiagCtxtHandle<'_>, module: ModuleCodegen, config: &ModuleConfig, ) -> Result { + let dcx = cgcx.create_dcx(); + let dcx = dcx.handle(); + let _timer = cgcx.prof.generic_activity_with_arg("GCC_module_codegen", &*module.name); { let context = &module.module_llvm.context; diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index a151a0ab755..34452bdd200 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -408,11 +408,10 @@ impl WriteBackendMethods for GccCodegenBackend { fn codegen( cgcx: &CodegenContext, - dcx: DiagCtxtHandle<'_>, module: ModuleCodegen, config: &ModuleConfig, ) -> Result { - back::write::codegen(cgcx, dcx, module, config) + back::write::codegen(cgcx, module, config) } fn prepare_thin( diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index bde6a9cf4bc..1f7a785bbe7 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -817,10 +817,12 @@ pub(crate) fn link( pub(crate) fn codegen( cgcx: &CodegenContext, - dcx: DiagCtxtHandle<'_>, module: ModuleCodegen, config: &ModuleConfig, ) -> Result { + let dcx = cgcx.create_dcx(); + let dcx = dcx.handle(); + let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_codegen", &*module.name); { let llmod = module.module_llvm.llmod(); diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 57b37959e0d..4d85683de8c 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -212,11 +212,10 @@ impl WriteBackendMethods for LlvmCodegenBackend { } fn codegen( cgcx: &CodegenContext, - dcx: DiagCtxtHandle<'_>, module: ModuleCodegen, config: &ModuleConfig, ) -> Result { - back::write::codegen(cgcx, dcx, module, config) + back::write::codegen(cgcx, module, config) } fn prepare_thin( module: ModuleCodegen, diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 5395b55092b..29e67be6eb6 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1026,11 +1026,8 @@ fn finish_intra_module_work( module: ModuleCodegen, module_config: &ModuleConfig, ) -> Result, FatalError> { - let dcx = cgcx.create_dcx(); - let dcx = dcx.handle(); - if !cgcx.opts.unstable_opts.combine_cgu || module.kind == ModuleKind::Allocator { - let module = B::codegen(cgcx, dcx, module, module_config)?; + let module = B::codegen(cgcx, module, module_config)?; Ok(WorkItemResult::Finished(module)) } else { Ok(WorkItemResult::NeedsLink(module)) @@ -1718,7 +1715,7 @@ fn start_executing_work( let dcx = dcx.handle(); let module = B::run_link(&cgcx, dcx, needs_link).map_err(|_| ())?; let module = - B::codegen(&cgcx, dcx, module, cgcx.config(ModuleKind::Regular)).map_err(|_| ())?; + B::codegen(&cgcx, module, cgcx.config(ModuleKind::Regular)).map_err(|_| ())?; compiled_modules.push(module); } diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index 78380973ffc..c732c4b2ab8 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -53,7 +53,6 @@ pub trait WriteBackendMethods: Clone + 'static { ) -> Result, FatalError>; fn codegen( cgcx: &CodegenContext, - dcx: DiagCtxtHandle<'_>, module: ModuleCodegen, config: &ModuleConfig, ) -> Result; -- cgit 1.4.1-3-g733a5 From 8d63c7a1d68cd30383dceb03a76499c658fa7f40 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Jul 2025 16:09:10 +0000 Subject: Remove unused config param from WriteBackendMethods::autodiff --- compiler/rustc_codegen_gcc/src/lib.rs | 1 - compiler/rustc_codegen_llvm/src/builder/autodiff.rs | 2 -- compiler/rustc_codegen_llvm/src/lib.rs | 3 +-- compiler/rustc_codegen_ssa/src/back/write.rs | 3 +-- compiler/rustc_codegen_ssa/src/traits/write.rs | 1 - 5 files changed, 2 insertions(+), 8 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 34452bdd200..8e63ebc8494 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -437,7 +437,6 @@ impl WriteBackendMethods for GccCodegenBackend { _cgcx: &CodegenContext, _module: &ModuleCodegen, _diff_functions: Vec, - _config: &ModuleConfig, ) -> Result<(), FatalError> { unimplemented!() } diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index b07d9a5cfca..c27e161ba99 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -2,7 +2,6 @@ use std::ptr; use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, AutoDiffItem, DiffActivity, DiffMode}; use rustc_codegen_ssa::ModuleCodegen; -use rustc_codegen_ssa::back::write::ModuleConfig; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::traits::BaseTypeCodegenMethods; use rustc_errors::FatalError; @@ -461,7 +460,6 @@ pub(crate) fn differentiate<'ll>( module: &'ll ModuleCodegen, cgcx: &CodegenContext, diff_items: Vec, - _config: &ModuleConfig, ) -> Result<(), FatalError> { for item in &diff_items { trace!("{}", item); diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 4d85683de8c..7f54416ec0e 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -231,13 +231,12 @@ impl WriteBackendMethods for LlvmCodegenBackend { cgcx: &CodegenContext, module: &ModuleCodegen, diff_fncs: Vec, - config: &ModuleConfig, ) -> Result<(), FatalError> { if cgcx.lto != Lto::Fat { let dcx = cgcx.create_dcx(); return Err(dcx.handle().emit_almost_fatal(AutoDiffWithoutLTO)); } - builder::autodiff::differentiate(module, cgcx, diff_fncs, config) + builder::autodiff::differentiate(module, cgcx, diff_fncs) } } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 433cb63882f..24f648bdb2e 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -999,8 +999,7 @@ fn execute_fat_lto_work_item( B::run_fat_lto(cgcx, needs_fat_lto, import_only_modules).unwrap_or_else(|e| e.raise()); if !autodiff.is_empty() { - let config = cgcx.config(ModuleKind::Regular); - if let Err(err) = B::autodiff(cgcx, &module, autodiff, config) { + if let Err(err) = B::autodiff(cgcx, &module, autodiff) { err.raise(); } } diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index c732c4b2ab8..949fb818c78 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -65,7 +65,6 @@ pub trait WriteBackendMethods: Clone + 'static { cgcx: &CodegenContext, module: &ModuleCodegen, diff_fncs: Vec, - config: &ModuleConfig, ) -> Result<(), FatalError>; } -- cgit 1.4.1-3-g733a5 From 21026cae8d34241b65924198b72c7231ce4f5a3d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Jul 2025 16:22:32 +0000 Subject: Merge run_fat_lto, optimize_fat and autodiff into run_and_optimize_fat_lto --- compiler/rustc_codegen_gcc/src/lib.rs | 23 ++++----------- compiler/rustc_codegen_llvm/messages.ftl | 1 - compiler/rustc_codegen_llvm/src/errors.rs | 4 --- compiler/rustc_codegen_llvm/src/lib.rs | 39 ++++++++++---------------- compiler/rustc_codegen_ssa/src/back/write.rs | 12 +------- compiler/rustc_codegen_ssa/src/traits/write.rs | 16 +++-------- 6 files changed, 26 insertions(+), 69 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 8e63ebc8494..75c36fffec9 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -357,11 +357,16 @@ impl WriteBackendMethods for GccCodegenBackend { type ThinData = ThinData; type ThinBuffer = ThinBuffer; - fn run_fat_lto( + fn run_and_optimize_fat_lto( cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, + diff_fncs: Vec, ) -> Result, FatalError> { + if !diff_fncs.is_empty() { + unimplemented!(); + } + back::lto::run_fat(cgcx, modules, cached_modules) } @@ -391,14 +396,6 @@ impl WriteBackendMethods for GccCodegenBackend { Ok(()) } - fn optimize_fat( - _cgcx: &CodegenContext, - _module: &mut ModuleCodegen, - ) -> Result<(), FatalError> { - // TODO(antoyo) - Ok(()) - } - fn optimize_thin( cgcx: &CodegenContext, thin: ThinModule, @@ -432,14 +429,6 @@ impl WriteBackendMethods for GccCodegenBackend { ) -> Result, FatalError> { back::write::link(cgcx, dcx, modules) } - - fn autodiff( - _cgcx: &CodegenContext, - _module: &ModuleCodegen, - _diff_functions: Vec, - ) -> Result<(), FatalError> { - unimplemented!() - } } /// This is the entrypoint for a hot plugged rustc_codegen_gccjit diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index 3885f18271f..f197ea74473 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -1,5 +1,4 @@ codegen_llvm_autodiff_without_enable = using the autodiff feature requires -Z autodiff=Enable -codegen_llvm_autodiff_without_lto = using the autodiff feature requires using fat-lto codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err} diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index d50ad8a1a9c..31d49e86319 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -37,10 +37,6 @@ impl Diagnostic<'_, G> for ParseTargetMachineConfig<'_> { } } -#[derive(Diagnostic)] -#[diag(codegen_llvm_autodiff_without_lto)] -pub(crate) struct AutoDiffWithoutLTO; - #[derive(Diagnostic)] #[diag(codegen_llvm_autodiff_without_enable)] pub(crate) struct AutoDiffWithoutEnable; diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 7f54416ec0e..5d551c3af87 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -26,7 +26,7 @@ use std::mem::ManuallyDrop; use back::owned_target_machine::OwnedTargetMachine; use back::write::{create_informational_target_machine, create_target_machine}; use context::SimpleCx; -use errors::{AutoDiffWithoutLTO, ParseTargetMachineConfig}; +use errors::ParseTargetMachineConfig; use llvm_util::target_config; use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::expand::autodiff_attrs::AutoDiffItem; @@ -43,7 +43,7 @@ use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; use rustc_session::Session; -use rustc_session::config::{Lto, OptLevel, OutputFilenames, PrintKind, PrintRequest}; +use rustc_session::config::{OptLevel, OutputFilenames, PrintKind, PrintRequest}; use rustc_span::Symbol; mod back { @@ -174,12 +174,23 @@ impl WriteBackendMethods for LlvmCodegenBackend { ) -> Result, FatalError> { back::write::link(cgcx, dcx, modules) } - fn run_fat_lto( + fn run_and_optimize_fat_lto( cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, + diff_fncs: Vec, ) -> Result, FatalError> { - back::lto::run_fat(cgcx, modules, cached_modules) + let mut module = back::lto::run_fat(cgcx, modules, cached_modules)?; + + if !diff_fncs.is_empty() { + builder::autodiff::differentiate(&module, cgcx, diff_fncs)?; + } + + let dcx = cgcx.create_dcx(); + let dcx = dcx.handle(); + back::lto::run_pass_manager(cgcx, dcx, &mut module, false)?; + + Ok(module) } fn run_thin_lto( cgcx: &CodegenContext, @@ -196,14 +207,6 @@ impl WriteBackendMethods for LlvmCodegenBackend { ) -> Result<(), FatalError> { back::write::optimize(cgcx, dcx, module, config) } - fn optimize_fat( - cgcx: &CodegenContext, - module: &mut ModuleCodegen, - ) -> Result<(), FatalError> { - let dcx = cgcx.create_dcx(); - let dcx = dcx.handle(); - back::lto::run_pass_manager(cgcx, dcx, module, false) - } fn optimize_thin( cgcx: &CodegenContext, thin: ThinModule, @@ -226,18 +229,6 @@ impl WriteBackendMethods for LlvmCodegenBackend { fn serialize_module(module: ModuleCodegen) -> (String, Self::ModuleBuffer) { (module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod())) } - /// Generate autodiff rules - fn autodiff( - cgcx: &CodegenContext, - module: &ModuleCodegen, - diff_fncs: Vec, - ) -> Result<(), FatalError> { - if cgcx.lto != Lto::Fat { - let dcx = cgcx.create_dcx(); - return Err(dcx.handle().emit_almost_fatal(AutoDiffWithoutLTO)); - } - builder::autodiff::differentiate(module, cgcx, diff_fncs) - } } impl LlvmCodegenBackend { diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 24f648bdb2e..26fc593da98 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -995,17 +995,7 @@ fn execute_fat_lto_work_item( autodiff: Vec, module_config: &ModuleConfig, ) -> Result, FatalError> { - let mut module = - B::run_fat_lto(cgcx, needs_fat_lto, import_only_modules).unwrap_or_else(|e| e.raise()); - - if !autodiff.is_empty() { - if let Err(err) = B::autodiff(cgcx, &module, autodiff) { - err.raise(); - } - } - - B::optimize_fat(cgcx, &mut module)?; - + let module = B::run_and_optimize_fat_lto(cgcx, needs_fat_lto, import_only_modules, autodiff)?; let module = B::codegen(cgcx, module, module_config)?; Ok(WorkItemResult::Finished(module)) } diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index 949fb818c78..5e993640472 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -20,12 +20,13 @@ pub trait WriteBackendMethods: Clone + 'static { dcx: DiagCtxtHandle<'_>, modules: Vec>, ) -> Result, FatalError>; - /// Performs fat LTO by merging all modules into a single one and returning it - /// for further optimization. - fn run_fat_lto( + /// Performs fat LTO by merging all modules into a single one, running autodiff + /// if necessary and running any further optimizations + fn run_and_optimize_fat_lto( cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, + diff_fncs: Vec, ) -> Result, FatalError>; /// Performs thin LTO by performing necessary global analysis and returning two /// lists, one of the modules that need optimization and another for modules that @@ -43,10 +44,6 @@ pub trait WriteBackendMethods: Clone + 'static { module: &mut ModuleCodegen, config: &ModuleConfig, ) -> Result<(), FatalError>; - fn optimize_fat( - cgcx: &CodegenContext, - llmod: &mut ModuleCodegen, - ) -> Result<(), FatalError>; fn optimize_thin( cgcx: &CodegenContext, thin: ThinModule, @@ -61,11 +58,6 @@ pub trait WriteBackendMethods: Clone + 'static { want_summary: bool, ) -> (String, Self::ThinBuffer); fn serialize_module(module: ModuleCodegen) -> (String, Self::ModuleBuffer); - fn autodiff( - cgcx: &CodegenContext, - module: &ModuleCodegen, - diff_fncs: Vec, - ) -> Result<(), FatalError>; } pub trait ThinBufferMethods: Send + Sync { -- cgit 1.4.1-3-g733a5 From 2b22d0f0d2b9d0d71025065db93058e34f846600 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Thu, 3 Jul 2025 09:17:48 -0700 Subject: Make __rust_alloc_error_handler_should_panic a function --- compiler/rustc_codegen_cranelift/src/allocator.rs | 41 +++++++++++++------- compiler/rustc_codegen_gcc/src/allocator.rs | 44 +++++++++++++++------ compiler/rustc_codegen_llvm/src/allocator.rs | 45 ++++++++++++++++++---- compiler/rustc_session/src/config.rs | 2 +- library/alloc/src/alloc.rs | 4 +- library/std/src/alloc.rs | 4 +- src/tools/miri/src/shims/extern_static.rs | 11 ------ src/tools/miri/src/shims/foreign_items.rs | 6 +++ src/tools/miri/tests/pass/alloc-access-tracking.rs | 4 +- 9 files changed, 111 insertions(+), 50 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs index ffb932a3c38..04f1129d87c 100644 --- a/compiler/rustc_codegen_cranelift/src/allocator.rs +++ b/compiler/rustc_codegen_cranelift/src/allocator.rs @@ -84,19 +84,34 @@ fn codegen_inner( &mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind)), ); - let data_id = module - .declare_data( - &mangle_internal_symbol(tcx, OomStrategy::SYMBOL), - Linkage::Export, - false, - false, - ) - .unwrap(); - let mut data = DataDescription::new(); - data.set_align(1); - let val = oom_strategy.should_panic(); - data.define(Box::new([val])); - module.define_data(data_id, &data).unwrap(); + { + let sig = Signature { + call_conv: module.target_config().default_call_conv, + params: vec![], + returns: vec![AbiParam::new(types::I8)], + }; + let func_id = module + .declare_function( + &mangle_internal_symbol(tcx, OomStrategy::SYMBOL), + Linkage::Export, + &sig, + ) + .unwrap(); + let mut ctx = Context::new(); + ctx.func.signature = sig; + { + let mut func_ctx = FunctionBuilderContext::new(); + let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); + + let block = bcx.create_block(); + bcx.switch_to_block(block); + let value = bcx.ins().iconst(types::I8, oom_strategy.should_panic() as i64); + bcx.ins().return_(&[value]); + bcx.seal_all_blocks(); + bcx.finalize(); + } + module.define_function(func_id, &mut ctx).unwrap(); + } { let sig = Signature { diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs index cf8aa500c77..0d8dc93274f 100644 --- a/compiler/rustc_codegen_gcc/src/allocator.rs +++ b/compiler/rustc_codegen_gcc/src/allocator.rs @@ -1,6 +1,6 @@ -use gccjit::{Context, FunctionType, GlobalKind, ToRValue, Type}; #[cfg(feature = "master")] -use gccjit::{FnAttribute, VarAttribute}; +use gccjit::FnAttribute; +use gccjit::{Context, FunctionType, RValue, ToRValue, Type}; use rustc_ast::expand::allocator::{ ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, alloc_error_handler_name, default_fn_name, global_fn_name, @@ -71,15 +71,13 @@ pub(crate) unsafe fn codegen( None, ); - let name = mangle_internal_symbol(tcx, OomStrategy::SYMBOL); - let global = context.new_global(None, GlobalKind::Exported, i8, name); - #[cfg(feature = "master")] - global.add_attribute(VarAttribute::Visibility(symbol_visibility_to_gcc( - tcx.sess.default_visibility(), - ))); - let value = tcx.sess.opts.unstable_opts.oom.should_panic(); - let value = context.new_rvalue_from_int(i8, value as i32); - global.global_set_initializer_rvalue(value); + create_const_value_function( + tcx, + context, + &mangle_internal_symbol(tcx, OomStrategy::SYMBOL), + i8, + context.new_rvalue_from_int(i8, tcx.sess.opts.unstable_opts.oom.should_panic() as i32), + ); create_wrapper_function( tcx, @@ -91,6 +89,30 @@ pub(crate) unsafe fn codegen( ); } +fn create_const_value_function( + tcx: TyCtxt<'_>, + context: &Context<'_>, + name: &str, + output: Type<'_>, + value: RValue<'_>, +) { + let func = context.new_function(None, FunctionType::Exported, output, &[], name, false); + + #[cfg(feature = "master")] + func.add_attribute(FnAttribute::Visibility(symbol_visibility_to_gcc( + tcx.sess.default_visibility(), + ))); + + func.add_attribute(FnAttribute::AlwaysInline); + + if tcx.sess.must_emit_unwind_tables() { + // TODO(antoyo): emit unwind tables. + } + + let block = func.new_block("entry"); + block.end_with_return(None, value); +} + fn create_wrapper_function( tcx: TyCtxt<'_>, context: &Context<'_>, diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 9dca63cfc8d..2b5090ed6db 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -11,7 +11,7 @@ use rustc_symbol_mangling::mangle_internal_symbol; use crate::builder::SBuilder; use crate::declare::declare_simple_fn; -use crate::llvm::{self, False, True, Type}; +use crate::llvm::{self, False, True, Type, Value}; use crate::{SimpleCx, attributes, debuginfo}; pub(crate) unsafe fn codegen( @@ -73,13 +73,14 @@ pub(crate) unsafe fn codegen( ); unsafe { - // __rust_alloc_error_handler_should_panic - let name = mangle_internal_symbol(tcx, OomStrategy::SYMBOL); - let ll_g = cx.declare_global(&name, i8); - llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility())); - let val = tcx.sess.opts.unstable_opts.oom.should_panic(); - let llval = llvm::LLVMConstInt(i8, val as u64, False); - llvm::set_initializer(ll_g, llval); + // __rust_alloc_error_handler_should_panic_v2 + create_const_value_function( + tcx, + &cx, + &mangle_internal_symbol(tcx, OomStrategy::SYMBOL), + &i8, + &llvm::LLVMConstInt(i8, tcx.sess.opts.unstable_opts.oom.should_panic() as u64, False), + ); // __rust_no_alloc_shim_is_unstable_v2 create_wrapper_function( @@ -100,6 +101,34 @@ pub(crate) unsafe fn codegen( } } +fn create_const_value_function( + tcx: TyCtxt<'_>, + cx: &SimpleCx<'_>, + name: &str, + output: &Type, + value: &Value, +) { + let ty = cx.type_func(&[], output); + let llfn = declare_simple_fn( + &cx, + name, + llvm::CallConv::CCallConv, + llvm::UnnamedAddr::Global, + llvm::Visibility::from_generic(tcx.sess.default_visibility()), + ty, + ); + + attributes::apply_to_llfn( + llfn, + llvm::AttributePlace::Function, + &[llvm::AttributeKind::AlwaysInline.create_attr(cx.llcx)], + ); + + let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(cx.llcx, llfn, c"entry".as_ptr()) }; + let mut bx = SBuilder::build(&cx, llbb); + bx.ret(value); +} + fn create_wrapper_function( tcx: TyCtxt<'_>, cx: &SimpleCx<'_>, diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 73bb0471c22..0639363febb 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -3340,7 +3340,7 @@ pub enum OomStrategy { } impl OomStrategy { - pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic"; + pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic_v2"; pub fn should_panic(self) -> u8 { match self { diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index b4176e9c1f4..c9b98fa4e5a 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -429,10 +429,10 @@ pub mod __alloc_error_handler { // This symbol is emitted by rustc next to __rust_alloc_error_handler. // Its value depends on the -Zoom={panic,abort} compiler option. #[rustc_std_internal_symbol] - static __rust_alloc_error_handler_should_panic: u8; + fn __rust_alloc_error_handler_should_panic_v2() -> u8; } - if unsafe { __rust_alloc_error_handler_should_panic != 0 } { + if unsafe { __rust_alloc_error_handler_should_panic_v2() != 0 } { panic!("memory allocation of {size} bytes failed") } else { core::panicking::panic_nounwind_fmt( diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index b574e9f3a25..1d61630269a 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -349,10 +349,10 @@ fn default_alloc_error_hook(layout: Layout) { // This symbol is emitted by rustc next to __rust_alloc_error_handler. // Its value depends on the -Zoom={panic,abort} compiler option. #[rustc_std_internal_symbol] - static __rust_alloc_error_handler_should_panic: u8; + fn __rust_alloc_error_handler_should_panic_v2() -> u8; } - if unsafe { __rust_alloc_error_handler_should_panic != 0 } { + if unsafe { __rust_alloc_error_handler_should_panic_v2() != 0 } { panic!("memory allocation of {} bytes failed", layout.size()); } else { // This is the default path taken on OOM, and the only path taken on stable with std. diff --git a/src/tools/miri/src/shims/extern_static.rs b/src/tools/miri/src/shims/extern_static.rs index a2ea3dbd88b..f02a3f425d1 100644 --- a/src/tools/miri/src/shims/extern_static.rs +++ b/src/tools/miri/src/shims/extern_static.rs @@ -1,7 +1,5 @@ //! Provides the `extern static` that this platform expects. -use rustc_symbol_mangling::mangle_internal_symbol; - use crate::*; impl<'tcx> MiriMachine<'tcx> { @@ -45,15 +43,6 @@ impl<'tcx> MiriMachine<'tcx> { /// Sets up the "extern statics" for this machine. pub fn init_extern_statics(ecx: &mut MiriInterpCx<'tcx>) -> InterpResult<'tcx> { - // "__rust_alloc_error_handler_should_panic" - let val = ecx.tcx.sess.opts.unstable_opts.oom.should_panic(); - let val = ImmTy::from_int(val, ecx.machine.layouts.u8); - Self::alloc_extern_static( - ecx, - &mangle_internal_symbol(*ecx.tcx, "__rust_alloc_error_handler_should_panic"), - val, - )?; - if ecx.target_os_is_unix() { // "environ" is mandated by POSIX. let environ = ecx.machine.env_vars.unix().environ(); diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 97070eb742f..1b66735ddb1 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -615,6 +615,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // This is a no-op shim that only exists to prevent making the allocator shims instantly stable. let [] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?; } + name if name == this.mangle_internal_symbol("__rust_alloc_error_handler_should_panic_v2") => { + // Gets the value of the `oom` option. + let [] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?; + let val = this.tcx.sess.opts.unstable_opts.oom.should_panic(); + this.write_int(val, dest)?; + } // C memory handling functions "memcmp" => { diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.rs b/src/tools/miri/tests/pass/alloc-access-tracking.rs index 9eba0ca171b..b285250c8ab 100644 --- a/src/tools/miri/tests/pass/alloc-access-tracking.rs +++ b/src/tools/miri/tests/pass/alloc-access-tracking.rs @@ -1,7 +1,7 @@ #![no_std] #![no_main] -//@compile-flags: -Zmiri-track-alloc-id=19 -Zmiri-track-alloc-accesses -Cpanic=abort -//@normalize-stderr-test: "id 19" -> "id $$ALLOC" +//@compile-flags: -Zmiri-track-alloc-id=18 -Zmiri-track-alloc-accesses -Cpanic=abort +//@normalize-stderr-test: "id 18" -> "id $$ALLOC" //@only-target: linux # alloc IDs differ between OSes (due to extern static allocations) extern "Rust" { -- cgit 1.4.1-3-g733a5 From 51857ade80c531c0ae0ee801dde5d425d13d38f8 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 3 Jul 2025 20:57:34 +0200 Subject: Always use the pure Rust fallback instead of `llvm.{maximum,minimum}` --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 26 ++++++++++++++------------ library/core/src/num/f64.rs | 4 ++-- 2 files changed, 16 insertions(+), 14 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 776658b9cca..35922c100cd 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -103,23 +103,25 @@ fn call_simple_intrinsic<'ll, 'tcx>( sym::minnumf64 => ("llvm.minnum", &[bx.type_f64()]), sym::minnumf128 => ("llvm.minnum", &[bx.type_f128()]), - sym::minimumf16 => ("llvm.minimum", &[bx.type_f16()]), - sym::minimumf32 => ("llvm.minimum", &[bx.type_f32()]), - sym::minimumf64 => ("llvm.minimum", &[bx.type_f64()]), - // There are issues on x86_64 and aarch64 with the f128 variant, - // let's instead use the intrinsic fallback body. - // sym::minimumf128 => ("llvm.minimum", &[cx.type_f128()]), + // FIXME: LLVM currently mis-compile those intrinsics, re-enable them + // when llvm/llvm-project#{139380,139381,140445} are fixed. + //sym::minimumf16 => ("llvm.minimum", &[bx.type_f16()]), + //sym::minimumf32 => ("llvm.minimum", &[bx.type_f32()]), + //sym::minimumf64 => ("llvm.minimum", &[bx.type_f64()]), + //sym::minimumf128 => ("llvm.minimum", &[cx.type_f128()]), + // sym::maxnumf16 => ("llvm.maxnum", &[bx.type_f16()]), sym::maxnumf32 => ("llvm.maxnum", &[bx.type_f32()]), sym::maxnumf64 => ("llvm.maxnum", &[bx.type_f64()]), sym::maxnumf128 => ("llvm.maxnum", &[bx.type_f128()]), - sym::maximumf16 => ("llvm.maximum", &[bx.type_f16()]), - sym::maximumf32 => ("llvm.maximum", &[bx.type_f32()]), - sym::maximumf64 => ("llvm.maximum", &[bx.type_f64()]), - // There are issues on x86_64 and aarch64 with the f128 variant, - // let's instead use the intrinsic fallback body. - // sym::maximumf128 => ("llvm.maximum", &[cx.type_f128()]), + // FIXME: LLVM currently mis-compile those intrinsics, re-enable them + // when llvm/llvm-project#{139380,139381,140445} are fixed. + //sym::maximumf16 => ("llvm.maximum", &[bx.type_f16()]), + //sym::maximumf32 => ("llvm.maximum", &[bx.type_f32()]), + //sym::maximumf64 => ("llvm.maximum", &[bx.type_f64()]), + //sym::maximumf128 => ("llvm.maximum", &[cx.type_f128()]), + // sym::copysignf16 => ("llvm.copysign", &[bx.type_f16()]), sym::copysignf32 => ("llvm.copysign", &[bx.type_f32()]), sym::copysignf64 => ("llvm.copysign", &[bx.type_f64()]), diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 93bfdbdd60b..3cd079b84eb 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -943,7 +943,7 @@ impl f64 { /// This returns NaN when *either* argument is NaN, as opposed to /// [`f64::max`] which only returns NaN when *both* arguments are NaN. /// - /// ```ignore-arm-unknown-linux-gnueabihf,ignore-i586 (see https://github.com/rust-lang/rust/issues/141087) + /// ``` /// #![feature(float_minimum_maximum)] /// let x = 1.0_f64; /// let y = 2.0_f64; @@ -970,7 +970,7 @@ impl f64 { /// This returns NaN when *either* argument is NaN, as opposed to /// [`f64::min`] which only returns NaN when *both* arguments are NaN. /// - /// ```ignore-arm-unknown-linux-gnueabihf,ignore-i586 (see https://github.com/rust-lang/rust/issues/141087) + /// ``` /// #![feature(float_minimum_maximum)] /// let x = 1.0_f64; /// let y = 2.0_f64; -- cgit 1.4.1-3-g733a5 From 226b0fbe11812c71c8002b10a40063571cf52b3f Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 5 Jul 2025 08:26:32 +0200 Subject: use `is_multiple_of` instead of manual modulo --- compiler/rustc_borrowck/src/polonius/legacy/location.rs | 2 +- compiler/rustc_codegen_llvm/src/abi.rs | 2 +- compiler/rustc_const_eval/src/interpret/memory.rs | 4 ++-- compiler/rustc_query_system/src/query/plumbing.rs | 2 +- compiler/rustc_target/src/callconv/sparc64.rs | 6 +++--- compiler/rustc_ty_utils/src/layout/invariant.rs | 2 +- library/core/src/slice/mod.rs | 8 ++++---- library/core/src/slice/sort/shared/smallsort.rs | 2 +- library/core/src/str/count.rs | 2 +- library/core/src/str/validations.rs | 2 +- 10 files changed, 16 insertions(+), 16 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_borrowck/src/polonius/legacy/location.rs b/compiler/rustc_borrowck/src/polonius/legacy/location.rs index 5f816bb9bbd..618119a6a3d 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/location.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/location.rs @@ -109,6 +109,6 @@ impl PoloniusLocationTable { impl LocationIndex { fn is_start(self) -> bool { // even indices are start points; odd indices are mid points - (self.index() % 2) == 0 + self.index().is_multiple_of(2) } } diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 4b07c8aef91..009e7e2487b 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -146,7 +146,7 @@ impl LlvmType for CastTarget { "total size {:?} cannot be divided into units of zero size", self.rest.total ); - if self.rest.total.bytes() % self.rest.unit.size.bytes() != 0 { + if !self.rest.total.bytes().is_multiple_of(self.rest.unit.size.bytes()) { assert_eq!(self.rest.unit.kind, RegKind::Integer, "only int regs can be split"); } self.rest.total.bytes().div_ceil(self.rest.unit.size.bytes()) diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index ff822b52a8d..c97d53a45de 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -537,7 +537,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { #[inline] fn is_offset_misaligned(offset: u64, align: Align) -> Option { - if offset % align.bytes() == 0 { + if offset.is_multiple_of(align.bytes()) { None } else { // The biggest power of two through which `offset` is divisible. @@ -1554,7 +1554,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // If the allocation is N-aligned, and the offset is not divisible by N, // then `base + offset` has a non-zero remainder after division by `N`, // which means `base + offset` cannot be null. - if offset.bytes() % info.align.bytes() != 0 { + if !offset.bytes().is_multiple_of(info.align.bytes()) { return interp_ok(false); } // We don't know enough, this might be null. diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 3c1fc731784..06e59eb4ccc 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -597,7 +597,7 @@ where // from disk. Re-hashing results is fairly expensive, so we can't // currently afford to verify every hash. This subset should still // give us some coverage of potential bugs though. - let try_verify = prev_fingerprint.split().1.as_u64() % 32 == 0; + let try_verify = prev_fingerprint.split().1.as_u64().is_multiple_of(32); if std::intrinsics::unlikely( try_verify || qcx.dep_context().sess().opts.unstable_opts.incremental_verify_ich, ) { diff --git a/compiler/rustc_target/src/callconv/sparc64.rs b/compiler/rustc_target/src/callconv/sparc64.rs index 186826c08fc..ecc9067ced3 100644 --- a/compiler/rustc_target/src/callconv/sparc64.rs +++ b/compiler/rustc_target/src/callconv/sparc64.rs @@ -90,7 +90,7 @@ where _ => {} } - if (offset.bytes() % 4) != 0 + if !offset.bytes().is_multiple_of(4) && matches!(scalar2.primitive(), Primitive::Float(Float::F32 | Float::F64)) { offset += Size::from_bytes(4 - (offset.bytes() % 4)); @@ -181,7 +181,7 @@ where // Structure { float, int, int } doesn't like to be handled like // { float, long int }. Other way around it doesn't mind. if data.last_offset < arg.layout.size - && (data.last_offset.bytes() % 8) != 0 + && !data.last_offset.bytes().is_multiple_of(8) && data.prefix_index < data.prefix.len() { data.prefix[data.prefix_index] = Some(Reg::i32()); @@ -190,7 +190,7 @@ where } let mut rest_size = arg.layout.size - data.last_offset; - if (rest_size.bytes() % 8) != 0 && data.prefix_index < data.prefix.len() { + if !rest_size.bytes().is_multiple_of(8) && data.prefix_index < data.prefix.len() { data.prefix[data.prefix_index] = Some(Reg::i32()); rest_size = rest_size - Reg::i32().size; } diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index 4b65c05d0e9..1311ee31182 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, TyAndLayout}; pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) { let tcx = cx.tcx(); - if layout.size.bytes() % layout.align.abi.bytes() != 0 { + if !layout.size.bytes().is_multiple_of(layout.align.abi.bytes()) { bug!("size is not a multiple of align, in the following layout:\n{layout:#?}"); } if layout.size.bytes() >= tcx.data_layout.obj_size_bound() { diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 3a3f44c6b85..dc09ba8d788 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1316,7 +1316,7 @@ impl [T] { assert_unsafe_precondition!( check_language_ub, "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", - (n: usize = N, len: usize = self.len()) => n != 0 && len % n == 0, + (n: usize = N, len: usize = self.len()) => n != 0 && len.is_multiple_of(n), ); // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length let new_len = unsafe { exact_div(self.len(), N) }; @@ -1512,7 +1512,7 @@ impl [T] { assert_unsafe_precondition!( check_language_ub, "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", - (n: usize = N, len: usize = self.len()) => n != 0 && len % n == 0 + (n: usize = N, len: usize = self.len()) => n != 0 && len.is_multiple_of(n) ); // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length let new_len = unsafe { exact_div(self.len(), N) }; @@ -4866,7 +4866,7 @@ impl [T] { let byte_offset = elem_start.wrapping_sub(self_start); - if byte_offset % size_of::() != 0 { + if !byte_offset.is_multiple_of(size_of::()) { return None; } @@ -4920,7 +4920,7 @@ impl [T] { let byte_start = subslice_start.wrapping_sub(self_start); - if byte_start % size_of::() != 0 { + if !byte_start.is_multiple_of(size_of::()) { return None; } diff --git a/library/core/src/slice/sort/shared/smallsort.rs b/library/core/src/slice/sort/shared/smallsort.rs index 4280f7570db..400daba16c1 100644 --- a/library/core/src/slice/sort/shared/smallsort.rs +++ b/library/core/src/slice/sort/shared/smallsort.rs @@ -823,7 +823,7 @@ unsafe fn bidirectional_merge bool>( let right_end = right_rev.wrapping_add(1); // Odd length, so one element is left unconsumed in the input. - if len % 2 != 0 { + if !len.is_multiple_of(2) { let left_nonempty = left < left_end; let last_src = if left_nonempty { left } else { right }; ptr::copy_nonoverlapping(last_src, dst, 1); diff --git a/library/core/src/str/count.rs b/library/core/src/str/count.rs index 452403b23de..f59ad3e66b4 100644 --- a/library/core/src/str/count.rs +++ b/library/core/src/str/count.rs @@ -52,7 +52,7 @@ fn do_count_chars(s: &str) -> usize { // Check the properties of `CHUNK_SIZE` and `UNROLL_INNER` that are required // for correctness. const _: () = assert!(CHUNK_SIZE < 256); - const _: () = assert!(CHUNK_SIZE % UNROLL_INNER == 0); + const _: () = assert!(CHUNK_SIZE.is_multiple_of(UNROLL_INNER)); // SAFETY: transmuting `[u8]` to `[usize]` is safe except for size // differences which are handled by `align_to`. diff --git a/library/core/src/str/validations.rs b/library/core/src/str/validations.rs index 8174e4ff97d..b54d6478e58 100644 --- a/library/core/src/str/validations.rs +++ b/library/core/src/str/validations.rs @@ -219,7 +219,7 @@ pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { // Ascii case, try to skip forward quickly. // When the pointer is aligned, read 2 words of data per iteration // until we find a word containing a non-ascii byte. - if align != usize::MAX && align.wrapping_sub(index) % USIZE_BYTES == 0 { + if align != usize::MAX && align.wrapping_sub(index).is_multiple_of(USIZE_BYTES) { let ptr = v.as_ptr(); while index < blocks_end { // SAFETY: since `align - index` and `ascii_block_size` are -- cgit 1.4.1-3-g733a5 From ed3711ea29398b09483e4e2a3930567e9ba81d93 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 5 Jul 2025 08:36:27 +0200 Subject: use `div_ceil` instead of manual logic --- compiler/rustc_abi/src/lib.rs | 3 +-- compiler/rustc_codegen_llvm/src/va_arg.rs | 4 ++-- compiler/rustc_index/src/bit_set.rs | 4 ++-- compiler/rustc_passes/src/liveness/rwu_table.rs | 2 +- compiler/rustc_serialize/src/leb128.rs | 2 +- compiler/rustc_span/src/edit_distance.rs | 2 +- compiler/rustc_target/src/callconv/x86.rs | 2 +- compiler/rustc_target/src/callconv/x86_64.rs | 2 +- compiler/rustc_target/src/callconv/xtensa.rs | 2 +- library/core/src/slice/sort/stable/drift.rs | 4 ++-- library/core/src/str/iter.rs | 6 +++--- library/portable-simd/crates/core_simd/src/lane_count.rs | 2 +- 12 files changed, 17 insertions(+), 18 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 0df8921c9b7..a438545c76f 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -527,8 +527,7 @@ impl Size { /// not a multiple of 8. pub fn from_bits(bits: impl TryInto) -> Size { let bits = bits.try_into().ok().unwrap(); - // Avoid potential overflow from `bits + 7`. - Size { raw: bits / 8 + ((bits % 8) + 7) / 8 } + Size { raw: bits.div_ceil(8) } } #[inline] diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 4fe4c9bcbf2..486dc894a4e 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -172,10 +172,10 @@ fn emit_aapcs_va_arg<'ll, 'tcx>( let gr_type = target_ty.is_any_ptr() || target_ty.is_integral(); let (reg_off, reg_top, slot_size) = if gr_type { - let nreg = (layout.size.bytes() + 7) / 8; + let nreg = layout.size.bytes().div_ceil(8); (gr_offs, gr_top, nreg * 8) } else { - let nreg = (layout.size.bytes() + 15) / 16; + let nreg = layout.size.bytes().div_ceil(16); (vr_offs, vr_top, nreg * 16) }; diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index a4885aabe1f..645d95b1dba 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -1744,13 +1744,13 @@ impl SparseBitMatrix { #[inline] fn num_words(domain_size: T) -> usize { - (domain_size.index() + WORD_BITS - 1) / WORD_BITS + domain_size.index().div_ceil(WORD_BITS) } #[inline] fn num_chunks(domain_size: T) -> usize { assert!(domain_size.index() > 0); - (domain_size.index() + CHUNK_BITS - 1) / CHUNK_BITS + domain_size.index().div_ceil(CHUNK_BITS) } #[inline] diff --git a/compiler/rustc_passes/src/liveness/rwu_table.rs b/compiler/rustc_passes/src/liveness/rwu_table.rs index 4c1f6ea141e..a1177946f86 100644 --- a/compiler/rustc_passes/src/liveness/rwu_table.rs +++ b/compiler/rustc_passes/src/liveness/rwu_table.rs @@ -44,7 +44,7 @@ impl RWUTable { const WORD_RWU_COUNT: usize = Self::WORD_BITS / Self::RWU_BITS; pub(super) fn new(live_nodes: usize, vars: usize) -> RWUTable { - let live_node_words = (vars + Self::WORD_RWU_COUNT - 1) / Self::WORD_RWU_COUNT; + let live_node_words = vars.div_ceil(Self::WORD_RWU_COUNT); Self { live_nodes, vars, live_node_words, words: vec![0u8; live_node_words * live_nodes] } } diff --git a/compiler/rustc_serialize/src/leb128.rs b/compiler/rustc_serialize/src/leb128.rs index 954c1f728f2..da328dcea03 100644 --- a/compiler/rustc_serialize/src/leb128.rs +++ b/compiler/rustc_serialize/src/leb128.rs @@ -7,7 +7,7 @@ use crate::serialize::Decoder; /// Returns the length of the longest LEB128 encoding for `T`, assuming `T` is an integer type pub const fn max_leb128_len() -> usize { // The longest LEB128 encoding for an integer uses 7 bits per byte. - (size_of::() * 8 + 6) / 7 + (size_of::() * 8).div_ceil(7) } /// Returns the length of the longest LEB128 encoding of all supported integer types. diff --git a/compiler/rustc_span/src/edit_distance.rs b/compiler/rustc_span/src/edit_distance.rs index 4f3202b694c..416e9daa8fb 100644 --- a/compiler/rustc_span/src/edit_distance.rs +++ b/compiler/rustc_span/src/edit_distance.rs @@ -130,7 +130,7 @@ pub fn edit_distance_with_substrings(a: &str, b: &str, limit: usize) -> Option( continue; } - let size_in_regs = (arg.layout.size.bits() + 31) / 32; + let size_in_regs = arg.layout.size.bits().div_ceil(32); if size_in_regs == 0 { continue; diff --git a/compiler/rustc_target/src/callconv/x86_64.rs b/compiler/rustc_target/src/callconv/x86_64.rs index 700ee73c8fd..d8db7ed6e4c 100644 --- a/compiler/rustc_target/src/callconv/x86_64.rs +++ b/compiler/rustc_target/src/callconv/x86_64.rs @@ -95,7 +95,7 @@ where Ok(()) } - let n = ((arg.layout.size.bytes() + 7) / 8) as usize; + let n = arg.layout.size.bytes().div_ceil(8) as usize; if n > MAX_EIGHTBYTES { return Err(Memory); } diff --git a/compiler/rustc_target/src/callconv/xtensa.rs b/compiler/rustc_target/src/callconv/xtensa.rs index b687f0e20c6..a73a70a1a0c 100644 --- a/compiler/rustc_target/src/callconv/xtensa.rs +++ b/compiler/rustc_target/src/callconv/xtensa.rs @@ -54,7 +54,7 @@ where // Determine the number of GPRs needed to pass the current argument // according to the ABI. 2*XLen-aligned varargs are passed in "aligned" // register pairs, so may consume 3 registers. - let mut needed_arg_gprs = (size + 32 - 1) / 32; + let mut needed_arg_gprs = size.div_ceil(32); if needed_align == 64 { needed_arg_gprs += *arg_gprs_left % 2; } diff --git a/library/core/src/slice/sort/stable/drift.rs b/library/core/src/slice/sort/stable/drift.rs index cf1df1e91a5..1edffe095a8 100644 --- a/library/core/src/slice/sort/stable/drift.rs +++ b/library/core/src/slice/sort/stable/drift.rs @@ -158,7 +158,7 @@ fn merge_tree_scale_factor(n: usize) -> u64 { panic!("Platform not supported"); } - ((1 << 62) + n as u64 - 1) / n as u64 + (1u64 << 62).div_ceil(n as u64) } // Note: merge_tree_depth output is < 64 when left < right as f*x and f*y must @@ -182,7 +182,7 @@ fn sqrt_approx(n: usize) -> usize { // Finally we note that the exponentiation / division can be done directly // with shifts. We OR with 1 to avoid zero-checks in the integer log. let ilog = (n | 1).ilog2(); - let shift = (1 + ilog) / 2; + let shift = ilog.div_ceil(2); ((1 << shift) + (n >> shift)) / 2 } diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 425c4eaee28..bcf886484ad 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -102,7 +102,7 @@ impl<'a> Iterator for Chars<'a> { // `(len + 3)` can't overflow, because we know that the `slice::Iter` // belongs to a slice in memory which has a maximum length of // `isize::MAX` (that's well below `usize::MAX`). - ((len + 3) / 4, Some(len)) + (len.div_ceil(4), Some(len)) } #[inline] @@ -1532,11 +1532,11 @@ impl<'a> Iterator for EncodeUtf16<'a> { // belongs to a slice in memory which has a maximum length of // `isize::MAX` (that's well below `usize::MAX`) if self.extra == 0 { - ((len + 2) / 3, Some(len)) + (len.div_ceil(3), Some(len)) } else { // We're in the middle of a surrogate pair, so add the remaining // surrogate to the bounds. - ((len + 2) / 3 + 1, Some(len + 1)) + (len.div_ceil(3) + 1, Some(len + 1)) } } } diff --git a/library/portable-simd/crates/core_simd/src/lane_count.rs b/library/portable-simd/crates/core_simd/src/lane_count.rs index 280b27bc9bc..bbdfd5f5f3e 100644 --- a/library/portable-simd/crates/core_simd/src/lane_count.rs +++ b/library/portable-simd/crates/core_simd/src/lane_count.rs @@ -8,7 +8,7 @@ pub struct LaneCount; impl LaneCount { /// The number of bytes in a bitmask with this many lanes. - pub const BITMASK_LEN: usize = (N + 7) / 8; + pub const BITMASK_LEN: usize = N.div_ceil(8); } /// Statically guarantees that a lane count is marked as supported. -- cgit 1.4.1-3-g733a5 From 93f1201c0616672d71e640a0ad600d029448c40a Mon Sep 17 00:00:00 2001 From: Edoardo Marangoni Date: Sun, 29 Jun 2025 12:11:51 +0200 Subject: compiler: Parse `p-` specs in datalayout string, allow definition of custom default data address space --- compiler/rustc_abi/src/lib.rs | 295 ++++++++++++++++++--- compiler/rustc_ast_lowering/src/format.rs | 4 +- compiler/rustc_codegen_cranelift/src/abi/mod.rs | 2 +- .../rustc_codegen_cranelift/src/abi/pass_mode.rs | 2 +- compiler/rustc_codegen_cranelift/src/common.rs | 2 +- compiler/rustc_codegen_cranelift/src/constant.rs | 2 +- compiler/rustc_codegen_gcc/src/common.rs | 2 +- compiler/rustc_codegen_gcc/src/consts.rs | 4 +- compiler/rustc_codegen_gcc/src/intrinsic/mod.rs | 2 +- compiler/rustc_codegen_gcc/src/intrinsic/simd.rs | 2 +- compiler/rustc_codegen_llvm/src/common.rs | 2 +- compiler/rustc_codegen_llvm/src/consts.rs | 11 +- compiler/rustc_codegen_llvm/src/context.rs | 2 +- .../rustc_codegen_llvm/src/debuginfo/metadata.rs | 14 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 20 +- compiler/rustc_codegen_llvm/src/lib.rs | 2 +- compiler/rustc_codegen_llvm/src/type_.rs | 4 +- compiler/rustc_codegen_llvm/src/va_arg.rs | 54 ++-- compiler/rustc_codegen_ssa/src/back/write.rs | 2 +- compiler/rustc_codegen_ssa/src/base.rs | 6 +- compiler/rustc_codegen_ssa/src/meth.rs | 8 +- compiler/rustc_codegen_ssa/src/mir/naked_asm.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 2 +- compiler/rustc_const_eval/src/interpret/memory.rs | 4 +- compiler/rustc_errors/messages.ftl | 3 + compiler/rustc_errors/src/diagnostic_impls.rs | 4 + compiler/rustc_middle/src/mir/consts.rs | 2 +- .../rustc_middle/src/mir/interpret/allocation.rs | 6 +- .../src/mir/interpret/allocation/provenance_map.rs | 15 +- compiler/rustc_middle/src/mir/interpret/mod.rs | 4 +- compiler/rustc_middle/src/mir/interpret/pointer.rs | 2 +- compiler/rustc_middle/src/mir/interpret/value.rs | 8 +- compiler/rustc_middle/src/mir/pretty.rs | 2 +- compiler/rustc_middle/src/ty/consts/int.rs | 6 +- compiler/rustc_middle/src/ty/layout.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 2 +- compiler/rustc_middle/src/ty/vtable.rs | 4 +- compiler/rustc_mir_build/src/thir/constant.rs | 2 +- compiler/rustc_session/src/config/cfg.rs | 2 +- compiler/rustc_smir/src/rustc_smir/alloc.rs | 9 +- .../rustc_smir/src/rustc_smir/context/impls.rs | 2 +- compiler/rustc_target/src/callconv/loongarch.rs | 4 +- compiler/rustc_target/src/callconv/mips.rs | 2 +- compiler/rustc_target/src/callconv/mod.rs | 4 +- compiler/rustc_target/src/callconv/riscv.rs | 4 +- compiler/rustc_target/src/callconv/sparc.rs | 2 +- compiler/rustc_target/src/callconv/x86.rs | 2 +- compiler/rustc_target/src/spec/mod.rs | 16 +- compiler/rustc_transmute/src/layout/tree.rs | 2 +- compiler/rustc_ty_utils/src/layout.rs | 4 +- .../clippy_lints/src/casts/fn_to_numeric_cast.rs | 2 +- .../casts/fn_to_numeric_cast_with_truncation.rs | 2 +- src/tools/clippy/clippy_lints/src/casts/utils.rs | 2 +- src/tools/clippy/clippy_lints/src/enum_clike.rs | 2 +- src/tools/clippy/clippy_utils/src/consts.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/layout.rs | 4 +- .../crates/hir-ty/src/layout/target.rs | 5 +- .../rust-analyzer/crates/hir-ty/src/mir/eval.rs | 2 +- 58 files changed, 416 insertions(+), 170 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 0df8921c9b7..891ac854f49 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -221,6 +221,20 @@ impl ReprOptions { /// * Cranelift stores the base-2 log of the lane count in a 4 bit integer. pub const MAX_SIMD_LANES: u64 = 1 << 0xF; +/// How pointers are represented in a given address space +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct PointerSpec { + /// The size of the bitwise representation of the pointer. + pointer_size: Size, + /// The alignment of pointers for this address space + pointer_align: AbiAlign, + /// The size of the value a pointer can be offset by in this address space. + pointer_offset: Size, + /// Pointers into this address space contain extra metadata + /// FIXME(workingjubilee): Consider adequately reflecting this in the compiler? + _is_fat: bool, +} + /// Parsed [Data layout](https://llvm.org/docs/LangRef.html#data-layout) /// for a target, which contains everything needed to compute layouts. #[derive(Debug, PartialEq, Eq)] @@ -236,13 +250,22 @@ pub struct TargetDataLayout { pub f32_align: AbiAlign, pub f64_align: AbiAlign, pub f128_align: AbiAlign, - pub pointer_size: Size, - pub pointer_align: AbiAlign, pub aggregate_align: AbiAlign, /// Alignments for vector types. pub vector_align: Vec<(Size, AbiAlign)>, + pub default_address_space: AddressSpace, + pub default_address_space_pointer_spec: PointerSpec, + + /// Address space information of all known address spaces. + /// + /// # Note + /// + /// This vector does not contain the [`PointerSpec`] relative to the default address space, + /// which instead lives in [`Self::default_address_space_pointer_spec`]. + address_space_info: Vec<(AddressSpace, PointerSpec)>, + pub instruction_address_space: AddressSpace, /// Minimum size of #[repr(C)] enums (default c_int::BITS, usually 32) @@ -267,14 +290,20 @@ impl Default for TargetDataLayout { f32_align: AbiAlign::new(align(32)), f64_align: AbiAlign::new(align(64)), f128_align: AbiAlign::new(align(128)), - pointer_size: Size::from_bits(64), - pointer_align: AbiAlign::new(align(64)), aggregate_align: AbiAlign { abi: align(8) }, vector_align: vec![ (Size::from_bits(64), AbiAlign::new(align(64))), (Size::from_bits(128), AbiAlign::new(align(128))), ], - instruction_address_space: AddressSpace::DATA, + default_address_space: AddressSpace::ZERO, + default_address_space_pointer_spec: PointerSpec { + pointer_size: Size::from_bits(64), + pointer_align: AbiAlign::new(align(64)), + pointer_offset: Size::from_bits(64), + _is_fat: false, + }, + address_space_info: vec![], + instruction_address_space: AddressSpace::ZERO, c_enum_min_size: Integer::I32, } } @@ -288,6 +317,7 @@ pub enum TargetDataLayoutErrors<'a> { InconsistentTargetArchitecture { dl: &'a str, target: &'a str }, InconsistentTargetPointerWidth { pointer_size: u64, target: u32 }, InvalidBitsSize { err: String }, + UnknownPointerSpecification { err: String }, } impl TargetDataLayout { @@ -298,6 +328,7 @@ impl TargetDataLayout { /// determined from llvm string. pub fn parse_from_llvm_datalayout_string<'a>( input: &'a str, + default_address_space: AddressSpace, ) -> Result> { // Parse an address space index from a string. let parse_address_space = |s: &'a str, cause: &'a str| { @@ -321,19 +352,27 @@ impl TargetDataLayout { |s: &'a str, cause: &'a str| parse_bits(s, "size", cause).map(Size::from_bits); // Parse an alignment string. - let parse_align = |s: &[&'a str], cause: &'a str| { - if s.is_empty() { - return Err(TargetDataLayoutErrors::MissingAlignment { cause }); - } + let parse_align_str = |s: &'a str, cause: &'a str| { let align_from_bits = |bits| { Align::from_bits(bits) .map_err(|err| TargetDataLayoutErrors::InvalidAlignment { cause, err }) }; - let abi = parse_bits(s[0], "alignment", cause)?; + let abi = parse_bits(s, "alignment", cause)?; Ok(AbiAlign::new(align_from_bits(abi)?)) }; + // Parse an alignment sequence, possibly in the form `[:]`, + // ignoring the secondary alignment specifications. + let parse_align_seq = |s: &[&'a str], cause: &'a str| { + if s.is_empty() { + return Err(TargetDataLayoutErrors::MissingAlignment { cause }); + } + parse_align_str(s[0], cause) + }; + let mut dl = TargetDataLayout::default(); + dl.default_address_space = default_address_space; + let mut i128_align_src = 64; for spec in input.split('-') { let spec_parts = spec.split(':').collect::>(); @@ -344,24 +383,107 @@ impl TargetDataLayout { [p] if p.starts_with('P') => { dl.instruction_address_space = parse_address_space(&p[1..], "P")? } - ["a", a @ ..] => dl.aggregate_align = parse_align(a, "a")?, - ["f16", a @ ..] => dl.f16_align = parse_align(a, "f16")?, - ["f32", a @ ..] => dl.f32_align = parse_align(a, "f32")?, - ["f64", a @ ..] => dl.f64_align = parse_align(a, "f64")?, - ["f128", a @ ..] => dl.f128_align = parse_align(a, "f128")?, - // FIXME(erikdesjardins): we should be parsing nonzero address spaces - // this will require replacing TargetDataLayout::{pointer_size,pointer_align} - // with e.g. `fn pointer_size_in(AddressSpace)` - [p @ "p", s, a @ ..] | [p @ "p0", s, a @ ..] => { - dl.pointer_size = parse_size(s, p)?; - dl.pointer_align = parse_align(a, p)?; + ["a", a @ ..] => dl.aggregate_align = parse_align_seq(a, "a")?, + ["f16", a @ ..] => dl.f16_align = parse_align_seq(a, "f16")?, + ["f32", a @ ..] => dl.f32_align = parse_align_seq(a, "f32")?, + ["f64", a @ ..] => dl.f64_align = parse_align_seq(a, "f64")?, + ["f128", a @ ..] => dl.f128_align = parse_align_seq(a, "f128")?, + [p, s, a @ ..] if p.starts_with("p") => { + let mut p = p.strip_prefix('p').unwrap(); + let mut _is_fat = false; + + // Some targets, such as CHERI, use the 'f' suffix in the p- spec to signal that + // they use 'fat' pointers. The resulting prefix may look like `pf`. + + if p.starts_with('f') { + p = p.strip_prefix('f').unwrap(); + _is_fat = true; + } + + // However, we currently don't take into account further specifications: + // an error is emitted instead. + if p.starts_with(char::is_alphabetic) { + return Err(TargetDataLayoutErrors::UnknownPointerSpecification { + err: p.to_string(), + }); + } + + let addr_space = if !p.is_empty() { + parse_address_space(p, "p-")? + } else { + AddressSpace::ZERO + }; + + let pointer_size = parse_size(s, "p-")?; + let pointer_align = parse_align_seq(a, "p-")?; + let info = PointerSpec { + pointer_offset: pointer_size, + pointer_size, + pointer_align, + _is_fat, + }; + if addr_space == default_address_space { + dl.default_address_space_pointer_spec = info; + } else { + match dl.address_space_info.iter_mut().find(|(a, _)| *a == addr_space) { + Some(e) => e.1 = info, + None => { + dl.address_space_info.push((addr_space, info)); + } + } + } + } + [p, s, a, _pr, i] if p.starts_with("p") => { + let mut p = p.strip_prefix('p').unwrap(); + let mut _is_fat = false; + + // Some targets, such as CHERI, use the 'f' suffix in the p- spec to signal that + // they use 'fat' pointers. The resulting prefix may look like `pf`. + + if p.starts_with('f') { + p = p.strip_prefix('f').unwrap(); + _is_fat = true; + } + + // However, we currently don't take into account further specifications: + // an error is emitted instead. + if p.starts_with(char::is_alphabetic) { + return Err(TargetDataLayoutErrors::UnknownPointerSpecification { + err: p.to_string(), + }); + } + + let addr_space = if !p.is_empty() { + parse_address_space(p, "p")? + } else { + AddressSpace::ZERO + }; + + let info = PointerSpec { + pointer_size: parse_size(s, "p-")?, + pointer_align: parse_align_str(a, "p-")?, + pointer_offset: parse_size(i, "p-")?, + _is_fat, + }; + + if addr_space == default_address_space { + dl.default_address_space_pointer_spec = info; + } else { + match dl.address_space_info.iter_mut().find(|(a, _)| *a == addr_space) { + Some(e) => e.1 = info, + None => { + dl.address_space_info.push((addr_space, info)); + } + } + } } + [s, a @ ..] if s.starts_with('i') => { let Ok(bits) = s[1..].parse::() else { parse_size(&s[1..], "i")?; // For the user error. continue; }; - let a = parse_align(a, s)?; + let a = parse_align_seq(a, s)?; match bits { 1 => dl.i1_align = a, 8 => dl.i8_align = a, @@ -379,7 +501,7 @@ impl TargetDataLayout { } [s, a @ ..] if s.starts_with('v') => { let v_size = parse_size(&s[1..], "v")?; - let a = parse_align(a, s)?; + let a = parse_align_seq(a, s)?; if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) { v.1 = a; continue; @@ -390,10 +512,27 @@ impl TargetDataLayout { _ => {} // Ignore everything else. } } + + // Inherit, if not given, address space information for specific LLVM elements from the + // default data address space. + if (dl.instruction_address_space != dl.default_address_space) + && dl + .address_space_info + .iter() + .find(|(a, _)| *a == dl.instruction_address_space) + .is_none() + { + dl.address_space_info.push(( + dl.instruction_address_space, + dl.default_address_space_pointer_spec.clone(), + )); + } + Ok(dl) } - /// Returns **exclusive** upper bound on object size in bytes. + /// Returns **exclusive** upper bound on object size in bytes, in the default data address + /// space. /// /// The theoretical maximum object size is defined as the maximum positive `isize` value. /// This ensures that the `offset` semantics remain well-defined by allowing it to correctly @@ -404,7 +543,26 @@ impl TargetDataLayout { /// so we adopt such a more-constrained size bound due to its technical limitations. #[inline] pub fn obj_size_bound(&self) -> u64 { - match self.pointer_size.bits() { + match self.pointer_size().bits() { + 16 => 1 << 15, + 32 => 1 << 31, + 64 => 1 << 61, + bits => panic!("obj_size_bound: unknown pointer bit size {bits}"), + } + } + + /// Returns **exclusive** upper bound on object size in bytes. + /// + /// The theoretical maximum object size is defined as the maximum positive `isize` value. + /// This ensures that the `offset` semantics remain well-defined by allowing it to correctly + /// index every address within an object along with one byte past the end, along with allowing + /// `isize` to store the difference between any two pointers into an object. + /// + /// LLVM uses a 64-bit integer to represent object size in *bits*, but we care only for bytes, + /// so we adopt such a more-constrained size bound due to its technical limitations. + #[inline] + pub fn obj_size_bound_in(&self, address_space: AddressSpace) -> u64 { + match self.pointer_size_in(address_space).bits() { 16 => 1 << 15, 32 => 1 << 31, 64 => 1 << 61, @@ -415,7 +573,18 @@ impl TargetDataLayout { #[inline] pub fn ptr_sized_integer(&self) -> Integer { use Integer::*; - match self.pointer_size.bits() { + match self.pointer_offset().bits() { + 16 => I16, + 32 => I32, + 64 => I64, + bits => panic!("ptr_sized_integer: unknown pointer bit size {bits}"), + } + } + + #[inline] + pub fn ptr_sized_integer_in(&self, address_space: AddressSpace) -> Integer { + use Integer::*; + match self.pointer_offset_in(address_space).bits() { 16 => I16, 32 => I32, 64 => I64, @@ -439,6 +608,66 @@ impl TargetDataLayout { Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap(), )) } + + /// Get the pointer size in the default data address space. + #[inline] + pub fn pointer_size(&self) -> Size { + self.default_address_space_pointer_spec.pointer_size + } + + /// Get the pointer size in a specific address space. + #[inline] + pub fn pointer_size_in(&self, c: AddressSpace) -> Size { + if c == self.default_address_space { + return self.default_address_space_pointer_spec.pointer_size; + } + + if let Some(e) = self.address_space_info.iter().find(|(a, _)| a == &c) { + e.1.pointer_size + } else { + panic!("Use of unknown address space {c:?}"); + } + } + + /// Get the pointer index in the default data address space. + #[inline] + pub fn pointer_offset(&self) -> Size { + self.default_address_space_pointer_spec.pointer_offset + } + + /// Get the pointer index in a specific address space. + #[inline] + pub fn pointer_offset_in(&self, c: AddressSpace) -> Size { + if c == self.default_address_space { + return self.default_address_space_pointer_spec.pointer_offset; + } + + if let Some(e) = self.address_space_info.iter().find(|(a, _)| a == &c) { + e.1.pointer_offset + } else { + panic!("Use of unknown address space {c:?}"); + } + } + + /// Get the pointer alignment in the default data address space. + #[inline] + pub fn pointer_align(&self) -> AbiAlign { + self.default_address_space_pointer_spec.pointer_align + } + + /// Get the pointer alignment in a specific address space. + #[inline] + pub fn pointer_align_in(&self, c: AddressSpace) -> AbiAlign { + if c == self.default_address_space { + return self.default_address_space_pointer_spec.pointer_align; + } + + if let Some(e) = self.address_space_info.iter().find(|(a, _)| a == &c) { + e.1.pointer_align + } else { + panic!("Use of unknown address space {c:?}"); + } + } } pub trait HasDataLayout { @@ -1101,10 +1330,7 @@ impl Primitive { match self { Int(i, _) => i.size(), Float(f) => f.size(), - // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in - // different address spaces can have different sizes - // (but TargetDataLayout doesn't currently parse that part of the DL string) - Pointer(_) => dl.pointer_size, + Pointer(a) => dl.pointer_size_in(a), } } @@ -1115,10 +1341,7 @@ impl Primitive { match self { Int(i, _) => i.align(dl), Float(f) => f.align(dl), - // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in - // different address spaces can have different alignments - // (but TargetDataLayout doesn't currently parse that part of the DL string) - Pointer(_) => dl.pointer_align, + Pointer(a) => dl.pointer_align_in(a), } } } @@ -1422,8 +1645,8 @@ impl FieldsShape { pub struct AddressSpace(pub u32); impl AddressSpace { - /// The default address space, corresponding to data space. - pub const DATA: Self = AddressSpace(0); + /// LLVM's `0` address space. + pub const ZERO: Self = AddressSpace(0); } /// The way we represent values to the backend diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 943cde90dd2..5b1dcab87b9 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -55,7 +55,7 @@ impl<'hir> LoweringContext<'_, 'hir> { /// Get the maximum value of int_ty. It is platform-dependent due to the byte size of isize fn int_ty_max(&self, int_ty: IntTy) -> u128 { match int_ty { - IntTy::Isize => self.tcx.data_layout.pointer_size.signed_int_max() as u128, + IntTy::Isize => self.tcx.data_layout.pointer_size().signed_int_max() as u128, IntTy::I8 => i8::MAX as u128, IntTy::I16 => i16::MAX as u128, IntTy::I32 => i32::MAX as u128, @@ -67,7 +67,7 @@ impl<'hir> LoweringContext<'_, 'hir> { /// Get the maximum value of uint_ty. It is platform-dependent due to the byte size of usize fn uint_ty_max(&self, uint_ty: UintTy) -> u128 { match uint_ty { - UintTy::Usize => self.tcx.data_layout.pointer_size.unsigned_int_max(), + UintTy::Usize => self.tcx.data_layout.pointer_size().unsigned_int_max(), UintTy::U8 => u8::MAX as u128, UintTy::U16 => u16::MAX as u128, UintTy::U32 => u32::MAX as u128, diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 8965e4a944d..7d0731c77bd 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -786,7 +786,7 @@ pub(crate) fn codegen_drop<'tcx>( pub(crate) fn lib_call_arg_param(tcx: TyCtxt<'_>, ty: Type, is_signed: bool) -> AbiParam { let param = AbiParam::new(ty); - if ty.is_int() && u64::from(ty.bits()) < tcx.data_layout.pointer_size.bits() { + if ty.is_int() && u64::from(ty.bits()) < tcx.data_layout.pointer_size().bits() { match (&*tcx.sess.target.arch, &*tcx.sess.target.vendor) { ("x86_64", _) | ("aarch64", "apple") => match (ty, is_signed) { (types::I8 | types::I16, true) => param.sext(), diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs index cd0afee0cfb..2031842062d 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs @@ -127,7 +127,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { PassMode::Indirect { attrs, meta_attrs: None, on_stack } => { if on_stack { // Abi requires aligning struct size to pointer size - let size = self.layout.size.align_to(tcx.data_layout.pointer_align.abi); + let size = self.layout.size.align_to(tcx.data_layout.pointer_align().abi); let size = u32::try_from(size.bytes()).unwrap(); smallvec![apply_attrs_to_abi_param( AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructArgument(size),), diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 2f11b2d2dcc..2fbe5c02802 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -15,7 +15,7 @@ use crate::debuginfo::FunctionDebugContext; use crate::prelude::*; pub(crate) fn pointer_ty(tcx: TyCtxt<'_>) -> types::Type { - match tcx.data_layout.pointer_size.bits() { + match tcx.data_layout.pointer_size().bits() { 16 => types::I16, 32 => types::I32, 64 => types::I64, diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index ee43eb736e6..ed06423b260 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -443,7 +443,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant let addend = { let endianness = tcx.data_layout.endian; let offset = offset.bytes() as usize; - let ptr_size = tcx.data_layout.pointer_size; + let ptr_size = tcx.data_layout.pointer_size(); let bytes = &alloc.inspect_with_uninit_and_ptr_outside_interpreter( offset..offset + ptr_size.bytes() as usize, ); diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index dd582834fac..32713eb56c6 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -162,7 +162,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { } fn const_usize(&self, i: u64) -> RValue<'gcc> { - let bit_size = self.data_layout().pointer_size.bits(); + let bit_size = self.data_layout().pointer_size().bits(); if bit_size < 64 { // make sure it doesn't overflow assert!(i < (1 << bit_size)); diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index b43f9b24c6a..c04c75e1b11 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -294,7 +294,7 @@ pub(crate) fn const_alloc_to_gcc_uncached<'gcc>( let alloc = alloc.inner(); let mut llvals = Vec::with_capacity(alloc.provenance().ptrs().len() + 1); let dl = cx.data_layout(); - let pointer_size = dl.pointer_size.bytes() as usize; + let pointer_size = dl.pointer_size().bytes() as usize; let mut next_offset = 0; for &(offset, prov) in alloc.provenance().ptrs().iter() { @@ -331,7 +331,7 @@ pub(crate) fn const_alloc_to_gcc_uncached<'gcc>( ), abi::Scalar::Initialized { value: Primitive::Pointer(address_space), - valid_range: WrappingRange::full(dl.pointer_size), + valid_range: WrappingRange::full(dl.pointer_size()), }, cx.type_i8p_ext(address_space), )); diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 497605978fe..0753ac1aeb8 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -541,7 +541,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), // so we re-use that same threshold here. - layout.size() <= self.data_layout().pointer_size * 2 + layout.size() <= self.data_layout().pointer_size() * 2 } }; diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index 2e508813fc3..350915a277e 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -1184,7 +1184,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let lhs = args[0].immediate(); let rhs = args[1].immediate(); let is_add = name == sym::simd_saturating_add; - let ptr_bits = bx.tcx().data_layout.pointer_size.bits() as _; + let ptr_bits = bx.tcx().data_layout.pointer_size().bits() as _; let (signed, elem_width, elem_ty) = match *in_elem.kind() { ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits) / 8, bx.cx.type_int_from_ty(i)), ty::Uint(i) => { diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 7cfab25bc50..92f38565eef 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -175,7 +175,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { } fn const_usize(&self, i: u64) -> &'ll Value { - let bit_size = self.data_layout().pointer_size.bits(); + let bit_size = self.data_layout().pointer_size().bits(); if bit_size < 64 { // make sure it doesn't overflow assert!(i < (1 << bit_size)); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index a4492d76c3c..28f5282c6b0 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -43,7 +43,8 @@ pub(crate) fn const_alloc_to_llvm<'ll>( } let mut llvals = Vec::with_capacity(alloc.provenance().ptrs().len() + 1); let dl = cx.data_layout(); - let pointer_size = dl.pointer_size.bytes() as usize; + let pointer_size = dl.pointer_size(); + let pointer_size_bytes = pointer_size.bytes() as usize; // Note: this function may call `inspect_with_uninit_and_ptr_outside_interpreter`, so `range` // must be within the bounds of `alloc` and not contain or overlap a pointer provenance. @@ -100,7 +101,9 @@ pub(crate) fn const_alloc_to_llvm<'ll>( // This `inspect` is okay since it is within the bounds of the allocation, it doesn't // affect interpreter execution (we inspect the result after interpreter execution), // and we properly interpret the provenance as a relocation pointer offset. - alloc.inspect_with_uninit_and_ptr_outside_interpreter(offset..(offset + pointer_size)), + alloc.inspect_with_uninit_and_ptr_outside_interpreter( + offset..(offset + pointer_size_bytes), + ), ) .expect("const_alloc_to_llvm: could not read relocation pointer") as u64; @@ -111,11 +114,11 @@ pub(crate) fn const_alloc_to_llvm<'ll>( InterpScalar::from_pointer(Pointer::new(prov, Size::from_bytes(ptr_offset)), &cx.tcx), Scalar::Initialized { value: Primitive::Pointer(address_space), - valid_range: WrappingRange::full(dl.pointer_size), + valid_range: WrappingRange::full(pointer_size), }, cx.type_ptr_ext(address_space), )); - next_offset = offset + pointer_size; + next_offset = offset + pointer_size_bytes; } if alloc.len() >= next_offset { let range = next_offset..alloc.len(); diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 0324dff6ff2..90582e23b04 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -605,7 +605,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { GenericCx( FullCx { tcx, - scx: SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size), + scx: SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size()), use_dll_storage_attrs, tls_model, codegen_unit, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 7f3e486ca31..9b4736e50e6 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -159,13 +159,15 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( return_if_di_node_created_in_meantime!(cx, unique_type_id); let data_layout = &cx.tcx.data_layout; + let pointer_size = data_layout.pointer_size(); + let pointer_align = data_layout.pointer_align(); let ptr_type_debuginfo_name = compute_debuginfo_type_name(cx.tcx, ptr_type, true); match wide_pointer_kind(cx, pointee_type) { None => { // This is a thin pointer. Create a regular pointer type and give it the correct name. assert_eq!( - (data_layout.pointer_size, data_layout.pointer_align.abi), + (pointer_size, pointer_align.abi), cx.size_and_align_of(ptr_type), "ptr_type={ptr_type}, pointee_type={pointee_type}", ); @@ -174,8 +176,8 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreatePointerType( DIB(cx), pointee_type_di_node, - data_layout.pointer_size.bits(), - data_layout.pointer_align.abi.bits() as u32, + pointer_size.bits(), + pointer_align.abi.bits() as u32, 0, // Ignore DWARF address space. ptr_type_debuginfo_name.as_c_char_ptr(), ptr_type_debuginfo_name.len(), @@ -319,7 +321,9 @@ fn build_subroutine_type_di_node<'ll, 'tcx>( let name = compute_debuginfo_type_name(cx.tcx, fn_ty, false); let (size, align) = match fn_ty.kind() { ty::FnDef(..) => (Size::ZERO, Align::ONE), - ty::FnPtr(..) => (cx.tcx.data_layout.pointer_size, cx.tcx.data_layout.pointer_align.abi), + ty::FnPtr(..) => { + (cx.tcx.data_layout.pointer_size(), cx.tcx.data_layout.pointer_align().abi) + } _ => unreachable!(), }; let di_node = unsafe { @@ -504,7 +508,7 @@ fn recursion_marker_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> &'ll D create_basic_type( cx, "", - cx.tcx.data_layout.pointer_size, + cx.tcx.data_layout.pointer_size(), dwarf_const::DW_ATE_unsigned, ) }) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 35922c100cd..fcc0d378f06 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -458,7 +458,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), // so we re-use that same threshold here. - layout.size() <= self.data_layout().pointer_size * 2 + layout.size() <= self.data_layout().pointer_size() * 2 } }; @@ -758,8 +758,8 @@ fn codegen_msvc_try<'ll, 'tcx>( // } // // More information can be found in libstd's seh.rs implementation. - let ptr_size = bx.tcx().data_layout.pointer_size; - let ptr_align = bx.tcx().data_layout.pointer_align.abi; + let ptr_size = bx.tcx().data_layout.pointer_size(); + let ptr_align = bx.tcx().data_layout.pointer_align().abi; let slot = bx.alloca(ptr_size, ptr_align); let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void()); bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None, None); @@ -1031,8 +1031,8 @@ fn codegen_emcc_try<'ll, 'tcx>( // We need to pass two values to catch_func (ptr and is_rust_panic), so // create an alloca and pass a pointer to that. - let ptr_size = bx.tcx().data_layout.pointer_size; - let ptr_align = bx.tcx().data_layout.pointer_align.abi; + let ptr_size = bx.tcx().data_layout.pointer_size(); + let ptr_align = bx.tcx().data_layout.pointer_align().abi; let i8_align = bx.tcx().data_layout.i8_align.abi; // Required in order for there to be no padding between the fields. assert!(i8_align <= ptr_align); @@ -1158,9 +1158,11 @@ fn generic_simd_intrinsic<'ll, 'tcx>( macro_rules! require_int_or_uint_ty { ($ty: expr, $diag: expr) => { match $ty { - ty::Int(i) => i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits()), + ty::Int(i) => { + i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size().bits()) + } ty::Uint(i) => { - i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits()) + i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size().bits()) } _ => { return_error!($diag); @@ -2014,10 +2016,10 @@ fn generic_simd_intrinsic<'ll, 'tcx>( } else { let bitwidth = match in_elem.kind() { ty::Int(i) => { - i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits()) + i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size().bits()) } ty::Uint(i) => { - i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits()) + i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size().bits()) } _ => return_error!(InvalidMonomorphization::UnsupportedSymbol { span, diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index cdfffbe47bf..63ca51b006d 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -113,7 +113,7 @@ impl ExtraBackendMethods for LlvmCodegenBackend { ) -> ModuleLlvm { let module_llvm = ModuleLlvm::new_metadata(tcx, module_name); let cx = - SimpleCx::new(module_llvm.llmod(), &module_llvm.llcx, tcx.data_layout.pointer_size); + SimpleCx::new(module_llvm.llmod(), &module_llvm.llcx, tcx.data_layout.pointer_size()); unsafe { allocator::codegen(tcx, cx, module_name, kind, alloc_error_handler_kind); } diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 453eca2bbe1..ee472e75ed4 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -208,7 +208,7 @@ impl<'ll, CX: Borrow>> BaseTypeCodegenMethods for GenericCx<'ll, CX> { } fn type_ptr(&self) -> &'ll Type { - self.type_ptr_ext(AddressSpace::DATA) + self.type_ptr_ext(AddressSpace::ZERO) } fn type_ptr_ext(&self, address_space: AddressSpace) -> &'ll Type { @@ -258,7 +258,7 @@ impl Type { } pub(crate) fn ptr_llcx(llcx: &llvm::Context) -> &Type { - unsafe { llvm::LLVMPointerTypeInContext(llcx, AddressSpace::DATA.0) } + unsafe { llvm::LLVMPointerTypeInContext(llcx, AddressSpace::ZERO.0) } } } diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 4fe4c9bcbf2..b52847f5bcf 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -45,7 +45,8 @@ fn emit_direct_ptr_va_arg<'ll, 'tcx>( let va_list_ty = bx.type_ptr(); let va_list_addr = list.immediate(); - let ptr = bx.load(va_list_ty, va_list_addr, bx.tcx().data_layout.pointer_align.abi); + let ptr_align_abi = bx.tcx().data_layout.pointer_align().abi; + let ptr = bx.load(va_list_ty, va_list_addr, ptr_align_abi); let (addr, addr_align) = if allow_higher_align && align > slot_size { (round_pointer_up_to_alignment(bx, ptr, align, bx.type_ptr()), align) @@ -56,7 +57,7 @@ fn emit_direct_ptr_va_arg<'ll, 'tcx>( let aligned_size = size.align_to(slot_size).bytes() as i32; let full_direct_size = bx.cx().const_i32(aligned_size); let next = bx.inbounds_ptradd(addr, full_direct_size); - bx.store(next, va_list_addr, bx.tcx().data_layout.pointer_align.abi); + bx.store(next, va_list_addr, ptr_align_abi); if size.bytes() < slot_size.bytes() && bx.tcx().sess.target.endian == Endian::Big @@ -108,8 +109,8 @@ fn emit_ptr_va_arg<'ll, 'tcx>( let (llty, size, align) = if indirect { ( bx.cx.layout_of(Ty::new_imm_ptr(bx.cx.tcx, target_ty)).llvm_type(bx.cx), - bx.cx.data_layout().pointer_size, - bx.cx.data_layout().pointer_align, + bx.cx.data_layout().pointer_size(), + bx.cx.data_layout().pointer_align(), ) } else { (layout.llvm_type(bx.cx), layout.size, layout.align) @@ -204,7 +205,7 @@ fn emit_aapcs_va_arg<'ll, 'tcx>( bx.switch_to_block(in_reg); let top_type = bx.type_ptr(); - let top = bx.load(top_type, reg_top, dl.pointer_align.abi); + let top = bx.load(top_type, reg_top, dl.pointer_align().abi); // reg_value = *(@top + reg_off_v); let mut reg_addr = bx.ptradd(top, reg_off_v); @@ -297,6 +298,7 @@ fn emit_powerpc_va_arg<'ll, 'tcx>( let max_regs = 8u8; let use_regs = bx.icmp(IntPredicate::IntULT, num_regs, bx.const_u8(max_regs)); + let ptr_align_abi = bx.tcx().data_layout.pointer_align().abi; let in_reg = bx.append_sibling_block("va_arg.in_reg"); let in_mem = bx.append_sibling_block("va_arg.in_mem"); @@ -308,7 +310,7 @@ fn emit_powerpc_va_arg<'ll, 'tcx>( bx.switch_to_block(in_reg); let reg_safe_area_ptr = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(1 + 1 + 2 + 4)); - let mut reg_addr = bx.load(bx.type_ptr(), reg_safe_area_ptr, dl.pointer_align.abi); + let mut reg_addr = bx.load(bx.type_ptr(), reg_safe_area_ptr, ptr_align_abi); // Floating-point registers start after the general-purpose registers. if !is_int && !is_soft_float_abi { @@ -342,11 +344,11 @@ fn emit_powerpc_va_arg<'ll, 'tcx>( let size = if !is_indirect { layout.layout.size.align_to(overflow_area_align) } else { - dl.pointer_size + dl.pointer_size() }; let overflow_area_ptr = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(1 + 1 + 2)); - let mut overflow_area = bx.load(bx.type_ptr(), overflow_area_ptr, dl.pointer_align.abi); + let mut overflow_area = bx.load(bx.type_ptr(), overflow_area_ptr, ptr_align_abi); // Round up address of argument to alignment if layout.layout.align.abi > overflow_area_align { @@ -362,7 +364,7 @@ fn emit_powerpc_va_arg<'ll, 'tcx>( // Increase the overflow area. overflow_area = bx.inbounds_ptradd(overflow_area, bx.const_usize(size.bytes())); - bx.store(overflow_area, overflow_area_ptr, dl.pointer_align.abi); + bx.store(overflow_area, overflow_area_ptr, ptr_align_abi); bx.br(end); @@ -373,11 +375,8 @@ fn emit_powerpc_va_arg<'ll, 'tcx>( bx.switch_to_block(end); let val_addr = bx.phi(bx.type_ptr(), &[reg_addr, mem_addr], &[in_reg, in_mem]); let val_type = layout.llvm_type(bx); - let val_addr = if is_indirect { - bx.load(bx.cx.type_ptr(), val_addr, dl.pointer_align.abi) - } else { - val_addr - }; + let val_addr = + if is_indirect { bx.load(bx.cx.type_ptr(), val_addr, ptr_align_abi) } else { val_addr }; bx.load(val_type, val_addr, layout.align.abi) } @@ -414,6 +413,7 @@ fn emit_s390x_va_arg<'ll, 'tcx>( let in_reg = bx.append_sibling_block("va_arg.in_reg"); let in_mem = bx.append_sibling_block("va_arg.in_mem"); let end = bx.append_sibling_block("va_arg.end"); + let ptr_align_abi = dl.pointer_align().abi; // FIXME: vector ABI not yet supported. let target_ty_size = bx.cx.size_of(target_ty).bytes(); @@ -435,7 +435,7 @@ fn emit_s390x_va_arg<'ll, 'tcx>( bx.switch_to_block(in_reg); // Work out the address of the value in the register save area. - let reg_ptr_v = bx.load(bx.type_ptr(), reg_save_area, dl.pointer_align.abi); + let reg_ptr_v = bx.load(bx.type_ptr(), reg_save_area, ptr_align_abi); let scaled_reg_count = bx.mul(reg_count_v, bx.const_u64(8)); let reg_off = bx.add(scaled_reg_count, bx.const_u64(reg_save_index * 8 + reg_padding)); let reg_addr = bx.ptradd(reg_ptr_v, reg_off); @@ -449,15 +449,14 @@ fn emit_s390x_va_arg<'ll, 'tcx>( bx.switch_to_block(in_mem); // Work out the address of the value in the argument overflow area. - let arg_ptr_v = - bx.load(bx.type_ptr(), overflow_arg_area, bx.tcx().data_layout.pointer_align.abi); + let arg_ptr_v = bx.load(bx.type_ptr(), overflow_arg_area, ptr_align_abi); let arg_off = bx.const_u64(padding); let mem_addr = bx.ptradd(arg_ptr_v, arg_off); // Update the argument overflow area pointer. let arg_size = bx.cx().const_u64(padded_size); let new_arg_ptr_v = bx.inbounds_ptradd(arg_ptr_v, arg_size); - bx.store(new_arg_ptr_v, overflow_arg_area, dl.pointer_align.abi); + bx.store(new_arg_ptr_v, overflow_arg_area, ptr_align_abi); bx.br(end); // Return the appropriate result. @@ -465,7 +464,7 @@ fn emit_s390x_va_arg<'ll, 'tcx>( let val_addr = bx.phi(bx.type_ptr(), &[reg_addr, mem_addr], &[in_reg, in_mem]); let val_type = layout.llvm_type(bx); let val_addr = - if indirect { bx.load(bx.cx.type_ptr(), val_addr, dl.pointer_align.abi) } else { val_addr }; + if indirect { bx.load(bx.cx.type_ptr(), val_addr, ptr_align_abi) } else { val_addr }; bx.load(val_type, val_addr, layout.align.abi) } @@ -607,7 +606,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>( // loads than necessary. Can we clean this up? let reg_save_area_ptr = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(2 * unsigned_int_offset + ptr_offset)); - let reg_save_area_v = bx.load(bx.type_ptr(), reg_save_area_ptr, dl.pointer_align.abi); + let reg_save_area_v = bx.load(bx.type_ptr(), reg_save_area_ptr, dl.pointer_align().abi); let reg_addr = match layout.layout.backend_repr() { BackendRepr::Scalar(scalar) => match scalar.primitive() { @@ -749,10 +748,11 @@ fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>( layout: TyAndLayout<'tcx, Ty<'tcx>>, ) -> &'ll Value { let dl = bx.cx.data_layout(); + let ptr_align_abi = dl.data_layout().pointer_align().abi; let overflow_arg_area_ptr = bx.inbounds_ptradd(va_list_addr, bx.const_usize(8)); - let overflow_arg_area_v = bx.load(bx.type_ptr(), overflow_arg_area_ptr, dl.pointer_align.abi); + let overflow_arg_area_v = bx.load(bx.type_ptr(), overflow_arg_area_ptr, ptr_align_abi); // AMD64-ABI 3.5.7p5: Step 7. Align l->overflow_arg_area upwards to a 16 // byte boundary if alignment needed by type exceeds 8 byte boundary. // It isn't stated explicitly in the standard, but in practice we use @@ -771,7 +771,7 @@ fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>( let size_in_bytes = layout.layout.size().bytes(); let offset = bx.const_i32(size_in_bytes.next_multiple_of(8) as i32); let overflow_arg_area = bx.inbounds_ptradd(overflow_arg_area_v, offset); - bx.store(overflow_arg_area, overflow_arg_area_ptr, dl.pointer_align.abi); + bx.store(overflow_arg_area, overflow_arg_area_ptr, ptr_align_abi); mem_addr } @@ -803,6 +803,7 @@ fn emit_xtensa_va_arg<'ll, 'tcx>( let from_stack = bx.append_sibling_block("va_arg.from_stack"); let from_regsave = bx.append_sibling_block("va_arg.from_regsave"); let end = bx.append_sibling_block("va_arg.end"); + let ptr_align_abi = bx.tcx().data_layout.pointer_align().abi; // (*va).va_ndx let va_reg_offset = 4; @@ -825,12 +826,11 @@ fn emit_xtensa_va_arg<'ll, 'tcx>( bx.switch_to_block(from_regsave); // update va_ndx - bx.store(offset_next, offset_ptr, bx.tcx().data_layout.pointer_align.abi); + bx.store(offset_next, offset_ptr, ptr_align_abi); // (*va).va_reg let regsave_area_ptr = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(va_reg_offset)); - let regsave_area = - bx.load(bx.type_ptr(), regsave_area_ptr, bx.tcx().data_layout.pointer_align.abi); + let regsave_area = bx.load(bx.type_ptr(), regsave_area_ptr, ptr_align_abi); let regsave_value_ptr = bx.inbounds_ptradd(regsave_area, offset); bx.br(end); @@ -849,11 +849,11 @@ fn emit_xtensa_va_arg<'ll, 'tcx>( // va_ndx = offset_next_corrected; let offset_next_corrected = bx.add(offset_next, bx.const_i32(slot_size)); // update va_ndx - bx.store(offset_next_corrected, offset_ptr, bx.tcx().data_layout.pointer_align.abi); + bx.store(offset_next_corrected, offset_ptr, ptr_align_abi); // let stack_value_ptr = unsafe { (*va).va_stk.byte_add(offset_corrected) }; let stack_area_ptr = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(0)); - let stack_area = bx.load(bx.type_ptr(), stack_area_ptr, bx.tcx().data_layout.pointer_align.abi); + let stack_area = bx.load(bx.type_ptr(), stack_area_ptr, ptr_align_abi); let stack_value_ptr = bx.inbounds_ptradd(stack_area, offset_corrected); bx.br(end); diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 8330e4f7af0..d2a64ec2993 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1208,7 +1208,7 @@ fn start_executing_work( split_debuginfo: tcx.sess.split_debuginfo(), split_dwarf_kind: tcx.sess.opts.unstable_opts.split_dwarf_kind, parallel: backend.supports_parallel() && !sess.opts.unstable_opts.no_parallel_backend, - pointer_size: tcx.data_layout.pointer_size, + pointer_size: tcx.data_layout.pointer_size(), invocation_temp: sess.invocation_temp.clone(), }; diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 102d4ea2fa6..18581f854b6 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -200,7 +200,7 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let vptr_entry_idx = cx.tcx().supertrait_vtable_slot((source, target)); if let Some(entry_idx) = vptr_entry_idx { - let ptr_size = bx.data_layout().pointer_size; + let ptr_size = bx.data_layout().pointer_size(); let vtable_byte_offset = u64::try_from(entry_idx).unwrap() * ptr_size.bytes(); load_vtable(bx, old_info, bx.type_ptr(), vtable_byte_offset, source, true) } else { @@ -577,8 +577,8 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(bx: &mut Bx) -> (Bx::Va // Params for UEFI let param_handle = bx.get_param(0); let param_system_table = bx.get_param(1); - let ptr_size = bx.tcx().data_layout.pointer_size; - let ptr_align = bx.tcx().data_layout.pointer_align.abi; + let ptr_size = bx.tcx().data_layout.pointer_size(); + let ptr_align = bx.tcx().data_layout.pointer_align().abi; let arg_argc = bx.const_int(bx.cx().type_isize(), 2); let arg_argv = bx.alloca(2 * ptr_size, ptr_align); bx.store(param_handle, arg_argv, ptr_align); diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index 3a11ce6befb..2aa5c3c27ea 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -27,7 +27,7 @@ impl<'a, 'tcx> VirtualIndex { debug!("get_fn({llvtable:?}, {ty:?}, {self:?})"); let llty = bx.fn_ptr_backend_type(fn_abi); - let ptr_size = bx.data_layout().pointer_size; + let ptr_size = bx.data_layout().pointer_size(); let vtable_byte_offset = self.0 * ptr_size.bytes(); load_vtable(bx, llvtable, llty, vtable_byte_offset, ty, nonnull) @@ -63,7 +63,7 @@ impl<'a, 'tcx> VirtualIndex { debug!("get_int({:?}, {:?})", llvtable, self); let llty = bx.type_isize(); - let ptr_size = bx.data_layout().pointer_size; + let ptr_size = bx.data_layout().pointer_size(); let vtable_byte_offset = self.0 * ptr_size.bytes(); load_vtable(bx, llvtable, llty, vtable_byte_offset, ty, false) @@ -115,7 +115,7 @@ pub(crate) fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( let vtable_alloc_id = tcx.vtable_allocation((ty, trait_ref)); let vtable_allocation = tcx.global_alloc(vtable_alloc_id).unwrap_memory(); let vtable_const = cx.const_data_from_alloc(vtable_allocation); - let align = cx.data_layout().pointer_align.abi; + let align = cx.data_layout().pointer_align().abi; let vtable = cx.static_addr_of(vtable_const, align, Some("vtable")); cx.apply_vcall_visibility_metadata(ty, trait_ref, vtable); @@ -133,7 +133,7 @@ pub(crate) fn load_vtable<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ty: Ty<'tcx>, nonnull: bool, ) -> Bx::Value { - let ptr_align = bx.data_layout().pointer_align.abi; + let ptr_align = bx.data_layout().pointer_align().abi; if bx.cx().sess().opts.unstable_opts.virtual_function_elimination && bx.cx().sess().lto() == Lto::Fat diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index 9da4b8cc8fd..beaf8950978 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -326,7 +326,7 @@ fn prefix_and_suffix<'tcx>( fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String { let mut signature = String::with_capacity(64); - let ptr_type = match tcx.data_layout.pointer_size.bits() { + let ptr_type = match tcx.data_layout.pointer_size().bits() { 32 => "i32", 64 => "i64", other => bug!("wasm pointer size cannot be {other} bits"), diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index a8f9cbbe19b..bb9a8b4e49a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -1189,7 +1189,7 @@ fn assume_scalar_range<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let range = scalar.valid_range(bx.cx()); bx.assume_integer_range(imm, backend_ty, range); } - abi::Primitive::Pointer(abi::AddressSpace::DATA) + abi::Primitive::Pointer(abi::AddressSpace::ZERO) if !scalar.valid_range(bx.cx()).contains(0) => { bx.assume_nonnull(imm); diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index ff822b52a8d..541eede59db 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -1233,7 +1233,7 @@ impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> /// `offset` is relative to this allocation reference, not the base of the allocation. pub fn write_ptr_sized(&mut self, offset: Size, val: Scalar) -> InterpResult<'tcx> { - self.write_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size), val) + self.write_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size()), val) } /// Mark the given sub-range (relative to this allocation reference) as uninitialized. @@ -1285,7 +1285,7 @@ impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRef<'a, 'tcx, Pr /// `offset` is relative to this allocation reference, not the base of the allocation. pub fn read_pointer(&self, offset: Size) -> InterpResult<'tcx, Scalar> { self.read_scalar( - alloc_range(offset, self.tcx.data_layout().pointer_size), + alloc_range(offset, self.tcx.data_layout().pointer_size()), /*read_provenance*/ true, ) } diff --git a/compiler/rustc_errors/messages.ftl b/compiler/rustc_errors/messages.ftl index d68dba0be5e..ad2e206260d 100644 --- a/compiler/rustc_errors/messages.ftl +++ b/compiler/rustc_errors/messages.ftl @@ -41,5 +41,8 @@ errors_target_invalid_bits = errors_target_invalid_bits_size = {$err} +errors_target_invalid_datalayout_pointer_spec = + unknown pointer specification `{$err}` in datalayout string + errors_target_missing_alignment = missing alignment for `{$cause}` in "data-layout" diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 8b59ba9984c..eeb9ac28808 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -374,6 +374,10 @@ impl Diagnostic<'_, G> for TargetDataLayoutErrors<'_> { TargetDataLayoutErrors::InvalidBitsSize { err } => { Diag::new(dcx, level, fluent::errors_target_invalid_bits_size).with_arg("err", err) } + TargetDataLayoutErrors::UnknownPointerSpecification { err } => { + Diag::new(dcx, level, fluent::errors_target_invalid_datalayout_pointer_spec) + .with_arg("err", err) + } } } } diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 16edc240544..fb941977528 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -142,7 +142,7 @@ impl<'tcx> ConstValue<'tcx> { // The reference itself is stored behind an indirection. // Load the reference, and then load the actual slice contents. let a = tcx.global_alloc(alloc_id).unwrap_memory().inner(); - let ptr_size = tcx.data_layout.pointer_size; + let ptr_size = tcx.data_layout.pointer_size(); if a.size() < offset + 2 * ptr_size { // (partially) dangling reference return None; diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index d2cadc96b63..f039849d1bb 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -519,7 +519,7 @@ impl Allocation { let mut bytes = alloc_bytes(&*self.bytes, self.align)?; // Adjust provenance of pointers stored in this allocation. let mut new_provenance = Vec::with_capacity(self.provenance.ptrs().len()); - let ptr_size = cx.data_layout().pointer_size.bytes_usize(); + let ptr_size = cx.data_layout().pointer_size().bytes_usize(); let endian = cx.data_layout().endian; for &(offset, alloc_id) in self.provenance.ptrs().iter() { let idx = offset.bytes_usize(); @@ -709,7 +709,7 @@ impl Allocation let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap(); if read_provenance { - assert_eq!(range.size, cx.data_layout().pointer_size); + assert_eq!(range.size, cx.data_layout().pointer_size()); // When reading data with provenance, the easy case is finding provenance exactly where we // are reading, then we can put data and provenance back together and return that. @@ -782,7 +782,7 @@ impl Allocation // See if we have to also store some provenance. if let Some(provenance) = provenance { - assert_eq!(range.size, cx.data_layout().pointer_size); + assert_eq!(range.size, cx.data_layout().pointer_size()); self.provenance.insert_ptr(range.start, provenance, cx); } diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs index 63608947eb3..9c6e1664386 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs @@ -71,7 +71,7 @@ impl ProvenanceMap { // We have to go back `pointer_size - 1` bytes, as that one would still overlap with // the beginning of this range. let adjusted_start = Size::from_bytes( - range.start.bytes().saturating_sub(cx.data_layout().pointer_size.bytes() - 1), + range.start.bytes().saturating_sub(cx.data_layout().pointer_size().bytes() - 1), ); adjusted_start..range.end() } @@ -142,7 +142,7 @@ impl ProvenanceMap { } pub fn insert_ptr(&mut self, offset: Size, prov: Prov, cx: &impl HasDataLayout) { - debug_assert!(self.range_empty(alloc_range(offset, cx.data_layout().pointer_size), cx)); + debug_assert!(self.range_empty(alloc_range(offset, cx.data_layout().pointer_size()), cx)); self.ptrs.insert(offset, prov); } @@ -160,6 +160,8 @@ impl ProvenanceMap { debug_assert!(self.bytes.is_none()); } + let pointer_size = cx.data_layout().pointer_size(); + // For the ptr-sized part, find the first (inclusive) and last (exclusive) byte of // provenance that overlaps with the given range. let (first, last) = { @@ -172,10 +174,7 @@ impl ProvenanceMap { // This redoes some of the work of `range_get_ptrs_is_empty`, but this path is much // colder than the early return above, so it's worth it. let provenance = self.range_ptrs_get(range, cx); - ( - provenance.first().unwrap().0, - provenance.last().unwrap().0 + cx.data_layout().pointer_size, - ) + (provenance.first().unwrap().0, provenance.last().unwrap().0 + pointer_size) }; // We need to handle clearing the provenance from parts of a pointer. @@ -192,7 +191,7 @@ impl ProvenanceMap { } } if last > end { - let begin_of_last = last - cx.data_layout().pointer_size; + let begin_of_last = last - pointer_size; if !Prov::OFFSET_IS_ADDR { // We can't split up the provenance into less than a pointer. return Err(AllocError::OverwritePartialPointer(begin_of_last)); @@ -255,7 +254,7 @@ impl ProvenanceMap { // shift offsets from source allocation to destination allocation (offset - src.start) + dest_offset // `Size` operations }; - let ptr_size = cx.data_layout().pointer_size; + let ptr_size = cx.data_layout().pointer_size(); // # Pointer-sized provenances // Get the provenances that are entirely within this range. diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index da9e5bdbadd..0b2645013ba 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -297,7 +297,7 @@ impl<'tcx> GlobalAlloc<'tcx> { match self { GlobalAlloc::Function { .. } => cx.data_layout().instruction_address_space, GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => { - AddressSpace::DATA + AddressSpace::ZERO } } } @@ -380,7 +380,7 @@ impl<'tcx> GlobalAlloc<'tcx> { GlobalAlloc::Function { .. } => (Size::ZERO, Align::ONE), GlobalAlloc::VTable(..) => { // No data to be accessed here. But vtables are pointer-aligned. - return (Size::ZERO, tcx.data_layout.pointer_align.abi); + return (Size::ZERO, tcx.data_layout.pointer_align().abi); } } } diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index 0ff14f15c13..e25ff7651f6 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -16,7 +16,7 @@ pub trait PointerArithmetic: HasDataLayout { #[inline(always)] fn pointer_size(&self) -> Size { - self.data_layout().pointer_size + self.data_layout().pointer_size() } #[inline(always)] diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 8092f634dc8..90df29bb7e3 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -167,7 +167,7 @@ impl Scalar { #[inline] pub fn from_target_usize(i: u64, cx: &impl HasDataLayout) -> Self { - Self::from_uint(i, cx.data_layout().pointer_size) + Self::from_uint(i, cx.data_layout().pointer_offset()) } #[inline] @@ -205,7 +205,7 @@ impl Scalar { #[inline] pub fn from_target_isize(i: i64, cx: &impl HasDataLayout) -> Self { - Self::from_int(i, cx.data_layout().pointer_size) + Self::from_int(i, cx.data_layout().pointer_offset()) } #[inline] @@ -393,7 +393,7 @@ impl<'tcx, Prov: Provenance> Scalar { /// Converts the scalar to produce a machine-pointer-sized unsigned integer. /// Fails if the scalar is a pointer. pub fn to_target_usize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> { - let b = self.to_uint(cx.data_layout().pointer_size)?; + let b = self.to_uint(cx.data_layout().pointer_size())?; interp_ok(u64::try_from(b).unwrap()) } @@ -433,7 +433,7 @@ impl<'tcx, Prov: Provenance> Scalar { /// Converts the scalar to produce a machine-pointer-sized signed integer. /// Fails if the scalar is a pointer. pub fn to_target_isize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, i64> { - let b = self.to_int(cx.data_layout().pointer_size)?; + let b = self.to_int(cx.data_layout().pointer_size())?; interp_ok(i64::try_from(b).unwrap()) } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 6b262a27500..e9f3fb6ac8d 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1753,7 +1753,7 @@ pub fn write_allocation_bytes<'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>( let mut i = Size::ZERO; let mut line_start = Size::ZERO; - let ptr_size = tcx.data_layout.pointer_size; + let ptr_size = tcx.data_layout.pointer_size(); let mut ascii = String::new(); diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index b087ae25486..6ee76b94507 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -252,7 +252,7 @@ impl ScalarInt { #[inline] pub fn try_from_target_usize(i: impl Into, tcx: TyCtxt<'_>) -> Option { - Self::try_from_uint(i, tcx.data_layout.pointer_size) + Self::try_from_uint(i, tcx.data_layout.pointer_size()) } /// Try to convert this ScalarInt to the raw underlying bits. @@ -328,7 +328,7 @@ impl ScalarInt { #[inline] pub fn to_target_usize(&self, tcx: TyCtxt<'_>) -> u64 { - self.to_uint(tcx.data_layout.pointer_size).try_into().unwrap() + self.to_uint(tcx.data_layout.pointer_size()).try_into().unwrap() } #[inline] @@ -402,7 +402,7 @@ impl ScalarInt { #[inline] pub fn to_target_isize(&self, tcx: TyCtxt<'_>) -> i64 { - self.to_int(tcx.data_layout.pointer_size).try_into().unwrap() + self.to_int(tcx.data_layout.pointer_size()).try_into().unwrap() } #[inline] diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 09379d9d805..809717513c7 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1067,7 +1067,7 @@ where if let Some(variant) = data_variant { // FIXME(erikdesjardins): handle non-default addrspace ptr sizes // (requires passing in the expected address space from the caller) - let ptr_end = offset + Primitive::Pointer(AddressSpace::DATA).size(cx); + let ptr_end = offset + Primitive::Pointer(AddressSpace::ZERO).size(cx); for i in 0..variant.fields.count() { let field_start = variant.fields.offset(i); if field_start <= offset { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index b4c4f48a0a6..19f2258fe99 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1848,7 +1848,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } // Pointer types ty::Ref(..) | ty::RawPtr(_, _) | ty::FnPtr(..) => { - let data = int.to_bits(self.tcx().data_layout.pointer_size); + let data = int.to_bits(self.tcx().data_layout.pointer_size()); self.typed_value( |this| { write!(this, "0x{data:x}")?; diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index 74b6a840a2e..6fc19c82342 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -106,8 +106,8 @@ pub(super) fn vtable_allocation_provider<'tcx>( let size = layout.size.bytes(); let align = layout.align.abi.bytes(); - let ptr_size = tcx.data_layout.pointer_size; - let ptr_align = tcx.data_layout.pointer_align.abi; + let ptr_size = tcx.data_layout.pointer_size(); + let ptr_align = tcx.data_layout.pointer_align().abi; let vtable_size = ptr_size * u64::try_from(vtable_entries.len()).unwrap(); let mut vtable = Allocation::new(vtable_size, ptr_align, AllocInit::Uninit, ()); diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index 8e218a380e9..52e6f2d3e1a 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -20,7 +20,7 @@ pub(crate) fn lit_to_const<'tcx>( let trunc = |n, width: ty::UintTy| { let width = width - .normalize(tcx.data_layout.pointer_size.bits().try_into().unwrap()) + .normalize(tcx.data_layout.pointer_size().bits().try_into().unwrap()) .bit_width() .unwrap(); let width = Size::from_bits(width); diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index cbfe9e0da6a..62891eb4f26 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -278,7 +278,7 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg { }; insert_atomic(sym::integer(i), align); if sess.target.pointer_width as u64 == i { - insert_atomic(sym::ptr, layout.pointer_align.abi); + insert_atomic(sym::ptr, layout.pointer_align().abi); } } } diff --git a/compiler/rustc_smir/src/rustc_smir/alloc.rs b/compiler/rustc_smir/src/rustc_smir/alloc.rs index ecaf3571896..acd805e3574 100644 --- a/compiler/rustc_smir/src/rustc_smir/alloc.rs +++ b/compiler/rustc_smir/src/rustc_smir/alloc.rs @@ -47,15 +47,12 @@ pub fn try_new_slice<'tcx, B: Bridge>( let scalar_ptr = Scalar::from_pointer(ptr, &cx.tcx); let scalar_meta: Scalar = Scalar::from_target_usize(meta, &cx.tcx); let mut allocation = Allocation::new(layout.size, layout.align.abi, AllocInit::Uninit, ()); + let ptr_size = cx.tcx.data_layout.pointer_size(); allocation - .write_scalar(&cx.tcx, alloc_range(Size::ZERO, cx.tcx.data_layout.pointer_size), scalar_ptr) + .write_scalar(&cx.tcx, alloc_range(Size::ZERO, ptr_size), scalar_ptr) .map_err(|e| B::Error::from_internal(e))?; allocation - .write_scalar( - &cx.tcx, - alloc_range(cx.tcx.data_layout.pointer_size, scalar_meta.size()), - scalar_meta, - ) + .write_scalar(&cx.tcx, alloc_range(ptr_size, scalar_meta.size()), scalar_meta) .map_err(|e| B::Error::from_internal(e))?; Ok(allocation) diff --git a/compiler/rustc_smir/src/rustc_smir/context/impls.rs b/compiler/rustc_smir/src/rustc_smir/context/impls.rs index 89ae47143ef..56021d93714 100644 --- a/compiler/rustc_smir/src/rustc_smir/context/impls.rs +++ b/compiler/rustc_smir/src/rustc_smir/context/impls.rs @@ -112,7 +112,7 @@ impl<'tcx, B: Bridge> SmirCtxt<'tcx, B> { } pub fn target_pointer_size(&self) -> usize { - self.tcx.data_layout.pointer_size.bits().try_into().unwrap() + self.tcx.data_layout.pointer_size().bits().try_into().unwrap() } pub fn entry_fn(&self) -> Option { diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs index c779720f97b..27b41cc09ed 100644 --- a/compiler/rustc_target/src/callconv/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs @@ -334,7 +334,7 @@ where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout + HasTargetSpec, { - let xlen = cx.data_layout().pointer_size.bits(); + let xlen = cx.data_layout().pointer_size().bits(); let flen = match &cx.target_spec().llvm_abiname[..] { "ilp32f" | "lp64f" => 32, "ilp32d" | "lp64d" => 64, @@ -369,7 +369,7 @@ where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout + HasTargetSpec, { - let grlen = cx.data_layout().pointer_size.bits(); + let grlen = cx.data_layout().pointer_size().bits(); for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { diff --git a/compiler/rustc_target/src/callconv/mips.rs b/compiler/rustc_target/src/callconv/mips.rs index 6162267a0d0..48a01da865b 100644 --- a/compiler/rustc_target/src/callconv/mips.rs +++ b/compiler/rustc_target/src/callconv/mips.rs @@ -10,7 +10,7 @@ where ret.extend_integer_width_to(32); } else { ret.make_indirect(); - *offset += cx.data_layout().pointer_size; + *offset += cx.data_layout().pointer_size(); } } diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 71cc2a45563..ab3271220eb 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -733,7 +733,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { } if arg_idx.is_none() - && arg.layout.size > Primitive::Pointer(AddressSpace::DATA).size(cx) * 2 + && arg.layout.size > Primitive::Pointer(AddressSpace::ZERO).size(cx) * 2 && !matches!(arg.layout.backend_repr, BackendRepr::SimdVector { .. }) { // Return values larger than 2 registers using a return area @@ -792,7 +792,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { let size = arg.layout.size; if arg.layout.is_sized() - && size <= Primitive::Pointer(AddressSpace::DATA).size(cx) + && size <= Primitive::Pointer(AddressSpace::ZERO).size(cx) { // We want to pass small aggregates as immediates, but using // an LLVM aggregate type for this leads to bad optimizations, diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs index 6a2038f9381..a06f54d60e7 100644 --- a/compiler/rustc_target/src/callconv/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs @@ -418,7 +418,7 @@ where "ilp32d" | "lp64d" => 64, _ => 0, }; - let xlen = cx.data_layout().pointer_size.bits(); + let xlen = cx.data_layout().pointer_size().bits(); let mut avail_gprs = 8; let mut avail_fprs = 8; @@ -448,7 +448,7 @@ where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout + HasTargetSpec, { - let xlen = cx.data_layout().pointer_size.bits(); + let xlen = cx.data_layout().pointer_size().bits(); for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { diff --git a/compiler/rustc_target/src/callconv/sparc.rs b/compiler/rustc_target/src/callconv/sparc.rs index 6162267a0d0..48a01da865b 100644 --- a/compiler/rustc_target/src/callconv/sparc.rs +++ b/compiler/rustc_target/src/callconv/sparc.rs @@ -10,7 +10,7 @@ where ret.extend_integer_width_to(32); } else { ret.make_indirect(); - *offset += cx.data_layout().pointer_size; + *offset += cx.data_layout().pointer_size(); } } diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index 8328f818f9b..943ca808c27 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -219,7 +219,7 @@ where // SSE ABI. We prefer this over integer registers as float scalars need to be in SSE // registers for float operations, so that's the best place to pass them around. fn_abi.ret.cast_to(Reg { kind: RegKind::Vector, size: fn_abi.ret.layout.size }); - } else if fn_abi.ret.layout.size <= Primitive::Pointer(AddressSpace::DATA).size(cx) { + } else if fn_abi.ret.layout.size <= Primitive::Pointer(AddressSpace::ZERO).size(cx) { // Same size or smaller than pointer, return in an integer register. fn_abi.ret.cast_to(Reg { kind: RegKind::Integer, size: fn_abi.ret.layout.size }); } else { diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 7a49f004072..5346b206a17 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2198,7 +2198,10 @@ pub struct TargetMetadata { impl Target { pub fn parse_data_layout(&self) -> Result> { - let mut dl = TargetDataLayout::parse_from_llvm_datalayout_string(&self.data_layout)?; + let mut dl = TargetDataLayout::parse_from_llvm_datalayout_string( + &self.data_layout, + self.options.default_address_space, + )?; // Perform consistency checks against the Target information. if dl.endian != self.endian { @@ -2209,9 +2212,10 @@ impl Target { } let target_pointer_width: u64 = self.pointer_width.into(); - if dl.pointer_size.bits() != target_pointer_width { + let dl_pointer_size: u64 = dl.pointer_size().bits(); + if dl_pointer_size != target_pointer_width { return Err(TargetDataLayoutErrors::InconsistentTargetPointerWidth { - pointer_size: dl.pointer_size.bits(), + pointer_size: dl_pointer_size, target: self.pointer_width, }); } @@ -2650,6 +2654,11 @@ pub struct TargetOptions { /// Whether the target supports XRay instrumentation. pub supports_xray: bool, + /// The default address space for this target. When using LLVM as a backend, most targets simply + /// use LLVM's default address space (0). Some other targets, such as CHERI targets, use a + /// custom default address space (in this specific case, `200`). + pub default_address_space: rustc_abi::AddressSpace, + /// Whether the targets supports -Z small-data-threshold small_data_threshold_support: SmallDataThresholdSupport, } @@ -2878,6 +2887,7 @@ impl Default for TargetOptions { entry_name: "main".into(), entry_abi: CanonAbi::C, supports_xray: false, + default_address_space: rustc_abi::AddressSpace::ZERO, small_data_threshold_support: SmallDataThresholdSupport::DefaultForArch, } } diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 150f5d118e0..3f83b4d50aa 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -296,7 +296,7 @@ pub(crate) mod rustc { } let target = cx.data_layout(); - let pointer_size = target.pointer_size; + let pointer_size = target.pointer_size(); match ty.kind() { ty::Bool => Ok(Self::bool()), diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index a225b712d4b..163e2b30883 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -379,7 +379,7 @@ fn layout_of_uncached<'tcx>( // Potentially-wide pointers. ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => { - let mut data_ptr = scalar_unit(Pointer(AddressSpace::DATA)); + let mut data_ptr = scalar_unit(Pointer(AddressSpace::ZERO)); if !ty.is_raw_ptr() { data_ptr.valid_range_mut().start = 1; } @@ -435,7 +435,7 @@ fn layout_of_uncached<'tcx>( } ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)), ty::Dynamic(..) => { - let mut vtable = scalar_unit(Pointer(AddressSpace::DATA)); + let mut vtable = scalar_unit(Pointer(AddressSpace::ZERO)); vtable.valid_range_mut().start = 1; vtable } diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs index 105477093b5..55e27a05f3c 100644 --- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs @@ -17,7 +17,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, ty::FnDef(..) | ty::FnPtr(..) => { let mut applicability = Applicability::MaybeIncorrect; - if to_nbits >= cx.tcx.data_layout.pointer_size.bits() && !cast_to.is_usize() { + if to_nbits >= cx.tcx.data_layout.pointer_size().bits() && !cast_to.is_usize() { let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability); span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs index 700b7d0d426..4da79205e20 100644 --- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs +++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs @@ -17,7 +17,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, let mut applicability = Applicability::MaybeIncorrect; let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability); - if to_nbits < cx.tcx.data_layout.pointer_size.bits() { + if to_nbits < cx.tcx.data_layout.pointer_size().bits() { span_lint_and_sugg( cx, FN_TO_NUMERIC_CAST_WITH_TRUNCATION, diff --git a/src/tools/clippy/clippy_lints/src/casts/utils.rs b/src/tools/clippy/clippy_lints/src/casts/utils.rs index 318a1646477..d846d78b9ee 100644 --- a/src/tools/clippy/clippy_lints/src/casts/utils.rs +++ b/src/tools/clippy/clippy_lints/src/casts/utils.rs @@ -5,7 +5,7 @@ use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TyCtxt, UintTy, VariantDiscr}; /// integral type. pub(super) fn int_ty_to_nbits(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option { match ty.kind() { - ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(tcx.data_layout.pointer_size.bits()), + ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(tcx.data_layout.pointer_size().bits()), ty::Int(i) => i.bit_width(), ty::Uint(i) => i.bit_width(), _ => None, diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs index 098571a5351..c828fc57f76 100644 --- a/src/tools/clippy/clippy_lints/src/enum_clike.rs +++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs @@ -35,7 +35,7 @@ declare_lint_pass!(UnportableVariant => [ENUM_CLIKE_UNPORTABLE_VARIANT]); impl<'tcx> LateLintPass<'tcx> for UnportableVariant { #[expect(clippy::cast_possible_wrap)] fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if cx.tcx.data_layout.pointer_size.bits() != 64 { + if cx.tcx.data_layout.pointer_size().bits() != 64 { return; } if let ItemKind::Enum(_, _, def) = &item.kind { diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 09299c869dc..ba0376e4d40 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -918,7 +918,7 @@ fn mir_is_empty<'tcx>(tcx: TyCtxt<'tcx>, result: mir::Const<'tcx>) -> Option { - let mut data_ptr = scalar_unit(dl, Primitive::Pointer(AddressSpace::DATA)); + let mut data_ptr = scalar_unit(dl, Primitive::Pointer(AddressSpace::ZERO)); if matches!(ty.kind(Interner), TyKind::Ref(..)) { data_ptr.valid_range_mut().start = 1; } @@ -285,7 +285,7 @@ pub fn layout_of_ty_query( scalar_unit(dl, Primitive::Int(dl.ptr_sized_integer(), false)) } TyKind::Dyn(..) => { - let mut vtable = scalar_unit(dl, Primitive::Pointer(AddressSpace::DATA)); + let mut vtable = scalar_unit(dl, Primitive::Pointer(AddressSpace::ZERO)); vtable.valid_range_mut().start = 1; vtable } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs index e1e1c44996c..88c33ecccad 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs @@ -2,7 +2,7 @@ use base_db::Crate; use hir_def::layout::TargetDataLayout; -use rustc_abi::{AlignFromBytesError, TargetDataLayoutErrors}; +use rustc_abi::{AlignFromBytesError, TargetDataLayoutErrors, AddressSpace}; use triomphe::Arc; use crate::db::HirDatabase; @@ -12,7 +12,7 @@ pub fn target_data_layout_query( krate: Crate, ) -> Result, Arc> { match &krate.workspace_data(db).data_layout { - Ok(it) => match TargetDataLayout::parse_from_llvm_datalayout_string(it) { + Ok(it) => match TargetDataLayout::parse_from_llvm_datalayout_string(it, AddressSpace::ZERO) { Ok(it) => Ok(Arc::new(it)), Err(e) => { Err(match e { @@ -39,6 +39,7 @@ pub fn target_data_layout_query( target, } => format!(r#"inconsistent target specification: "data-layout" claims pointers are {pointer_size}-bit, while "target-pointer-width" is `{target}`"#), TargetDataLayoutErrors::InvalidBitsSize { err } => err, + TargetDataLayoutErrors::UnknownPointerSpecification { err } => format!(r#"use of unknown pointer specifer in "data-layout": {err}"#), }.into()) } }, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index 1ec55a82092..55fada14363 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -630,7 +630,7 @@ impl Evaluator<'_> { Ok(target_data_layout) => target_data_layout, Err(e) => return Err(MirEvalError::TargetDataLayoutNotAvailable(e)), }; - let cached_ptr_size = target_data_layout.pointer_size.bytes_usize(); + let cached_ptr_size = target_data_layout.pointer_size().bytes_usize(); Ok(Evaluator { target_data_layout, stack: vec![0], -- cgit 1.4.1-3-g733a5 From 1eff043e7aab5f5634c1e29f5cf161a6437bcfa3 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Mon, 7 Jul 2025 09:22:28 +0200 Subject: rustc_codegen_llvm: Remove reference to non-existing `no_landing_pads()` Removing this reference was forgotten in eb4725fc54056. Grepping for no_landing_pads returns no hits after this. --- compiler/rustc_codegen_llvm/src/attributes.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index adb53e0b66c..5a065f31c30 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -377,12 +377,11 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( // that no exceptions passes by it. This is normally the case for the // ELF x86-64 abi, but it can be disabled for some compilation units. // - // Typically when we're compiling with `-C panic=abort` (which implies this - // `no_landing_pads` check) we don't need `uwtable` because we can't - // generate any exceptions! On Windows, however, exceptions include other - // events such as illegal instructions, segfaults, etc. This means that on - // Windows we end up still needing the `uwtable` attribute even if the `-C - // panic=abort` flag is passed. + // Typically when we're compiling with `-C panic=abort` we don't need + // `uwtable` because we can't generate any exceptions! On Windows, however, + // exceptions include other events such as illegal instructions, segfaults, + // etc. This means that on Windows we end up still needing the `uwtable` + // attribute even if the `-C panic=abort` flag is passed. // // You can also find more info on why Windows always requires uwtables here: // https://bugzilla.mozilla.org/show_bug.cgi?id=1302078 -- cgit 1.4.1-3-g733a5 From aa364cac52f6f4b79dfd3eeb7189bbd259184d57 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Mon, 7 Jul 2025 09:04:16 +0200 Subject: compiler: Deduplicate `must_emit_unwind_tables()` comments There is one comment at a call site and one comment in the function definition that are mostly saying the same thing. Fold the call site comment into the function definition comment to reduce duplication. There are actually some inaccuracies in the comments but let's deduplicate before we address the inaccuracies. --- compiler/rustc_codegen_llvm/src/attributes.rs | 15 --------------- compiler/rustc_session/src/session.rs | 9 ++++++++- 2 files changed, 8 insertions(+), 16 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 5a065f31c30..1ea5a062254 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -370,21 +370,6 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( }; to_add.extend(inline_attr(cx, inline)); - // The `uwtable` attribute according to LLVM is: - // - // This attribute indicates that the ABI being targeted requires that an - // unwind table entry be produced for this function even if we can show - // that no exceptions passes by it. This is normally the case for the - // ELF x86-64 abi, but it can be disabled for some compilation units. - // - // Typically when we're compiling with `-C panic=abort` we don't need - // `uwtable` because we can't generate any exceptions! On Windows, however, - // exceptions include other events such as illegal instructions, segfaults, - // etc. This means that on Windows we end up still needing the `uwtable` - // attribute even if the `-C panic=abort` flag is passed. - // - // You can also find more info on why Windows always requires uwtables here: - // https://bugzilla.mozilla.org/show_bug.cgi?id=1302078 if cx.sess().must_emit_unwind_tables() { to_add.push(uwtable_attr(cx.llcx, cx.sess().opts.unstable_opts.use_sync_unwind)); } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 8386fe8dab0..85bd8340c3c 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -776,8 +776,15 @@ impl Session { pub fn must_emit_unwind_tables(&self) -> bool { // This is used to control the emission of the `uwtable` attribute on - // LLVM functions. + // LLVM functions. The `uwtable` attribute according to LLVM is: // + // This attribute indicates that the ABI being targeted requires that an + // unwind table entry be produced for this function even if we can show + // that no exceptions passes by it. This is normally the case for the + // ELF x86-64 abi, but it can be disabled for some compilation units. + // + // Typically when we're compiling with `-C panic=abort` we don't need + // `uwtable` because we can't generate any exceptions! // Unwind tables are needed when compiling with `-C panic=unwind`, but // LLVM won't omit unwind tables unless the function is also marked as // `nounwind`, so users are allowed to disable `uwtable` emission. -- cgit 1.4.1-3-g733a5 From 3b48407f93abd565b24d138cc7df56ee37855d82 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Sat, 28 Jun 2025 23:40:02 +0000 Subject: Remove unused allow attrs --- compiler/rustc_codegen_gcc/src/lib.rs | 1 - compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 1 - compiler/rustc_errors/src/lib.rs | 1 - compiler/rustc_infer/src/lib.rs | 2 -- compiler/rustc_lint/src/early/diagnostics.rs | 3 --- compiler/rustc_lint/src/lints.rs | 1 - compiler/rustc_middle/src/arena.rs | 2 -- compiler/rustc_parse/src/lib.rs | 1 - compiler/rustc_query_impl/src/lib.rs | 1 - src/librustdoc/json/conversions.rs | 2 -- 10 files changed, 15 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 1a6eec0ed0b..d8fae1ca47d 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -19,7 +19,6 @@ #![doc(rust_logo)] #![feature(rustdoc_internals)] #![feature(rustc_private)] -#![allow(broken_intra_doc_links)] #![recursion_limit = "256"] #![warn(rust_2018_idioms)] #![warn(unused_lifetimes)] diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index 7b00b2da6ba..c696b8d8ff2 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -1,4 +1,3 @@ -#![allow(non_camel_case_types)] #![expect(dead_code)] use libc::{c_char, c_uint}; diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 69ad15c6081..381d780077d 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -3,7 +3,6 @@ //! This module contains the code for creating and emitting diagnostics. // tidy-alphabetical-start -#![allow(incomplete_features)] #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::direct_use_of_rustc_type_ir)] diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 285e2912937..e562c583313 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -14,9 +14,7 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::direct_use_of_rustc_type_ir)] -#![allow(rustc::untranslatable_diagnostic)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 3b0a36186b6..653559009cc 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -1,6 +1,3 @@ -#![allow(rustc::diagnostic_outside_of_impl)] -#![allow(rustc::untranslatable_diagnostic)] - use std::borrow::Cow; use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 5e05b58146e..21148833eaf 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1,4 +1,3 @@ -#![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] use std::num::NonZero; diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index a0f45974089..f140ab4755b 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -1,5 +1,3 @@ -#![allow(rustc::usage_of_ty_tykind)] - /// This higher-order macro declares a list of types which can be allocated by `Arena`. /// /// Specifying the `decode` modifier will add decode impls for `&T` and `&[T]` where `T` is the type diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 8ea535599c9..2050c5f9608 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -1,7 +1,6 @@ //! The main parser interface. // tidy-alphabetical-start -#![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] #![feature(assert_matches)] diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index b7d8af2c995..306d4dbc4b4 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -2,7 +2,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![allow(unused_parens)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(min_specialization)] diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index f51b35097f6..abf3f3fcedd 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -2,8 +2,6 @@ //! the `clean` types but with some fields removed or stringified to simplify the output and not //! expose unstable compiler internals. -#![allow(rustc::default_hash_types)] - use rustc_abi::ExternAbi; use rustc_ast::ast; use rustc_attr_data_structures::{self as attrs, DeprecatedSince}; -- cgit 1.4.1-3-g733a5 From 49421d1fa382fba84792e5d5dd7721c1c3e0e46e Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 24 Jun 2025 16:58:46 +0200 Subject: Remove support for dynamic allocas --- compiler/rustc_codegen_gcc/src/builder.rs | 4 --- compiler/rustc_codegen_llvm/src/builder.rs | 10 ------ compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 6 ---- compiler/rustc_codegen_ssa/src/mir/mod.rs | 6 ++-- compiler/rustc_codegen_ssa/src/mir/operand.rs | 40 +----------------------- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 21 ------------- compiler/rustc_codegen_ssa/src/mir/statement.rs | 7 ++++- compiler/rustc_codegen_ssa/src/traits/builder.rs | 1 - library/core/src/mem/mod.rs | 2 +- 9 files changed, 11 insertions(+), 86 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index b1785af444a..28d1ec7d895 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -926,10 +926,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { .get_address(self.location) } - fn dynamic_alloca(&mut self, _len: RValue<'gcc>, _align: Align) -> RValue<'gcc> { - unimplemented!(); - } - fn load(&mut self, pointee_ty: Type<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { let block = self.llbb(); let function = block.get_function(); diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index d0aa7320b4b..9c3b866aa3c 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -538,16 +538,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } } - fn dynamic_alloca(&mut self, size: &'ll Value, align: Align) -> &'ll Value { - unsafe { - let alloca = - llvm::LLVMBuildArrayAlloca(self.llbuilder, self.cx().type_i8(), size, UNNAMED); - llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint); - // Cast to default addrspace if necessary - llvm::LLVMBuildPointerCast(self.llbuilder, alloca, self.cx().type_ptr(), UNNAMED) - } - } - fn load(&mut self, ty: &'ll Type, ptr: &'ll Value, align: Align) -> &'ll Value { unsafe { let load = llvm::LLVMBuildLoad2(self.llbuilder, ty, ptr, UNNAMED); diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 91ada856d59..00a6ec7dfba 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1492,12 +1492,6 @@ unsafe extern "C" { Ty: &'a Type, Name: *const c_char, ) -> &'a Value; - pub(crate) fn LLVMBuildArrayAlloca<'a>( - B: &Builder<'a>, - Ty: &'a Type, - Val: &'a Value, - Name: *const c_char, - ) -> &'a Value; pub(crate) fn LLVMBuildLoad2<'a>( B: &Builder<'a>, Ty: &'a Type, diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 10b44a1faf0..4e35b143173 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -140,8 +140,8 @@ enum LocalRef<'tcx, V> { Place(PlaceRef<'tcx, V>), /// `UnsizedPlace(p)`: `p` itself is a thin pointer (indirect place). /// `*p` is the wide pointer that references the actual unsized place. - /// Every time it is initialized, we have to reallocate the place - /// and update the wide pointer. That's the reason why it is indirect. + /// + /// Rust has no alloca and thus no ability to move the unsized place. UnsizedPlace(PlaceRef<'tcx, V>), /// The backend [`OperandValue`] has already been generated. Operand(OperandRef<'tcx, V>), @@ -498,7 +498,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( LocalRef::Place(PlaceRef::new_sized(llarg, arg.layout)) } } - // Unsized indirect qrguments + // Unsized indirect arguments PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { // As the storage for the indirect argument lives during // the whole function call, we just copy the wide pointer. diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 2896dfd5463..f6a8e1fc6a5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -16,9 +16,9 @@ use tracing::{debug, instrument}; use super::place::{PlaceRef, PlaceValue}; use super::rvalue::transmute_scalar; use super::{FunctionCx, LocalRef}; +use crate::MemFlags; use crate::common::IntPredicate; use crate::traits::*; -use crate::{MemFlags, size_of_val}; /// The representation of a Rust value. The enum variant is in fact /// uniquely determined by the value's type, but is kept as a @@ -800,44 +800,6 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue { } } } - - pub fn store_unsized>( - self, - bx: &mut Bx, - indirect_dest: PlaceRef<'tcx, V>, - ) { - debug!("OperandRef::store_unsized: operand={:?}, indirect_dest={:?}", self, indirect_dest); - // `indirect_dest` must have `*mut T` type. We extract `T` out of it. - let unsized_ty = indirect_dest - .layout - .ty - .builtin_deref(true) - .unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest)); - - let OperandValue::Ref(PlaceValue { llval: llptr, llextra: Some(llextra), .. }) = self - else { - bug!("store_unsized called with a sized value (or with an extern type)") - }; - - // Allocate an appropriate region on the stack, and copy the value into it. Since alloca - // doesn't support dynamic alignment, we allocate an extra align - 1 bytes, and align the - // pointer manually. - let (size, align) = size_of_val::size_and_align_of_dst(bx, unsized_ty, Some(llextra)); - let one = bx.const_usize(1); - let align_minus_1 = bx.sub(align, one); - let size_extra = bx.add(size, align_minus_1); - let min_align = Align::ONE; - let alloca = bx.dynamic_alloca(size_extra, min_align); - let address = bx.ptrtoint(alloca, bx.type_isize()); - let neg_address = bx.neg(address); - let offset = bx.and(neg_address, align_minus_1); - let dst = bx.inbounds_ptradd(alloca, offset); - bx.memcpy(dst, min_align, llptr, min_align, size, MemFlags::empty()); - - // Store the allocated region and the extra to the indirect place. - let indirect_operand = OperandValue::Pair(dst, llextra); - indirect_operand.store(bx, indirect_dest); - } } impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 43726e93252..4572dc19594 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -328,27 +328,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { Some(imm) } - pub(crate) fn codegen_rvalue_unsized( - &mut self, - bx: &mut Bx, - indirect_dest: PlaceRef<'tcx, Bx::Value>, - rvalue: &mir::Rvalue<'tcx>, - ) { - debug!( - "codegen_rvalue_unsized(indirect_dest.llval={:?}, rvalue={:?})", - indirect_dest.val.llval, rvalue - ); - - match *rvalue { - mir::Rvalue::Use(ref operand) => { - let cg_operand = self.codegen_operand(bx, operand); - cg_operand.val.store_unsized(bx, indirect_dest); - } - - _ => bug!("unsized assignment other than `Rvalue::Use`"), - } - } - pub(crate) fn codegen_rvalue_operand( &mut self, bx: &mut Bx, diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index cd55a838a75..f164e0f9123 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -15,7 +15,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { match self.locals[index] { LocalRef::Place(cg_dest) => self.codegen_rvalue(bx, cg_dest, rvalue), LocalRef::UnsizedPlace(cg_indirect_dest) => { - self.codegen_rvalue_unsized(bx, cg_indirect_dest, rvalue) + let ty = cg_indirect_dest.layout.ty; + span_bug!( + statement.source_info.span, + "cannot reallocate from `UnsizedPlace({ty})` \ + into `{rvalue:?}`; dynamic alloca is not supported", + ); } LocalRef::PendingOperand => { let operand = self.codegen_rvalue_operand(bx, rvalue); diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 9d367748c2a..1f266514f34 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -224,7 +224,6 @@ pub trait BuilderMethods<'a, 'tcx>: fn to_immediate_scalar(&mut self, val: Self::Value, scalar: Scalar) -> Self::Value; fn alloca(&mut self, size: Size, align: Align) -> Self::Value; - fn dynamic_alloca(&mut self, size: Self::Value, align: Align) -> Self::Value; fn load(&mut self, ty: Self::Type, ptr: Self::Value, align: Align) -> Self::Value; fn volatile_load(&mut self, ty: Self::Type, ptr: Self::Value) -> Self::Value; diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index c00585de064..1bd12d818cf 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -151,7 +151,7 @@ pub const fn forget(t: T) { /// /// While Rust does not permit unsized locals since its removal in [#111942] it is /// still possible to call functions with unsized values from a function argument -/// or in-place construction. +/// or place expression. /// /// ```rust /// #![feature(unsized_fn_params, forget_unsized)] -- cgit 1.4.1-3-g733a5 From 045557797431bfff807145341efbe8f8fb08817e Mon Sep 17 00:00:00 2001 From: Dillon Amburgey Date: Tue, 8 Jul 2025 06:17:03 -0500 Subject: fix: correct parameter names in LLVMRustBuildMinNum and LLVMRustBuildMaxNum FFI declarations --- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 91ada856d59..b9dd10ff014 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1980,12 +1980,12 @@ unsafe extern "C" { pub(crate) fn LLVMRustBuildMinNum<'a>( B: &Builder<'a>, LHS: &'a Value, - LHS: &'a Value, + RHS: &'a Value, ) -> &'a Value; pub(crate) fn LLVMRustBuildMaxNum<'a>( B: &Builder<'a>, LHS: &'a Value, - LHS: &'a Value, + RHS: &'a Value, ) -> &'a Value; // Atomic Operations -- cgit 1.4.1-3-g733a5 From b2299e20b2c2a25254fb554ccc59a8b60fdc25e0 Mon Sep 17 00:00:00 2001 From: Dillon Amburgey Date: Tue, 8 Jul 2025 06:18:18 -0500 Subject: fix: correct assertion to check for 'noinline' attribute presence before removal --- compiler/rustc_codegen_llvm/src/back/lto.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 9c62244f3c9..74418adc43c 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -680,7 +680,7 @@ pub(crate) fn run_pass_manager( if attributes::has_string_attr(function, enzyme_marker) { // Sanity check: Ensure 'noinline' is present before replacing it. assert!( - !attributes::has_attr(function, Function, llvm::AttributeKind::NoInline), + attributes::has_attr(function, Function, llvm::AttributeKind::NoInline), "Expected __enzyme function to have 'noinline' before adding 'alwaysinline'" ); -- cgit 1.4.1-3-g733a5 From 6fc5d4edda88d0dd28c45ccba1a1e217ddad11c4 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 7 Jul 2025 19:23:06 +0200 Subject: emit `.att_syntax` when global/naked asm use that option --- compiler/rustc_codegen_llvm/src/asm.rs | 22 +++++++--- tests/assembly/emit-intel-att-syntax.rs | 75 +++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 tests/assembly/emit-intel-att-syntax.rs (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 9ddadcf16aa..a643a91141e 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -384,15 +384,19 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { ) { let asm_arch = self.tcx.sess.asm_arch.unwrap(); - // Default to Intel syntax on x86 - let intel_syntax = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64) - && !options.contains(InlineAsmOptions::ATT_SYNTAX); - // Build the template string let mut template_str = String::new(); - if intel_syntax { - template_str.push_str(".intel_syntax\n"); + + // On X86 platforms there are two assembly syntaxes. Rust uses intel by default, + // but AT&T can be specified explicitly. + if matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64) { + if options.contains(InlineAsmOptions::ATT_SYNTAX) { + template_str.push_str(".att_syntax\n") + } else { + template_str.push_str(".intel_syntax\n") + } } + for piece in template { match *piece { InlineAsmTemplatePiece::String(ref s) => template_str.push_str(s), @@ -431,7 +435,11 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { } } } - if intel_syntax { + + // Just to play it safe, if intel was used, reset the assembly syntax to att. + if matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64) + && !options.contains(InlineAsmOptions::ATT_SYNTAX) + { template_str.push_str("\n.att_syntax\n"); } diff --git a/tests/assembly/emit-intel-att-syntax.rs b/tests/assembly/emit-intel-att-syntax.rs new file mode 100644 index 00000000000..7b479a0f79e --- /dev/null +++ b/tests/assembly/emit-intel-att-syntax.rs @@ -0,0 +1,75 @@ +//@ assembly-output: emit-asm +//@ revisions: att intel +//@ [att] compile-flags: -Cllvm-args=-x86-asm-syntax=att +//@ [intel] compile-flags: -Cllvm-args=-x86-asm-syntax=intel +//@ only-x86_64 + +#![crate_type = "lib"] + +// CHECK-LABEL: naked_att: +// intel-CHECK: mov rax, qword ptr [rdi] +// intel-CHECK: ret +// att-CHECK: movq (%rdi), %rax +// att-CHECK: retq + +#[unsafe(naked)] +#[unsafe(no_mangle)] +extern "sysv64" fn naked_att() { + std::arch::naked_asm!( + " + movq (%rdi), %rax + retq + ", + options(att_syntax), + ); +} + +// CHECK-LABEL: naked_intel: +// intel-CHECK: mov rax, rdi +// intel-CHECK: ret +// att-CHECK: movq (%rdi), %rax +// att-CHECK: retq + +#[unsafe(naked)] +#[unsafe(no_mangle)] +extern "sysv64" fn naked_intel() { + std::arch::naked_asm!( + " + mov rax, rdi + ret + ", + options(), + ); +} + +// CHECK-LABEL: global_att: +// intel-CHECK: mov rax, rdi +// intel-CHECK: ret +// att-CHECK: movq (%rdi), %rax +// att-CHECK: retq + +core::arch::global_asm!( + " + .globl global_att + global_att: + movq (%rdi), %rax + retq + ", + options(att_syntax), +); + +// CHECK-LABEL: global_intel: +// intel-CHECK: mov rax, rdi +// intel-CHECK: ret +// att-CHECK: movq (%rdi), %rax +// att-CHECK: retq + +core::arch::global_asm!( + " + .globl global_intel + global_intel: + mov rax, rdi + ret + ", + options(), +); -- cgit 1.4.1-3-g733a5 From 486ffda9dcd0d4ef0a09d81e6ce5f241e77526a1 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 12 Mar 2025 10:26:37 +0000 Subject: Add opaque TypeId handles for CTFE --- compiler/rustc_codegen_cranelift/src/constant.rs | 13 ++++ compiler/rustc_codegen_gcc/src/common.rs | 10 ++- compiler/rustc_codegen_llvm/src/common.rs | 18 +++-- compiler/rustc_codegen_llvm/src/consts.rs | 5 +- compiler/rustc_codegen_ssa/src/mir/operand.rs | 2 +- compiler/rustc_const_eval/messages.ftl | 2 + compiler/rustc_const_eval/src/errors.rs | 6 +- .../rustc_const_eval/src/interpret/intrinsics.rs | 79 +++++++++++++++++++- compiler/rustc_const_eval/src/interpret/memory.rs | 30 +++++++- .../rustc_const_eval/src/interpret/projection.rs | 6 +- .../rustc_const_eval/src/interpret/validity.rs | 64 +++++++++-------- compiler/rustc_hir/src/lang_items.rs | 2 + compiler/rustc_hir_analysis/src/check/intrinsic.rs | 9 ++- compiler/rustc_middle/src/mir/interpret/error.rs | 2 + compiler/rustc_middle/src/mir/interpret/mod.rs | 33 +++++++-- compiler/rustc_middle/src/mir/pretty.rs | 1 + compiler/rustc_middle/src/ty/print/pretty.rs | 1 + compiler/rustc_monomorphize/src/collector.rs | 1 + compiler/rustc_passes/src/reachable.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + compiler/stable_mir/src/mir/alloc.rs | 3 + .../stable_mir/src/unstable/convert/stable/mir.rs | 3 + library/core/Cargo.toml | 2 - library/core/src/any.rs | 84 +++++++++++++++------- library/core/src/intrinsics/mod.rs | 15 +++- library/coretests/tests/any.rs | 8 --- library/std/Cargo.toml | 2 - library/sysroot/Cargo.toml | 1 - tests/codegen/error-provide.rs | 6 +- tests/ui/const-generics/issues/issue-90318.rs | 3 +- tests/ui/const-generics/issues/issue-90318.stderr | 25 +------ tests/ui/consts/const_cmp_type_id.rs | 3 +- tests/ui/consts/const_cmp_type_id.stderr | 20 +++--- tests/ui/consts/const_transmute_type_id.rs | 11 +++ tests/ui/consts/const_transmute_type_id.stderr | 12 ++++ tests/ui/consts/const_transmute_type_id2.rs | 14 ++++ tests/ui/consts/const_transmute_type_id2.stderr | 15 ++++ tests/ui/consts/const_transmute_type_id3.rs | 16 +++++ tests/ui/consts/const_transmute_type_id3.stderr | 15 ++++ tests/ui/consts/const_transmute_type_id4.rs | 16 +++++ tests/ui/consts/const_transmute_type_id4.stderr | 15 ++++ tests/ui/consts/issue-73976-monomorphic.rs | 2 +- tests/ui/consts/issue-73976-monomorphic.stderr | 9 --- 43 files changed, 438 insertions(+), 148 deletions(-) create mode 100644 tests/ui/consts/const_transmute_type_id.rs create mode 100644 tests/ui/consts/const_transmute_type_id.stderr create mode 100644 tests/ui/consts/const_transmute_type_id2.rs create mode 100644 tests/ui/consts/const_transmute_type_id2.stderr create mode 100644 tests/ui/consts/const_transmute_type_id3.rs create mode 100644 tests/ui/consts/const_transmute_type_id3.stderr create mode 100644 tests/ui/consts/const_transmute_type_id4.rs create mode 100644 tests/ui/consts/const_transmute_type_id4.stderr delete mode 100644 tests/ui/consts/issue-73976-monomorphic.stderr (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index ed06423b260..85adf0f3716 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -175,6 +175,13 @@ pub(crate) fn codegen_const_value<'tcx>( fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); fx.bcx.ins().global_value(fx.pointer_type, local_data_id) } + GlobalAlloc::TypeId { .. } => { + return CValue::const_val( + fx, + layout, + ScalarInt::try_from_target_usize(offset.bytes(), fx.tcx).unwrap(), + ); + } GlobalAlloc::Static(def_id) => { assert!(fx.tcx.is_static(def_id)); let data_id = data_id_for_static( @@ -360,6 +367,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant GlobalAlloc::Memory(alloc) => alloc, GlobalAlloc::Function { .. } | GlobalAlloc::Static(_) + | GlobalAlloc::TypeId { .. } | GlobalAlloc::VTable(..) => { unreachable!() } @@ -471,6 +479,11 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant .principal() .map(|principal| tcx.instantiate_bound_regions_with_erased(principal)), ), + GlobalAlloc::TypeId { .. } => { + // Nothing to do, the bytes/offset of this pointer have already been written together with all other bytes, + // so we just need to drop this provenance. + continue; + } GlobalAlloc::Static(def_id) => { if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 32713eb56c6..28848ca6184 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -1,7 +1,6 @@ use gccjit::{LValue, RValue, ToRValue, Type}; -use rustc_abi as abi; -use rustc_abi::HasDataLayout; use rustc_abi::Primitive::Pointer; +use rustc_abi::{self as abi, HasDataLayout}; use rustc_codegen_ssa::traits::{ BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, StaticCodegenMethods, }; @@ -282,6 +281,13 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { let init = self.const_data_from_alloc(alloc); self.static_addr_of(init, alloc.inner().align, None) } + GlobalAlloc::TypeId { .. } => { + let val = self.const_usize(offset.bytes()); + // This is still a variable of pointer type, even though we only use the provenance + // of that pointer in CTFE and Miri. But to make LLVM's type system happy, + // we need an int-to-ptr cast here (it doesn't matter at all which provenance that picks). + return self.context.new_cast(None, val, ty); + } GlobalAlloc::Static(def_id) => { assert!(self.tcx.is_static(def_id)); self.get_static(def_id).get_address(None) diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 92f38565eef..b9b5c776d86 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -3,9 +3,8 @@ use std::borrow::Borrow; use libc::{c_char, c_uint}; -use rustc_abi as abi; -use rustc_abi::HasDataLayout; use rustc_abi::Primitive::Pointer; +use rustc_abi::{self as abi, HasDataLayout as _}; use rustc_ast::Mutability; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::traits::*; @@ -284,7 +283,8 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { self.const_bitcast(llval, llty) }; } else { - let init = const_alloc_to_llvm(self, alloc, /*static*/ false); + let init = + const_alloc_to_llvm(self, alloc.inner(), /*static*/ false); let alloc = alloc.inner(); let value = match alloc.mutability { Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None), @@ -316,15 +316,19 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { }), ))) .unwrap_memory(); - let init = const_alloc_to_llvm(self, alloc, /*static*/ false); - let value = self.static_addr_of_impl(init, alloc.inner().align, None); - value + let init = const_alloc_to_llvm(self, alloc.inner(), /*static*/ false); + self.static_addr_of_impl(init, alloc.inner().align, None) } GlobalAlloc::Static(def_id) => { assert!(self.tcx.is_static(def_id)); assert!(!self.tcx.is_thread_local_static(def_id)); self.get_static(def_id) } + GlobalAlloc::TypeId { .. } => { + // Drop the provenance, the offset contains the bytes of the hash + let llval = self.const_usize(offset.bytes()); + return unsafe { llvm::LLVMConstIntToPtr(llval, llty) }; + } }; let base_addr_space = global_alloc.address_space(self); let llval = unsafe { @@ -346,7 +350,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { } fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value { - const_alloc_to_llvm(self, alloc, /*static*/ false) + const_alloc_to_llvm(self, alloc.inner(), /*static*/ false) } fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value { diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 28f5282c6b0..21524fd2eb8 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -27,10 +27,9 @@ use crate::{base, debuginfo}; pub(crate) fn const_alloc_to_llvm<'ll>( cx: &CodegenCx<'ll, '_>, - alloc: ConstAllocation<'_>, + alloc: &Allocation, is_static: bool, ) -> &'ll Value { - let alloc = alloc.inner(); // We expect that callers of const_alloc_to_llvm will instead directly codegen a pointer or // integer for any &ZST where the ZST is a constant (i.e. not a static). We should never be // producing empty LLVM allocations as they're just adding noise to binaries and forcing less @@ -141,7 +140,7 @@ fn codegen_static_initializer<'ll, 'tcx>( def_id: DefId, ) -> Result<(&'ll Value, ConstAllocation<'tcx>), ErrorHandled> { let alloc = cx.tcx.eval_static_initializer(def_id)?; - Ok((const_alloc_to_llvm(cx, alloc, /*static*/ true), alloc)) + Ok((const_alloc_to_llvm(cx, alloc.inner(), /*static*/ true), alloc)) } fn set_global_alignment<'ll>(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align: Align) { diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 2896dfd5463..a639803ea60 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -186,7 +186,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { offset: Size, ) -> Self { let alloc_align = alloc.inner().align; - assert!(alloc_align >= layout.align.abi); + assert!(alloc_align >= layout.align.abi, "{alloc_align:?} < {:?}", layout.align.abi); let read_scalar = |start, size, s: abi::Scalar, ty| { match alloc.0.read_scalar( diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 22a1894ee72..b767ca9a3c2 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -78,6 +78,8 @@ const_eval_dealloc_kind_mismatch = const_eval_deref_function_pointer = accessing {$allocation} which contains a function +const_eval_deref_typeid_pointer = + accessing {$allocation} which contains a `TypeId` const_eval_deref_vtable_pointer = accessing {$allocation} which contains a vtable const_eval_division_by_zero = diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 9133a5fc8ef..49cd7138748 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -475,6 +475,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { WriteToReadOnly(_) => const_eval_write_to_read_only, DerefFunctionPointer(_) => const_eval_deref_function_pointer, DerefVTablePointer(_) => const_eval_deref_vtable_pointer, + DerefTypeIdPointer(_) => const_eval_deref_typeid_pointer, InvalidBool(_) => const_eval_invalid_bool, InvalidChar(_) => const_eval_invalid_char, InvalidTag(_) => const_eval_invalid_tag, @@ -588,7 +589,10 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { diag.arg("has", has.bytes()); diag.arg("msg", format!("{msg:?}")); } - WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => { + WriteToReadOnly(alloc) + | DerefFunctionPointer(alloc) + | DerefVTablePointer(alloc) + | DerefTypeIdPointer(alloc) => { diag.arg("allocation", alloc); } InvalidBool(b) => { diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 378ed6d0e10..ee5382af0b2 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -4,8 +4,10 @@ use std::assert_matches::assert_matches; -use rustc_abi::Size; +use rustc_abi::{FieldIdx, Size}; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; +use rustc_ast::Mutability; +use rustc_middle::mir::interpret::{AllocId, AllocInit, alloc_range}; use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic}; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{Ty, TyCtxt}; @@ -29,6 +31,37 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAll tcx.mk_const_alloc(alloc) } +pub(crate) fn alloc_type_id<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> AllocId { + let size = Size::from_bytes(16); + let align = tcx.data_layout.pointer_align(); + let mut alloc = Allocation::new(size, *align, AllocInit::Uninit, ()); + let ptr_size = tcx.data_layout.pointer_size(); + let type_id_hash = tcx.type_id_hash(ty).as_u128(); + alloc + .write_scalar( + &tcx, + alloc_range(Size::ZERO, Size::from_bytes(16)), + Scalar::from_u128(type_id_hash), + ) + .unwrap(); + + // Give the first pointer-size bytes provenance that knows about the type id + + let alloc_id = tcx.reserve_and_set_type_id_alloc(ty); + let offset = alloc + .read_scalar(&tcx, alloc_range(Size::ZERO, ptr_size), false) + .unwrap() + .to_target_usize(&tcx) + .unwrap(); + let ptr = Pointer::new(alloc_id.into(), Size::from_bytes(offset)); + let val = Scalar::from_pointer(ptr, &tcx); + alloc.write_scalar(&tcx, alloc_range(Size::ZERO, ptr_size), val).unwrap(); + + alloc.mutability = Mutability::Not; + + tcx.reserve_and_set_memory_alloc(tcx.mk_const_alloc(alloc)) +} + impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Returns `true` if emulation happened. /// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own @@ -63,10 +96,52 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { sym::type_id => { let tp_ty = instance.args.type_at(0); ensure_monomorphic_enough(tcx, tp_ty)?; - let val = ConstValue::from_u128(tcx.type_id_hash(tp_ty).as_u128()); + let alloc_id = alloc_type_id(tcx, tp_ty); + let val = ConstValue::Indirect { alloc_id, offset: Size::ZERO }; let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?; self.copy_op(&val, dest)?; } + sym::type_id_eq => { + // Both operands are `TypeId`, which is a newtype around an array of pointers. + // Project until we have the array elements. + let a_fields = self.project_field(&args[0], FieldIdx::ZERO)?; + let b_fields = self.project_field(&args[1], FieldIdx::ZERO)?; + + let mut a_fields = self.project_array_fields(&a_fields)?; + let mut b_fields = self.project_array_fields(&b_fields)?; + + let (_idx, a) = a_fields + .next(self)? + .expect("we know the layout of TypeId has at least 2 array elements"); + let a = self.deref_pointer(&a)?; + let (a, offset_a) = self.get_ptr_type_id(a.ptr())?; + + let (_idx, b) = b_fields + .next(self)? + .expect("we know the layout of TypeId has at least 2 array elements"); + let b = self.deref_pointer(&b)?; + let (b, offset_b) = self.get_ptr_type_id(b.ptr())?; + + let provenance_matches = a == b; + + let mut eq_id = offset_a == offset_b; + + while let Some((_, a)) = a_fields.next(self)? { + let (_, b) = b_fields.next(self)?.unwrap(); + + let a = self.read_target_usize(&a)?; + let b = self.read_target_usize(&b)?; + eq_id &= a == b; + } + + if !eq_id && provenance_matches { + throw_ub_format!( + "type_id_eq: one of the TypeId arguments is invalid, the hash does not match the type it represents" + ) + } + + self.write_scalar(Scalar::from_bool(provenance_matches), dest)?; + } sym::variant_count => { let tp_ty = instance.args.type_at(0); let ty = match tp_ty.kind() { diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 524023b8104..bb301600135 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -15,9 +15,9 @@ use std::{fmt, ptr}; use rustc_abi::{Align, HasDataLayout, Size}; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; -use rustc_middle::bug; use rustc_middle::mir::display_allocation; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; +use rustc_middle::{bug, throw_ub_format}; use tracing::{debug, instrument, trace}; use super::{ @@ -346,6 +346,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { kind = "vtable", ) } + Some(GlobalAlloc::TypeId { .. }) => { + err_ub_custom!( + fluent::const_eval_invalid_dealloc, + alloc_id = alloc_id, + kind = "typeid", + ) + } Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => { err_ub_custom!( fluent::const_eval_invalid_dealloc, @@ -615,6 +622,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } Some(GlobalAlloc::Function { .. }) => throw_ub!(DerefFunctionPointer(id)), Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)), + Some(GlobalAlloc::TypeId { .. }) => throw_ub!(DerefTypeIdPointer(id)), None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccess)), Some(GlobalAlloc::Static(def_id)) => { assert!(self.tcx.is_static(def_id)); @@ -896,7 +904,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let (size, align) = global_alloc.size_and_align(*self.tcx, self.typing_env); let mutbl = global_alloc.mutability(*self.tcx, self.typing_env); let kind = match global_alloc { - GlobalAlloc::Static { .. } | GlobalAlloc::Memory { .. } => AllocKind::LiveData, + GlobalAlloc::TypeId { .. } + | GlobalAlloc::Static { .. } + | GlobalAlloc::Memory { .. } => AllocKind::LiveData, GlobalAlloc::Function { .. } => bug!("We already checked function pointers above"), GlobalAlloc::VTable { .. } => AllocKind::VTable, }; @@ -936,6 +946,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } + /// Takes a pointer that is the first chunk of a `TypeId` and return the type that its + /// provenance refers to, as well as the segment of the hash that this pointer covers. + pub fn get_ptr_type_id( + &self, + ptr: Pointer>, + ) -> InterpResult<'tcx, (Ty<'tcx>, Size)> { + let (alloc_id, offset, _meta) = self.ptr_get_alloc_id(ptr, 0)?; + let GlobalAlloc::TypeId { ty } = self.tcx.global_alloc(alloc_id) else { + throw_ub_format!("type_id_eq: `TypeId` provenance is not a type id") + }; + interp_ok((ty, offset)) + } + pub fn get_ptr_fn( &self, ptr: Pointer>, @@ -1197,6 +1220,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> std::fmt::Debug for DumpAllocs<'a, 'tcx, M> { Some(GlobalAlloc::VTable(ty, dyn_ty)) => { write!(fmt, " (vtable: impl {dyn_ty} for {ty})")?; } + Some(GlobalAlloc::TypeId { ty }) => { + write!(fmt, " (typeid for {ty})")?; + } Some(GlobalAlloc::Static(did)) => { write!(fmt, " (static: {})", self.ecx.tcx.def_path_str(did))?; } diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 306697d4ec9..f72c4418081 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -296,7 +296,11 @@ where base: &'a P, ) -> InterpResult<'tcx, ArrayIterator<'a, 'tcx, M::Provenance, P>> { let abi::FieldsShape::Array { stride, .. } = base.layout().fields else { - span_bug!(self.cur_span(), "project_array_fields: expected an array layout"); + span_bug!( + self.cur_span(), + "project_array_fields: expected an array layout, got {:#?}", + base.layout() + ); }; let len = base.len(self)?; let field_layout = base.layout().field(self, 0); diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index fc4d13af8c4..fc44490c96d 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -571,40 +571,42 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { let alloc_actual_mutbl = global_alloc.mutability(*self.ecx.tcx, self.ecx.typing_env); - if let GlobalAlloc::Static(did) = global_alloc { - let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else { - bug!() - }; - // Special handling for pointers to statics (irrespective of their type). - assert!(!self.ecx.tcx.is_thread_local_static(did)); - assert!(self.ecx.tcx.is_static(did)); - // Mode-specific checks - match ctfe_mode { - CtfeValidationMode::Static { .. } - | CtfeValidationMode::Promoted { .. } => { - // We skip recursively checking other statics. These statics must be sound by - // themselves, and the only way to get broken statics here is by using - // unsafe code. - // The reasons we don't check other statics is twofold. For one, in all - // sound cases, the static was already validated on its own, and second, we - // trigger cycle errors if we try to compute the value of the other static - // and that static refers back to us (potentially through a promoted). - // This could miss some UB, but that's fine. - // We still walk nested allocations, as they are fundamentally part of this validation run. - // This means we will also recurse into nested statics of *other* - // statics, even though we do not recurse into other statics directly. - // That's somewhat inconsistent but harmless. - skip_recursive_check = !nested; - } - CtfeValidationMode::Const { .. } => { - // If this is mutable memory or an `extern static`, there's no point in checking it -- we'd - // just get errors trying to read the value. - if alloc_actual_mutbl.is_mut() || self.ecx.tcx.is_foreign_item(did) - { - skip_recursive_check = true; + match global_alloc { + GlobalAlloc::Static(did) => { + let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else { + bug!() + }; + assert!(!self.ecx.tcx.is_thread_local_static(did)); + assert!(self.ecx.tcx.is_static(did)); + match ctfe_mode { + CtfeValidationMode::Static { .. } + | CtfeValidationMode::Promoted { .. } => { + // We skip recursively checking other statics. These statics must be sound by + // themselves, and the only way to get broken statics here is by using + // unsafe code. + // The reasons we don't check other statics is twofold. For one, in all + // sound cases, the static was already validated on its own, and second, we + // trigger cycle errors if we try to compute the value of the other static + // and that static refers back to us (potentially through a promoted). + // This could miss some UB, but that's fine. + // We still walk nested allocations, as they are fundamentally part of this validation run. + // This means we will also recurse into nested statics of *other* + // statics, even though we do not recurse into other statics directly. + // That's somewhat inconsistent but harmless. + skip_recursive_check = !nested; + } + CtfeValidationMode::Const { .. } => { + // If this is mutable memory or an `extern static`, there's no point in checking it -- we'd + // just get errors trying to read the value. + if alloc_actual_mutbl.is_mut() + || self.ecx.tcx.is_foreign_item(did) + { + skip_recursive_check = true; + } } } } + _ => (), } // If this allocation has size zero, there is no actual mutability here. diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index c11db63ba11..6347f1bfa71 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -274,6 +274,8 @@ language_item_table! { PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1); CVoid, sym::c_void, c_void, Target::Enum, GenericRequirement::None; + TypeId, sym::type_id, type_id, Target::Struct, GenericRequirement::None; + // A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and // various panic cases with `match`. The `panic_bounds_check` item is for indexing arrays. // diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index cebf7d1b532..e3532ade32f 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -93,6 +93,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::three_way_compare | sym::discriminant_value | sym::type_id + | sym::type_id_eq | sym::select_unpredictable | sym::cold_path | sym::ptr_guaranteed_cmp @@ -220,7 +221,13 @@ pub(crate) fn check_intrinsic_type( sym::needs_drop => (1, 0, vec![], tcx.types.bool), sym::type_name => (1, 0, vec![], Ty::new_static_str(tcx)), - sym::type_id => (1, 0, vec![], tcx.types.u128), + sym::type_id => { + (1, 0, vec![], tcx.type_of(tcx.lang_items().type_id().unwrap()).instantiate_identity()) + } + sym::type_id_eq => { + let type_id = tcx.type_of(tcx.lang_items().type_id().unwrap()).instantiate_identity(); + (0, 0, vec![type_id, type_id], tcx.types.bool) + } sym::offset => (2, 0, vec![param(0), param(1)], param(0)), sym::arith_offset => ( 1, diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 8acb8fa9f80..71e0c943fbb 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -392,6 +392,8 @@ pub enum UndefinedBehaviorInfo<'tcx> { DerefFunctionPointer(AllocId), /// Trying to access the data behind a vtable pointer. DerefVTablePointer(AllocId), + /// Trying to access the actual type id. + DerefTypeIdPointer(AllocId), /// Using a non-boolean `u8` as bool. InvalidBool(u8), /// Using a non-character `u32` as character. diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 0b2645013ba..bed99a4ff2a 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -103,6 +103,7 @@ enum AllocDiscriminant { Fn, VTable, Static, + Type, } pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<'tcx>>( @@ -127,6 +128,11 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<'tcx>>( ty.encode(encoder); poly_trait_ref.encode(encoder); } + GlobalAlloc::TypeId { ty } => { + trace!("encoding {alloc_id:?} with {ty:#?}"); + AllocDiscriminant::Type.encode(encoder); + ty.encode(encoder); + } GlobalAlloc::Static(did) => { assert!(!tcx.is_thread_local_static(did)); // References to statics doesn't need to know about their allocations, @@ -228,6 +234,12 @@ impl<'s> AllocDecodingSession<'s> { trace!("decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}"); decoder.interner().reserve_and_set_vtable_alloc(ty, poly_trait_ref, CTFE_ALLOC_SALT) } + AllocDiscriminant::Type => { + trace!("creating typeid alloc ID"); + let ty = Decodable::decode(decoder); + trace!("decoded typid: {ty:?}"); + decoder.interner().reserve_and_set_type_id_alloc(ty) + } AllocDiscriminant::Static => { trace!("creating extern static alloc ID"); let did = >::decode(decoder); @@ -258,6 +270,9 @@ pub enum GlobalAlloc<'tcx> { Static(DefId), /// The alloc ID points to memory. Memory(ConstAllocation<'tcx>), + /// The first pointer-sized segment of a type id. On 64 bit systems, the 128 bit type id + /// is split into two segments, on 32 bit systems there are 4 segments, and so on. + TypeId { ty: Ty<'tcx> }, } impl<'tcx> GlobalAlloc<'tcx> { @@ -296,9 +311,10 @@ impl<'tcx> GlobalAlloc<'tcx> { pub fn address_space(&self, cx: &impl HasDataLayout) -> AddressSpace { match self { GlobalAlloc::Function { .. } => cx.data_layout().instruction_address_space, - GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => { - AddressSpace::ZERO - } + GlobalAlloc::TypeId { .. } + | GlobalAlloc::Static(..) + | GlobalAlloc::Memory(..) + | GlobalAlloc::VTable(..) => AddressSpace::ZERO, } } @@ -334,7 +350,7 @@ impl<'tcx> GlobalAlloc<'tcx> { } } GlobalAlloc::Memory(alloc) => alloc.inner().mutability, - GlobalAlloc::Function { .. } | GlobalAlloc::VTable(..) => { + GlobalAlloc::TypeId { .. } | GlobalAlloc::Function { .. } | GlobalAlloc::VTable(..) => { // These are immutable. Mutability::Not } @@ -380,8 +396,10 @@ impl<'tcx> GlobalAlloc<'tcx> { GlobalAlloc::Function { .. } => (Size::ZERO, Align::ONE), GlobalAlloc::VTable(..) => { // No data to be accessed here. But vtables are pointer-aligned. - return (Size::ZERO, tcx.data_layout.pointer_align().abi); + (Size::ZERO, tcx.data_layout.pointer_align().abi) } + // Fake allocation, there's nothing to access here + GlobalAlloc::TypeId { .. } => (Size::ZERO, Align::ONE), } } } @@ -487,6 +505,11 @@ impl<'tcx> TyCtxt<'tcx> { self.reserve_and_set_dedup(GlobalAlloc::VTable(ty, dyn_ty), salt) } + /// Generates an [AllocId] for a [core::any::TypeId]. Will get deduplicated. + pub fn reserve_and_set_type_id_alloc(self, ty: Ty<'tcx>) -> AllocId { + self.reserve_and_set_dedup(GlobalAlloc::TypeId { ty }, 0) + } + /// Interns the `Allocation` and return a new `AllocId`, even if there's already an identical /// `Allocation` with a different `AllocId`. /// Statics with identical content will still point to the same `Allocation`, i.e., diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index e9f3fb6ac8d..8e403dfddae 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1621,6 +1621,7 @@ pub fn write_allocations<'tcx>( Some(GlobalAlloc::VTable(ty, dyn_ty)) => { write!(w, " (vtable: impl {dyn_ty} for {ty})")? } + Some(GlobalAlloc::TypeId { ty }) => write!(w, " (typeid for {ty})")?, Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => { write!(w, " (static: {}", tcx.def_path_str(did))?; if body.phase <= MirPhase::Runtime(RuntimePhase::PostCleanup) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 4e078847815..7c48a4b0885 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1773,6 +1773,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } Some(GlobalAlloc::Function { .. }) => p!(""), Some(GlobalAlloc::VTable(..)) => p!(""), + Some(GlobalAlloc::TypeId { .. }) => p!(""), None => p!(""), } return Ok(()); diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 131064f9832..91c8e64ce9a 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1219,6 +1219,7 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt )); collect_alloc(tcx, alloc_id, output) } + GlobalAlloc::TypeId { .. } => {} } } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 7e15267a953..b49e8118fe3 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -325,6 +325,7 @@ impl<'tcx> ReachableContext<'tcx> { self.visit(args); } } + GlobalAlloc::TypeId { ty, .. } => self.visit(ty), GlobalAlloc::Memory(alloc) => self.propagate_from_alloc(alloc), } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 09f01d8704e..4df91cc3429 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2194,6 +2194,7 @@ symbols! { type_changing_struct_update, type_const, type_id, + type_id_eq, type_ir, type_ir_infer_ctxt_like, type_ir_inherent, diff --git a/compiler/stable_mir/src/mir/alloc.rs b/compiler/stable_mir/src/mir/alloc.rs index 0d45e59885c..9a94551f3ec 100644 --- a/compiler/stable_mir/src/mir/alloc.rs +++ b/compiler/stable_mir/src/mir/alloc.rs @@ -23,6 +23,9 @@ pub enum GlobalAlloc { Static(StaticDef), /// The alloc ID points to memory. Memory(Allocation), + /// The first pointer-sized segment of a type id. On 64 bit systems, the 128 bit type id + /// is split into two segments, on 32 bit systems there are 4 segments, and so on. + TypeId { ty: Ty }, } impl From for GlobalAlloc { diff --git a/compiler/stable_mir/src/unstable/convert/stable/mir.rs b/compiler/stable_mir/src/unstable/convert/stable/mir.rs index f6f4706e40b..ad39fc37600 100644 --- a/compiler/stable_mir/src/unstable/convert/stable/mir.rs +++ b/compiler/stable_mir/src/unstable/convert/stable/mir.rs @@ -864,6 +864,9 @@ impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> { mir::interpret::GlobalAlloc::Memory(alloc) => { GlobalAlloc::Memory(alloc.stable(tables, cx)) } + mir::interpret::GlobalAlloc::TypeId { ty } => { + GlobalAlloc::TypeId { ty: ty.stable(tables, cx) } + } } } } diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index f88661ee001..3e34e03a61e 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml @@ -23,8 +23,6 @@ optimize_for_size = [] # Make `RefCell` store additional debugging information, which is printed out when # a borrow error occurs debug_refcell = [] -# Make `TypeId` store a reference to the name of the type, so that it can print that name. -debug_typeid = [] [lints.rust.unexpected_cfgs] level = "warn" diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 01dce114592..39cdf6efda0 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -707,19 +707,52 @@ impl dyn Any + Send + Sync { /// ``` #[derive(Clone, Copy, Eq, PartialOrd, Ord)] #[stable(feature = "rust1", since = "1.0.0")] +#[lang = "type_id"] pub struct TypeId { - // We avoid using `u128` because that imposes higher alignment requirements on many platforms. - // See issue #115620 for more information. - t: (u64, u64), - #[cfg(feature = "debug_typeid")] - name: &'static str, + /// This needs to be an array of pointers, since there is provenance + /// in the first array field. This provenance knows exactly which type + /// the TypeId actually is, allowing CTFE and miri to operate based off it. + /// At runtime all the pointers in the array contain bits of the hash, making + /// the entire `TypeId` actually just be a `u128` hash of the type. + pub(crate) data: [*const (); 16 / size_of::<*const ()>()], } +// SAFETY: the raw pointer is always an integer #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for TypeId { +unsafe impl Send for TypeId {} +// SAFETY: the raw pointer is always an integer +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Sync for TypeId {} + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_type_id", issue = "77125")] +impl const PartialEq for TypeId { #[inline] fn eq(&self, other: &Self) -> bool { - self.t == other.t + #[cfg(miri)] + return crate::intrinsics::type_id_eq(*self, *other); + #[cfg(not(miri))] + { + let this = self; + crate::intrinsics::const_eval_select!( + @capture { this: &TypeId, other: &TypeId } -> bool: + if const { + crate::intrinsics::type_id_eq(*this, *other) + } else { + // Ideally we would just invoke `type_id_eq` unconditionally here, + // but since we do not MIR inline intrinsics, because backends + // may want to override them (and miri does!), MIR opts do not + // clean up this call sufficiently for LLVM to turn repeated calls + // of `TypeId` comparisons against one specific `TypeId` into + // a lookup table. + // SAFETY: We know that at runtime none of the bits have provenance and all bits + // are initialized. So we can just convert the whole thing to a `u128` and compare that. + unsafe { + crate::mem::transmute::<_, u128>(*this) == crate::mem::transmute::<_, u128>(*other) + } + } + ) + } } } @@ -742,19 +775,19 @@ impl TypeId { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_type_id", issue = "77125")] pub const fn of() -> TypeId { - let t: u128 = const { intrinsics::type_id::() }; - let t1 = (t >> 64) as u64; - let t2 = t as u64; - - TypeId { - t: (t1, t2), - #[cfg(feature = "debug_typeid")] - name: type_name::(), - } + const { intrinsics::type_id::() } } fn as_u128(self) -> u128 { - u128::from(self.t.0) << 64 | u128::from(self.t.1) + let mut bytes = [0; 16]; + + // This is a provenance-stripping memcpy. + for (i, chunk) in self.data.iter().copied().enumerate() { + let chunk = chunk.expose_provenance().to_ne_bytes(); + let start = i * chunk.len(); + bytes[start..(start + chunk.len())].copy_from_slice(&chunk); + } + u128::from_ne_bytes(bytes) } } @@ -774,22 +807,19 @@ impl hash::Hash for TypeId { // - It is correct to do so -- only hashing a subset of `self` is still // compatible with an `Eq` implementation that considers the entire // value, as ours does. - self.t.1.hash(state); + let data = + // SAFETY: The `offset` stays in-bounds, it just moves the pointer to the 2nd half of the `TypeId`. + // Only the first ptr-sized chunk ever has provenance, so that second half is always + // fine to read at integer type. + unsafe { crate::ptr::read_unaligned(self.data.as_ptr().cast::().offset(1)) }; + data.hash(state); } } #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for TypeId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - #[cfg(feature = "debug_typeid")] - { - write!(f, "TypeId({:#034x} = {})", self.as_u128(), self.name)?; - } - #[cfg(not(feature = "debug_typeid"))] - { - write!(f, "TypeId({:#034x})", self.as_u128())?; - } - Ok(()) + write!(f, "TypeId({:#034x})", self.as_u128()) } } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 791d10eda6d..f5dcfeebed8 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2724,7 +2724,20 @@ pub const fn type_name() -> &'static str; #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] -pub const fn type_id() -> u128; +pub const fn type_id() -> crate::any::TypeId; + +/// Tests (at compile-time) if two [`crate::any::TypeId`] instances identify the +/// same type. This is necessary because at const-eval time the actual discriminating +/// data is opaque and cannot be inspected directly. +/// +/// The stabilized version of this intrinsic is the [PartialEq] impl for [`core::any::TypeId`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_intrinsic] +#[rustc_do_not_const_check] +pub const fn type_id_eq(a: crate::any::TypeId, b: crate::any::TypeId) -> bool { + a.data == b.data +} /// Lowers in MIR to `Rvalue::Aggregate` with `AggregateKind::RawPtr`. /// diff --git a/library/coretests/tests/any.rs b/library/coretests/tests/any.rs index 117ef004238..25002617d0b 100644 --- a/library/coretests/tests/any.rs +++ b/library/coretests/tests/any.rs @@ -118,14 +118,6 @@ fn any_unsized() { is_any::<[i32]>(); } -#[cfg(feature = "debug_typeid")] -#[test] -fn debug_typeid_includes_name() { - let type_id = TypeId::of::<[usize; 2]>(); - let debug_str = format!("{type_id:?}"); - assert!(debug_str.ends_with("= [usize; 2])"), "{debug_str:?} did not match"); -} - #[test] fn distinct_type_names() { // https://github.com/rust-lang/rust/issues/84666 diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 3a75d316871..62ece4b6961 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -113,8 +113,6 @@ optimize_for_size = ["core/optimize_for_size", "alloc/optimize_for_size"] # Make `RefCell` store additional debugging information, which is printed out when # a borrow error occurs debug_refcell = ["core/debug_refcell"] -# Make `TypeId` store a reference to the name of the type, so that it can print that name. -debug_typeid = ["core/debug_typeid"] # Enable std_detect default features for stdarch/crates/std_detect: diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index 3adc0224971..c4937c36d4c 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -22,7 +22,6 @@ compiler-builtins-no-asm = ["std/compiler-builtins-no-asm"] compiler-builtins-no-f16-f128 = ["std/compiler-builtins-no-f16-f128"] compiler-builtins-mangled-names = ["std/compiler-builtins-mangled-names"] debug_refcell = ["std/debug_refcell"] -debug_typeid = ["std/debug_typeid"] llvm-libunwind = ["std/llvm-libunwind"] system-llvm-libunwind = ["std/system-llvm-libunwind"] optimize_for_size = ["std/optimize_for_size"] diff --git a/tests/codegen/error-provide.rs b/tests/codegen/error-provide.rs index 25a66078fd4..7f091e34359 100644 --- a/tests/codegen/error-provide.rs +++ b/tests/codegen/error-provide.rs @@ -37,9 +37,9 @@ impl std::error::Error for MyError { // and eliminate redundant ones, rather than compare one-by-one. // CHECK-NEXT: start: - // CHECK-NEXT: %[[SCRUTINEE:[^ ]+]] = load i64, ptr - // CHECK-NEXT: switch i64 %[[SCRUTINEE]], label %{{.*}} [ - // CHECK-COUNT-3: i64 {{.*}}, label %{{.*}} + // CHECK-NEXT: %[[SCRUTINEE:[^ ]+]] = load i128, ptr + // CHECK-NEXT: switch i128 %[[SCRUTINEE]], label %{{.*}} [ + // CHECK-COUNT-3: i128 {{.*}}, label %{{.*}} // CHECK-NEXT: ] request .provide_ref::(&self.backtrace1) diff --git a/tests/ui/const-generics/issues/issue-90318.rs b/tests/ui/const-generics/issues/issue-90318.rs index 317ddad49cd..dfba90a5575 100644 --- a/tests/ui/const-generics/issues/issue-90318.rs +++ b/tests/ui/const-generics/issues/issue-90318.rs @@ -1,5 +1,6 @@ #![feature(const_type_id)] #![feature(generic_const_exprs)] +#![feature(const_trait_impl)] #![feature(core_intrinsics)] #![allow(incomplete_features)] @@ -13,7 +14,6 @@ fn consume(_val: T) where If<{ TypeId::of::() != TypeId::of::<()>() }>: True, //~^ ERROR overly complex generic constant - //~| ERROR: cannot call { } @@ -21,7 +21,6 @@ fn test() where If<{ TypeId::of::() != TypeId::of::<()>() }>: True, //~^ ERROR overly complex generic constant - //~| ERROR: cannot call { } diff --git a/tests/ui/const-generics/issues/issue-90318.stderr b/tests/ui/const-generics/issues/issue-90318.stderr index 9c7cb5ceb58..7031230db91 100644 --- a/tests/ui/const-generics/issues/issue-90318.stderr +++ b/tests/ui/const-generics/issues/issue-90318.stderr @@ -1,5 +1,5 @@ error: overly complex generic constant - --> $DIR/issue-90318.rs:14:8 + --> $DIR/issue-90318.rs:15:8 | LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, | ^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,26 +20,5 @@ LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, = help: consider moving this anonymous constant into a `const` function = note: this operation may be supported in the future -error[E0015]: cannot call non-const operator in constants - --> $DIR/issue-90318.rs:14:10 - | -LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: impl defined here, but it is not `const` - --> $SRC_DIR/core/src/any.rs:LL:COL - = note: calls in constants are limited to constant functions, tuple structs and tuple variants - -error[E0015]: cannot call non-const operator in constants - --> $DIR/issue-90318.rs:22:10 - | -LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: impl defined here, but it is not `const` - --> $SRC_DIR/core/src/any.rs:LL:COL - = note: calls in constants are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/const_cmp_type_id.rs b/tests/ui/consts/const_cmp_type_id.rs index dca0615083a..def615bd92b 100644 --- a/tests/ui/consts/const_cmp_type_id.rs +++ b/tests/ui/consts/const_cmp_type_id.rs @@ -6,10 +6,9 @@ use std::any::TypeId; fn main() { const { assert!(TypeId::of::() == TypeId::of::()); - //~^ ERROR the trait bound `TypeId: const PartialEq` is not satisfied assert!(TypeId::of::<()>() != TypeId::of::()); - //~^ ERROR the trait bound `TypeId: const PartialEq` is not satisfied let _a = TypeId::of::() < TypeId::of::(); + //~^ ERROR: cannot call non-const operator in constants // can't assert `_a` because it is not deterministic // FIXME(const_trait_impl) make it pass } diff --git a/tests/ui/consts/const_cmp_type_id.stderr b/tests/ui/consts/const_cmp_type_id.stderr index a8242a200ef..540eec5098b 100644 --- a/tests/ui/consts/const_cmp_type_id.stderr +++ b/tests/ui/consts/const_cmp_type_id.stderr @@ -1,15 +1,13 @@ -error[E0277]: the trait bound `TypeId: const PartialEq` is not satisfied - --> $DIR/const_cmp_type_id.rs:8:17 +error[E0015]: cannot call non-const operator in constants + --> $DIR/const_cmp_type_id.rs:10:18 | -LL | assert!(TypeId::of::() == TypeId::of::()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: the trait bound `TypeId: const PartialEq` is not satisfied - --> $DIR/const_cmp_type_id.rs:10:17 +LL | let _a = TypeId::of::() < TypeId::of::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -LL | assert!(TypeId::of::<()>() != TypeId::of::()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: impl defined here, but it is not `const` + --> $SRC_DIR/core/src/any.rs:LL:COL + = note: calls in constants are limited to constant functions, tuple structs and tuple variants -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/const_transmute_type_id.rs b/tests/ui/consts/const_transmute_type_id.rs new file mode 100644 index 00000000000..56ead6a622b --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id.rs @@ -0,0 +1,11 @@ +#![feature(const_type_id, const_trait_impl)] + +use std::any::TypeId; + +const _: () = { + let id = TypeId::of::(); + let id: u8 = unsafe { (&raw const id).cast::().read() }; + //~^ ERROR: unable to turn pointer into integer +}; + +fn main() {} diff --git a/tests/ui/consts/const_transmute_type_id.stderr b/tests/ui/consts/const_transmute_type_id.stderr new file mode 100644 index 00000000000..85bd4ea2736 --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id.stderr @@ -0,0 +1,12 @@ +error[E0080]: unable to turn pointer into integer + --> $DIR/const_transmute_type_id.rs:7:27 + | +LL | let id: u8 = unsafe { (&raw const id).cast::().read() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const_transmute_type_id2.rs b/tests/ui/consts/const_transmute_type_id2.rs new file mode 100644 index 00000000000..e29cf8171ac --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id2.rs @@ -0,0 +1,14 @@ +//@ normalize-stderr: "0x(ff)+" -> "" + +#![feature(const_type_id, const_trait_impl)] + +use std::any::TypeId; + +const _: () = { + let a: TypeId = unsafe { std::mem::transmute(u128::MAX) }; + let b: TypeId = unsafe { std::mem::transmute(u128::MAX) }; + assert!(a == b); + //~^ ERROR: pointer must point to some allocation +}; + +fn main() {} diff --git a/tests/ui/consts/const_transmute_type_id2.stderr b/tests/ui/consts/const_transmute_type_id2.stderr new file mode 100644 index 00000000000..5646eb1257d --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id2.stderr @@ -0,0 +1,15 @@ +error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got [noalloc] which is a dangling pointer (it has no provenance) + --> $DIR/const_transmute_type_id2.rs:10:13 + | +LL | assert!(a == b); + | ^^^^^^ evaluation of `_` failed inside this call + | +note: inside `::eq` + --> $SRC_DIR/core/src/any.rs:LL:COL +note: inside `::eq::compiletime` + --> $SRC_DIR/core/src/any.rs:LL:COL + = note: this error originates in the macro `$crate::intrinsics::const_eval_select` which comes from the expansion of the macro `crate::intrinsics::const_eval_select` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const_transmute_type_id3.rs b/tests/ui/consts/const_transmute_type_id3.rs new file mode 100644 index 00000000000..a870d6e7e80 --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id3.rs @@ -0,0 +1,16 @@ +#![feature(const_type_id, const_trait_impl)] + +use std::any::TypeId; + +const _: () = { + let a = TypeId::of::<()>(); + let mut b = TypeId::of::<()>(); + unsafe { + let ptr = &mut b as *mut TypeId as *mut usize; + std::ptr::write(ptr.offset(1), 999); + } + assert!(a == b); + //~^ ERROR: one of the TypeId arguments is invalid, the hash does not match the type it represents +}; + +fn main() {} diff --git a/tests/ui/consts/const_transmute_type_id3.stderr b/tests/ui/consts/const_transmute_type_id3.stderr new file mode 100644 index 00000000000..8cfdcfebaa4 --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id3.stderr @@ -0,0 +1,15 @@ +error[E0080]: type_id_eq: one of the TypeId arguments is invalid, the hash does not match the type it represents + --> $DIR/const_transmute_type_id3.rs:12:13 + | +LL | assert!(a == b); + | ^^^^^^ evaluation of `_` failed inside this call + | +note: inside `::eq` + --> $SRC_DIR/core/src/any.rs:LL:COL +note: inside `::eq::compiletime` + --> $SRC_DIR/core/src/any.rs:LL:COL + = note: this error originates in the macro `$crate::intrinsics::const_eval_select` which comes from the expansion of the macro `crate::intrinsics::const_eval_select` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const_transmute_type_id4.rs b/tests/ui/consts/const_transmute_type_id4.rs new file mode 100644 index 00000000000..bc71f961a51 --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id4.rs @@ -0,0 +1,16 @@ +#![feature(const_type_id, const_trait_impl)] + +use std::any::TypeId; + +const _: () = { + let a = TypeId::of::<()>(); + let mut b = TypeId::of::<()>(); + unsafe { + let ptr = &mut b as *mut TypeId as *mut *const (); + std::ptr::write(ptr.offset(0), main as fn() as *const ()); + } + assert!(a == b); + //~^ ERROR: type_id_eq: `TypeId` provenance is not a type id +}; + +fn main() {} diff --git a/tests/ui/consts/const_transmute_type_id4.stderr b/tests/ui/consts/const_transmute_type_id4.stderr new file mode 100644 index 00000000000..b418a79d7f0 --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id4.stderr @@ -0,0 +1,15 @@ +error[E0080]: type_id_eq: `TypeId` provenance is not a type id + --> $DIR/const_transmute_type_id4.rs:12:13 + | +LL | assert!(a == b); + | ^^^^^^ evaluation of `_` failed inside this call + | +note: inside `::eq` + --> $SRC_DIR/core/src/any.rs:LL:COL +note: inside `::eq::compiletime` + --> $SRC_DIR/core/src/any.rs:LL:COL + = note: this error originates in the macro `$crate::intrinsics::const_eval_select` which comes from the expansion of the macro `crate::intrinsics::const_eval_select` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/issue-73976-monomorphic.rs b/tests/ui/consts/issue-73976-monomorphic.rs index 561c1976051..3bfdb397afb 100644 --- a/tests/ui/consts/issue-73976-monomorphic.rs +++ b/tests/ui/consts/issue-73976-monomorphic.rs @@ -1,4 +1,4 @@ -//@ known-bug: #110395 +//@ check-pass // // This test is complement to the test in issue-73976-polymorphic.rs. // In that test we ensure that polymorphic use of type_id and type_name in patterns diff --git a/tests/ui/consts/issue-73976-monomorphic.stderr b/tests/ui/consts/issue-73976-monomorphic.stderr deleted file mode 100644 index 367d5be09da..00000000000 --- a/tests/ui/consts/issue-73976-monomorphic.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0277]: the trait bound `TypeId: [const] PartialEq` is not satisfied - --> $DIR/issue-73976-monomorphic.rs:21:5 - | -LL | GetTypeId::::VALUE == GetTypeId::::VALUE - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. -- cgit 1.4.1-3-g733a5 From 84eeca2e2fc40bb8d6641846f18af9d8fc6a9681 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 10 Jul 2025 07:27:41 +0000 Subject: Make some "safe" llvm ops actually sound --- compiler/rustc_codegen_llvm/src/back/write.rs | 2 +- compiler/rustc_codegen_llvm/src/builder/autodiff.rs | 2 +- compiler/rustc_codegen_llvm/src/consts.rs | 2 +- compiler/rustc_codegen_llvm/src/llvm/mod.rs | 10 ++++++---- 4 files changed, 9 insertions(+), 7 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index bde6a9cf4bc..506286fc255 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -1182,7 +1182,7 @@ fn create_msvc_imps( .filter_map(|val| { // Exclude some symbols that we know are not Rust symbols. let name = llvm::get_value_name(val); - if ignored(name) { None } else { Some((val, name)) } + if ignored(&name) { None } else { Some((val, name)) } }) .map(move |(val, name)| { let mut imp_name = prefix.as_bytes().to_vec(); diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index b07d9a5cfca..5afb9a60d42 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -306,7 +306,7 @@ fn generate_enzyme_call<'ll>( // add outer_fn name to ad_name to make it unique, in case users apply autodiff to multiple // functions. Unwrap will only panic, if LLVM gave us an invalid string. let name = llvm::get_value_name(outer_fn); - let outer_fn_name = std::str::from_utf8(name).unwrap(); + let outer_fn_name = std::str::from_utf8(&name).unwrap(); ad_name.push_str(outer_fn_name); // Let us assume the user wrote the following function square: diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 28f5282c6b0..9c5008e0304 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -430,7 +430,7 @@ impl<'ll> CodegenCx<'ll, '_> { // specific rules on what can be cast. So instead of adding a new way to // generate static initializers that match the static's type, we picked // the easier option and retroactively change the type of the static item itself. - let name = llvm::get_value_name(g).to_vec(); + let name = llvm::get_value_name(g); llvm::set_value_name(g, b""); let linkage = llvm::get_linkage(g); diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 661174a80df..3fc83fca352 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -211,7 +211,7 @@ pub(crate) fn SetFunctionCallConv(fn_: &Value, cc: CallConv) { // function. // For more details on COMDAT sections see e.g., https://www.airs.com/blog/archives/52 pub(crate) fn SetUniqueComdat(llmod: &Module, val: &Value) { - let name_buf = get_value_name(val).to_vec(); + let name_buf = get_value_name(val); let name = CString::from_vec_with_nul(name_buf).or_else(|buf| CString::new(buf.into_bytes())).unwrap(); set_comdat(llmod, val, &name); @@ -319,12 +319,14 @@ pub(crate) fn get_param(llfn: &Value, index: c_uint) -> &Value { } } -/// Safe wrapper for `LLVMGetValueName2` into a byte slice -pub(crate) fn get_value_name(value: &Value) -> &[u8] { +/// Safe wrapper for `LLVMGetValueName2` +/// Needs to allocate the value, because `set_value_name` will invalidate +/// the pointer. +pub(crate) fn get_value_name(value: &Value) -> Vec { unsafe { let mut len = 0; let data = LLVMGetValueName2(value, &mut len); - std::slice::from_raw_parts(data.cast(), len) + std::slice::from_raw_parts(data.cast(), len).to_vec() } } -- cgit 1.4.1-3-g733a5 From 86349e31dde1f9aa5a8a519ff0213c5461f7f4d7 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 12 Jul 2025 22:53:51 +0200 Subject: Port `#[omit_gdb_pretty_printer_section]` to the new attribute parsing infrastructure Signed-off-by: Jonathan Brouwer --- compiler/rustc_attr_data_structures/src/attributes.rs | 3 +++ .../rustc_attr_data_structures/src/encode_cross_crate.rs | 1 + .../rustc_attr_parsing/src/attributes/codegen_attrs.rs | 8 ++++++++ compiler/rustc_attr_parsing/src/context.rs | 5 +++-- compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs | 5 ++--- compiler/rustc_parse/src/validate_attr.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 4 ++-- tests/ui/attributes/malformed-attrs.stderr | 15 +++++++++------ 8 files changed, 29 insertions(+), 13 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index f61efcf2388..2e2d1fd5f30 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -328,6 +328,9 @@ pub enum AttributeKind { /// Represents `#[non_exhaustive]` NonExhaustive(Span), + /// Represents `#[omit_gdb_pretty_printer_section]` + OmitGdbPrettyPrinterSection, + /// Represents `#[optimize(size|speed)]` Optimize(OptimizeAttr, Span), diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs index ad587523e03..342e995541f 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -50,6 +50,7 @@ impl AttributeKind { NoImplicitPrelude(..) => No, NoMangle(..) => No, NonExhaustive(..) => Yes, + OmitGdbPrettyPrinterSection => No, Optimize(..) => No, ParenSugar(..) => No, PassByValue(..) => Yes, diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index fdec09edaa1..34d9b048348 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -334,3 +334,11 @@ impl CombineAttributeParser for TargetFeatureParser { features } } + +pub(crate) struct OmitGdbPrettyPrinterSectionParser; + +impl NoArgsAttributeParser for OmitGdbPrettyPrinterSectionParser { + const PATH: &[Symbol] = &[sym::omit_gdb_pretty_printer_section]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::OmitGdbPrettyPrinterSection; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index cc10bb3098a..ca0834972f7 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -16,8 +16,8 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; use crate::attributes::codegen_attrs::{ - ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TargetFeatureParser, - TrackCallerParser, UsedParser, + ColdParser, ExportNameParser, NakedParser, NoMangleParser, OmitGdbPrettyPrinterSectionParser, + OptimizeParser, TargetFeatureParser, TrackCallerParser, UsedParser, }; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; @@ -171,6 +171,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 8f0948b8183..49ee96a41d6 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -1,13 +1,12 @@ // .debug_gdb_scripts binary section. -use rustc_ast::attr; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive; use rustc_codegen_ssa::traits::*; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::bug; use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerType; use rustc_session::config::{CrateType, DebugInfo}; -use rustc_span::sym; use crate::builder::Builder; use crate::common::CodegenCx; @@ -87,7 +86,7 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>( pub(crate) fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool { let omit_gdb_pretty_printer_section = - attr::contains_name(cx.tcx.hir_krate_attrs(), sym::omit_gdb_pretty_printer_section); + find_attr!(cx.tcx.hir_krate_attrs(), AttributeKind::OmitGdbPrettyPrinterSection); // To ensure the section `__rustc_debug_gdb_scripts_section__` will not create // ODR violations at link time, this section will not be emitted for rlibs since diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index bb5c1e0e653..422c0982234 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -305,6 +305,7 @@ pub fn check_builtin_meta_item( | sym::naked | sym::no_mangle | sym::non_exhaustive + | sym::omit_gdb_pretty_printer_section | sym::path | sym::ignore | sym::must_use diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2c95fead9e8..912513e88a7 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -240,7 +240,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect | AttributeKind::MacroTransparency(_) - | AttributeKind::Dummy, + | AttributeKind::Dummy + | AttributeKind::OmitGdbPrettyPrinterSection, ) => { /* do nothing */ } Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => { self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target) @@ -369,7 +370,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // need to be fixed | sym::cfi_encoding // FIXME(cfi_encoding) | sym::pointee // FIXME(derive_coerce_pointee) - | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section) | sym::instruction_set // broken on stable!!! | sym::windows_subsystem // broken on stable!!! | sym::patchable_function_entry // FIXME(patchable_function_entry) diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index be529df3a49..b8a71be18fc 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -22,12 +22,6 @@ error[E0463]: can't find crate for `wloop` LL | extern crate wloop; | ^^^^^^^^^^^^^^^^^^^ can't find crate -error: malformed `omit_gdb_pretty_printer_section` attribute input - --> $DIR/malformed-attrs.rs:26:1 - | -LL | #![omit_gdb_pretty_printer_section = 1] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![omit_gdb_pretty_printer_section]` - error: malformed `windows_subsystem` attribute input --> $DIR/malformed-attrs.rs:29:1 | @@ -283,6 +277,15 @@ LL | #[debugger_visualizer] = note: OR = note: expected: `gdb_script_file = "..."` +error[E0565]: malformed `omit_gdb_pretty_printer_section` attribute input + --> $DIR/malformed-attrs.rs:26:1 + | +LL | #![omit_gdb_pretty_printer_section = 1] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[omit_gdb_pretty_printer_section]` + error[E0539]: malformed `export_name` attribute input --> $DIR/malformed-attrs.rs:32:1 | -- cgit 1.4.1-3-g733a5 From d3d51b4fdbd6854da015f501e6566ca17cb023e5 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Jul 2025 09:12:42 +0000 Subject: Avoid a bunch of unnecessary `unsafe` blocks in cg_llvm --- compiler/rustc_codegen_llvm/src/back/write.rs | 77 ++++++++++------------ compiler/rustc_codegen_llvm/src/common.rs | 8 +-- compiler/rustc_codegen_llvm/src/consts.rs | 12 ++-- compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs | 2 +- .../rustc_codegen_llvm/src/debuginfo/metadata.rs | 2 +- compiler/rustc_codegen_llvm/src/declare.rs | 2 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 6 +- compiler/rustc_codegen_llvm/src/llvm/mod.rs | 10 +-- 8 files changed, 54 insertions(+), 65 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 506286fc255..313bf6d20a6 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -879,9 +879,7 @@ pub(crate) fn codegen( .generic_activity_with_arg("LLVM_module_codegen_embed_bitcode", &*module.name); let thin_bc = module.thin_lto_buffer.as_deref().expect("cannot find embedded bitcode"); - unsafe { - embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, &thin_bc); - } + embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, &thin_bc); } } @@ -945,7 +943,7 @@ pub(crate) fn codegen( // binaries. So we must clone the module to produce the asm output // if we are also producing object code. let llmod = if let EmitObj::ObjectCode(_) = config.emit_obj { - unsafe { llvm::LLVMCloneModule(llmod) } + llvm::LLVMCloneModule(llmod) } else { llmod }; @@ -1073,7 +1071,7 @@ pub(crate) fn bitcode_section_name(cgcx: &CodegenContext) -> } /// Embed the bitcode of an LLVM module for LTO in the LLVM module itself. -unsafe fn embed_bitcode( +fn embed_bitcode( cgcx: &CodegenContext, llcx: &llvm::Context, llmod: &llvm::Module, @@ -1115,43 +1113,40 @@ unsafe fn embed_bitcode( // Unfortunately, LLVM provides no way to set custom section flags. For ELF // and COFF we emit the sections using module level inline assembly for that // reason (see issue #90326 for historical background). - unsafe { - if cgcx.target_is_like_darwin - || cgcx.target_is_like_aix - || cgcx.target_arch == "wasm32" - || cgcx.target_arch == "wasm64" - { - // We don't need custom section flags, create LLVM globals. - let llconst = common::bytes_in_context(llcx, bitcode); - let llglobal = - llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.module"); - llvm::set_initializer(llglobal, llconst); - - llvm::set_section(llglobal, bitcode_section_name(cgcx)); - llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); - llvm::LLVMSetGlobalConstant(llglobal, llvm::True); - - let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); - let llglobal = - llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.cmdline"); - llvm::set_initializer(llglobal, llconst); - let section = if cgcx.target_is_like_darwin { - c"__LLVM,__cmdline" - } else if cgcx.target_is_like_aix { - c".info" - } else { - c".llvmcmd" - }; - llvm::set_section(llglobal, section); - llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); + + if cgcx.target_is_like_darwin + || cgcx.target_is_like_aix + || cgcx.target_arch == "wasm32" + || cgcx.target_arch == "wasm64" + { + // We don't need custom section flags, create LLVM globals. + let llconst = common::bytes_in_context(llcx, bitcode); + let llglobal = llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.module"); + llvm::set_initializer(llglobal, llconst); + + llvm::set_section(llglobal, bitcode_section_name(cgcx)); + llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); + llvm::LLVMSetGlobalConstant(llglobal, llvm::True); + + let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); + let llglobal = llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.cmdline"); + llvm::set_initializer(llglobal, llconst); + let section = if cgcx.target_is_like_darwin { + c"__LLVM,__cmdline" + } else if cgcx.target_is_like_aix { + c".info" } else { - // We need custom section flags, so emit module-level inline assembly. - let section_flags = if cgcx.is_pe_coff { "n" } else { "e" }; - let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode); - llvm::append_module_inline_asm(llmod, &asm); - let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes()); - llvm::append_module_inline_asm(llmod, &asm); - } + c".llvmcmd" + }; + llvm::set_section(llglobal, section); + llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); + } else { + // We need custom section flags, so emit module-level inline assembly. + let section_flags = if cgcx.is_pe_coff { "n" } else { "e" }; + let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode); + llvm::append_module_inline_asm(llmod, &asm); + let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes()); + llvm::append_module_inline_asm(llmod, &asm); } } diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index b9b5c776d86..f9ab96b5789 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -215,10 +215,10 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { bug!("symbol `{}` is already defined", sym); }); llvm::set_initializer(g, sc); - unsafe { - llvm::LLVMSetGlobalConstant(g, True); - llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global); - } + + llvm::set_global_constant(g, true); + llvm::set_unnamed_address(g, llvm::UnnamedAddr::Global); + llvm::set_linkage(g, llvm::Linkage::InternalLinkage); // Cast to default address space if globals are in a different addrspace let g = self.const_pointercast(g, self.type_ptr()); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 5deddb3ed98..070a9b64486 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -19,11 +19,10 @@ use tracing::{debug, instrument, trace}; use crate::common::{AsCCharPtr, CodegenCx}; use crate::errors::SymbolAlreadyDefined; -use crate::llvm::{self, True}; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; -use crate::{base, debuginfo}; +use crate::{base, debuginfo, llvm}; pub(crate) fn const_alloc_to_llvm<'ll>( cx: &CodegenCx<'ll, '_>, @@ -247,7 +246,7 @@ impl<'ll> CodegenCx<'ll, '_> { }; llvm::set_initializer(gv, cv); set_global_alignment(self, gv, align); - llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global); + llvm::set_unnamed_address(gv, llvm::UnnamedAddr::Global); gv } @@ -272,9 +271,8 @@ impl<'ll> CodegenCx<'ll, '_> { return gv; } let gv = self.static_addr_of_mut(cv, align, kind); - unsafe { - llvm::LLVMSetGlobalConstant(gv, True); - } + llvm::set_global_constant(gv, true); + self.const_globals.borrow_mut().insert(cv, gv); gv } @@ -465,7 +463,7 @@ impl<'ll> CodegenCx<'ll, '_> { // Forward the allocation's mutability (picked by the const interner) to LLVM. if alloc.mutability.is_not() { - llvm::LLVMSetGlobalConstant(g, llvm::True); + llvm::set_global_constant(g, true); } debuginfo::build_global_var_di_node(self, def_id, g); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 8f0948b8183..3e04dac6cd6 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -75,7 +75,7 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>( llvm::set_section(section_var, c".debug_gdb_scripts"); llvm::set_initializer(section_var, cx.const_bytes(section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); - llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global); + llvm::set_unnamed_address(section_var, llvm::UnnamedAddr::Global); llvm::set_linkage(section_var, llvm::Linkage::LinkOnceODRLinkage); // This should make sure that the whole section is not larger than // the string it contains. Otherwise we get a warning from GDB. diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 9b4736e50e6..1a50fb5823b 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1630,7 +1630,7 @@ pub(crate) fn create_vtable_di_node<'ll, 'tcx>( // When full debuginfo is enabled, we want to try and prevent vtables from being // merged. Otherwise debuggers will have a hard time mapping from dyn pointer // to concrete type. - llvm::SetUnnamedAddress(vtable, llvm::UnnamedAddr::No); + llvm::set_unnamed_address(vtable, llvm::UnnamedAddr::No); let vtable_name = compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::GlobalVariable); diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 2419ec1f888..710032c774b 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -49,7 +49,7 @@ pub(crate) fn declare_simple_fn<'ll>( }; llvm::SetFunctionCallConv(llfn, callconv); - llvm::SetUnnamedAddress(llfn, unnamed); + llvm::set_unnamed_address(llfn, unnamed); llvm::set_visibility(llfn, visibility); llfn diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 5c34ab2e304..2af57e22cd5 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1009,7 +1009,7 @@ unsafe extern "C" { ModuleID: *const c_char, C: &Context, ) -> &Module; - pub(crate) fn LLVMCloneModule(M: &Module) -> &Module; + pub(crate) safe fn LLVMCloneModule(M: &Module) -> &Module; /// Data layout. See Module::getDataLayout. pub(crate) fn LLVMGetDataLayoutStr(M: &Module) -> *const c_char; @@ -1179,7 +1179,7 @@ unsafe extern "C" { pub(crate) fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool; pub(crate) fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode); pub(crate) fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; - pub(crate) fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); + pub(crate) safe fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); // Operations on attributes @@ -1718,7 +1718,7 @@ unsafe extern "C" { pub(crate) safe fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value; - pub(crate) fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr); + pub(crate) safe fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr); pub(crate) fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&ConstantInt>; diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 3fc83fca352..154ba4fd690 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -217,10 +217,8 @@ pub(crate) fn SetUniqueComdat(llmod: &Module, val: &Value) { set_comdat(llmod, val, &name); } -pub(crate) fn SetUnnamedAddress(global: &Value, unnamed: UnnamedAddr) { - unsafe { - LLVMSetUnnamedAddress(global, unnamed); - } +pub(crate) fn set_unnamed_address(global: &Value, unnamed: UnnamedAddr) { + LLVMSetUnnamedAddress(global, unnamed); } pub(crate) fn set_thread_local_mode(global: &Value, mode: ThreadLocalMode) { @@ -260,9 +258,7 @@ pub(crate) fn set_initializer(llglobal: &Value, constant_val: &Value) { } pub(crate) fn set_global_constant(llglobal: &Value, is_constant: bool) { - unsafe { - LLVMSetGlobalConstant(llglobal, if is_constant { ffi::True } else { ffi::False }); - } + LLVMSetGlobalConstant(llglobal, if is_constant { ffi::True } else { ffi::False }); } pub(crate) fn get_linkage(llglobal: &Value) -> Linkage { -- cgit 1.4.1-3-g733a5 From e574fef728605089da8144960348469896751c3c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Jul 2025 09:23:05 +0000 Subject: Shrink some `unsafe` blocks in cg_llvm --- compiler/rustc_codegen_llvm/src/builder.rs | 13 +- compiler/rustc_codegen_llvm/src/consts.rs | 251 +++++++++++++-------------- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 8 +- compiler/rustc_codegen_llvm/src/mono_item.rs | 4 +- 4 files changed, 137 insertions(+), 139 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 9c3b866aa3c..7304460c493 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -637,17 +637,16 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } else if place.layout.is_llvm_immediate() { let mut const_llval = None; let llty = place.layout.llvm_type(self); - unsafe { - if let Some(global) = llvm::LLVMIsAGlobalVariable(place.val.llval) { - if llvm::LLVMIsGlobalConstant(global) == llvm::True { - if let Some(init) = llvm::LLVMGetInitializer(global) { - if self.val_ty(init) == llty { - const_llval = Some(init); - } + if let Some(global) = llvm::LLVMIsAGlobalVariable(place.val.llval) { + if llvm::LLVMIsGlobalConstant(global) == llvm::True { + if let Some(init) = llvm::LLVMGetInitializer(global) { + if self.val_ty(init) == llty { + const_llval = Some(init); } } } } + let llval = const_llval.unwrap_or_else(|| { let load = self.load(llty, place.val.llval, place.val.align); if let abi::BackendRepr::Scalar(scalar) = place.layout.backend_repr { diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 070a9b64486..27f6a119727 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -396,149 +396,148 @@ impl<'ll> CodegenCx<'ll, '_> { } fn codegen_static_item(&mut self, def_id: DefId) { - unsafe { - assert!( - llvm::LLVMGetInitializer( - self.instances.borrow().get(&Instance::mono(self.tcx, def_id)).unwrap() - ) - .is_none() - ); - let attrs = self.tcx.codegen_fn_attrs(def_id); + assert!( + llvm::LLVMGetInitializer( + self.instances.borrow().get(&Instance::mono(self.tcx, def_id)).unwrap() + ) + .is_none() + ); + let attrs = self.tcx.codegen_fn_attrs(def_id); - let Ok((v, alloc)) = codegen_static_initializer(self, def_id) else { - // Error has already been reported - return; - }; - let alloc = alloc.inner(); + let Ok((v, alloc)) = codegen_static_initializer(self, def_id) else { + // Error has already been reported + return; + }; + let alloc = alloc.inner(); - let val_llty = self.val_ty(v); + let val_llty = self.val_ty(v); - let g = self.get_static_inner(def_id, val_llty); - let llty = self.get_type_of_global(g); + let g = self.get_static_inner(def_id, val_llty); + let llty = self.get_type_of_global(g); - let g = if val_llty == llty { - g - } else { - // codegen_static_initializer creates the global value just from the - // `Allocation` data by generating one big struct value that is just - // all the bytes and pointers after each other. This will almost never - // match the type that the static was declared with. Unfortunately - // we can't just LLVMConstBitCast our way out of it because that has very - // specific rules on what can be cast. So instead of adding a new way to - // generate static initializers that match the static's type, we picked - // the easier option and retroactively change the type of the static item itself. - let name = llvm::get_value_name(g); - llvm::set_value_name(g, b""); - - let linkage = llvm::get_linkage(g); - let visibility = llvm::get_visibility(g); - - let new_g = llvm::LLVMRustGetOrInsertGlobal( - self.llmod, - name.as_c_char_ptr(), - name.len(), - val_llty, - ); - - llvm::set_linkage(new_g, linkage); - llvm::set_visibility(new_g, visibility); - - // The old global has had its name removed but is returned by - // get_static since it is in the instance cache. Provide an - // alternative lookup that points to the new global so that - // global_asm! can compute the correct mangled symbol name - // for the global. - self.renamed_statics.borrow_mut().insert(def_id, new_g); - - // To avoid breaking any invariants, we leave around the old - // global for the moment; we'll replace all references to it - // with the new global later. (See base::codegen_backend.) - self.statics_to_rauw.borrow_mut().push((g, new_g)); - new_g - }; - set_global_alignment(self, g, alloc.align); - llvm::set_initializer(g, v); - - self.assume_dso_local(g, true); - - // Forward the allocation's mutability (picked by the const interner) to LLVM. - if alloc.mutability.is_not() { - llvm::set_global_constant(g, true); - } + let g = if val_llty == llty { + g + } else { + // codegen_static_initializer creates the global value just from the + // `Allocation` data by generating one big struct value that is just + // all the bytes and pointers after each other. This will almost never + // match the type that the static was declared with. Unfortunately + // we can't just LLVMConstBitCast our way out of it because that has very + // specific rules on what can be cast. So instead of adding a new way to + // generate static initializers that match the static's type, we picked + // the easier option and retroactively change the type of the static item itself. + let name = String::from_utf8(llvm::get_value_name(g)) + .expect("we declare our statics with a utf8-valid name"); + llvm::set_value_name(g, b""); + + let linkage = llvm::get_linkage(g); + let visibility = llvm::get_visibility(g); + + let new_g = self.declare_global(&name, val_llty); + + llvm::set_linkage(new_g, linkage); + llvm::set_visibility(new_g, visibility); + + // The old global has had its name removed but is returned by + // get_static since it is in the instance cache. Provide an + // alternative lookup that points to the new global so that + // global_asm! can compute the correct mangled symbol name + // for the global. + self.renamed_statics.borrow_mut().insert(def_id, new_g); + + // To avoid breaking any invariants, we leave around the old + // global for the moment; we'll replace all references to it + // with the new global later. (See base::codegen_backend.) + self.statics_to_rauw.borrow_mut().push((g, new_g)); + new_g + }; + set_global_alignment(self, g, alloc.align); + llvm::set_initializer(g, v); - debuginfo::build_global_var_di_node(self, def_id, g); + self.assume_dso_local(g, true); - if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { - llvm::set_thread_local_mode(g, self.tls_model); - } + // Forward the allocation's mutability (picked by the const interner) to LLVM. + if alloc.mutability.is_not() { + llvm::set_global_constant(g, true); + } - // Wasm statics with custom link sections get special treatment as they - // go into custom sections of the wasm executable. The exception to this - // is the `.init_array` section which are treated specially by the wasm linker. - if self.tcx.sess.target.is_like_wasm - && attrs - .link_section - .map(|link_section| !link_section.as_str().starts_with(".init_array")) - .unwrap_or(true) - { - if let Some(section) = attrs.link_section { - let section = llvm::LLVMMDStringInContext2( + debuginfo::build_global_var_di_node(self, def_id, g); + + if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { + llvm::set_thread_local_mode(g, self.tls_model); + } + + // Wasm statics with custom link sections get special treatment as they + // go into custom sections of the wasm executable. The exception to this + // is the `.init_array` section which are treated specially by the wasm linker. + if self.tcx.sess.target.is_like_wasm + && attrs + .link_section + .map(|link_section| !link_section.as_str().starts_with(".init_array")) + .unwrap_or(true) + { + if let Some(section) = attrs.link_section { + let section = unsafe { + llvm::LLVMMDStringInContext2( self.llcx, section.as_str().as_c_char_ptr(), section.as_str().len(), - ); - assert!(alloc.provenance().ptrs().is_empty()); - - // The `inspect` method is okay here because we checked for provenance, and - // because we are doing this access to inspect the final interpreter state (not - // as part of the interpreter execution). - let bytes = - alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()); - let alloc = - llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len()); - let data = [section, alloc]; - let meta = llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()); - let val = self.get_metadata_value(meta); + ) + }; + assert!(alloc.provenance().ptrs().is_empty()); + + // The `inspect` method is okay here because we checked for provenance, and + // because we are doing this access to inspect the final interpreter state (not + // as part of the interpreter execution). + let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()); + let alloc = unsafe { + llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len()) + }; + let data = [section, alloc]; + let meta = + unsafe { llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()) }; + let val = self.get_metadata_value(meta); + unsafe { llvm::LLVMAddNamedMetadataOperand( self.llmod, c"wasm.custom_sections".as_ptr(), val, - ); - } - } else { - base::set_link_section(g, attrs); + ) + }; } + } else { + base::set_link_section(g, attrs); + } - base::set_variable_sanitizer_attrs(g, attrs); - - if attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) { - // `USED` and `USED_LINKER` can't be used together. - assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)); - - // The semantics of #[used] in Rust only require the symbol to make it into the - // object file. It is explicitly allowed for the linker to strip the symbol if it - // is dead, which means we are allowed to use `llvm.compiler.used` instead of - // `llvm.used` here. - // - // Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique - // sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs - // in the handling of `.init_array` (the static constructor list) in versions of - // the gold linker (prior to the one released with binutils 2.36). - // - // That said, we only ever emit these when `#[used(compiler)]` is explicitly - // requested. This is to avoid similar breakage on other targets, in particular - // MachO targets have *their* static constructor lists broken if `llvm.compiler.used` - // is emitted rather than `llvm.used`. However, that check happens when assigning - // the `CodegenFnAttrFlags` in the `codegen_fn_attrs` query, so we don't need to - // take care of it here. - self.add_compiler_used_global(g); - } - if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { - // `USED` and `USED_LINKER` can't be used together. - assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)); + base::set_variable_sanitizer_attrs(g, attrs); + + if attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) { + // `USED` and `USED_LINKER` can't be used together. + assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)); + + // The semantics of #[used] in Rust only require the symbol to make it into the + // object file. It is explicitly allowed for the linker to strip the symbol if it + // is dead, which means we are allowed to use `llvm.compiler.used` instead of + // `llvm.used` here. + // + // Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique + // sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs + // in the handling of `.init_array` (the static constructor list) in versions of + // the gold linker (prior to the one released with binutils 2.36). + // + // That said, we only ever emit these when `#[used(compiler)]` is explicitly + // requested. This is to avoid similar breakage on other targets, in particular + // MachO targets have *their* static constructor lists broken if `llvm.compiler.used` + // is emitted rather than `llvm.used`. However, that check happens when assigning + // the `CodegenFnAttrFlags` in the `codegen_fn_attrs` query, so we don't need to + // take care of it here. + self.add_compiler_used_global(g); + } + if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { + // `USED` and `USED_LINKER` can't be used together. + assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)); - self.add_used_global(g); - } + self.add_used_global(g); } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 2af57e22cd5..0b1e632cbc4 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1168,17 +1168,17 @@ unsafe extern "C" { pub(crate) fn LLVMGlobalGetValueType(Global: &Value) -> &Type; // Operations on global variables - pub(crate) fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>; + pub(crate) safe fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>; pub(crate) fn LLVMAddGlobal<'a>(M: &'a Module, Ty: &'a Type, Name: *const c_char) -> &'a Value; pub(crate) fn LLVMGetNamedGlobal(M: &Module, Name: *const c_char) -> Option<&Value>; pub(crate) fn LLVMGetFirstGlobal(M: &Module) -> Option<&Value>; pub(crate) fn LLVMGetNextGlobal(GlobalVar: &Value) -> Option<&Value>; pub(crate) fn LLVMDeleteGlobal(GlobalVar: &Value); - pub(crate) fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>; + pub(crate) safe fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>; pub(crate) fn LLVMSetInitializer<'a>(GlobalVar: &'a Value, ConstantVal: &'a Value); - pub(crate) fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool; + pub(crate) safe fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool; pub(crate) fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode); - pub(crate) fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; + pub(crate) safe fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; pub(crate) safe fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 3f38e1e191b..8f70270f203 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -131,8 +131,8 @@ impl CodegenCx<'_, '_> { } // Thread-local variables generally don't support copy relocations. - let is_thread_local_var = unsafe { llvm::LLVMIsAGlobalVariable(llval) } - .is_some_and(|v| unsafe { llvm::LLVMIsThreadLocal(v) } == llvm::True); + let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval) + .is_some_and(|v| llvm::LLVMIsThreadLocal(v) == llvm::True); if is_thread_local_var { return false; } -- cgit 1.4.1-3-g733a5 From b9baf63f99bbdf69571e26fca907af032c416591 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Jul 2025 09:31:58 +0000 Subject: Merge `typeid_metadata` and `create_metadata` --- compiler/rustc_codegen_llvm/src/builder.rs | 2 +- compiler/rustc_codegen_llvm/src/builder/autodiff.rs | 16 ++++++++-------- compiler/rustc_codegen_llvm/src/context.rs | 7 ++++--- compiler/rustc_codegen_llvm/src/type_.rs | 10 ++++------ 4 files changed, 17 insertions(+), 18 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 7304460c493..4c5bc8430cc 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1720,7 +1720,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { } else { cfi::typeid_for_fnabi(self.tcx, fn_abi, options) }; - let typeid_metadata = self.cx.typeid_metadata(typeid).unwrap(); + let typeid_metadata = self.cx.create_metadata(typeid); let dbg_loc = self.get_dbg_loc(); // Test whether the function pointer is associated with the type identifier using the diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index 5afb9a60d42..9383903fd02 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -76,12 +76,12 @@ fn match_args_from_caller_to_enzyme<'ll>( outer_pos = 1; } - let enzyme_const = cx.create_metadata("enzyme_const".to_string()).unwrap(); - let enzyme_out = cx.create_metadata("enzyme_out".to_string()).unwrap(); - let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()).unwrap(); - let enzyme_dupv = cx.create_metadata("enzyme_dupv".to_string()).unwrap(); - let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()).unwrap(); - let enzyme_dupnoneedv = cx.create_metadata("enzyme_dupnoneedv".to_string()).unwrap(); + let enzyme_const = cx.create_metadata("enzyme_const".to_string()); + let enzyme_out = cx.create_metadata("enzyme_out".to_string()); + let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()); + let enzyme_dupv = cx.create_metadata("enzyme_dupv".to_string()); + let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()); + let enzyme_dupnoneedv = cx.create_metadata("enzyme_dupnoneedv".to_string()); while activity_pos < inputs.len() { let diff_activity = inputs[activity_pos as usize]; @@ -378,12 +378,12 @@ fn generate_enzyme_call<'ll>( let mut args = Vec::with_capacity(num_args as usize + 1); args.push(fn_to_diff); - let enzyme_primal_ret = cx.create_metadata("enzyme_primal_return".to_string()).unwrap(); + let enzyme_primal_ret = cx.create_metadata("enzyme_primal_return".to_string()); if matches!(attrs.ret_activity, DiffActivity::Dual | DiffActivity::Active) { args.push(cx.get_metadata_value(enzyme_primal_ret)); } if attrs.width > 1 { - let enzyme_width = cx.create_metadata("enzyme_width".to_string()).unwrap(); + let enzyme_width = cx.create_metadata("enzyme_width".to_string()); args.push(cx.get_metadata_value(enzyme_width)); args.push(cx.get_const_int(cx.type_i64(), attrs.width as u64)); } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 90582e23b04..5616c4d4e45 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -473,6 +473,7 @@ pub(crate) unsafe fn create_module<'ll>( #[allow(clippy::option_env_unwrap)] let rustc_producer = format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION")); + let name_metadata = unsafe { llvm::LLVMMDStringInContext2( llcx, @@ -698,10 +699,10 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { } } - pub(crate) fn create_metadata(&self, name: String) -> Option<&'ll Metadata> { - Some(unsafe { + pub(crate) fn create_metadata(&self, name: String) -> &'ll Metadata { + unsafe { llvm::LLVMMDStringInContext2(self.llcx(), name.as_ptr() as *const c_char, name.len()) - }) + } } pub(crate) fn get_functions(&self) -> Vec<&'ll Value> { diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index ee472e75ed4..5b19ca91e4d 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -2,7 +2,7 @@ use std::borrow::Borrow; use std::hash::{Hash, Hasher}; use std::{fmt, ptr}; -use libc::{c_char, c_uint}; +use libc::c_uint; use rustc_abi::{AddressSpace, Align, Integer, Reg, Size}; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::traits::*; @@ -299,7 +299,7 @@ impl<'ll, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn add_type_metadata(&self, function: &'ll Value, typeid: String) { - let typeid_metadata = self.typeid_metadata(typeid).unwrap(); + let typeid_metadata = self.create_metadata(typeid); unsafe { let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; llvm::LLVMRustGlobalAddMetadata( @@ -311,7 +311,7 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn set_type_metadata(&self, function: &'ll Value, typeid: String) { - let typeid_metadata = self.typeid_metadata(typeid).unwrap(); + let typeid_metadata = self.create_metadata(typeid); unsafe { let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; llvm::LLVMGlobalSetMetadata( @@ -323,9 +323,7 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn typeid_metadata(&self, typeid: String) -> Option<&'ll Metadata> { - Some(unsafe { - llvm::LLVMMDStringInContext2(self.llcx, typeid.as_ptr() as *const c_char, typeid.len()) - }) + Some(self.create_metadata(typeid)) } fn add_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) { -- cgit 1.4.1-3-g733a5 From 56d22cd29ff6d3ea1fa8972462ad94792960b1ef Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Jul 2025 09:36:19 +0000 Subject: Use context methods instead of directly calling FFI --- compiler/rustc_codegen_llvm/src/builder.rs | 4 +--- compiler/rustc_codegen_llvm/src/consts.rs | 8 +------- compiler/rustc_codegen_llvm/src/context.rs | 14 +++++--------- compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs | 8 ++------ 4 files changed, 9 insertions(+), 25 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 4c5bc8430cc..3c64cb79d5e 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -303,9 +303,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } let id_str = "branch_weights"; - let id = unsafe { - llvm::LLVMMDStringInContext2(self.cx.llcx, id_str.as_ptr().cast(), id_str.len()) - }; + let id = self.cx.create_metadata(id_str.into()); // For switch instructions with 2 targets, the `llvm.expect` intrinsic is used. // This function handles switch instructions with more than 2 targets and it needs to diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 27f6a119727..40e686b253c 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -477,13 +477,7 @@ impl<'ll> CodegenCx<'ll, '_> { .unwrap_or(true) { if let Some(section) = attrs.link_section { - let section = unsafe { - llvm::LLVMMDStringInContext2( - self.llcx, - section.as_str().as_c_char_ptr(), - section.as_str().len(), - ) - }; + let section = self.create_metadata(section.as_str().into()); assert!(alloc.provenance().ptrs().is_empty()); // The `inspect` method is okay here because we checked for provenance, and diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 5616c4d4e45..51ba3fb8089 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -34,7 +34,6 @@ use smallvec::SmallVec; use crate::back::write::to_llvm_code_model; use crate::callee::get_fn; -use crate::common::AsCCharPtr; use crate::debuginfo::metadata::apply_vcall_visibility_metadata; use crate::llvm::Metadata; use crate::type_::Type; @@ -169,6 +168,8 @@ pub(crate) unsafe fn create_module<'ll>( let mod_name = SmallCStr::new(mod_name); let llmod = unsafe { llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx) }; + let cx = SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size()); + let mut target_data_layout = sess.target.data_layout.to_string(); let llvm_version = llvm_util::get_version(); @@ -474,18 +475,13 @@ pub(crate) unsafe fn create_module<'ll>( let rustc_producer = format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION")); - let name_metadata = unsafe { - llvm::LLVMMDStringInContext2( - llcx, - rustc_producer.as_c_char_ptr(), - rustc_producer.as_bytes().len(), - ) - }; + let name_metadata = cx.create_metadata(rustc_producer); + unsafe { llvm::LLVMAddNamedMetadataOperand( llmod, c"llvm.ident".as_ptr(), - &llvm::LLVMMetadataAsValue(llcx, llvm::LLVMMDNodeInContext2(llcx, &name_metadata, 1)), + &cx.get_metadata_value(llvm::LLVMMDNodeInContext2(llcx, &name_metadata, 1)), ); } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 1a50fb5823b..3fdf4e19d58 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -5,7 +5,7 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use std::{iter, ptr}; -use libc::{c_char, c_longlong, c_uint}; +use libc::{c_longlong, c_uint}; use rustc_abi::{Align, Size}; use rustc_codegen_ssa::debuginfo::type_names::{VTableNameKind, cpp_like_debuginfo}; use rustc_codegen_ssa::traits::*; @@ -1582,13 +1582,9 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( }; let trait_ref_typeid = typeid_for_trait_ref(cx.tcx, trait_ref); + let typeid = cx.create_metadata(trait_ref_typeid); unsafe { - let typeid = llvm::LLVMMDStringInContext2( - cx.llcx, - trait_ref_typeid.as_ptr() as *const c_char, - trait_ref_typeid.as_bytes().len(), - ); let v = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid]; llvm::LLVMRustGlobalAddMetadata( vtable, -- cgit 1.4.1-3-g733a5 From 7f95f042677f86df55da58cdebe9ce31a1e928a8 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Jul 2025 09:48:46 +0000 Subject: Eliminate all direct uses of LLVMMDStringInContext2 --- compiler/rustc_codegen_llvm/src/builder.rs | 5 ++--- compiler/rustc_codegen_llvm/src/builder/autodiff.rs | 16 ++++++++-------- compiler/rustc_codegen_llvm/src/consts.rs | 8 +++----- compiler/rustc_codegen_llvm/src/context.rs | 4 ++-- compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs | 2 +- compiler/rustc_codegen_llvm/src/declare.rs | 4 ++-- compiler/rustc_codegen_llvm/src/type_.rs | 6 +++--- compiler/rustc_codegen_ssa/src/meth.rs | 3 ++- compiler/rustc_codegen_ssa/src/traits/type_.rs | 6 +++--- 9 files changed, 26 insertions(+), 28 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 3c64cb79d5e..514923ad6f3 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -302,8 +302,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { return; } - let id_str = "branch_weights"; - let id = self.cx.create_metadata(id_str.into()); + let id = self.cx.create_metadata(b"branch_weights"); // For switch instructions with 2 targets, the `llvm.expect` intrinsic is used. // This function handles switch instructions with more than 2 targets and it needs to @@ -1718,7 +1717,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { } else { cfi::typeid_for_fnabi(self.tcx, fn_abi, options) }; - let typeid_metadata = self.cx.create_metadata(typeid); + let typeid_metadata = self.cx.create_metadata(typeid.as_bytes()); let dbg_loc = self.get_dbg_loc(); // Test whether the function pointer is associated with the type identifier using the diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index 9383903fd02..dff68472847 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -76,12 +76,12 @@ fn match_args_from_caller_to_enzyme<'ll>( outer_pos = 1; } - let enzyme_const = cx.create_metadata("enzyme_const".to_string()); - let enzyme_out = cx.create_metadata("enzyme_out".to_string()); - let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()); - let enzyme_dupv = cx.create_metadata("enzyme_dupv".to_string()); - let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()); - let enzyme_dupnoneedv = cx.create_metadata("enzyme_dupnoneedv".to_string()); + let enzyme_const = cx.create_metadata(b"enzyme_const"); + let enzyme_out = cx.create_metadata(b"enzyme_out"); + let enzyme_dup = cx.create_metadata(b"enzyme_dup"); + let enzyme_dupv = cx.create_metadata(b"enzyme_dupv"); + let enzyme_dupnoneed = cx.create_metadata(b"enzyme_dupnoneed"); + let enzyme_dupnoneedv = cx.create_metadata(b"enzyme_dupnoneedv"); while activity_pos < inputs.len() { let diff_activity = inputs[activity_pos as usize]; @@ -378,12 +378,12 @@ fn generate_enzyme_call<'ll>( let mut args = Vec::with_capacity(num_args as usize + 1); args.push(fn_to_diff); - let enzyme_primal_ret = cx.create_metadata("enzyme_primal_return".to_string()); + let enzyme_primal_ret = cx.create_metadata(b"enzyme_primal_return"); if matches!(attrs.ret_activity, DiffActivity::Dual | DiffActivity::Active) { args.push(cx.get_metadata_value(enzyme_primal_ret)); } if attrs.width > 1 { - let enzyme_width = cx.create_metadata("enzyme_width".to_string()); + let enzyme_width = cx.create_metadata(b"enzyme_width"); args.push(cx.get_metadata_value(enzyme_width)); args.push(cx.get_const_int(cx.type_i64(), attrs.width as u64)); } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 40e686b253c..0b96b63bc85 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::{self, Instance}; use rustc_middle::{bug, span_bug}; use tracing::{debug, instrument, trace}; -use crate::common::{AsCCharPtr, CodegenCx}; +use crate::common::CodegenCx; use crate::errors::SymbolAlreadyDefined; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; @@ -477,16 +477,14 @@ impl<'ll> CodegenCx<'ll, '_> { .unwrap_or(true) { if let Some(section) = attrs.link_section { - let section = self.create_metadata(section.as_str().into()); + let section = self.create_metadata(section.as_str().as_bytes()); assert!(alloc.provenance().ptrs().is_empty()); // The `inspect` method is okay here because we checked for provenance, and // because we are doing this access to inspect the final interpreter state (not // as part of the interpreter execution). let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()); - let alloc = unsafe { - llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len()) - }; + let alloc = self.create_metadata(bytes); let data = [section, alloc]; let meta = unsafe { llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()) }; diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 51ba3fb8089..6a23becaa96 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -475,7 +475,7 @@ pub(crate) unsafe fn create_module<'ll>( let rustc_producer = format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION")); - let name_metadata = cx.create_metadata(rustc_producer); + let name_metadata = cx.create_metadata(rustc_producer.as_bytes()); unsafe { llvm::LLVMAddNamedMetadataOperand( @@ -695,7 +695,7 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { } } - pub(crate) fn create_metadata(&self, name: String) -> &'ll Metadata { + pub(crate) fn create_metadata(&self, name: &[u8]) -> &'ll Metadata { unsafe { llvm::LLVMMDStringInContext2(self.llcx(), name.as_ptr() as *const c_char, name.len()) } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 3fdf4e19d58..0e9dbfba658 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1582,7 +1582,7 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( }; let trait_ref_typeid = typeid_for_trait_ref(cx.tcx, trait_ref); - let typeid = cx.create_metadata(trait_ref_typeid); + let typeid = cx.create_metadata(trait_ref_typeid.as_bytes()); unsafe { let v = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid]; diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 710032c774b..eb75716d768 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -176,7 +176,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { { let typeid = cfi::typeid_for_instance(self.tcx, instance, options); if typeids.insert(typeid.clone()) { - self.add_type_metadata(llfn, typeid); + self.add_type_metadata(llfn, typeid.as_bytes()); } } } else { @@ -189,7 +189,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { .map(cfi::TypeIdOptions::from_iter) { let typeid = cfi::typeid_for_fnabi(self.tcx, fn_abi, options); - self.add_type_metadata(llfn, typeid); + self.add_type_metadata(llfn, typeid.as_bytes()); } } } diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 5b19ca91e4d..89365503138 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -298,7 +298,7 @@ impl<'ll, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { - fn add_type_metadata(&self, function: &'ll Value, typeid: String) { + fn add_type_metadata(&self, function: &'ll Value, typeid: &[u8]) { let typeid_metadata = self.create_metadata(typeid); unsafe { let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; @@ -310,7 +310,7 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - fn set_type_metadata(&self, function: &'ll Value, typeid: String) { + fn set_type_metadata(&self, function: &'ll Value, typeid: &[u8]) { let typeid_metadata = self.create_metadata(typeid); unsafe { let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; @@ -322,7 +322,7 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - fn typeid_metadata(&self, typeid: String) -> Option<&'ll Metadata> { + fn typeid_metadata(&self, typeid: &[u8]) -> Option<&'ll Metadata> { Some(self.create_metadata(typeid)) } diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index 2aa5c3c27ea..34ad35a729b 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -139,7 +139,8 @@ pub(crate) fn load_vtable<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( && bx.cx().sess().lto() == Lto::Fat { if let Some(trait_ref) = dyn_trait_in_self(bx.tcx(), ty) { - let typeid = bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref)).unwrap(); + let typeid = + bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref).as_bytes()).unwrap(); let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid); return func; } else if nonnull { diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index dcd9e25b2c9..32c24965e1b 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -154,9 +154,9 @@ pub trait LayoutTypeCodegenMethods<'tcx>: BackendTypes { // For backends that support CFI using type membership (i.e., testing whether a given pointer is // associated with a type identifier). pub trait TypeMembershipCodegenMethods<'tcx>: BackendTypes { - fn add_type_metadata(&self, _function: Self::Function, _typeid: String) {} - fn set_type_metadata(&self, _function: Self::Function, _typeid: String) {} - fn typeid_metadata(&self, _typeid: String) -> Option { + fn add_type_metadata(&self, _function: Self::Function, _typeid: &[u8]) {} + fn set_type_metadata(&self, _function: Self::Function, _typeid: &[u8]) {} + fn typeid_metadata(&self, _typeid: &[u8]) -> Option { None } fn add_kcfi_type_metadata(&self, _function: Self::Function, _typeid: u32) {} -- cgit 1.4.1-3-g733a5 From 9c8ab891876b37aac458a7461d904fe593856745 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 2 Jul 2025 11:12:54 +0200 Subject: use `codegen_instance_attrs` where an instance is (easily) available --- compiler/rustc_codegen_cranelift/src/driver/jit.rs | 2 +- compiler/rustc_codegen_cranelift/src/driver/mod.rs | 2 +- compiler/rustc_codegen_gcc/src/attributes.rs | 2 +- compiler/rustc_codegen_gcc/src/callee.rs | 2 +- compiler/rustc_codegen_gcc/src/mono_item.rs | 2 +- compiler/rustc_codegen_llvm/src/attributes.rs | 2 +- compiler/rustc_codegen_llvm/src/callee.rs | 2 +- compiler/rustc_codegen_llvm/src/mono_item.rs | 4 ++-- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 1 - compiler/rustc_codegen_ssa/src/mir/naked_asm.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 12 ++++++++++-- compiler/rustc_codegen_ssa/src/mono_item.rs | 2 +- compiler/rustc_const_eval/src/interpret/memory.rs | 2 +- compiler/rustc_middle/src/middle/codegen_fn_attrs.rs | 4 +++- compiler/rustc_middle/src/mir/mono.rs | 13 ++++++------- compiler/rustc_middle/src/query/mod.rs | 9 +++++++++ compiler/rustc_symbol_mangling/src/lib.rs | 2 +- src/tools/miri/src/machine.rs | 4 ++-- 18 files changed, 43 insertions(+), 26 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index b1f185b551c..b3497503bf0 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -127,7 +127,7 @@ fn codegen_and_compile_fn<'tcx>( module: &mut dyn Module, instance: Instance<'tcx>, ) { - if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) { + if tcx.codegen_instance_attrs(instance.def).flags.contains(CodegenFnAttrFlags::NAKED) { tcx.dcx() .span_fatal(tcx.def_span(instance.def_id()), "Naked asm is not supported in JIT mode"); } diff --git a/compiler/rustc_codegen_cranelift/src/driver/mod.rs b/compiler/rustc_codegen_cranelift/src/driver/mod.rs index ffd47cace38..8f83c30b598 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/mod.rs @@ -35,7 +35,7 @@ fn predefine_mono_items<'tcx>( is_compiler_builtins, ); let is_naked = tcx - .codegen_fn_attrs(instance.def_id()) + .codegen_instance_attrs(instance.def) .flags .contains(CodegenFnAttrFlags::NAKED); module diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs index bf0927dc590..7a1ae6ca9c8 100644 --- a/compiler/rustc_codegen_gcc/src/attributes.rs +++ b/compiler/rustc_codegen_gcc/src/attributes.rs @@ -87,7 +87,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>( #[cfg_attr(not(feature = "master"), allow(unused_variables))] func: Function<'gcc>, instance: ty::Instance<'tcx>, ) { - let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id()); + let codegen_fn_attrs = cx.tcx.codegen_instance_attrs(instance.def); #[cfg(feature = "master")] { diff --git a/compiler/rustc_codegen_gcc/src/callee.rs b/compiler/rustc_codegen_gcc/src/callee.rs index 189ac7cd779..e7ca95af594 100644 --- a/compiler/rustc_codegen_gcc/src/callee.rs +++ b/compiler/rustc_codegen_gcc/src/callee.rs @@ -105,7 +105,7 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) let is_hidden = if is_generic { // This is a monomorphization of a generic function. if !(cx.tcx.sess.opts.share_generics() - || tcx.codegen_fn_attrs(instance_def_id).inline + || tcx.codegen_instance_attrs(instance.def).inline == rustc_attr_data_structures::InlineAttr::Never) { // When not sharing generics, all instances are in the same diff --git a/compiler/rustc_codegen_gcc/src/mono_item.rs b/compiler/rustc_codegen_gcc/src/mono_item.rs index 539e3ac8507..51f35cbdee4 100644 --- a/compiler/rustc_codegen_gcc/src/mono_item.rs +++ b/compiler/rustc_codegen_gcc/src/mono_item.rs @@ -53,7 +53,7 @@ impl<'gcc, 'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); self.linkage.set(base::linkage_to_gcc(linkage)); let decl = self.declare_fn(symbol_name, fn_abi); - //let attrs = self.tcx.codegen_fn_attrs(instance.def_id()); + //let attrs = self.tcx.codegen_instance_attrs(instance.def); attributes::from_fn_attrs(self, decl, instance); diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 1ea5a062254..c32f11b27f3 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -344,7 +344,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( llfn: &'ll Value, instance: ty::Instance<'tcx>, ) { - let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id()); + let codegen_fn_attrs = cx.tcx.codegen_instance_attrs(instance.def); let mut to_add = SmallVec::<[_; 16]>::new(); diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index 6d68eca60af..5a3dd90ab24 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -102,7 +102,7 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t let is_hidden = if is_generic { // This is a monomorphization of a generic function. if !(cx.tcx.sess.opts.share_generics() - || tcx.codegen_fn_attrs(instance_def_id).inline + || tcx.codegen_instance_attrs(instance.def).inline == rustc_attr_data_structures::InlineAttr::Never) { // When not sharing generics, all instances are in the same diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 3f38e1e191b..c471a02baa2 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -55,8 +55,8 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); let lldecl = self.declare_fn(symbol_name, fn_abi, Some(instance)); llvm::set_linkage(lldecl, base::linkage_to_llvm(linkage)); - let attrs = self.tcx.codegen_fn_attrs(instance.def_id()); - base::set_link_section(lldecl, attrs); + let attrs = self.tcx.codegen_instance_attrs(instance.def); + base::set_link_section(lldecl, &attrs); if (linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR) && self.tcx.sess.target.supports_comdat() { diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index a1dd64736fc..85d01d4f938 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -114,7 +114,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { codegen_fn_attrs.export_name = Some(*name); } AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, - AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align), AttributeKind::LinkName { name, .. } => codegen_fn_attrs.link_name = Some(*name), AttributeKind::LinkSection { name, .. } => { diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index beaf8950978..42e435cf0a3 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -128,7 +128,7 @@ fn prefix_and_suffix<'tcx>( let is_arm = tcx.sess.target.arch == "arm"; let is_thumb = tcx.sess.unstable_target_features.contains(&sym::thumb_mode); - let attrs = tcx.codegen_fn_attrs(instance.def_id()); + let attrs = tcx.codegen_instance_attrs(instance.def); let link_section = attrs.link_section.map(|symbol| symbol.as_str().to_string()); // If no alignment is specified, an alignment of 4 bytes is used. diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index e90463aacc8..2587e89417a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -611,11 +611,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty()); let fn_ty = bx.fn_decl_backend_type(fn_abi); let fn_attrs = if bx.tcx().def_kind(instance.def_id()).has_codegen_attrs() { - Some(bx.tcx().codegen_fn_attrs(instance.def_id())) + Some(bx.tcx().codegen_instance_attrs(instance.def)) } else { None }; - bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, &[], None, Some(instance)) + bx.call( + fn_ty, + fn_attrs.as_deref(), + Some(fn_abi), + fn_ptr, + &[], + None, + Some(instance), + ) } else { bx.get_static(def_id) }; diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index 2c3a6de750e..b9040c330fb 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -71,7 +71,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { cx.predefine_static(def_id, linkage, visibility, symbol_name); } MonoItem::Fn(instance) => { - let attrs = cx.tcx().codegen_fn_attrs(instance.def_id()); + let attrs = cx.tcx().codegen_instance_attrs(instance.def); if attrs.flags.contains(CodegenFnAttrFlags::NAKED) { // do not define this function; it will become a global assembly block diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 6414821e21d..0dd274b1b00 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -890,7 +890,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if let Some(fn_val) = self.get_fn_alloc(id) { let align = match fn_val { FnVal::Instance(instance) => { - self.tcx.codegen_fn_attrs(instance.def_id()).alignment.unwrap_or(Align::ONE) + self.tcx.codegen_instance_attrs(instance.def).alignment.unwrap_or(Align::ONE) } // Machine-specific extra functions currently do not support alignment restrictions. FnVal::Other(_) => Align::ONE, diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 92670e7e018..6eae3b51e29 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -20,7 +20,9 @@ impl<'tcx> TyCtxt<'tcx> { // Drop the `#[naked]` attribute on non-item `InstanceKind`s, like the shims that // are generated for indirect function calls. if !matches!(instance_kind, InstanceKind::Item(_)) { - attrs.to_mut().flags.remove(CodegenFnAttrFlags::NAKED); + if attrs.flags.contains(CodegenFnAttrFlags::NAKED) { + attrs.to_mut().flags.remove(CodegenFnAttrFlags::NAKED); + } } attrs diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 47ba850d50d..2d7ddd105bd 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -152,7 +152,7 @@ impl<'tcx> MonoItem<'tcx> { // If the function is #[naked] or contains any other attribute that requires exactly-once // instantiation: // We emit an unused_attributes lint for this case, which should be kept in sync if possible. - let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id()); + let codegen_fn_attrs = tcx.codegen_instance_attrs(instance.def); if codegen_fn_attrs.contains_extern_indicator() || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { @@ -219,7 +219,7 @@ impl<'tcx> MonoItem<'tcx> { // functions the same as those that unconditionally get LocalCopy codegen. It's only when // we get here that we can at least not codegen a #[inline(never)] generic function in all // of our CGUs. - if let InlineAttr::Never = tcx.codegen_fn_attrs(instance.def_id()).inline + if let InlineAttr::Never = codegen_fn_attrs.inline && self.is_generic_fn() { return InstantiationMode::GloballyShared { may_conflict: true }; @@ -234,14 +234,13 @@ impl<'tcx> MonoItem<'tcx> { } pub fn explicit_linkage(&self, tcx: TyCtxt<'tcx>) -> Option { - let def_id = match *self { - MonoItem::Fn(ref instance) => instance.def_id(), - MonoItem::Static(def_id) => def_id, + let instance_kind = match *self { + MonoItem::Fn(ref instance) => instance.def, + MonoItem::Static(def_id) => InstanceKind::Item(def_id), MonoItem::GlobalAsm(..) => return None, }; - let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id); - codegen_fn_attrs.linkage + tcx.codegen_instance_attrs(instance_kind).linkage } /// Returns `true` if this instance is instantiable - whether it has no unsatisfied diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 842d118449a..ec9f6d918e2 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1505,6 +1505,15 @@ rustc_queries! { separate_provide_extern } + /// Returns the `CodegenFnAttrs` for the item at `def_id`. + /// + /// If possible, use `tcx.codegen_instance_attrs` instead. That function takes the + /// instance kind into account. + /// + /// For example, the `#[naked]` attribute should be applied for `InstanceKind::Item`, + /// but should not be applied if the instance kind is `InstanceKind::ReifyShim`. + /// Using this query would include the attribute regardless of the actual instance + /// kind at the call site. query codegen_fn_attrs(def_id: DefId) -> &'tcx CodegenFnAttrs { desc { |tcx| "computing codegen attributes of `{}`", tcx.def_path_str(def_id) } arena_cache diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index a9bf5eae445..6bcb7f6e093 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -180,7 +180,7 @@ fn compute_symbol_name<'tcx>( // FIXME(eddyb) Precompute a custom symbol name based on attributes. let attrs = if tcx.def_kind(def_id).has_codegen_attrs() { - tcx.codegen_fn_attrs(def_id) + &tcx.codegen_instance_attrs(instance.def) } else { CodegenFnAttrs::EMPTY }; diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 35399dbf4cb..e8ae3350e56 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1086,7 +1086,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { ecx: &MiriInterpCx<'tcx>, instance: ty::Instance<'tcx>, ) -> InterpResult<'tcx> { - let attrs = ecx.tcx.codegen_fn_attrs(instance.def_id()); + let attrs = ecx.tcx.codegen_instance_attrs(instance.def); if attrs .target_features .iter() @@ -1790,7 +1790,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { ecx.tcx.sess.opts.unstable_opts.cross_crate_inline_threshold, InliningThreshold::Always ) || !matches!( - ecx.tcx.codegen_fn_attrs(instance.def_id()).inline, + ecx.tcx.codegen_instance_attrs(instance.def).inline, InlineAttr::Never ); !is_generic && !can_be_inlined -- cgit 1.4.1-3-g733a5