use crate::{
attribute::AttributeDict,
basic_block::BasicBlock,
builtin::attributes::{ATTR_KEY_GIVEN_NAMES, GivenNamesAttr},
context::{Context, Ptr},
graph::{
walkers,
walkers::{IRNode, WALKCONFIG_PREORDER_FORWARD},
},
identifier::Identifier,
operation::Operation,
utils::table::smalltable,
};
fn set_name_in_attr_map(attributes: &mut AttributeDict, idx: usize, name: Option<Identifier>) {
match attributes.0.entry(ATTR_KEY_GIVEN_NAMES.clone()) {
smalltable::Entry::Occupied(mut occupied) => {
let given_names = occupied
.get_mut()
.downcast_mut::<GivenNamesAttr>()
.expect("Existing attribute entry for given names incorrect");
let name_is_none = name.is_none();
given_names.set_name(idx, name);
if name_is_none && given_names.are_all_names_unset() {
occupied.remove();
}
}
smalltable::Entry::Vacant(vacant) => {
if name.is_some() {
let mut given_names = GivenNamesAttr::default();
given_names.set_name(idx, name);
vacant.insert(given_names.into());
}
}
}
}
fn insert_name_in_attr_map(attributes: &mut AttributeDict, idx: usize, name: Option<Identifier>) {
match attributes.0.entry(ATTR_KEY_GIVEN_NAMES.clone()) {
smalltable::Entry::Occupied(mut occupied) => {
let given_names = occupied
.get_mut()
.downcast_mut::<GivenNamesAttr>()
.expect("Existing attribute entry for given names incorrect");
let name_is_none = name.is_none();
given_names.insert_name(idx, name);
if name_is_none && given_names.are_all_names_unset() {
occupied.remove();
}
}
smalltable::Entry::Vacant(vacant) => {
if name.is_some() {
let mut given_names = GivenNamesAttr::default();
given_names.insert_name(idx, name);
vacant.insert(given_names.into());
}
}
}
}
fn remove_name_from_attr_map(attributes: &mut AttributeDict, idx: usize) {
if let smalltable::Entry::Occupied(mut occupied) =
attributes.0.entry(ATTR_KEY_GIVEN_NAMES.clone())
{
let given_names = occupied
.get_mut()
.downcast_mut::<GivenNamesAttr>()
.expect("Existing attribute entry for given names incorrect");
given_names.remove_name(idx);
if given_names.are_all_names_unset() {
occupied.remove();
}
}
}
fn get_name_from_attr_map(attributes: &AttributeDict, idx: usize) -> Option<Identifier> {
attributes
.get::<GivenNamesAttr>(&ATTR_KEY_GIVEN_NAMES)
.and_then(|given_names| given_names.get_name(idx))
}
pub fn set_operation_result_name(
ctx: &Context,
op: Ptr<Operation>,
res_idx: usize,
name: Option<Identifier>,
) {
let op = &mut *op.deref_mut(ctx);
let num_results = op.get_num_results();
assert!(res_idx < num_results);
set_name_in_attr_map(&mut op.attributes, res_idx, name);
}
pub fn insert_operation_result_name(
ctx: &Context,
op: Ptr<Operation>,
res_idx: usize,
name: Option<Identifier>,
) {
let op = &mut *op.deref_mut(ctx);
let num_results = op.get_num_results();
assert!(res_idx <= num_results);
insert_name_in_attr_map(&mut op.attributes, res_idx, name);
}
pub fn remove_operation_result_name(ctx: &Context, op: Ptr<Operation>, res_idx: usize) {
let op = &mut *op.deref_mut(ctx);
let num_results = op.get_num_results();
assert!(res_idx < num_results);
remove_name_from_attr_map(&mut op.attributes, res_idx);
}
pub fn get_operation_result_name(
ctx: &Context,
op: Ptr<Operation>,
res_idx: usize,
) -> Option<Identifier> {
let op = &*op.deref(ctx);
get_name_from_attr_map(&op.attributes, res_idx)
}
pub fn set_block_arg_name(
ctx: &Context,
block: Ptr<BasicBlock>,
arg_idx: usize,
name: Option<Identifier>,
) {
let block = &mut *block.deref_mut(ctx);
let num_args = block.get_num_arguments();
assert!(arg_idx < num_args);
set_name_in_attr_map(&mut block.attributes, arg_idx, name);
}
pub fn insert_block_arg_name(
ctx: &Context,
block: Ptr<BasicBlock>,
arg_idx: usize,
name: Option<Identifier>,
) {
let block = &mut *block.deref_mut(ctx);
let num_args = block.get_num_arguments();
assert!(arg_idx <= num_args);
insert_name_in_attr_map(&mut block.attributes, arg_idx, name);
}
pub fn remove_block_arg_name(ctx: &Context, block: Ptr<BasicBlock>, arg_idx: usize) {
let block = &mut *block.deref_mut(ctx);
let num_args = block.get_num_arguments();
assert!(arg_idx < num_args);
remove_name_from_attr_map(&mut block.attributes, arg_idx);
}
pub fn get_block_arg_name(
ctx: &Context,
block: Ptr<BasicBlock>,
arg_idx: usize,
) -> Option<Identifier> {
let block = &*block.deref(ctx);
get_name_from_attr_map(&block.attributes, arg_idx)
}
pub fn erase_given_names(ctx: &Context, op: Ptr<Operation>) {
walkers::uninterruptible::immutable::walk_op(
ctx,
&mut (),
&WALKCONFIG_PREORDER_FORWARD,
op,
|ctx: &Context, _state: &mut (), node: IRNode| match node {
IRNode::Operation(op) => {
let num_results = op.deref(ctx).get_num_results();
for res_idx in 0..num_results {
set_operation_result_name(ctx, op, res_idx, None);
}
}
IRNode::BasicBlock(block) => {
let num_args = block.deref(ctx).get_num_arguments();
for arg_idx in 0..num_args {
set_block_arg_name(ctx, block, arg_idx, None);
}
block.deref_mut(ctx).set_label(None);
}
IRNode::Region(_) => {}
},
);
}
#[cfg(test)]
mod tests {
use super::{
get_block_arg_name, get_operation_result_name, insert_block_arg_name,
insert_operation_result_name, remove_block_arg_name, remove_operation_result_name,
set_block_arg_name, set_operation_result_name,
};
use crate::{
basic_block::BasicBlock,
builtin::{
op_interfaces::{NOpdsInterface, OneResultInterface},
types::{IntegerType, Signedness},
},
context::Context,
ident,
op::Op,
operation::{Operation, verify_operation},
result::Result,
};
use alloc::vec;
use pliron::derive::pliron_op;
#[pliron_op(
name = "test.zero",
format,
interfaces = [OneResultInterface, NOpdsInterface<0>],
verifier = "succ",
)]
struct ZeroOp;
impl ZeroOp {
pub fn new(ctx: &mut Context) -> Self {
let i64_ty = IntegerType::get(ctx, 64, Signedness::Signed);
ZeroOp {
op: Operation::new(
ctx,
Self::get_concrete_op_info(),
vec![i64_ty.into()],
vec![],
vec![],
0,
),
}
}
}
#[test]
fn test_op_result_name() -> Result<()> {
let mut ctx = Context::new();
let cop = ZeroOp::new(&mut ctx);
let op = cop.get_operation();
set_operation_result_name(&ctx, op, 0, Some(ident!("foo")));
assert_eq!(
get_operation_result_name(&ctx, op, 0).unwrap(),
ident!("foo")
);
verify_operation(op, &ctx)?;
Ok(())
}
#[test]
fn test_block_arg_name() -> Result<()> {
let mut ctx = Context::new();
let i64_ty = IntegerType::get(&ctx, 64, Signedness::Signed);
let block = BasicBlock::new(&mut ctx, Some(ident!("entry")), vec![i64_ty.into()]);
set_block_arg_name(&ctx, block, 0, Some(ident!("foo")));
assert!(get_block_arg_name(&ctx, block, 0).unwrap() == ident!("foo"));
Ok(())
}
#[test]
fn test_op_result_name_insert_remove_shift() {
let mut ctx = Context::new();
let i64_ty = IntegerType::get(&ctx, 64, Signedness::Signed);
let op = Operation::new(
&mut ctx,
ZeroOp::get_concrete_op_info(),
vec![i64_ty.into(), i64_ty.into(), i64_ty.into()],
vec![],
vec![],
0,
);
set_operation_result_name(&ctx, op, 0, Some(ident!("r0")));
set_operation_result_name(&ctx, op, 1, Some(ident!("r1")));
assert_eq!(get_operation_result_name(&ctx, op, 0), Some(ident!("r0")));
assert_eq!(get_operation_result_name(&ctx, op, 1), Some(ident!("r1")));
assert_eq!(get_operation_result_name(&ctx, op, 2), None);
insert_operation_result_name(&ctx, op, 2, Some(ident!("tail")));
assert_eq!(get_operation_result_name(&ctx, op, 0), Some(ident!("r0")));
assert_eq!(get_operation_result_name(&ctx, op, 1), Some(ident!("r1")));
assert_eq!(get_operation_result_name(&ctx, op, 2), Some(ident!("tail")));
remove_operation_result_name(&ctx, op, 2);
assert_eq!(get_operation_result_name(&ctx, op, 0), Some(ident!("r0")));
assert_eq!(get_operation_result_name(&ctx, op, 1), Some(ident!("r1")));
assert_eq!(get_operation_result_name(&ctx, op, 2), None);
insert_operation_result_name(&ctx, op, 0, None);
assert_eq!(get_operation_result_name(&ctx, op, 0), None);
assert_eq!(get_operation_result_name(&ctx, op, 1), Some(ident!("r0")));
assert_eq!(get_operation_result_name(&ctx, op, 2), Some(ident!("r1")));
insert_operation_result_name(&ctx, op, 0, Some(ident!("ins")));
assert_eq!(get_operation_result_name(&ctx, op, 0), Some(ident!("ins")));
assert_eq!(get_operation_result_name(&ctx, op, 1), None);
assert_eq!(get_operation_result_name(&ctx, op, 2), Some(ident!("r0")));
assert_eq!(get_operation_result_name(&ctx, op, 3), Some(ident!("r1")));
remove_operation_result_name(&ctx, op, 0);
assert_eq!(get_operation_result_name(&ctx, op, 0), None);
assert_eq!(get_operation_result_name(&ctx, op, 1), Some(ident!("r0")));
assert_eq!(get_operation_result_name(&ctx, op, 2), Some(ident!("r1")));
remove_operation_result_name(&ctx, op, 0);
assert_eq!(get_operation_result_name(&ctx, op, 0), Some(ident!("r0")));
assert_eq!(get_operation_result_name(&ctx, op, 1), Some(ident!("r1")));
}
#[test]
fn test_block_arg_name_insert_remove_shift() {
let mut ctx = Context::new();
let i64_ty = IntegerType::get(&ctx, 64, Signedness::Signed);
let block = BasicBlock::new(
&mut ctx,
Some(ident!("entry")),
vec![i64_ty.into(), i64_ty.into(), i64_ty.into()],
);
set_block_arg_name(&ctx, block, 0, Some(ident!("a0")));
set_block_arg_name(&ctx, block, 1, Some(ident!("a1")));
assert_eq!(get_block_arg_name(&ctx, block, 0), Some(ident!("a0")));
assert_eq!(get_block_arg_name(&ctx, block, 1), Some(ident!("a1")));
assert_eq!(get_block_arg_name(&ctx, block, 2), None);
insert_block_arg_name(&ctx, block, 2, Some(ident!("tail")));
assert_eq!(get_block_arg_name(&ctx, block, 0), Some(ident!("a0")));
assert_eq!(get_block_arg_name(&ctx, block, 1), Some(ident!("a1")));
assert_eq!(get_block_arg_name(&ctx, block, 2), Some(ident!("tail")));
remove_block_arg_name(&ctx, block, 2);
assert_eq!(get_block_arg_name(&ctx, block, 0), Some(ident!("a0")));
assert_eq!(get_block_arg_name(&ctx, block, 1), Some(ident!("a1")));
assert_eq!(get_block_arg_name(&ctx, block, 2), None);
insert_block_arg_name(&ctx, block, 0, None);
assert_eq!(get_block_arg_name(&ctx, block, 0), None);
assert_eq!(get_block_arg_name(&ctx, block, 1), Some(ident!("a0")));
assert_eq!(get_block_arg_name(&ctx, block, 2), Some(ident!("a1")));
insert_block_arg_name(&ctx, block, 0, Some(ident!("ins")));
assert_eq!(get_block_arg_name(&ctx, block, 0), Some(ident!("ins")));
assert_eq!(get_block_arg_name(&ctx, block, 1), None);
assert_eq!(get_block_arg_name(&ctx, block, 2), Some(ident!("a0")));
assert_eq!(get_block_arg_name(&ctx, block, 3), Some(ident!("a1")));
remove_block_arg_name(&ctx, block, 0);
assert_eq!(get_block_arg_name(&ctx, block, 0), None);
assert_eq!(get_block_arg_name(&ctx, block, 1), Some(ident!("a0")));
assert_eq!(get_block_arg_name(&ctx, block, 2), Some(ident!("a1")));
remove_block_arg_name(&ctx, block, 0);
assert_eq!(get_block_arg_name(&ctx, block, 0), Some(ident!("a0")));
assert_eq!(get_block_arg_name(&ctx, block, 1), Some(ident!("a1")));
}
}