Skip to content

TargetMachineOptions uses lazy initialization, which isn't necessary. #690

Description

@ErisianArchitect
/// LLVM target machine options provide another way to create target machines,
/// used with [Target::create_target_machine_from_options].
///
/// The option structure exposes an additional setting (i.e., the target ABI)
/// and provides default values for unspecified settings.
#[llvm_versions(18..)]
#[derive(Default, Debug)]
pub struct TargetMachineOptions(Option<LLVMTargetMachineOptionsRef>);

It stores an Option internally, but not for any particular reason besides lazy initialization, which doesn't seem necessary.

#[llvm_versions(18..)]
impl TargetMachineOptions {
    pub fn new() -> Self {
        Default::default()
    }

    pub fn set_cpu(mut self, cpu: &str) -> Self {
        let cpu = to_c_str(cpu);
        unsafe { LLVMTargetMachineOptionsSetCPU(self.inner(), cpu.as_ptr()) };

        self
    }

    pub fn set_features(mut self, features: &str) -> Self {
        let features = to_c_str(features);
        unsafe { LLVMTargetMachineOptionsSetFeatures(self.inner(), features.as_ptr()) };

        self
    }

    pub fn set_abi(mut self, abi: &str) -> Self {
        let abi = to_c_str(abi);
        unsafe { LLVMTargetMachineOptionsSetABI(self.inner(), abi.as_ptr()) };

        self
    }

    pub fn set_level(mut self, level: OptimizationLevel) -> Self {
        unsafe { LLVMTargetMachineOptionsSetCodeGenOptLevel(self.inner(), level.into()) };

        self
    }

    pub fn set_reloc_mode(mut self, reloc_mode: RelocMode) -> Self {
        unsafe { LLVMTargetMachineOptionsSetRelocMode(self.inner(), reloc_mode.into()) }

        self
    }

    pub fn set_code_model(mut self, code_model: CodeModel) -> Self {
        unsafe { LLVMTargetMachineOptionsSetCodeModel(self.inner(), code_model.into()) };

        self
    }

    fn into_target_machine(mut self, target: LLVMTargetRef, triple: &TargetTriple) -> Option<TargetMachine> {
        let target_machine = unsafe { LLVMCreateTargetMachineWithOptions(target, triple.as_ptr(), self.inner()) };

        if target_machine.is_null() {
            return None;
        }

        unsafe { Some(TargetMachine::new(target_machine)) }
    }

    /// SAFETY:
    /// - The internal `LLVMCreateTargetMachineOptionsRef` structure leaks memory
    /// if not disposed via `fn LLVMCreateTargetMachineWithOptions()`.
    /// - The only way to access it is via this private method.
    /// - Disposal is taken care of automatically in `Drop::drop`.
    unsafe fn inner(&mut self) -> LLVMTargetMachineOptionsRef {
        unsafe { *self.0.get_or_insert_with(|| LLVMCreateTargetMachineOptions()) }
    }
}

#[llvm_versions(18..)]
impl Drop for TargetMachineOptions {
    fn drop(&mut self) {
        if let Some(inner) = self.0 {
            unsafe { LLVMDisposeTargetMachineOptions(inner) };
        }
    }
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions