use crate::error::Error;
use crate::prelude::replace_uses_of_with;
use llzk_sys::MlirValueRange;
use melior::ir::{BlockRef, OperationRef, Value, ValueLike};
use mlir_sys::MlirValue;
use std::{marker::PhantomData, num::TryFromIntError};
#[derive(Debug, Copy, Clone)]
pub struct ValueRange<'c, 'a, 'b> {
raw: MlirValueRange,
_context: PhantomData<&'a [Value<'c, 'b>]>,
}
impl ValueRange<'_, '_, '_> {
pub fn to_raw(&self) -> MlirValueRange {
self.raw
}
pub fn from_raw(raw: MlirValueRange) -> Self {
Self {
raw,
_context: PhantomData,
}
}
}
#[derive(Debug, Clone)]
pub struct OwningValueRange<'c, 'b> {
values: Vec<MlirValue>,
_context: PhantomData<Value<'c, 'b>>,
}
impl<'c, 'b> OwningValueRange<'c, 'b> {
pub fn values(&self) -> &[MlirValue] {
self.values.as_slice()
}
}
impl<'c, 'b> From<&[Value<'c, 'b>]> for OwningValueRange<'c, 'b> {
fn from(range: &[Value<'c, 'b>]) -> Self {
let values = range.iter().map(|v| v.to_raw()).collect();
Self {
values,
_context: PhantomData,
}
}
}
impl<'c, 'a, 'b> TryFrom<&'a [MlirValue]> for ValueRange<'c, 'a, 'b> {
type Error = TryFromIntError;
fn try_from(vals: &'a [MlirValue]) -> Result<Self, Self::Error> {
Ok(Self {
raw: MlirValueRange {
values: vals.as_ptr(),
size: isize::try_from(vals.len())?,
},
_context: PhantomData,
})
}
}
impl<'c, 'a, 'b> TryFrom<&'a OwningValueRange<'c, 'b>> for ValueRange<'c, 'a, 'b> {
type Error = TryFromIntError;
fn try_from(owning_value_range: &'a OwningValueRange<'c, 'b>) -> Result<Self, Self::Error> {
owning_value_range.values().try_into()
}
}
#[inline]
pub fn has_uses<'c>(val: impl ValueLike<'c> + Copy) -> bool {
unsafe {
let first_use = mlir_sys::mlirValueGetFirstUse(val.to_raw());
!mlir_sys::mlirOpOperandIsNull(first_use)
}
}
pub fn get_single_user<'ctx, 'op>(
value: impl ValueLike<'ctx> + Clone + std::fmt::Display,
) -> Result<OperationRef<'ctx, 'op>, Error> {
let first_use = unsafe { mlir_sys::mlirValueGetFirstUse(value.to_raw()) };
if first_use.ptr.is_null() {
return Err(Error::GeneralError("expected value to have uses"));
}
let second_use = unsafe { mlir_sys::mlirOpOperandGetNextUse(first_use) };
if !second_use.ptr.is_null() {
return Err(Error::GeneralError("expected value to have a single use"));
}
unsafe { OperationRef::from_option_raw(mlir_sys::mlirOpOperandGetOwner(first_use)) }
.ok_or(Error::GeneralError("invalid OpRef for user of value"))
}
pub fn replace_all_uses_in_block_with<'c>(
block: BlockRef,
orig: impl ValueLike<'c> + Copy,
replacement: impl ValueLike<'c> + Copy,
) {
unsafe {
let mut op_use = mlir_sys::mlirValueGetFirstUse(orig.to_raw());
while !op_use.ptr.is_null() {
let next = mlir_sys::mlirOpOperandGetNextUse(op_use);
let owner = mlir_sys::mlirOpOperandGetOwner(op_use);
if mlir_sys::mlirBlockEqual(mlir_sys::mlirOperationGetBlock(owner), block.to_raw()) {
replace_uses_of_with(&OperationRef::from_raw(owner), orig, replacement);
}
op_use = next;
}
}
}
pub fn replace_all_uses<'c>(of: impl ValueLike<'c> + Copy, with: impl ValueLike<'c> + Copy) {
unsafe { mlir_sys::mlirValueReplaceAllUsesOfWith(of.to_raw(), with.to_raw()) }
}