use std::ops::Deref;
use llvm_sys::core;
use llvm_sys::prelude::{
LLVMMetadataRef, LLVMModuleFlagEntry, LLVMModuleRef, LLVMNamedMDNodeRef, LLVMValueRef,
};
use llvm_sys::{LLVMInlineAsmDialect, LLVMModuleFlagBehavior};
use crate::core::context::ContextRef;
use crate::core::types::TypeRef;
use crate::core::values::ValueRef;
use crate::{CInt, CStr, CString, GetRef, SizeT};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum InlineAsmDialect {
InlineAsmDialectATT,
InlineAsmDialectIntel,
}
impl From<InlineAsmDialect> for LLVMInlineAsmDialect {
fn from(value: InlineAsmDialect) -> Self {
match value {
InlineAsmDialect::InlineAsmDialectATT => Self::LLVMInlineAsmDialectATT,
InlineAsmDialect::InlineAsmDialectIntel => Self::LLVMInlineAsmDialectIntel,
}
}
}
impl From<LLVMInlineAsmDialect> for InlineAsmDialect {
fn from(value: LLVMInlineAsmDialect) -> Self {
match value {
LLVMInlineAsmDialect::LLVMInlineAsmDialectATT => Self::InlineAsmDialectATT,
LLVMInlineAsmDialect::LLVMInlineAsmDialectIntel => Self::InlineAsmDialectIntel,
}
}
}
#[derive(Debug)]
pub struct NamedMetadataNodeRef(LLVMNamedMDNodeRef);
impl From<LLVMNamedMDNodeRef> for NamedMetadataNodeRef {
fn from(value: LLVMNamedMDNodeRef) -> Self {
Self(value)
}
}
impl NamedMetadataNodeRef {
#[must_use]
pub fn get_next(&self) -> Option<Self> {
let next_md = unsafe { core::LLVMGetNextNamedMetadata(self.0) };
if next_md.is_null() {
None
} else {
Some(next_md.into())
}
}
#[must_use]
pub fn get_previous(&self) -> Option<Self> {
let prev_md = unsafe { core::LLVMGetPreviousNamedMetadata(self.0) };
if prev_md.is_null() {
None
} else {
Some(prev_md.into())
}
}
#[must_use]
pub fn get_name(&self) -> Option<String> {
let mut length = SizeT::from(0_usize);
unsafe {
let c_str = core::LLVMGetNamedMetadataName(self.0, &mut *length);
if c_str.is_null() {
return None;
}
Some(CStr::new(c_str).to_string())
}
}
}
#[derive(Debug, Clone)]
pub struct MetadataRef(LLVMMetadataRef);
impl From<LLVMMetadataRef> for MetadataRef {
fn from(metadata: LLVMMetadataRef) -> Self {
Self(metadata)
}
}
impl GetRef for MetadataRef {
type RawRef = LLVMMetadataRef;
fn get_ref(&self) -> Self::RawRef {
self.0
}
}
#[allow(dead_code)]
#[derive(Debug)]
pub struct ModuleFlagEntry(*mut LLVMModuleFlagEntry, SizeT);
impl ModuleFlagEntry {
#[must_use]
pub fn get_count(&self) -> usize {
*self.1
}
pub fn dispose_module_flags_metadata(&self) {
unsafe {
core::LLVMDisposeModuleFlagsMetadata(self.0);
}
}
#[must_use]
pub fn get_flag_behavior(&self, index: u32) -> ModuleFlagBehavior {
let behavior = unsafe { core::LLVMModuleFlagEntriesGetFlagBehavior(self.0, index) };
behavior.into()
}
#[must_use]
pub fn get_key(&self, index: u32) -> Option<String> {
unsafe {
let mut length: usize = 0;
let c_str = core::LLVMModuleFlagEntriesGetKey(self.0, index, &mut length);
if c_str.is_null() {
return None;
}
Some(CStr::new(c_str).to_string())
}
}
#[must_use]
pub fn get_metadata(&self, index: u32) -> MetadataRef {
let metadata = unsafe { core::LLVMModuleFlagEntriesGetMetadata(self.0, index) };
MetadataRef(metadata)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ModuleFlagBehavior {
ModuleFlagBehaviorError,
ModuleFlagBehaviorWarning,
ModuleFlagBehaviorRequire,
ModuleFlagBehaviorOverride,
ModuleFlagBehaviorAppend,
ModuleFlagBehaviorAppendUnique,
}
impl From<LLVMModuleFlagBehavior> for ModuleFlagBehavior {
fn from(value: LLVMModuleFlagBehavior) -> Self {
match value {
LLVMModuleFlagBehavior::LLVMModuleFlagBehaviorError => Self::ModuleFlagBehaviorError,
LLVMModuleFlagBehavior::LLVMModuleFlagBehaviorWarning => {
Self::ModuleFlagBehaviorWarning
}
LLVMModuleFlagBehavior::LLVMModuleFlagBehaviorRequire => {
Self::ModuleFlagBehaviorRequire
}
LLVMModuleFlagBehavior::LLVMModuleFlagBehaviorOverride => {
Self::ModuleFlagBehaviorOverride
}
LLVMModuleFlagBehavior::LLVMModuleFlagBehaviorAppend => Self::ModuleFlagBehaviorAppend,
LLVMModuleFlagBehavior::LLVMModuleFlagBehaviorAppendUnique => {
Self::ModuleFlagBehaviorAppendUnique
}
}
}
}
impl From<ModuleFlagBehavior> for LLVMModuleFlagBehavior {
fn from(value: ModuleFlagBehavior) -> Self {
match value {
ModuleFlagBehavior::ModuleFlagBehaviorError => Self::LLVMModuleFlagBehaviorError,
ModuleFlagBehavior::ModuleFlagBehaviorWarning => Self::LLVMModuleFlagBehaviorWarning,
ModuleFlagBehavior::ModuleFlagBehaviorRequire => Self::LLVMModuleFlagBehaviorRequire,
ModuleFlagBehavior::ModuleFlagBehaviorOverride => Self::LLVMModuleFlagBehaviorOverride,
ModuleFlagBehavior::ModuleFlagBehaviorAppend => Self::LLVMModuleFlagBehaviorAppend,
ModuleFlagBehavior::ModuleFlagBehaviorAppendUnique => {
Self::LLVMModuleFlagBehaviorAppendUnique
}
}
}
}
pub struct ModuleRef(LLVMModuleRef);
impl Deref for ModuleRef {
type Target = LLVMModuleRef;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Drop for ModuleRef {
fn drop(&mut self) {
unsafe {
core::LLVMDisposeModule(self.0);
}
}
}
impl From<LLVMModuleRef> for ModuleRef {
fn from(module: LLVMModuleRef) -> Self {
Self(module)
}
}
impl GetRef for ModuleRef {
type RawRef = LLVMModuleRef;
fn get_ref(&self) -> Self::RawRef {
self.0
}
}
impl ModuleRef {
#[must_use]
pub fn new(module_name: &str) -> Self {
Self::create_module_with_name(module_name)
}
#[must_use]
pub fn create_module_with_name(module_name: &str) -> Self {
let c_name = CString::from(module_name);
let module_ref = unsafe { core::LLVMModuleCreateWithName(c_name.as_ptr()) };
assert!(!module_ref.is_null(), "Failed to create LLVM module");
Self(module_ref)
}
#[must_use]
pub fn create_module_with_name_in_context(module_name: &str, context: &ContextRef) -> Self {
let c_name = CString::from(module_name);
let module_ref =
unsafe { core::LLVMModuleCreateWithNameInContext(c_name.as_ptr(), context.get_ref()) };
assert!(!module_ref.is_null(), "Failed to create LLVM module");
Self(module_ref)
}
#[must_use]
pub fn clone_module(&self) -> Self {
let module_ref = unsafe { core::LLVMCloneModule(self.0) };
Self(module_ref)
}
#[must_use]
pub fn get_module_identifier(&self) -> Option<String> {
let mut length = *SizeT::from(0_usize);
unsafe {
let c_str = core::LLVMGetModuleIdentifier(self.0, &mut length);
if c_str.is_null() {
return None;
}
Some(CStr::new(c_str).to_string())
}
}
pub fn set_module_identifier(&self, ident: &str) {
let c_ident = CString::from(ident);
unsafe {
core::LLVMSetModuleIdentifier(
self.0,
c_ident.as_ptr(),
*SizeT::from(c_ident.to_bytes().len()),
);
}
}
#[must_use]
pub fn get_source_file_name(&self) -> Option<String> {
let mut length = *SizeT::from(0_usize);
unsafe {
let c_str = core::LLVMGetSourceFileName(self.0, &mut length);
if c_str.is_null() {
return None;
}
Some(CStr::new(c_str).to_string())
}
}
pub fn set_source_file_name(&self, name: &str) {
let c_name = CString::from(name);
unsafe {
core::LLVMSetSourceFileName(
self.0,
c_name.as_ptr(),
*SizeT::from(c_name.to_bytes().len()),
);
}
}
#[must_use]
pub fn get_data_layout_str(&self) -> Option<String> {
unsafe {
let c_str = core::LLVMGetDataLayoutStr(self.0);
if c_str.is_null() {
return None;
}
Some(CStr::new(c_str).to_string())
}
}
pub fn set_data_layout(&self, data_layout_str: &str) {
let c_data_layout_str = CString::from(data_layout_str);
unsafe {
core::LLVMSetDataLayout(self.0, c_data_layout_str.as_ptr());
}
}
#[must_use]
pub fn get_target(&self) -> Option<String> {
unsafe {
let c_str = core::LLVMGetTarget(self.0);
if c_str.is_null() {
return None;
}
Some(CStr::new(c_str).to_string())
}
}
pub fn set_target(&self, triple: &str) {
let c_triple = CString::from(triple);
unsafe {
core::LLVMSetTarget(self.0, c_triple.as_ptr());
}
}
#[must_use]
pub fn copy_module_flags_metadata(&self) -> Option<ModuleFlagEntry> {
unsafe {
let mut length = SizeT(0_usize);
let entries = core::LLVMCopyModuleFlagsMetadata(self.0, &mut *length);
if entries.is_null() {
None
} else {
Some(ModuleFlagEntry(entries, length))
}
}
}
#[must_use]
pub fn get_module_flag(&self, key: &str) -> MetadataRef {
let c_key = CString::from(key);
let metadata = unsafe {
core::LLVMGetModuleFlag(self.0, c_key.as_ptr(), *SizeT(c_key.to_bytes().len()))
};
MetadataRef(metadata)
}
pub fn add_module_flag(&self, behavior: &ModuleFlagBehavior, key: &str, val: &MetadataRef) {
let c_key = CString::from(key);
unsafe {
core::LLVMAddModuleFlag(
self.0,
(*behavior).into(),
c_key.as_ptr(),
c_key.to_bytes().len(),
val.0,
);
}
}
pub fn dump_module(&self) {
unsafe {
core::LLVMDumpModule(self.0);
}
}
pub fn print_module_to_file(&self, filename: &str) -> Result<(), String> {
let c_filename = CString::from(filename);
let mut error_message: *mut std::ffi::c_char = std::ptr::null_mut();
let result =
unsafe { core::LLVMPrintModuleToFile(self.0, c_filename.as_ptr(), &mut error_message) };
if result == 0 {
Ok(())
} else {
unsafe {
let error = CStr::new(error_message).to_string();
core::LLVMDisposeMessage(error_message);
Err(error)
}
}
}
#[must_use]
pub fn print_module_to_string(&self) -> Option<String> {
unsafe {
let c_str = core::LLVMPrintModuleToString(self.0);
if c_str.is_null() {
return None;
}
let result = CStr::new(c_str).to_string();
core::LLVMDisposeMessage(c_str);
Some(result)
}
}
#[must_use]
pub fn get_module_inline_asm(&self) -> Option<String> {
unsafe {
let mut len = SizeT::from(0_usize);
let c_str = core::LLVMGetModuleInlineAsm(self.0, &mut *len);
if c_str.is_null() {
return None;
}
Some(CStr::new(c_str).to_string())
}
}
pub fn set_module_inline_asm(&self, asm: &str) {
let c_asm = CString::from(asm);
unsafe {
core::LLVMSetModuleInlineAsm2(self.0, c_asm.as_ptr(), *SizeT(c_asm.to_bytes().len()));
}
}
pub fn append_module_inline_asm(&self, asm: &str) {
let c_asm = CString::from(asm);
unsafe {
core::LLVMAppendModuleInlineAsm(self.0, c_asm.as_ptr(), *SizeT(c_asm.to_bytes().len()));
}
}
#[must_use]
pub fn get_module_context(&self) -> ContextRef {
ContextRef::from(unsafe { core::LLVMGetModuleContext(self.0) })
}
#[must_use]
pub fn get_first_named_metadata(&self) -> Option<NamedMetadataNodeRef> {
let md = unsafe { core::LLVMGetFirstNamedMetadata(self.0) };
if md.is_null() {
None
} else {
Some(md.into())
}
}
#[must_use]
pub fn get_last_named_metadata(&self) -> Option<NamedMetadataNodeRef> {
let md = unsafe { core::LLVMGetLastNamedMetadata(self.0) };
if md.is_null() {
None
} else {
Some(md.into())
}
}
#[must_use]
pub fn get_named_metadata(&self, name: &str) -> Option<NamedMetadataNodeRef> {
let c_name = CString::from(name);
let md = unsafe {
core::LLVMGetNamedMetadata(self.0, c_name.as_ptr(), *SizeT(c_name.as_bytes().len()))
};
if md.is_null() {
None
} else {
Some(md.into())
}
}
#[must_use]
pub fn get_or_insert_named_metadata(&self, name: &str) -> NamedMetadataNodeRef {
let c_name = CString::from(name);
let md = unsafe {
core::LLVMGetOrInsertNamedMetadata(
self.0,
c_name.as_ptr(),
*SizeT(c_name.as_bytes().len()),
)
};
md.into()
}
#[must_use]
pub fn get_named_metadata_num_operands(&self, name: &str) -> u32 {
let c_name = CString::from(name);
unsafe { core::LLVMGetNamedMetadataNumOperands(self.0, c_name.as_ptr()) }
}
#[must_use]
pub fn get_named_metadata_operands(&self, name: &str) -> Vec<ValueRef> {
let c_name = CString::from(name);
let num_operands = self.get_named_metadata_num_operands(name);
let mut raw_operands: Vec<LLVMValueRef> = Vec::with_capacity(num_operands as usize);
unsafe {
core::LLVMGetNamedMetadataOperands(self.0, c_name.as_ptr(), raw_operands.as_mut_ptr());
raw_operands.set_len(num_operands as usize);
}
raw_operands.into_iter().map(ValueRef::from).collect()
}
pub fn add_named_metadata_operand(&self, name: &str, val: &ValueRef) {
let c_name = CString::from(name);
unsafe { core::LLVMAddNamedMetadataOperand(self.0, c_name.as_ptr(), val.get_ref()) };
}
#[must_use]
pub fn add_function(&self, fn_name: &str, fn_type: &TypeRef) -> ValueRef {
unsafe {
let c_name = CString::from(fn_name);
ValueRef::from(core::LLVMAddFunction(self.0, c_name.as_ptr(), **fn_type))
}
}
#[must_use]
pub fn get_named_function(&self, name: &str) -> ValueRef {
let c_name = CString::from(name);
ValueRef::from(unsafe { core::LLVMGetNamedFunction(self.0, c_name.as_ptr()) })
}
#[must_use]
pub fn get_first_function(&self) -> ValueRef {
ValueRef::from(unsafe { core::LLVMGetFirstFunction(self.0) })
}
#[must_use]
pub fn get_last_function(&self) -> ValueRef {
ValueRef::from(unsafe { core::LLVMGetLastFunction(self.0) })
}
}
#[must_use]
pub fn get_inline_asm_asm_string(inline_asm_val: &ValueRef) -> Option<String> {
inline_asm_val.get_inline_asm_asm_string()
}
#[must_use]
pub fn get_inline_asm(
ty: &TypeRef,
asm_string: &str,
constraints: &str,
has_side_effects: bool,
is_align_stack: bool,
dialect: InlineAsmDialect,
can_throw: bool,
) -> ValueRef {
let c_asm_string = CString::from(asm_string);
let c_constraints = CString::from(constraints);
let value_ref = unsafe {
core::LLVMGetInlineAsm(
ty.get_ref(),
c_asm_string.as_ptr(),
*SizeT(c_asm_string.to_bytes().len()),
c_constraints.as_ptr(),
*SizeT(c_constraints.to_bytes().len()),
*CInt::from(has_side_effects),
*CInt::from(is_align_stack),
dialect.into(),
*CInt::from(can_throw),
)
};
ValueRef::from(value_ref)
}
#[must_use]
pub fn get_inline_asm_constraint_string(inline_asm_val: &ValueRef) -> Option<String> {
inline_asm_val.get_inline_asm_constraint_string()
}
#[must_use]
pub fn get_inline_asm_dialect(inline_asm_val: &ValueRef) -> InlineAsmDialect {
inline_asm_val.get_inline_asm_dialect()
}
#[must_use]
pub fn get_inline_asm_function_type(inline_asm_val: &ValueRef) -> TypeRef {
inline_asm_val.get_inline_asm_function_type()
}
#[must_use]
pub fn get_inline_asm_has_side_effects(inline_asm_val: &ValueRef) -> bool {
inline_asm_val.get_inline_asm_has_side_effects()
}
#[must_use]
pub fn get_inline_asm_needs_aligned_stack(inline_asm_val: &ValueRef) -> bool {
inline_asm_val.get_inline_asm_needs_aligned_stack()
}
#[must_use]
pub fn get_inline_asm_can_unwind(inline_asm_val: &ValueRef) -> bool {
inline_asm_val.get_inline_asm_can_unwind()
}
#[must_use]
pub fn get_debug_loc_directory(val: &ValueRef) -> Option<String> {
val.get_debug_loc_directory()
}
#[must_use]
pub fn get_debug_loc_filename(val: &ValueRef) -> Option<String> {
val.get_debug_loc_filename()
}
#[must_use]
pub fn get_debug_loc_line(val: &ValueRef) -> u32 {
val.get_debug_loc_line()
}
#[must_use]
pub fn get_debug_loc_column(val: &ValueRef) -> u32 {
val.get_debug_loc_column()
}
#[must_use]
pub fn get_next_function(func: &ValueRef) -> Option<ValueRef> {
func.get_next_function()
}
#[must_use]
pub fn get_previous_function(func: &ValueRef) -> Option<ValueRef> {
func.get_previous_function()
}