1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
#![allow(unused)]
use llvm_sys::{
analysis::{LLVMVerifierFailureAction, LLVMVerifyFunction},
core::{
LLVMAddIncoming, LLVMAppendExistingBasicBlock, LLVMCountBasicBlocks, LLVMCountParams,
LLVMDumpValue, LLVMGetParam, LLVMGetValueKind, LLVMGetValueName2, LLVMGlobalGetValueType,
LLVMIsAFunction, LLVMIsAPHINode, LLVMSetValueName2, LLVMTypeOf,
},
prelude::LLVMValueRef,
LLVMTypeKind, LLVMValueKind,
};
use std::ffi::CStr;
use std::marker::PhantomData;
use std::ops::Deref;
use super::BasicBlock;
use super::Type;
/// Wrapper for a LLVM Value Reference.
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct Value<'llvm>(LLVMValueRef, PhantomData<&'llvm ()>);
impl<'llvm> Value<'llvm> {
/// Create a new Value instance.
///
/// # Panics
///
/// Panics if `value_ref` is a null pointer.
pub(super) fn new(value_ref: LLVMValueRef) -> Self {
assert!(!value_ref.is_null());
Value(value_ref, PhantomData)
}
/// Get the raw LLVM value reference.
#[inline]
pub(super) fn value_ref(&self) -> LLVMValueRef {
self.0
}
/// Get the LLVM value kind for the given value reference.
pub(super) fn kind(&self) -> LLVMValueKind {
unsafe { LLVMGetValueKind(self.value_ref()) }
}
/// Check if value is `function` type.
pub(super) fn is_function(&self) -> bool {
let cast = unsafe { LLVMIsAFunction(self.value_ref()) };
!cast.is_null()
}
/// Check if value is `phinode` type.
pub(super) fn is_phinode(&self) -> bool {
let cast = unsafe { LLVMIsAPHINode(self.value_ref()) };
!cast.is_null()
}
/// Dump the LLVM Value to stdout.
pub fn dump(&self) {
unsafe { LLVMDumpValue(self.value_ref()) };
}
/// Get a type reference representing for the given value reference.
///
/// # Panics
///
/// Panics if LLVM API returns a `null` pointer.
pub fn type_of(&self) -> Type<'llvm> {
let type_ref = unsafe { LLVMTypeOf(self.value_ref()) };
Type::new(type_ref)
}
/// Set the name for the given value reference.
///
/// # Panics
///
/// Panics if LLVM API returns a `null` pointer.
pub fn set_name(&self, name: &str) {
unsafe { LLVMSetValueName2(self.value_ref(), name.as_ptr().cast(), name.len()) };
}
/// Get the name for the given value reference.
///
/// # Panics
///
/// Panics if LLVM API returns a `null` pointer.
pub fn get_name(&self) -> &'llvm str {
let name = unsafe {
let mut len: libc::size_t = 0;
let name = LLVMGetValueName2(self.0, &mut len as _);
assert!(!name.is_null());
CStr::from_ptr(name)
};
// TODO: Does this string live for the time of the LLVM context?!
name.to_str()
.expect("Expected valid UTF8 string from LLVM API")
}
/// Check if value is of `f64` type.
pub fn is_f64(&self) -> bool {
self.type_of().kind() == LLVMTypeKind::LLVMDoubleTypeKind
}
/// Check if value is of integer type.
pub fn is_int(&self) -> bool {
self.type_of().kind() == LLVMTypeKind::LLVMIntegerTypeKind
}
}
/// Wrapper for a LLVM Value Reference specialized for contexts where function values are needed.
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct FnValue<'llvm>(Value<'llvm>);
impl<'llvm> Deref for FnValue<'llvm> {
type Target = Value<'llvm>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'llvm> FnValue<'llvm> {
/// Create a new FnValue instance.
///
/// # Panics
///
/// Panics if `value_ref` is a null pointer.
pub(super) fn new(value_ref: LLVMValueRef) -> Self {
let value = Value::new(value_ref);
debug_assert!(
value.is_function(),
"Expected a fn value when constructing FnValue!"
);
FnValue(value)
}
/// Get a type reference representing the function type (return + args) of the given function
/// value.
///
/// # Panics
///
/// Panics if LLVM API returns a `null` pointer.
pub fn fn_type(&self) -> Type<'llvm> {
// https://github.com/llvm/llvm-project/issues/72798
let type_ref = unsafe { LLVMGlobalGetValueType(self.value_ref()) };
Type::new(type_ref)
}
/// Get the number of function arguments for the given function value.
pub fn args(&self) -> usize {
unsafe { LLVMCountParams(self.value_ref()) as usize }
}
/// Get a value reference for the function argument at index `idx`.
///
/// # Panics
///
/// Panics if LLVM API returns a `null` pointer or indexed out of bounds.
pub fn arg(&self, idx: usize) -> Value<'llvm> {
assert!(idx < self.args());
let value_ref = unsafe { LLVMGetParam(self.value_ref(), idx as libc::c_uint) };
Value::new(value_ref)
}
/// Get the number of Basic Blocks for the given function value.
pub fn basic_blocks(&self) -> usize {
unsafe { LLVMCountBasicBlocks(self.value_ref()) as usize }
}
/// Append a Basic Block to the end of the function value.
pub fn append_basic_block(&self, bb: BasicBlock<'llvm>) {
unsafe {
LLVMAppendExistingBasicBlock(self.value_ref(), bb.bb_ref());
}
}
/// Verify that the given function is valid.
pub fn verify(&self) -> bool {
unsafe {
LLVMVerifyFunction(
self.value_ref(),
LLVMVerifierFailureAction::LLVMPrintMessageAction,
) == 0
}
}
}
/// Wrapper for a LLVM Value Reference specialized for contexts where phi values are needed.
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct PhiValue<'llvm>(Value<'llvm>);
impl<'llvm> Deref for PhiValue<'llvm> {
type Target = Value<'llvm>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'llvm> PhiValue<'llvm> {
/// Create a new PhiValue instance.
///
/// # Panics
///
/// Panics if `value_ref` is a null pointer.
pub(super) fn new(value_ref: LLVMValueRef) -> Self {
let value = Value::new(value_ref);
debug_assert!(
value.is_phinode(),
"Expected a phinode value when constructing PhiValue!"
);
PhiValue(value)
}
/// Add an incoming value to the end of a PHI list.
pub fn add_incoming(&self, ival: Value<'llvm>, ibb: BasicBlock<'llvm>) {
debug_assert_eq!(
ival.type_of().kind(),
self.type_of().kind(),
"Type of incoming phi value must be the same as the type used to build the phi node."
);
unsafe {
LLVMAddIncoming(
self.value_ref(),
&mut ival.value_ref() as _,
&mut ibb.bb_ref() as _,
1,
);
}
}
}