diff options
Diffstat (limited to 'compiler/rustc_codegen_llvm/src')
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/abi.rs | 38 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/asm.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/attributes.rs | 14 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/back/write.rs | 89 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/base.rs | 9 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/builder.rs | 34 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/consts.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/context.rs | 15 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs | 43 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/debuginfo/mod.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/intrinsic.rs | 114 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/lib.rs | 74 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 84 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/llvm_util.rs | 38 |
15 files changed, 433 insertions, 139 deletions
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index dca9c1f04d3..d38ff588317 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -1,7 +1,6 @@ use crate::builder::Builder; use crate::context::CodegenCx; use crate::llvm::{self, AttributePlace}; -use crate::llvm_util; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; @@ -53,15 +52,10 @@ pub trait ArgAttributesExt { } fn should_use_mutable_noalias(cx: &CodegenCx<'_, '_>) -> bool { - // LLVM prior to version 12 has known miscompiles in the presence of - // noalias attributes (see #54878). Only enable mutable noalias by - // default for versions we believe to be safe. - cx.tcx - .sess - .opts - .debugging_opts - .mutable_noalias - .unwrap_or_else(|| llvm_util::get_version() >= (12, 0, 0)) + // LLVM prior to version 12 had known miscompiles in the presence of + // noalias attributes (see #54878), but we don't support earlier + // versions at all anymore. We now enable mutable noalias by default. + cx.tcx.sess.opts.debugging_opts.mutable_noalias.unwrap_or(true) } impl ArgAttributesExt for ArgAttributes { @@ -187,9 +181,7 @@ impl LlvmType for CastTarget { let mut args: Vec<_> = self .prefix .iter() - .flat_map(|option_kind| { - option_kind.map(|kind| Reg { kind, size: self.prefix_chunk_size }.llvm_type(cx)) - }) + .flat_map(|option_reg| option_reg.map(|reg| reg.llvm_type(cx))) .chain((0..rest_count).map(|_| rest_ll_unit)) .collect(); @@ -472,6 +464,9 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> { ); } } + PassMode::Cast(cast) => { + cast.attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn); + } _ => {} } for arg in &self.args { @@ -503,8 +498,8 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> { apply(a); apply(b); } - PassMode::Cast(_) => { - apply(&ArgAttributes::new()); + PassMode::Cast(cast) => { + apply(&cast.attrs); } } } @@ -539,6 +534,13 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> { ); } } + PassMode::Cast(cast) => { + cast.attrs.apply_attrs_to_callsite( + llvm::AttributePlace::ReturnValue, + &bx.cx, + callsite, + ); + } _ => {} } if let abi::Abi::Scalar(scalar) = self.ret.layout.abi { @@ -583,8 +585,8 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> { apply(bx.cx, a); apply(bx.cx, b); } - PassMode::Cast(_) => { - apply(bx.cx, &ArgAttributes::new()); + PassMode::Cast(cast) => { + apply(bx.cx, &cast.attrs); } } } @@ -613,7 +615,7 @@ impl AbiBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { fn_abi.apply_attrs_callsite(self, callsite) } - fn get_param(&self, index: usize) -> Self::Value { + fn get_param(&mut self, index: usize) -> Self::Value { llvm::get_param(self.llfn(), index as c_uint) } } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 341a8882416..02096f4abfa 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -13,7 +13,7 @@ use rustc_codegen_ssa::traits::*; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::{bug, span_bug}; +use rustc_middle::{bug, span_bug, ty::Instance}; use rustc_span::{Pos, Span, Symbol}; use rustc_target::abi::*; use rustc_target::asm::*; @@ -120,6 +120,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, line_spans: &[Span], + instance: Instance<'_>, ) { let asm_arch = self.tcx.sess.asm_arch.unwrap(); @@ -135,7 +136,10 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { let is_target_supported = |reg_class: InlineAsmRegClass| { for &(_, feature) in reg_class.supported_types(asm_arch) { if let Some(feature) = feature { - if self.tcx.sess.target_features.contains(&Symbol::intern(feature)) + let codegen_fn_attrs = self.tcx.codegen_fn_attrs(instance.def_id()); + let feature_name = Symbol::intern(feature); + if self.tcx.sess.target_features.contains(&feature_name) + || codegen_fn_attrs.target_features.contains(&feature_name) { return true; } @@ -316,7 +320,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { InlineAsmArch::Mips | InlineAsmArch::Mips64 => {} InlineAsmArch::S390x => {} InlineAsmArch::SpirV => {} - InlineAsmArch::Wasm32 => {} + InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {} InlineAsmArch::Bpf => {} } } diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 659cf9ea070..8e6329a997f 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -12,7 +12,7 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::OptLevel; use rustc_session::Session; use rustc_target::spec::abi::Abi; -use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType}; +use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector}; use crate::attributes; use crate::llvm::AttributePlace::Function; @@ -161,6 +161,17 @@ fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { } } +fn set_stackprotector(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { + let sspattr = match cx.sess().stack_protector() { + StackProtector::None => return, + StackProtector::All => Attribute::StackProtectReq, + StackProtector::Strong => Attribute::StackProtectStrong, + StackProtector::Basic => Attribute::StackProtect, + }; + + sspattr.apply_llfn(Function, llfn) +} + pub fn apply_target_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { let target_cpu = SmallCStr::new(llvm_util::target_cpu(cx.tcx.sess)); llvm::AddFunctionAttrStringValue( @@ -271,6 +282,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty:: set_frame_pointer_type(cx, llfn); set_instrument_function(cx, llfn); set_probestack(cx, llfn); + set_stackprotector(cx, llfn); if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) { Attribute::Cold.apply_llfn(Function, llfn); diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 380dfd38723..460a8cc6912 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -17,6 +17,7 @@ use rustc_codegen_ssa::back::write::{ }; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; +use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::small_c_str::SmallCStr; use rustc_errors::{FatalError, Handler, Level}; use rustc_fs_util::{link_or_copy, path_to_c_string}; @@ -53,6 +54,7 @@ pub fn write_output_file( output: &Path, dwo_output: Option<&Path>, file_type: llvm::FileType, + self_profiler_ref: &SelfProfilerRef, ) -> Result<(), FatalError> { unsafe { let output_c = path_to_c_string(output); @@ -76,6 +78,19 @@ pub fn write_output_file( file_type, ) }; + + // Record artifact sizes for self-profiling + if result == llvm::LLVMRustResult::Success { + let artifact_kind = match file_type { + llvm::FileType::ObjectFile => "object_file", + llvm::FileType::AssemblyFile => "assembly_file", + }; + record_artifact_size(self_profiler_ref, artifact_kind, output); + if let Some(dwo_file) = dwo_output { + record_artifact_size(self_profiler_ref, "dwo_file", dwo_file); + } + } + result.into_result().map_err(|()| { let msg = format!("could not write output to {}", output.display()); llvm_err(handler, &msg) @@ -161,6 +176,7 @@ pub fn target_machine_factory( let ffunction_sections = sess.opts.debugging_opts.function_sections.unwrap_or(sess.target.function_sections); let fdata_sections = ffunction_sections; + let funique_section_names = !sess.opts.debugging_opts.no_unique_section_names; let code_model = to_llvm_code_model(sess.code_model()); @@ -205,6 +221,7 @@ pub fn target_machine_factory( use_softfp, ffunction_sections, fdata_sections, + funique_section_names, trap_unreachable, singlethread, asm_comments, @@ -242,6 +259,7 @@ pub(crate) fn save_temp_bitcode( pub struct DiagnosticHandlers<'a> { data: *mut (&'a CodegenContext<LlvmCodegenBackend>, &'a Handler), llcx: &'a llvm::Context, + old_handler: Option<&'a llvm::DiagnosticHandler>, } impl<'a> DiagnosticHandlers<'a> { @@ -250,12 +268,35 @@ impl<'a> DiagnosticHandlers<'a> { handler: &'a Handler, llcx: &'a llvm::Context, ) -> Self { + let remark_passes_all: bool; + let remark_passes: Vec<CString>; + match &cgcx.remark { + Passes::All => { + remark_passes_all = true; + remark_passes = Vec::new(); + } + Passes::Some(passes) => { + remark_passes_all = false; + remark_passes = + passes.iter().map(|name| CString::new(name.as_str()).unwrap()).collect(); + } + }; + let remark_passes: Vec<*const c_char> = + remark_passes.iter().map(|name: &CString| name.as_ptr()).collect(); let data = Box::into_raw(Box::new((cgcx, handler))); unsafe { + let old_handler = llvm::LLVMRustContextGetDiagnosticHandler(llcx); + llvm::LLVMRustContextConfigureDiagnosticHandler( + llcx, + diagnostic_handler, + data.cast(), + remark_passes_all, + remark_passes.as_ptr(), + remark_passes.len(), + ); llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, data.cast()); - llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, data.cast()); + DiagnosticHandlers { data, llcx, old_handler } } - DiagnosticHandlers { data, llcx } } } @@ -264,7 +305,7 @@ impl<'a> Drop for DiagnosticHandlers<'a> { use std::ptr::null_mut; unsafe { llvm::LLVMRustSetInlineAsmDiagnosticHandler(self.llcx, inline_asm_handler, null_mut()); - llvm::LLVMContextSetDiagnosticHandler(self.llcx, diagnostic_handler, null_mut()); + llvm::LLVMRustContextSetDiagnosticHandler(self.llcx, self.old_handler); drop(Box::from_raw(self.data)); } } @@ -284,7 +325,7 @@ fn report_inline_asm( cookie = 0; } let level = match level { - llvm::DiagnosticLevel::Error => Level::Error, + llvm::DiagnosticLevel::Error => Level::Error { lint: false }, llvm::DiagnosticLevel::Warning => Level::Warning, llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note, }; @@ -320,13 +361,8 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void if enabled { diag_handler.note_without_error(&format!( - "optimization {} for {} at {}:{}:{}: {}", - opt.kind.describe(), - opt.pass_name, - opt.filename, - opt.line, - opt.column, - opt.message + "{}:{}:{}: {}: {}", + opt.filename, opt.line, opt.column, opt.pass_name, opt.message, )); } } @@ -750,6 +786,14 @@ pub(crate) unsafe fn codegen( let thin = ThinBuffer::new(llmod); let data = thin.data(); + if let Some(bitcode_filename) = bc_out.file_name() { + cgcx.prof.artifact_size( + "llvm_bitcode", + bitcode_filename.to_string_lossy(), + data.len() as u64, + ); + } + if config.emit_bc || config.emit_obj == EmitObj::Bitcode { let _timer = cgcx.prof.generic_activity_with_arg( "LLVM_module_codegen_emit_bitcode", @@ -810,6 +854,11 @@ pub(crate) unsafe fn codegen( } let result = llvm::LLVMRustPrintModule(llmod, out_c.as_ptr(), demangle_callback); + + if result == llvm::LLVMRustResult::Success { + record_artifact_size(&cgcx.prof, "llvm_ir", &out); + } + result.into_result().map_err(|()| { let msg = format!("failed to write LLVM IR to {}", out.display()); llvm_err(diag_handler, &msg) @@ -840,6 +889,7 @@ pub(crate) unsafe fn codegen( &path, None, llvm::FileType::AssemblyFile, + &cgcx.prof, ) })?; } @@ -873,6 +923,7 @@ pub(crate) unsafe fn codegen( &obj_out, dwo_out, llvm::FileType::ObjectFile, + &cgcx.prof, ) })?; } @@ -1129,3 +1180,19 @@ fn create_msvc_imps( symbol_name.starts_with(b"__llvm_profile_") } } + +fn record_artifact_size( + self_profiler_ref: &SelfProfilerRef, + artifact_kind: &'static str, + path: &Path, +) { + // Don't stat the file if we are not going to record its size. + if !self_profiler_ref.enabled() { + return; + } + + if let Some(artifact_name) = path.file_name() { + let file_size = std::fs::metadata(path).map(|m| m.len()).unwrap_or(0); + self_profiler_ref.artifact_size(artifact_kind, artifact_name.to_string_lossy(), file_size); + } +} diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 3026c2fa030..8766caef6e3 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -113,8 +113,13 @@ pub fn compile_codegen_unit( let start_time = Instant::now(); let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx); - let (module, _) = - tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result); + let (module, _) = tcx.dep_graph.with_task( + dep_node, + tcx, + cgu_name, + module_codegen, + Some(dep_graph::hash_result), + ); let time_to_codegen = start_time.elapsed(); // We assume that the cost to run LLVM on a CGU is proportional to diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index d5deacf3811..ff88302bf7a 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -604,6 +604,32 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } } + fn type_metadata(&mut self, function: &'ll Value, typeid: String) { + let typeid_metadata = self.typeid_metadata(typeid); + let v = [self.const_usize(0), typeid_metadata]; + unsafe { + llvm::LLVMGlobalSetMetadata( + function, + llvm::MD_type as c_uint, + llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext( + self.cx.llcx, + v.as_ptr(), + v.len() as c_uint, + )), + ) + } + } + + fn typeid_metadata(&mut self, typeid: String) -> Self::Value { + unsafe { + llvm::LLVMMDStringInContext( + self.cx.llcx, + typeid.as_ptr() as *const c_char, + typeid.as_bytes().len() as c_uint, + ) + } + } + fn store(&mut self, val: &'ll Value, ptr: &'ll Value, align: Align) -> &'ll Value { self.store_with_flags(val, ptr, align, MemFlags::empty()) } @@ -705,7 +731,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn fptoui_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> { - if llvm_util::get_version() >= (12, 0, 0) && !self.fptoint_sat_broken_in_llvm() { + if !self.fptoint_sat_broken_in_llvm() { let src_ty = self.cx.val_ty(val); let float_width = self.cx.float_width(src_ty); let int_width = self.cx.int_width(dest_ty); @@ -717,7 +743,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn fptosi_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> { - if llvm_util::get_version() >= (12, 0, 0) && !self.fptoint_sat_broken_in_llvm() { + if !self.fptoint_sat_broken_in_llvm() { let src_ty = self.cx.val_ty(val); let float_width = self.cx.float_width(src_ty); let int_width = self.cx.int_width(dest_ty); @@ -743,7 +769,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // we like. To ensure that LLVM picks the right instruction we choose // the raw wasm intrinsic functions which avoid LLVM inserting all the // other control flow automatically. - if self.sess().target.arch == "wasm32" { + if self.sess().target.is_like_wasm { let src_ty = self.cx.val_ty(val); if self.cx.type_kind(src_ty) != TypeKind::Vector { let float_width = self.cx.float_width(src_ty); @@ -765,7 +791,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn fptosi(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { // see `fptoui` above for why wasm is different here - if self.sess().target.arch == "wasm32" { + if self.sess().target.is_like_wasm { let src_ty = self.cx.val_ty(val); if self.cx.type_kind(src_ty) != TypeKind::Vector { let float_width = self.cx.float_width(src_ty); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 1afa6f02836..b154ced42f0 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -490,7 +490,7 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> { // Wasm statics with custom link sections get special treatment as they // go into custom sections of the wasm executable. - if self.tcx.sess.opts.target_triple.triple().starts_with("wasm32") { + if self.tcx.sess.target.is_like_wasm { if let Some(section) = attrs.link_section { let section = llvm::LLVMMDStringInContext( self.llcx, diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 257a0ac89d8..613a8df891c 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -134,9 +134,6 @@ pub unsafe fn create_module( let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx); let mut target_data_layout = sess.target.data_layout.clone(); - if llvm_util::get_version() < (12, 0, 0) && sess.target.arch == "powerpc64" { - target_data_layout = target_data_layout.replace("-v256:256:256-v512:512:512", ""); - } if llvm_util::get_version() < (13, 0, 0) { if sess.target.arch == "powerpc64" { target_data_layout = target_data_layout.replace("-S128", ""); @@ -221,6 +218,15 @@ pub unsafe fn create_module( llvm::LLVMRustAddModuleFlag(llmod, avoid_plt, 1); } + if sess.is_sanitizer_cfi_enabled() { + // FIXME(rcvalle): Add support for non canonical jump tables. + let canonical_jump_tables = "CFI Canonical Jump Tables\0".as_ptr().cast(); + // FIXME(rcvalle): Add it with Override behavior flag--LLVMRustAddModuleFlag adds it with + // Warning behavior flag. Add support for specifying the behavior flag to + // LLVMRustAddModuleFlag. + llvm::LLVMRustAddModuleFlag(llmod, canonical_jump_tables, 1); + } + // Control Flow Guard is currently only supported by the MSVC linker on Windows. if sess.target.is_like_msvc { match sess.opts.cg.control_flow_guard { @@ -591,7 +597,6 @@ impl CodegenCx<'b, 'tcx> { ifn!("llvm.trap", fn() -> void); ifn!("llvm.debugtrap", fn() -> void); ifn!("llvm.frameaddress", fn(t_i32) -> i8p); - ifn!("llvm.sideeffect", fn() -> void); ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32); ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64); @@ -779,6 +784,8 @@ impl CodegenCx<'b, 'tcx> { ifn!("llvm.instrprof.increment", fn(i8p, t_i64, t_i32, t_i32) -> void); } + ifn!("llvm.type.test", fn(i8p, self.type_metadata()) -> i1); + if self.sess().opts.debuginfo != DebugInfo::None { ifn!("llvm.dbg.declare", fn(self.type_metadata(), self.type_metadata()) -> void); ifn!("llvm.dbg.value", fn(self.type_metadata(), t_i64, self.type_metadata()) -> void); diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 6830864ba04..0390caaec33 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -9,6 +9,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_llvm::RustString; use rustc_middle::mir::coverage::CodeRegion; +use rustc_middle::ty::TyCtxt; use rustc_span::Symbol; use std::ffi::CString; @@ -17,10 +18,11 @@ use tracing::debug; /// Generates and exports the Coverage Map. /// -/// This Coverage Map complies with Coverage Mapping Format version 4 (zero-based encoded as 3), -/// as defined at [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format) -/// and published in Rust's November 2020 fork of LLVM. This version is supported by the LLVM -/// coverage tools (`llvm-profdata` and `llvm-cov`) bundled with Rust's fork of LLVM. +/// Rust Coverage Map generation supports LLVM Coverage Mapping Format versions +/// 5 (LLVM 12, only) and 6 (zero-based encoded as 4 and 5, respectively), as defined at +/// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format). +/// These versions are supported by the LLVM coverage tools (`llvm-profdata` and `llvm-cov`) +/// bundled with Rust's fork of LLVM. /// /// Consequently, Rust's bundled version of Clang also generates Coverage Maps compliant with /// the same version. Clang's implementation of Coverage Map generation was referenced when @@ -30,11 +32,12 @@ use tracing::debug; pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { let tcx = cx.tcx; - // Ensure LLVM supports Coverage Map Version 4 (encoded as a zero-based value: 3). - // If not, the LLVM Version must be less than 11. + // Ensure the installed version of LLVM supports at least Coverage Map + // Version 5 (encoded as a zero-based value: 4), which was introduced with + // LLVM 12. let version = coverageinfo::mapping_version(); - if version != 3 { - tcx.sess.fatal("rustc option `-Z instrument-coverage` requires LLVM 11 or higher."); + if version < 4 { + tcx.sess.fatal("rustc option `-Z instrument-coverage` requires LLVM 12 or higher."); } debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name()); @@ -57,7 +60,7 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { return; } - let mut mapgen = CoverageMapGenerator::new(); + let mut mapgen = CoverageMapGenerator::new(tcx, version); // Encode coverage mappings and generate function records let mut function_data = Vec::new(); @@ -112,8 +115,26 @@ struct CoverageMapGenerator { } impl CoverageMapGenerator { - fn new() -> Self { - Self { filenames: FxIndexSet::default() } + fn new(tcx: TyCtxt<'_>, version: u32) -> Self { + let mut filenames = FxIndexSet::default(); + if version >= 5 { + // LLVM Coverage Mapping Format version 6 (zero-based encoded as 5) + // requires setting the first filename to the compilation directory. + // Since rustc generates coverage maps with relative paths, the + // compilation directory can be combined with the the relative paths + // to get absolute paths, if needed. + let working_dir = tcx + .sess + .opts + .working_dir + .remapped_path_if_available() + .to_string_lossy() + .to_string(); + let c_filename = + CString::new(working_dir).expect("null error converting filename to C string"); + filenames.insert(c_filename); + } + Self { filenames } } /// Using the `expressions` and `counter_regions` collected for the current function, generate diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index cd29f2af016..10c7bb2eaea 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1525,14 +1525,12 @@ fn generator_layout_and_saved_local_names( // Deref of the `Pin<&mut Self>` state argument. mir::ProjectionElem::Field(..), mir::ProjectionElem::Deref, - // Field of a variant of the state. mir::ProjectionElem::Downcast(_, variant), mir::ProjectionElem::Field(field, _), ] => { - let name = &mut generator_saved_local_names[ - generator_layout.variant_fields[variant][field] - ]; + let name = &mut generator_saved_local_names + [generator_layout.variant_fields[variant][field]]; if name.is_none() { name.replace(var.name); } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 1f1bd73c7d0..2a6bf7d9b1a 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -322,7 +322,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { type_names::push_item_name(self.tcx(), def_id, false, &mut name); // Find the enclosing function, in case this is a closure. - let enclosing_fn_def_id = self.tcx().closure_base_def_id(def_id); + let enclosing_fn_def_id = self.tcx().typeck_root_def_id(def_id); // Get_template_parameters() will append a `<...>` clause to the function // name if necessary. diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index c43141c7695..a7e34b08059 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -19,7 +19,7 @@ use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf}; use rustc_middle::ty::{self, Ty}; use rustc_middle::{bug, span_bug}; use rustc_span::{sym, symbol::kw, Span, Symbol}; -use rustc_target::abi::{self, HasDataLayout, Primitive}; +use rustc_target::abi::{self, Align, HasDataLayout, Primitive}; use rustc_target::spec::{HasTargetSpec, PanicStrategy}; use std::cmp::Ordering; @@ -392,13 +392,12 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { self.call_intrinsic("llvm.expect.i1", &[cond, self.const_bool(expected)]) } - fn sideeffect(&mut self) { - // This kind of check would make a ton of sense in the caller, but currently the only - // caller of this function is in `rustc_codegen_ssa`, which is agnostic to whether LLVM - // codegen backend being used, and so is unable to check the LLVM version. - if unsafe { llvm::LLVMRustVersionMajor() } < 12 { - self.call_intrinsic("llvm.sideeffect", &[]); - } + fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value { + // Test the called operand using llvm.type.test intrinsic. The LowerTypeTests link-time + // optimization pass replaces calls to this intrinsic with code to test type membership. + let i8p_ty = self.type_i8p(); + let bitcast = self.bitcast(pointer, i8p_ty); + self.call_intrinsic("llvm.type.test", &[bitcast, typeid]) } fn va_start(&mut self, va_list: &'ll Value) -> &'ll Value { @@ -849,28 +848,39 @@ fn generic_simd_intrinsic( let arg_tys = sig.inputs(); if name == sym::simd_select_bitmask { - let in_ty = arg_tys[0]; - let m_len = match in_ty.kind() { - // Note that this `.unwrap()` crashes for isize/usize, that's sort - // of intentional as there's not currently a use case for that. - ty::Int(i) => i.bit_width().unwrap(), - ty::Uint(i) => i.bit_width().unwrap(), - _ => return_error!("`{}` is not an integral type", in_ty), - }; require_simd!(arg_tys[1], "argument"); - let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); - require!( - // Allow masks for vectors with fewer than 8 elements to be - // represented with a u8 or i8. - m_len == v_len || (m_len == 8 && v_len < 8), - "mismatched lengths: mask length `{}` != other vector length `{}`", - m_len, - v_len - ); + let (len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); + + let expected_int_bits = (len.max(8) - 1).next_power_of_two(); + let expected_bytes = len / 8 + ((len % 8 > 0) as u64); + + let mask_ty = arg_tys[0]; + let mask = match mask_ty.kind() { + ty::Int(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(), + ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(), + ty::Array(elem, len) + if matches!(elem.kind(), ty::Uint(ty::UintTy::U8)) + && len.try_eval_usize(bx.tcx, ty::ParamEnv::reveal_all()) + == Some(expected_bytes) => + { + let place = PlaceRef::alloca(bx, args[0].layout); + args[0].val.store(bx, place); + let int_ty = bx.type_ix(expected_bytes * 8); + let ptr = bx.pointercast(place.llval, bx.cx.type_ptr_to(int_ty)); + bx.load(int_ty, ptr, Align::ONE) + } + _ => return_error!( + "invalid bitmask `{}`, expected `u{}` or `[u8; {}]`", + mask_ty, + expected_int_bits, + expected_bytes + ), + }; + let i1 = bx.type_i1(); - let im = bx.type_ix(v_len); - let i1xn = bx.type_vector(i1, v_len); - let m_im = bx.trunc(args[0].immediate(), im); + let im = bx.type_ix(len); + let i1xn = bx.type_vector(i1, len); + let m_im = bx.trunc(mask, im); let m_i1s = bx.bitcast(m_im, i1xn); return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); } @@ -1048,16 +1058,16 @@ fn generic_simd_intrinsic( if name == sym::simd_bitmask { // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a - // vector mask and returns an unsigned integer containing the most - // significant bit (MSB) of each lane. - - // If the vector has less than 8 lanes, a u8 is returned with zeroed - // trailing bits. + // vector mask and returns the most significant bit (MSB) of each lane in the form + // of either: + // * an unsigned integer + // * an array of `u8` + // If the vector has less than 8 lanes, a u8 is returned with zeroed trailing bits. + // + // The bit order of the result depends on the byte endianness, LSB-first for little + // endian and MSB-first for big endian. let expected_int_bits = in_len.max(8); - match ret_ty.kind() { - ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => (), - _ => return_error!("bitmask `{}`, expected `u{}`", ret_ty, expected_int_bits), - } + let expected_bytes = expected_int_bits / 8 + ((expected_int_bits % 8 > 0) as u64); // Integer vector <i{in_bitwidth} x in_len>: let (i_xn, in_elem_bitwidth) = match in_elem.kind() { @@ -1087,8 +1097,34 @@ fn generic_simd_intrinsic( let i1xn = bx.trunc(i_xn_msb, bx.type_vector(bx.type_i1(), in_len)); // Bitcast <i1 x N> to iN: let i_ = bx.bitcast(i1xn, bx.type_ix(in_len)); - // Zero-extend iN to the bitmask type: - return Ok(bx.zext(i_, bx.type_ix(expected_int_bits))); + + match ret_ty.kind() { + ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => { + // Zero-extend iN to the bitmask type: + return Ok(bx.zext(i_, bx.type_ix(expected_int_bits))); + } + ty::Array(elem, len) + if matches!(elem.kind(), ty::Uint(ty::UintTy::U8)) + && len.try_eval_usize(bx.tcx, ty::ParamEnv::reveal_all()) + == Some(expected_bytes) => + { + // Zero-extend iN to the array lengh: + let ze = bx.zext(i_, bx.type_ix(expected_bytes * 8)); + + // Convert the integer to a byte array + let ptr = bx.alloca(bx.type_ix(expected_bytes * 8), Align::ONE); + bx.store(ze, ptr, Align::ONE); + let array_ty = bx.type_array(bx.type_i8(), expected_bytes); + let ptr = bx.pointercast(ptr, bx.cx.type_ptr_to(array_ty)); + return Ok(bx.load(array_ty, ptr, Align::ONE)); + } + _ => return_error!( + "cannot return `{}`, expected `u{}` or `[u8; {}]`", + ret_ty, + expected_int_bits, + expected_bytes + ), + } } fn simd_simple_float_intrinsic( diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 8f4d79e7147..c66d7d872c9 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -76,6 +76,27 @@ mod value; #[derive(Clone)] pub struct LlvmCodegenBackend(()); +struct TimeTraceProfiler { + enabled: bool, +} + +impl TimeTraceProfiler { + fn new(enabled: bool) -> Self { + if enabled { + unsafe { llvm::LLVMTimeTraceProfilerInitialize() } + } + TimeTraceProfiler { enabled } + } +} + +impl Drop for TimeTraceProfiler { + fn drop(&mut self) { + if self.enabled { + unsafe { llvm::LLVMTimeTraceProfilerFinishThread() } + } + } +} + impl ExtraBackendMethods for LlvmCodegenBackend { fn new_metadata(&self, tcx: TyCtxt<'_>, mod_name: &str) -> ModuleLlvm { ModuleLlvm::new_metadata(tcx, mod_name) @@ -119,6 +140,34 @@ impl ExtraBackendMethods for LlvmCodegenBackend { fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str> { llvm_util::tune_cpu(sess) } + + fn spawn_thread<F, T>(time_trace: bool, f: F) -> std::thread::JoinHandle<T> + where + F: FnOnce() -> T, + F: Send + 'static, + T: Send + 'static, + { + std::thread::spawn(move || { + let _profiler = TimeTraceProfiler::new(time_trace); + f() + }) + } + + fn spawn_named_thread<F, T>( + time_trace: bool, + name: String, + f: F, + ) -> std::io::Result<std::thread::JoinHandle<T>> + where + F: FnOnce() -> T, + F: Send + 'static, + T: Send + 'static, + { + std::thread::Builder::new().name(name).spawn(move || { + let _profiler = TimeTraceProfiler::new(time_trace); + f() + }) + } } impl WriteBackendMethods for LlvmCodegenBackend { @@ -239,6 +288,31 @@ impl CodegenBackend for LlvmCodegenBackend { } println!(); } + PrintRequest::StackProtectorStrategies => { + println!( + r#"Available stack protector strategies: + all + Generate stack canaries in all functions. + + strong + Generate stack canaries in a function if it either: + - has a local variable of `[T; N]` type, regardless of `T` and `N` + - takes the address of a local variable. + + (Note that a local variable being borrowed is not equivalent to its + address being taken: e.g. some borrows may be removed by optimization, + while by-value argument passing may be implemented with reference to a + local stack variable in the ABI.) + + basic + Generate stack canaries in functions with: + - local variables of `[T; N]` type, where `T` is byte-sized and `N` > 8. + + none + Do not generate stack canaries. +"# + ); + } req => llvm_util::print(req, sess), } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 4c9ae4faf72..2ef4c871825 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -166,6 +166,9 @@ pub enum Attribute { InaccessibleMemOnly = 27, SanitizeHWAddress = 28, WillReturn = 29, + StackProtectReq = 30, + StackProtectStrong = 31, + StackProtect = 32, } /// LLVMIntPredicate @@ -416,6 +419,7 @@ pub enum MetadataType { MD_nontemporal = 9, MD_mem_parallel_loop_access = 10, MD_nonnull = 11, + MD_type = 19, } /// LLVMRustAsmDialect @@ -671,13 +675,17 @@ pub struct OperandBundleDef<'a>(InvariantOpaque<'a>); #[repr(C)] pub struct Linker<'a>(InvariantOpaque<'a>); -pub type DiagnosticHandler = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void); -pub type InlineAsmDiagHandler = unsafe extern "C" fn(&SMDiagnostic, *const c_void, c_uint); +extern "C" { + pub type DiagnosticHandler; +} + +pub type DiagnosticHandlerTy = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void); +pub type InlineAsmDiagHandlerTy = unsafe extern "C" fn(&SMDiagnostic, *const c_void, c_uint); pub mod coverageinfo { use super::coverage_map; - /// Aligns with [llvm::coverage::CounterMappingRegion::RegionKind](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L206-L222) + /// Aligns with [llvm::coverage::CounterMappingRegion::RegionKind](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L209-L230) #[derive(Copy, Clone, Debug)] #[repr(C)] pub enum RegionKind { @@ -696,11 +704,16 @@ pub mod coverageinfo { /// A GapRegion is like a CodeRegion, but its count is only set as the /// line execution count when its the only region in the line. GapRegion = 3, + + /// A BranchRegion represents leaf-level boolean expressions and is + /// associated with two counters, each representing the number of times the + /// expression evaluates to true or false. + BranchRegion = 4, } /// This struct provides LLVM's representation of a "CoverageMappingRegion", encoded into the /// coverage map, in accordance with the - /// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format). + /// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format). /// The struct composes fields representing the `Counter` type and value(s) (injected counter /// ID, or expression type and operands), the source file (an indirect index into a "filenames /// array", encoded separately), and source location (start and end positions of the represented @@ -713,6 +726,10 @@ pub mod coverageinfo { /// The counter type and type-dependent counter data, if any. counter: coverage_map::Counter, + /// If the `RegionKind` is a `BranchRegion`, this represents the counter + /// for the false branch of the region. + false_counter: coverage_map::Counter, + /// An indirect reference to the source filename. In the LLVM Coverage Mapping Format, the /// file_id is an index into a function-specific `virtual_file_mapping` array of indexes /// that, in turn, are used to look up the filename for this region. @@ -750,6 +767,7 @@ pub mod coverageinfo { ) -> Self { Self { counter, + false_counter: coverage_map::Counter::zero(), file_id, expanded_file_id: 0, start_line, @@ -763,6 +781,31 @@ pub mod coverageinfo { // This function might be used in the future; the LLVM API is still evolving, as is coverage // support. #[allow(dead_code)] + crate fn branch_region( + counter: coverage_map::Counter, + false_counter: coverage_map::Counter, + file_id: u32, + start_line: u32, + start_col: u32, + end_line: u32, + end_col: u32, + ) -> Self { + Self { + counter, + false_counter, + file_id, + expanded_file_id: 0, + start_line, + start_col, + end_line, + end_col, + kind: RegionKind::BranchRegion, + } + } + + // This function might be used in the future; the LLVM API is still evolving, as is coverage + // support. + #[allow(dead_code)] crate fn expansion_region( file_id: u32, expanded_file_id: u32, @@ -773,6 +816,7 @@ pub mod coverageinfo { ) -> Self { Self { counter: coverage_map::Counter::zero(), + false_counter: coverage_map::Counter::zero(), file_id, expanded_file_id, start_line, @@ -795,6 +839,7 @@ pub mod coverageinfo { ) -> Self { Self { counter: coverage_map::Counter::zero(), + false_counter: coverage_map::Counter::zero(), file_id, expanded_file_id: 0, start_line, @@ -818,6 +863,7 @@ pub mod coverageinfo { ) -> Self { Self { counter, + false_counter: coverage_map::Counter::zero(), file_id, expanded_file_id: 0, start_line, @@ -1002,6 +1048,8 @@ extern "C" { pub fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t); pub fn LLVMReplaceAllUsesWith(OldVal: &'a Value, NewVal: &'a Value); pub fn LLVMSetMetadata(Val: &'a Value, KindID: c_uint, Node: &'a Value); + pub fn LLVMGlobalSetMetadata(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata); + pub fn LLVMValueAsMetadata(Node: &'a Value) -> &Metadata; // Operations on constants of any type pub fn LLVMConstNull(Ty: &Type) -> &Value; @@ -1734,6 +1782,8 @@ extern "C" { pub fn LLVMTimeTraceProfilerInitialize(); + pub fn LLVMTimeTraceProfilerFinishThread(); + pub fn LLVMTimeTraceProfilerFinish(FileName: *const c_char); pub fn LLVMAddAnalysisPasses(T: &'a TargetMachine, PM: &PassManager<'a>); @@ -1770,7 +1820,7 @@ extern "C" { pub fn LLVMDisposeMessage(message: *mut c_char); - pub fn LLVMStartMultithreaded() -> Bool; + pub fn LLVMIsMultithreaded() -> Bool; /// Returns a string describing the last error caused by an LLVMRust* call. pub fn LLVMRustGetLastError() -> *const c_char; @@ -2187,6 +2237,7 @@ extern "C" { UseSoftFP: bool, FunctionSections: bool, DataSections: bool, + UniqueSectionNames: bool, TrapUnreachable: bool, Singlethread: bool, AsmComments: bool, @@ -2280,12 +2331,6 @@ extern "C" { #[allow(improper_ctypes)] pub fn LLVMRustWriteTwineToString(T: &Twine, s: &RustString); - pub fn LLVMContextSetDiagnosticHandler( - C: &Context, - Handler: DiagnosticHandler, - DiagnosticContext: *mut c_void, - ); - #[allow(improper_ctypes)] pub fn LLVMRustUnpackOptimizationDiagnostic( DI: &'a DiagnosticInfo, @@ -2315,7 +2360,7 @@ extern "C" { pub fn LLVMRustSetInlineAsmDiagnosticHandler( C: &Context, - H: InlineAsmDiagHandler, + H: InlineAsmDiagHandlerTy, CX: *mut c_void, ); @@ -2430,4 +2475,19 @@ extern "C" { mod_id: *const c_char, data: &ThinLTOData, ); + + pub fn LLVMRustContextGetDiagnosticHandler(Context: &Context) -> Option<&DiagnosticHandler>; + pub fn LLVMRustContextSetDiagnosticHandler( + context: &Context, + diagnostic_handler: Option<&DiagnosticHandler>, + ); + pub fn LLVMRustContextConfigureDiagnosticHandler( + context: &Context, + diagnostic_handler_callback: DiagnosticHandlerTy, + diagnostic_handler_context: *mut c_void, + remark_all_passes: bool, + remark_passes: *const *const c_char, + remark_passes_len: usize, + ); + } diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index b15efcd0dc2..3393c9baa28 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -17,35 +17,25 @@ use std::path::Path; use std::ptr; use std::slice; use std::str; -use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Once; -static POISONED: AtomicBool = AtomicBool::new(false); static INIT: Once = Once::new(); pub(crate) fn init(sess: &Session) { unsafe { // Before we touch LLVM, make sure that multithreading is enabled. + if llvm::LLVMIsMultithreaded() != 1 { + bug!("LLVM compiled without support for threads"); + } INIT.call_once(|| { - if llvm::LLVMStartMultithreaded() != 1 { - // use an extra bool to make sure that all future usage of LLVM - // cannot proceed despite the Once not running more than once. - POISONED.store(true, Ordering::SeqCst); - } - configure_llvm(sess); }); - - if POISONED.load(Ordering::SeqCst) { - bug!("couldn't enable multi-threaded LLVM"); - } } } fn require_inited() { - INIT.call_once(|| bug!("llvm is not initialized")); - if POISONED.load(Ordering::SeqCst) { - bug!("couldn't enable multi-threaded LLVM"); + if !INIT.is_completed() { + bug!("LLVM is not initialized"); } } @@ -85,7 +75,9 @@ unsafe fn configure_llvm(sess: &Session) { if sess.print_llvm_passes() { add("-debug-pass=Structure", false); } - if !sess.opts.debugging_opts.no_generate_arange_section { + if sess.target.generate_arange_section + && !sess.opts.debugging_opts.no_generate_arange_section + { add("-generate-arange-section", false); } @@ -95,8 +87,7 @@ unsafe fn configure_llvm(sess: &Session) { // Ref: // - https://github.com/rust-lang/rust/issues/85351 // - https://reviews.llvm.org/D103167 - let llvm_version = llvm_util::get_version(); - if llvm_version >= (11, 0, 0) && llvm_version < (13, 0, 0) { + if llvm_util::get_version() < (13, 0, 0) { add("-enable-machine-outliner=never", false); } @@ -124,11 +115,6 @@ unsafe fn configure_llvm(sess: &Session) { } if sess.opts.debugging_opts.llvm_time_trace { - // time-trace is not thread safe and running it in parallel will cause seg faults. - if !sess.opts.debugging_opts.no_parallel_llvm { - bug!("`-Z llvm-time-trace` requires `-Z no-parallel-llvm") - } - llvm::LLVMTimeTraceProfilerInitialize(); } @@ -191,6 +177,7 @@ pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> Vec<&'a str> { ("aarch64", "dpb2") => vec!["ccdp"], ("aarch64", "frintts") => vec!["fptoint"], ("aarch64", "fcma") => vec!["complxnum"], + ("aarch64", "pmuv3") => vec!["perfmon"], (_, s) => vec![s], } } @@ -416,11 +403,6 @@ pub fn llvm_global_features(sess: &Session) -> Vec<String> { // -Ctarget-features features.extend(sess.opts.cg.target_feature.split(',').flat_map(&filter)); - // FIXME: Move outline-atomics to target definition when earliest supported LLVM is 12. - if get_version() >= (12, 0, 0) && sess.target.llvm_target.contains("aarch64-unknown-linux") { - features.push("+outline-atomics".to_string()); - } - features } |
