use rustc_hash::FxHashMap;
use crate::{
block::BlockArgument,
constant::Constant,
context::Context,
instruction::InstOp,
irtype::Type,
metadata::{combine, MetadataIndex},
pretty::DebugWithContext,
Block, Instruction,
};
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, DebugWithContext)]
pub struct Value(#[in_context(values)] pub slotmap::DefaultKey);
#[doc(hidden)]
#[derive(Debug, Clone, DebugWithContext)]
pub struct ValueContent {
pub value: ValueDatum,
pub metadata: Option<MetadataIndex>,
}
#[doc(hidden)]
#[derive(Debug, Clone, DebugWithContext)]
pub enum ValueDatum {
Argument(BlockArgument),
Constant(Constant),
Instruction(Instruction),
}
impl Value {
pub fn new_argument(context: &mut Context, arg: BlockArgument) -> Value {
let content = ValueContent {
value: ValueDatum::Argument(arg),
metadata: None,
};
Value(context.values.insert(content))
}
pub fn new_constant(context: &mut Context, constant: Constant) -> Value {
let content = ValueContent {
value: ValueDatum::Constant(constant),
metadata: None,
};
Value(context.values.insert(content))
}
pub fn new_instruction(context: &mut Context, block: Block, instruction: InstOp) -> Value {
let content = ValueContent {
value: ValueDatum::Instruction(Instruction {
op: instruction,
parent: block,
}),
metadata: None,
};
Value(context.values.insert(content))
}
pub fn add_metadatum(self, context: &mut Context, md_idx: Option<MetadataIndex>) -> Self {
if md_idx.is_some() {
let orig_md = context.values[self.0].metadata;
let new_md = combine(context, &orig_md, &md_idx);
context.values[self.0].metadata = new_md;
}
self
}
pub fn get_metadata(&self, context: &Context) -> Option<MetadataIndex> {
context.values[self.0].metadata
}
pub fn is_constant(&self, context: &Context) -> bool {
matches!(context.values[self.0].value, ValueDatum::Constant(_))
}
pub fn is_terminator(&self, context: &Context) -> bool {
match &context.values[self.0].value {
ValueDatum::Instruction(Instruction { op, .. }) => op.is_terminator(),
ValueDatum::Argument(..) | ValueDatum::Constant(..) => false,
}
}
pub fn replace_instruction_value(&self, context: &mut Context, old_val: Value, new_val: Value) {
self.replace_instruction_values(context, &FxHashMap::from_iter([(old_val, new_val)]))
}
pub fn replace_instruction_values(
&self,
context: &mut Context,
replace_map: &FxHashMap<Value, Value>,
) {
if let ValueDatum::Instruction(instruction) =
&mut context.values.get_mut(self.0).unwrap().value
{
instruction.op.replace_values(replace_map);
}
}
pub fn replace(&self, context: &mut Context, other: ValueDatum) {
context.values[self.0].value = other;
}
pub fn get_instruction<'a>(&self, context: &'a Context) -> Option<&'a Instruction> {
if let ValueDatum::Instruction(instruction) = &context.values[self.0].value {
Some(instruction)
} else {
None
}
}
pub fn get_instruction_mut<'a>(&self, context: &'a mut Context) -> Option<&'a mut Instruction> {
if let ValueDatum::Instruction(instruction) =
&mut context.values.get_mut(self.0).unwrap().value
{
Some(instruction)
} else {
None
}
}
pub fn get_constant<'a>(&self, context: &'a Context) -> Option<&'a Constant> {
if let ValueDatum::Constant(cn) = &context.values[self.0].value {
Some(cn)
} else {
None
}
}
pub fn get_argument<'a>(&self, context: &'a Context) -> Option<&'a BlockArgument> {
if let ValueDatum::Argument(arg) = &context.values[self.0].value {
Some(arg)
} else {
None
}
}
pub fn get_argument_mut<'a>(&self, context: &'a mut Context) -> Option<&'a mut BlockArgument> {
if let ValueDatum::Argument(arg) = &mut context.values[self.0].value {
Some(arg)
} else {
None
}
}
pub fn get_type(&self, context: &Context) -> Option<Type> {
match &context.values[self.0].value {
ValueDatum::Argument(BlockArgument { ty, .. }) => Some(*ty),
ValueDatum::Constant(c) => Some(c.ty),
ValueDatum::Instruction(ins) => ins.get_type(context),
}
}
pub fn match_ptr_type(&self, context: &Context) -> Option<Type> {
self.get_type(context)
.and_then(|ty| ty.get_pointee_type(context))
}
}