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_llvm/src/llvm/mod.rs | 45 ++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) (limited to 'compiler/rustc_codegen_llvm/src/llvm/mod.rs') 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 { -- 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/llvm/mod.rs') 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 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/llvm/mod.rs') 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 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/llvm/mod.rs') 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