Add OwnedTargetMachine to manage llvm:TargetMachine. Uses pointers

instead of &'static mut and provides safe interface to create/dispose
it.
This commit is contained in:
Florian Schmiderer 2023-09-17 14:40:22 +02:00
parent fc61fabc24
commit 3409ca65d8
7 changed files with 148 additions and 40 deletions

View file

@ -0,0 +1,101 @@
use std::{
ffi::{c_char, CStr},
marker::PhantomData,
ops::Deref,
ptr::NonNull,
};
use rustc_data_structures::small_c_str::SmallCStr;
use crate::{errors::LlvmError, llvm};
/// Responsible for safely creating and disposing llvm::TargetMachine via ffi functions.
/// Not cloneable as there is no clone function for llvm::TargetMachine.
#[repr(transparent)]
pub struct OwnedTargetMachine {
tm_unique: NonNull<llvm::TargetMachine>,
phantom: PhantomData<llvm::TargetMachine>,
}
impl OwnedTargetMachine {
pub fn new(
triple: &CStr,
cpu: &CStr,
features: &CStr,
abi: &CStr,
model: llvm::CodeModel,
reloc: llvm::RelocModel,
level: llvm::CodeGenOptLevel,
use_soft_fp: bool,
function_sections: bool,
data_sections: bool,
unique_section_names: bool,
trap_unreachable: bool,
singletree: bool,
asm_comments: bool,
emit_stack_size_section: bool,
relax_elf_relocations: bool,
use_init_array: bool,
split_dwarf_file: &CStr,
debug_info_compression: &CStr,
force_emulated_tls: bool,
args_cstr_buff: &[u8],
) -> Result<Self, LlvmError<'static>> {
assert!(args_cstr_buff.len() > 0);
assert!(
*args_cstr_buff.last().unwrap() == 0,
"The last character must be a null terminator."
);
// SAFETY: llvm::LLVMRustCreateTargetMachine copies pointed to data
let tm_ptr = unsafe {
llvm::LLVMRustCreateTargetMachine(
triple.as_ptr(),
cpu.as_ptr(),
features.as_ptr(),
abi.as_ptr(),
model,
reloc,
level,
use_soft_fp,
function_sections,
data_sections,
unique_section_names,
trap_unreachable,
singletree,
asm_comments,
emit_stack_size_section,
relax_elf_relocations,
use_init_array,
split_dwarf_file.as_ptr(),
debug_info_compression.as_ptr(),
force_emulated_tls,
args_cstr_buff.as_ptr() as *const c_char,
args_cstr_buff.len(),
)
};
NonNull::new(tm_ptr)
.map(|tm_unique| Self { tm_unique, phantom: PhantomData })
.ok_or_else(|| LlvmError::CreateTargetMachine { triple: SmallCStr::from(triple) })
}
}
impl Deref for OwnedTargetMachine {
type Target = llvm::TargetMachine;
fn deref(&self) -> &Self::Target {
// SAFETY: constructing ensures we have a valid pointer created by llvm::LLVMRustCreateTargetMachine
unsafe { self.tm_unique.as_ref() }
}
}
impl Drop for OwnedTargetMachine {
fn drop(&mut self) {
// SAFETY: constructing ensures we have a valid pointer created by llvm::LLVMRustCreateTargetMachine
// OwnedTargetMachine is not copyable so there is no double free or use after free
unsafe {
llvm::LLVMRustDisposeTargetMachine(self.tm_unique.as_mut());
}
}
}

View file

@ -1,4 +1,5 @@
use crate::back::lto::ThinBuffer;
use crate::back::owned_target_machine::OwnedTargetMachine;
use crate::back::profiling::{
selfprofile_after_pass_callback, selfprofile_before_pass_callback, LlvmSelfProfiler,
};
@ -98,7 +99,7 @@ pub fn write_output_file<'ll>(
}
}
pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm::TargetMachine {
pub fn create_informational_target_machine(sess: &Session) -> OwnedTargetMachine {
let config = TargetMachineFactoryConfig { split_dwarf_file: None };
// Can't use query system here quite yet because this function is invoked before the query
// system/tcx is set up.
@ -107,7 +108,7 @@ pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm:
.unwrap_or_else(|err| llvm_err(sess.diagnostic(), err).raise())
}
pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut llvm::TargetMachine {
pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> OwnedTargetMachine {
let split_dwarf_file = if tcx.sess.target_can_use_split_dwarf() {
tcx.output_filenames(()).split_dwarf_path(
tcx.sess.split_debuginfo(),
@ -259,34 +260,29 @@ pub fn target_machine_factory(
path_mapping.map_prefix(config.split_dwarf_file.unwrap_or_default()).0;
let split_dwarf_file = CString::new(split_dwarf_file.to_str().unwrap()).unwrap();
let tm = unsafe {
llvm::LLVMRustCreateTargetMachine(
triple.as_ptr(),
cpu.as_ptr(),
features.as_ptr(),
abi.as_ptr(),
code_model,
reloc_model,
opt_level,
use_softfp,
ffunction_sections,
fdata_sections,
funique_section_names,
trap_unreachable,
singlethread,
asm_comments,
emit_stack_size_section,
relax_elf_relocations,
use_init_array,
split_dwarf_file.as_ptr(),
debuginfo_compression.as_ptr(),
force_emulated_tls,
args_cstr_buff.as_ptr() as *const c_char,
args_cstr_buff.len(),
)
};
tm.ok_or_else(|| LlvmError::CreateTargetMachine { triple: triple.clone() })
OwnedTargetMachine::new(
&triple,
&cpu,
&features,
&abi,
code_model,
reloc_model,
opt_level,
use_softfp,
ffunction_sections,
fdata_sections,
funique_section_names,
trap_unreachable,
singlethread,
asm_comments,
emit_stack_size_section,
relax_elf_relocations,
use_init_array,
&split_dwarf_file,
&debuginfo_compression,
force_emulated_tls,
&args_cstr_buff,
)
})
}