diff --git a/macro/tests/operand.rs b/macro/tests/operand.rs index 52c1c15280..9c669a9206 100644 --- a/macro/tests/operand.rs +++ b/macro/tests/operand.rs @@ -1,6 +1,6 @@ mod utility; -use melior::ir::{Block, Location, Type}; +use melior::ir::{block::BlockApi, Block, Location, Type}; use utility::*; melior_macro::dialect! { diff --git a/melior/src/dialect/arith.rs b/melior/src/dialect/arith.rs index b3e455578c..deac34b89c 100644 --- a/melior/src/dialect/arith.rs +++ b/melior/src/dialect/arith.rs @@ -174,6 +174,7 @@ mod tests { dialect::func, ir::{ attribute::{StringAttribute, TypeAttribute}, + block::BlockApi, r#type::FunctionType, Attribute, Block, Location, Module, Region, Type, }, diff --git a/melior/src/dialect/cf.rs b/melior/src/dialect/cf.rs index bfb2ca8c4c..e4d39336c0 100644 --- a/melior/src/dialect/cf.rs +++ b/melior/src/dialect/cf.rs @@ -5,6 +5,7 @@ use crate::{ attribute::{ DenseElementsAttribute, DenseI32ArrayAttribute, IntegerAttribute, StringAttribute, }, + block::BlockApi, operation::OperationBuilder, r#type::RankedTensorType, Block, Identifier, Location, Operation, Type, Value, diff --git a/melior/src/dialect/func.rs b/melior/src/dialect/func.rs index 9ac0f2615e..7c5c26d4c2 100644 --- a/melior/src/dialect/func.rs +++ b/melior/src/dialect/func.rs @@ -87,7 +87,7 @@ pub fn r#return<'c>(operands: &[Value<'c, '_>], location: Location<'c>) -> Opera mod tests { use super::*; use crate::{ - ir::{Block, Module, Type}, + ir::{block::BlockApi, Block, Module, Type}, test::create_test_context, }; diff --git a/melior/src/dialect/index.rs b/melior/src/dialect/index.rs index fafce92695..2d6e8c0333 100644 --- a/melior/src/dialect/index.rs +++ b/melior/src/dialect/index.rs @@ -75,6 +75,7 @@ mod tests { dialect::func, ir::{ attribute::{StringAttribute, TypeAttribute}, + block::BlockApi, r#type::{FunctionType, IntegerType}, Block, Location, Module, Region, Type, }, diff --git a/melior/src/dialect/llvm.rs b/melior/src/dialect/llvm.rs index 0a61f34735..eef4f9b649 100644 --- a/melior/src/dialect/llvm.rs +++ b/melior/src/dialect/llvm.rs @@ -381,6 +381,7 @@ mod tests { }, ir::{ attribute::{IntegerAttribute, StringAttribute, TypeAttribute}, + block::BlockApi, r#type::{FunctionType, IntegerType}, Block, Module, Region, }, diff --git a/melior/src/dialect/memref.rs b/melior/src/dialect/memref.rs index dac24c6510..c710e77c48 100644 --- a/melior/src/dialect/memref.rs +++ b/melior/src/dialect/memref.rs @@ -324,6 +324,7 @@ mod tests { dialect::{func, index}, ir::{ attribute::{DenseElementsAttribute, StringAttribute, TypeAttribute}, + block::BlockApi, r#type::{FunctionType, IntegerType, RankedTensorType}, Block, Module, Region, Type, }, diff --git a/melior/src/dialect/ods.rs b/melior/src/dialect/ods.rs index 6c9ab91cbe..cc0c64f18b 100644 --- a/melior/src/dialect/ods.rs +++ b/melior/src/dialect/ods.rs @@ -140,6 +140,7 @@ mod tests { dialect, ir::{ attribute::{IntegerAttribute, StringAttribute, TypeAttribute}, + block::BlockApi, r#type::{FunctionType, IntegerType}, Block, Location, Module, Region, Type, }, diff --git a/melior/src/dialect/scf.rs b/melior/src/dialect/scf.rs index 76ab10b571..c8e62a8bc3 100644 --- a/melior/src/dialect/scf.rs +++ b/melior/src/dialect/scf.rs @@ -114,6 +114,7 @@ mod tests { dialect::{arith, func}, ir::{ attribute::{FloatAttribute, IntegerAttribute, StringAttribute, TypeAttribute}, + block::BlockApi, r#type::{FunctionType, IntegerType, Type}, Attribute, Block, Module, }, diff --git a/melior/src/helpers/builtin.rs b/melior/src/helpers/builtin.rs index 778b75275b..d2dc259883 100644 --- a/melior/src/helpers/builtin.rs +++ b/melior/src/helpers/builtin.rs @@ -1,5 +1,5 @@ use crate::{ - ir::{Block, Operation, Value}, + ir::{block::BlockApi, Block, Operation, Value}, Error, }; diff --git a/melior/src/helpers/llvm.rs b/melior/src/helpers/llvm.rs index 4dee69901c..61f5971a47 100644 --- a/melior/src/helpers/llvm.rs +++ b/melior/src/helpers/llvm.rs @@ -6,6 +6,7 @@ use crate::{ attribute::{ DenseI32ArrayAttribute, DenseI64ArrayAttribute, IntegerAttribute, TypeAttribute, }, + block::BlockApi, r#type::IntegerType, Attribute, Block, Location, Type, Value, ValueLike, }, diff --git a/melior/src/ir/block.rs b/melior/src/ir/block.rs index b9adc77287..a902960f70 100644 --- a/melior/src/ir/block.rs +++ b/melior/src/ir/block.rs @@ -23,6 +23,55 @@ use std::{ ops::Deref, }; +pub trait BlockApi<'c, 'v> { + /// Returns an argument at a position. + fn argument(&self, index: usize) -> Result, Error>; + /// Returns a number of arguments. + fn argument_count(&self) -> usize; + + /// Returns a reference to the first operation. + fn first_operation(&self) -> Option>; + /// Returns a mutable reference to the first operation. + fn first_operation_mut(&mut self) -> Option>; + + /// Returns a reference to a terminator operation. + fn terminator(&self) -> Option>; + /// Returns a mutable reference to a terminator operation. + fn terminator_mut(&mut self) -> Option>; + + /// Returns a parent region. + // TODO Store lifetime of regions in blocks, or create another type like + // `InsertedBlockRef`? + fn parent_region(&self) -> Option>; + /// Returns a parent operation. + fn parent_operation(&self) -> Option>; + + /// Adds an argument. + fn add_argument(&self, r#type: Type<'c>, location: Location<'c>) -> Value<'c, 'v>; + + /// Appends an operation. + fn append_operation(&self, operation: Operation<'c>) -> OperationRef<'c, 'v>; + /// Inserts an operation. + // TODO How can we make those update functions take `&mut self`? + // TODO Use cells? + fn insert_operation(&self, position: usize, operation: Operation<'c>) -> OperationRef<'c, 'v>; + /// Inserts an operation after another. + fn insert_operation_after( + &self, + one: OperationRef<'c, 'v>, + other: Operation<'c>, + ) -> OperationRef<'c, 'v>; + /// Inserts an operation before another. + fn insert_operation_before( + &self, + one: OperationRef<'c, 'v>, + other: Operation<'c>, + ) -> OperationRef<'c, 'v>; + + /// Returns a next block in a region. + fn next_in_region(&self) -> Option>; +} + /// A block. pub struct Block<'c> { raw: MlirBlock, @@ -50,8 +99,52 @@ impl<'c> Block<'c> { } } - /// Returns an argument at a position. - pub fn argument(&self, index: usize) -> Result, Error> { + /// Detaches a block from a region and assumes its ownership. + /// + /// # Safety + /// + /// This function might invalidate existing references to the block if you + /// drop it too early. + // TODO Implement this for BlockRefMut instead and mark it safe. + pub unsafe fn detach(&self) -> Option> { + if self.parent_region().is_some() { + mlirBlockDetach(self.raw); + + Some(Block::from_raw(self.raw)) + } else { + None + } + } + + /// Creates a block from a raw object. + /// + /// # Safety + /// + /// A raw object must be valid. + pub unsafe fn from_raw(raw: MlirBlock) -> Self { + Self { + raw, + _context: Default::default(), + } + } + + /// Converts a block into a raw object. + pub const fn into_raw(self) -> MlirBlock { + let block = self.raw; + + forget(self); + + block + } + + /// Converts a block into a raw object. + pub const fn to_raw(&self) -> MlirBlock { + self.raw + } +} + +impl<'c, 'v> BlockApi<'c, 'v> for Block<'c> { + fn argument(&self, index: usize) -> Result, Error> { unsafe { if index < self.argument_count() { Ok(BlockArgument::from_raw(mlirBlockGetArgument( @@ -68,45 +161,35 @@ impl<'c> Block<'c> { } } - /// Returns a number of arguments. - pub fn argument_count(&self) -> usize { + fn argument_count(&self) -> usize { unsafe { mlirBlockGetNumArguments(self.raw) as usize } } - /// Returns a reference to the first operation. - pub fn first_operation(&self) -> Option> { + fn first_operation(&self) -> Option> { unsafe { OperationRef::from_option_raw(mlirBlockGetFirstOperation(self.raw)) } } - /// Returns a mutable reference to the first operation. - pub fn first_operation_mut(&mut self) -> Option> { + fn first_operation_mut(&mut self) -> Option> { unsafe { OperationRefMut::from_option_raw(mlirBlockGetFirstOperation(self.raw)) } } - /// Returns a reference to a terminator operation. - pub fn terminator(&self) -> Option> { + fn terminator(&self) -> Option> { unsafe { OperationRef::from_option_raw(mlirBlockGetTerminator(self.raw)) } } - /// Returns a mutable reference to a terminator operation. - pub fn terminator_mut(&mut self) -> Option> { + fn terminator_mut(&mut self) -> Option> { unsafe { OperationRefMut::from_option_raw(mlirBlockGetTerminator(self.raw)) } } - /// Returns a parent region. - // TODO Store lifetime of regions in blocks, or create another type like - // `InsertedBlockRef`? - pub fn parent_region(&self) -> Option> { + fn parent_region(&self) -> Option> { unsafe { RegionRef::from_option_raw(mlirBlockGetParentRegion(self.raw)) } } - /// Returns a parent operation. - pub fn parent_operation(&self) -> Option> { + fn parent_operation(&self) -> Option> { unsafe { OperationRef::from_option_raw(mlirBlockGetParentOperation(self.raw)) } } - /// Adds an argument. - pub fn add_argument(&self, r#type: Type<'c>, location: Location<'c>) -> Value<'c, '_> { + fn add_argument(&self, r#type: Type<'c>, location: Location<'c>) -> Value<'c, 'v> { unsafe { Value::from_raw(mlirBlockAddArgument( self.raw, @@ -116,8 +199,7 @@ impl<'c> Block<'c> { } } - /// Appends an operation. - pub fn append_operation(&self, operation: Operation<'c>) -> OperationRef<'c, '_> { + fn append_operation(&self, operation: Operation<'c>) -> OperationRef<'c, 'v> { unsafe { let operation = operation.into_raw(); @@ -127,14 +209,7 @@ impl<'c> Block<'c> { } } - /// Inserts an operation. - // TODO How can we make those update functions take `&mut self`? - // TODO Use cells? - pub fn insert_operation( - &self, - position: usize, - operation: Operation<'c>, - ) -> OperationRef<'c, '_> { + fn insert_operation(&self, position: usize, operation: Operation<'c>) -> OperationRef<'c, 'v> { unsafe { let operation = operation.into_raw(); @@ -144,12 +219,11 @@ impl<'c> Block<'c> { } } - /// Inserts an operation after another. - pub fn insert_operation_after( + fn insert_operation_after( &self, - one: OperationRef<'c, '_>, + one: OperationRef<'c, 'v>, other: Operation<'c>, - ) -> OperationRef<'c, '_> { + ) -> OperationRef<'c, 'v> { unsafe { let other = other.into_raw(); @@ -159,12 +233,11 @@ impl<'c> Block<'c> { } } - /// Inserts an operation before another. - pub fn insert_operation_before( + fn insert_operation_before( &self, - one: OperationRef<'c, '_>, + one: OperationRef<'c, 'v>, other: Operation<'c>, - ) -> OperationRef<'c, '_> { + ) -> OperationRef<'c, 'v> { unsafe { let other = other.into_raw(); @@ -174,53 +247,9 @@ impl<'c> Block<'c> { } } - /// Detaches a block from a region and assumes its ownership. - /// - /// # Safety - /// - /// This function might invalidate existing references to the block if you - /// drop it too early. - // TODO Implement this for BlockRefMut instead and mark it safe. - pub unsafe fn detach(&self) -> Option> { - if self.parent_region().is_some() { - mlirBlockDetach(self.raw); - - Some(Block::from_raw(self.raw)) - } else { - None - } - } - - /// Returns a next block in a region. - pub fn next_in_region(&self) -> Option> { + fn next_in_region(&self) -> Option> { unsafe { BlockRef::from_option_raw(mlirBlockGetNextInRegion(self.raw)) } } - - /// Creates a block from a raw object. - /// - /// # Safety - /// - /// A raw object must be valid. - pub unsafe fn from_raw(raw: MlirBlock) -> Self { - Self { - raw, - _context: Default::default(), - } - } - - /// Converts a block into a raw object. - pub const fn into_raw(self) -> MlirBlock { - let block = self.raw; - - forget(self); - - block - } - - /// Converts a block into a raw object. - pub const fn to_raw(&self) -> MlirBlock { - self.raw - } } impl Drop for Block<'_> { @@ -295,8 +324,116 @@ impl BlockRef<'_, '_> { } } -impl<'a> Deref for BlockRef<'_, 'a> { - type Target = Block<'a>; +impl<'c, 'v> BlockApi<'c, 'v> for BlockRef<'c, 'v> { + fn argument(&self, index: usize) -> Result, Error> { + let block = unsafe { Block::from_raw(self.raw) }; + let result = block.argument(index); + Block::into_raw(block); + result + } + + fn argument_count(&self) -> usize { + let block = unsafe { Block::from_raw(self.raw) }; + let result = block.argument_count(); + Block::into_raw(block); + result + } + + fn first_operation(&self) -> Option> { + let block = unsafe { Block::from_raw(self.raw) }; + let result = block.first_operation(); + Block::into_raw(block); + result + } + + fn first_operation_mut(&mut self) -> Option> { + let mut block = unsafe { Block::from_raw(self.raw) }; + let result = block.first_operation_mut(); + Block::into_raw(block); + result + } + + fn terminator(&self) -> Option> { + let block = unsafe { Block::from_raw(self.raw) }; + let result = block.terminator(); + Block::into_raw(block); + result + } + + fn terminator_mut(&mut self) -> Option> { + let mut block = unsafe { Block::from_raw(self.raw) }; + let result = block.terminator_mut(); + Block::into_raw(block); + result + } + + fn parent_region(&self) -> Option> { + let block = unsafe { Block::from_raw(self.raw) }; + let result = block.parent_region(); + Block::into_raw(block); + result + } + + fn parent_operation(&self) -> Option> { + let block = unsafe { Block::from_raw(self.raw) }; + let result = block.parent_operation(); + Block::into_raw(block); + result + } + + fn add_argument(&self, r#type: Type<'c>, location: Location<'c>) -> Value<'c, 'v> { + let block = unsafe { Block::from_raw(self.raw) }; + let result = block.add_argument(r#type, location); + Block::into_raw(block); + result + } + + fn append_operation(&self, operation: Operation<'c>) -> OperationRef<'c, 'v> { + let block = unsafe { Block::from_raw(self.raw) }; + let result = block.append_operation(operation); + Block::into_raw(block); + result + } + + fn insert_operation(&self, position: usize, operation: Operation<'c>) -> OperationRef<'c, 'v> { + let block = unsafe { Block::from_raw(self.raw) }; + let result = block.insert_operation(position, operation); + Block::into_raw(block); + result + } + + fn insert_operation_after( + &self, + one: OperationRef<'c, 'v>, + other: Operation<'c>, + ) -> OperationRef<'c, 'v> { + let block = unsafe { Block::from_raw(self.raw) }; + let result = block.insert_operation_after(one, other); + Block::into_raw(block); + result + } + + fn insert_operation_before( + &self, + one: OperationRef<'c, 'v>, + other: Operation<'c>, + ) -> OperationRef<'c, 'v> { + let block = unsafe { Block::from_raw(self.raw) }; + let result = block.insert_operation_before(one, other); + Block::into_raw(block); + result + } + + fn next_in_region(&self) -> Option> { + let block = unsafe { Block::from_raw(self.raw) }; + let result = block.next_in_region(); + Block::into_raw(block); + result + } +} + +impl<'c> Deref for BlockRef<'c, '_> { + type Target = Block<'c>; fn deref(&self) -> &Self::Target { unsafe { transmute(self) } diff --git a/melior/src/ir/block/argument.rs b/melior/src/ir/block/argument.rs index 66303cbdce..4218c79a2c 100644 --- a/melior/src/ir/block/argument.rs +++ b/melior/src/ir/block/argument.rs @@ -71,7 +71,7 @@ mod tests { use super::*; use crate::{ context::Context, - ir::{Block, Location}, + ir::{block::BlockApi, Block, Location}, }; #[test] diff --git a/melior/src/ir/operation.rs b/melior/src/ir/operation.rs index a68535d2f6..02f70536e0 100644 --- a/melior/src/ir/operation.rs +++ b/melior/src/ir/operation.rs @@ -521,7 +521,7 @@ mod tests { use super::*; use crate::{ context::Context, - ir::{attribute::StringAttribute, Block, Location, Region, Type}, + ir::{attribute::StringAttribute, block::BlockApi, Block, Location, Region, Type}, test::create_test_context, }; use pretty_assertions::assert_eq; diff --git a/melior/src/ir/operation/builder.rs b/melior/src/ir/operation/builder.rs index ed787745bb..0429bafb1a 100644 --- a/melior/src/ir/operation/builder.rs +++ b/melior/src/ir/operation/builder.rs @@ -137,7 +137,7 @@ impl<'c> OperationBuilder<'c> { mod tests { use super::*; use crate::{ - ir::{Block, ValueLike}, + ir::{block::BlockApi, Block, ValueLike}, test::create_test_context, }; diff --git a/melior/src/ir/operation/result.rs b/melior/src/ir/operation/result.rs index 1d0109699f..e92a2e5b0b 100644 --- a/melior/src/ir/operation/result.rs +++ b/melior/src/ir/operation/result.rs @@ -61,7 +61,7 @@ impl<'c, 'a> TryFrom> for OperationResult<'c, 'a> { #[cfg(test)] mod tests { use crate::{ - ir::{operation::OperationBuilder, Block, Location, Type}, + ir::{block::BlockApi, operation::OperationBuilder, Block, Location, Type}, test::create_test_context, }; diff --git a/melior/src/ir/value.rs b/melior/src/ir/value.rs index d38fc0145a..444e1c71a5 100644 --- a/melior/src/ir/value.rs +++ b/melior/src/ir/value.rs @@ -79,7 +79,9 @@ from_borrowed_subtypes!(Value, BlockArgument, OperationResult); mod tests { use super::*; use crate::{ - ir::{operation::OperationBuilder, Attribute, Block, Identifier, Location}, + ir::{ + block::BlockApi, operation::OperationBuilder, Attribute, Block, Identifier, Location, + }, test::create_test_context, Context, }; diff --git a/melior/src/lib.rs b/melior/src/lib.rs index 230909ff0e..c4e2ccf03d 100644 --- a/melior/src/lib.rs +++ b/melior/src/lib.rs @@ -36,6 +36,7 @@ mod tests { dialect::{self, arith, func, scf}, ir::{ attribute::{IntegerAttribute, StringAttribute, TypeAttribute}, + block::BlockApi, operation::OperationBuilder, r#type::{FunctionType, IntegerType}, Block, Location, Module, Region, Type, Value, diff --git a/melior/src/pass/external.rs b/melior/src/pass/external.rs index 841b6f6a0b..218292d878 100644 --- a/melior/src/pass/external.rs +++ b/melior/src/pass/external.rs @@ -216,6 +216,7 @@ mod tests { dialect::func, ir::{ attribute::{StringAttribute, TypeAttribute}, + block::BlockApi, r#type::FunctionType, Block, Identifier, Location, Module, Region, },