Skip to content

Commit

Permalink
Added constants: composite, scalar (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
mrLSD authored Aug 15, 2024
1 parent d64c0df commit ad4523b
Show file tree
Hide file tree
Showing 5 changed files with 323 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "llvm-lib"
version = "0.5.0"
version = "0.5.1"
authors = ["Evgeny Ukhanov <evgeny@ukhanov.org.ua>"]
description = "LLVM library with safe and flexibility in mind, without over complexity based on LLVM-C API"
categories = ["compilers", "development-tools", "development-tools::build-utils"]
Expand Down
174 changes: 174 additions & 0 deletions src/core/values/constants/composite.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
//! Functions in this group operate on composite constants.

use super::ValueRef;
use crate::core::context::ContextRef;
use crate::core::types::TypeRef;
use crate::{CInt, CStr, CString, CUint, GetRef};
use llvm_sys::core;

impl ValueRef {
/// Create a `ConstantDataSequential` and initialize it with a string.
#[must_use]
pub fn const_string_in_context(
context: &ContextRef,
string: &str,
dont_null_terminate: bool,
) -> Self {
let c_string = CString::from(string);
unsafe {
Self(core::LLVMConstStringInContext(
context.get_ref(),
c_string.as_ptr(),
*CUint::from(string.len()),
*CInt::from(dont_null_terminate),
))
}
}

/// Create a `ConstantDataSequential` with string content in the global context.
///
/// This is the same as `const_string_in_context` except it operates on the
/// global context.
#[must_use]
pub fn const_string(string: &str, dont_null_terminate: bool) -> Self {
let c_string = CString::from(string);
unsafe {
Self(core::LLVMConstString(
c_string.as_ptr(),
*CUint::from(string.len()),
*CInt::from(dont_null_terminate),
))
}
}

/// Returns true if the specified constant is an array of `i8`.
#[must_use]
pub fn is_constant_string(&self) -> bool {
unsafe { core::LLVMIsConstantString(self.0) != 0 }
}

/// Get the given constant data sequential as a string.
#[must_use]
pub fn get_as_string(&self) -> Option<String> {
unsafe {
let mut length = 0;
let c_str = core::LLVMGetAsString(self.0, &mut length);
if c_str.is_null() {
None
} else {
Some(CStr::new(c_str).to_string())
}
}
}

/// Create an anonymous `ConstantStruct` with the specified values.
#[must_use]
pub fn const_struct_in_context(
context: &ContextRef,
constant_vals: &[Self],
packed: bool,
) -> Self {
let mut constant_vals = constant_vals.iter().map(|v| v.0).collect::<Vec<_>>();
let constant_vals_ptr = if constant_vals.is_empty() {
std::ptr::null_mut()
} else {
constant_vals.as_mut_ptr()
};
unsafe {
Self(core::LLVMConstStructInContext(
context.get_ref(),
constant_vals_ptr,
*CUint::from(constant_vals.len()),
*CInt::from(packed),
))
}
}

/// Create a `ConstantStruct` in the global `Context`.
///
/// This is the same as `constStruct_in_context` except it operates on the
/// global context.
#[must_use]
pub fn const_struct(constant_vals: &[Self], packed: bool) -> Self {
let mut constant_vals = constant_vals.iter().map(|v| v.0).collect::<Vec<_>>();
let constant_vals_ptr = if constant_vals.is_empty() {
std::ptr::null_mut()
} else {
constant_vals.as_mut_ptr()
};
unsafe {
Self(core::LLVMConstStruct(
constant_vals_ptr,
*CUint::from(constant_vals.len()),
*CInt::from(packed),
))
}
}

/// Create a `ConstantArray` from values.
#[must_use]
pub fn const_array2(element_type: &TypeRef, constant_vals: &[Self]) -> Self {
let mut constant_vals = constant_vals.iter().map(|v| v.0).collect::<Vec<_>>();
let constant_vals_ptr = if constant_vals.is_empty() {
std::ptr::null_mut()
} else {
constant_vals.as_mut_ptr()
};
unsafe {
Self(core::LLVMConstArray2(
element_type.get_ref(),
constant_vals_ptr,
u64::try_from(constant_vals.len()).unwrap_or(u64::MAX),
))
}
}

/// Create a non-anonymous `ConstantStruct` from values.
#[must_use]
pub fn const_named_struct(struct_type: &TypeRef, constant_vals: &[Self]) -> Self {
let mut constant_vals = constant_vals.iter().map(|v| v.0).collect::<Vec<_>>();
let constant_vals_ptr = if constant_vals.is_empty() {
std::ptr::null_mut()
} else {
constant_vals.as_mut_ptr()
};
unsafe {
Self(core::LLVMConstNamedStruct(
struct_type.get_ref(),
constant_vals_ptr,
*CUint::from(constant_vals.len()),
))
}
}

/// Get element of a constant aggregate `(struct, array or vector)` at the
/// specified index. Returns `None` if the index is out of range, or it's not
/// possible to determine the element (e.g., because the constant is a
/// constant expression.)
#[must_use]
pub fn get_aggregate_element(&self, idx: u32) -> Option<Self> {
let element = unsafe { core::LLVMGetAggregateElement(self.0, *CUint::from(idx)) };
if element.is_null() {
None
} else {
Some(Self(element))
}
}

/// Create a `ConstantVector` from values.
#[must_use]
pub fn const_vector(scalar_constant_vals: &[Self]) -> Self {
let mut scalar_constant_vals = scalar_constant_vals.iter().map(|v| v.0).collect::<Vec<_>>();
let scalar_constant_vals_ptr = if scalar_constant_vals.is_empty() {
std::ptr::null_mut()
} else {
scalar_constant_vals.as_mut_ptr()
};
unsafe {
Self(core::LLVMConstVector(
scalar_constant_vals_ptr,
*CUint::from(scalar_constant_vals.len()),
))
}
}
}
3 changes: 3 additions & 0 deletions src/core/values/constants/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
//! This section contains APIs for interacting with `MValueRef` that
//! correspond to `LLVM Constant` instances.

pub mod composite;
pub mod scalar;

use super::ValueRef;
use crate::core::types::TypeRef;
use crate::GetRef;
Expand Down
120 changes: 120 additions & 0 deletions src/core/values/constants/scalar.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
//! Functions in this group model `ValueRef` instances that correspond
//! to constants referring to scalar types.

use super::ValueRef;
use crate::core::types::TypeRef;
use crate::{CDouble, CInt, CString, CUint, GetRef};
use llvm_sys::core;

impl ValueRef {
/// Obtain a constant value for an integer type.
///
/// The returned value corresponds to a `llvm ConstantInt`.
#[must_use]
pub fn const_int(ty: &TypeRef, n: u64, sign_extend: bool) -> Self {
unsafe {
Self(core::LLVMConstInt(
ty.get_ref(),
n,
*CInt::from(sign_extend),
))
}
}

/// Obtain a constant value for an integer of arbitrary precision.
#[must_use]
pub fn const_int_of_arbitrary_precision(ty: &TypeRef, words: &[u64]) -> Self {
unsafe {
Self(core::LLVMConstIntOfArbitraryPrecision(
ty.get_ref(),
*CUint::from(words.len()),
words.as_ptr(),
))
}
}

/// Obtain a constant value for an integer parsed from a string.
///
/// A similar API, `const_int_of_string_and_size` is also available. If the
/// string's length is available, it is preferred to call that function
/// instead.
#[must_use]
pub fn const_int_of_string(ty: &TypeRef, text: &str, radix: u8) -> Self {
let c_text = CString::from(text);
unsafe {
Self(core::LLVMConstIntOfString(
ty.get_ref(),
c_text.as_ptr(),
radix,
))
}
}

/// Obtain a constant value for an integer parsed from a string with
/// specified length.
#[must_use]
pub fn const_int_of_string_and_size(ty: &TypeRef, text: &str, radix: u8) -> Self {
let c_text = CString::from(text);
unsafe {
Self(core::LLVMConstIntOfStringAndSize(
ty.get_ref(),
c_text.as_ptr(),
*CUint::from(text.len()),
radix,
))
}
}

/// Obtain a constant value referring to a double floating point value.
#[must_use]
pub fn const_real(ty: &TypeRef, n: f64) -> Self {
unsafe { Self(core::LLVMConstReal(ty.get_ref(), *CDouble::from(n))) }
}

/// Obtain a constant for a floating point value parsed from a string.
///
/// A similar API, `const_real_of_string_and_size` is also available. It
/// should be used if the input string's length is known.
#[must_use]
pub fn const_real_of_string(ty: &TypeRef, text: &str) -> Self {
let c_text = CString::from(text);
unsafe { Self(core::LLVMConstRealOfString(ty.get_ref(), c_text.as_ptr())) }
}

/// Obtain a constant for a floating point value parsed from a string with specified length.
#[must_use]
pub fn const_real_of_string_and_size(ty: &TypeRef, text: &str) -> Self {
let c_text = CString::from(text);
unsafe {
Self(core::LLVMConstRealOfStringAndSize(
ty.get_ref(),
c_text.as_ptr(),
*CUint::from(text.len()),
))
}
}

/// Obtain the zero extended value for an integer constant value.
#[must_use]
pub fn const_int_get_zext_value(&self) -> u64 {
unsafe { core::LLVMConstIntGetZExtValue(self.0) }
}

/// Obtain the sign extended value for an integer constant value.
#[must_use]
pub fn const_int_get_sext_value(&self) -> i64 {
unsafe { core::LLVMConstIntGetSExtValue(self.0) }
}

/// Obtain the double value for a floating point constant value.
/// `losesInfo` indicates if some precision was lost in the conversion.
///
/// ## Returns
/// `f64` constant value and `losesInfo` flag
#[must_use]
pub fn const_real_get_double(&self) -> (f64, bool) {
let mut loses_info_c = 0;
let result = unsafe { core::LLVMConstRealGetDouble(self.0, &mut loses_info_c) };
(result, loses_info_c != 0)
}
}
26 changes: 25 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub mod basic_block;
pub mod builder;
pub mod core;

use libc::{c_char, c_int, c_uint, size_t};
use libc::{c_char, c_double, c_int, c_uint, size_t};
use std::ops::{Deref, DerefMut};

/// Get raw references trait
Expand Down Expand Up @@ -56,6 +56,30 @@ impl DerefMut for CUint {
}
}

/// `c_double` wrapper (from C-type)
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct CDouble(c_double);

impl From<f64> for CDouble {
fn from(value: f64) -> Self {
// Force to unwrap
Self(c_double::try_from(value).expect("c_double casting fail from u32"))
}
}

impl From<CDouble> for f64 {
fn from(value: CDouble) -> Self {
value.0
}
}

impl Deref for CDouble {
type Target = c_double;
fn deref(&self) -> &Self::Target {
&self.0
}
}

/// `c_int` wrapper (from C-type)
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct CInt(c_int);
Expand Down

0 comments on commit ad4523b

Please sign in to comment.