1use rustc_hash::FxHashMap;
10
11use crate::{
12 block::BlockArgument,
13 context::Context,
14 instruction::InstOp,
15 irtype::Type,
16 metadata::{combine, MetadataIndex},
17 pretty::DebugWithContext,
18 Block, Constant, Instruction,
19};
20
21#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, DebugWithContext)]
24pub struct Value(#[in_context(values)] pub slotmap::DefaultKey);
25
26#[doc(hidden)]
27#[derive(Debug, Clone, DebugWithContext)]
28pub struct ValueContent {
29 pub value: ValueDatum,
30 pub metadata: Option<MetadataIndex>,
31}
32
33#[doc(hidden)]
34#[derive(Debug, Clone, DebugWithContext)]
35pub enum ValueDatum {
36 Argument(BlockArgument),
37 Constant(Constant),
38 Instruction(Instruction),
39}
40
41impl Value {
42 pub fn new_argument(context: &mut Context, arg: BlockArgument) -> Value {
44 let content = ValueContent {
45 value: ValueDatum::Argument(arg),
46 metadata: None,
47 };
48 Value(context.values.insert(content))
49 }
50
51 pub fn new_constant(context: &mut Context, constant: Constant) -> Value {
53 let content = ValueContent {
54 value: ValueDatum::Constant(constant),
55 metadata: None,
56 };
57 Value(context.values.insert(content))
58 }
59
60 pub fn new_instruction(context: &mut Context, block: Block, instruction: InstOp) -> Value {
62 let content = ValueContent {
63 value: ValueDatum::Instruction(Instruction {
64 op: instruction,
65 parent: block,
66 }),
67 metadata: None,
68 };
69 Value(context.values.insert(content))
70 }
71
72 pub fn add_metadatum(self, context: &mut Context, md_idx: Option<MetadataIndex>) -> Self {
80 if md_idx.is_some() {
81 let orig_md = context.values[self.0].metadata;
82 let new_md = combine(context, &orig_md, &md_idx);
83 context.values[self.0].metadata = new_md;
84 }
85 self
86 }
87
88 pub fn get_metadata(&self, context: &Context) -> Option<MetadataIndex> {
90 context.values[self.0].metadata
91 }
92
93 pub fn is_constant(&self, context: &Context) -> bool {
95 matches!(context.values[self.0].value, ValueDatum::Constant(_))
96 }
97
98 pub fn is_terminator(&self, context: &Context) -> bool {
103 match &context.values[self.0].value {
104 ValueDatum::Instruction(Instruction { op, .. }) => op.is_terminator(),
105 ValueDatum::Argument(..) | ValueDatum::Constant(..) => false,
106 }
107 }
108
109 pub fn replace_instruction_value(&self, context: &mut Context, old_val: Value, new_val: Value) {
112 self.replace_instruction_values(context, &FxHashMap::from_iter([(old_val, new_val)]))
113 }
114
115 pub fn replace_instruction_values(
118 &self,
119 context: &mut Context,
120 replace_map: &FxHashMap<Value, Value>,
121 ) {
122 if let ValueDatum::Instruction(instruction) =
123 &mut context.values.get_mut(self.0).unwrap().value
124 {
125 instruction.op.replace_values(replace_map);
126 }
127 }
128
129 pub fn replace(&self, context: &mut Context, other: ValueDatum) {
131 context.values[self.0].value = other;
132 }
133
134 pub fn get_instruction<'a>(&self, context: &'a Context) -> Option<&'a Instruction> {
136 if let ValueDatum::Instruction(instruction) = &context.values[self.0].value {
137 Some(instruction)
138 } else {
139 None
140 }
141 }
142
143 pub fn get_instruction_mut<'a>(&self, context: &'a mut Context) -> Option<&'a mut Instruction> {
145 if let ValueDatum::Instruction(instruction) =
146 &mut context.values.get_mut(self.0).unwrap().value
147 {
148 Some(instruction)
149 } else {
150 None
151 }
152 }
153
154 pub fn get_constant<'a>(&self, context: &'a Context) -> Option<&'a Constant> {
156 if let ValueDatum::Constant(cn) = &context.values[self.0].value {
157 Some(cn)
158 } else {
159 None
160 }
161 }
162
163 pub fn get_argument<'a>(&self, context: &'a Context) -> Option<&'a BlockArgument> {
165 if let ValueDatum::Argument(arg) = &context.values[self.0].value {
166 Some(arg)
167 } else {
168 None
169 }
170 }
171
172 pub fn get_argument_mut<'a>(&self, context: &'a mut Context) -> Option<&'a mut BlockArgument> {
174 if let ValueDatum::Argument(arg) = &mut context.values[self.0].value {
175 Some(arg)
176 } else {
177 None
178 }
179 }
180
181 pub fn get_type(&self, context: &Context) -> Option<Type> {
185 match &context.values[self.0].value {
186 ValueDatum::Argument(BlockArgument { ty, .. }) => Some(*ty),
187 ValueDatum::Constant(c) => Some(c.get_content(context).ty),
188 ValueDatum::Instruction(ins) => ins.get_type(context),
189 }
190 }
191
192 pub fn match_ptr_type(&self, context: &Context) -> Option<Type> {
194 self.get_type(context)
195 .and_then(|ty| ty.get_pointee_type(context))
196 }
197}