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_u64_constant(context: &mut Context, value: u64) -> Value {
62 let constant = crate::ConstantContent::new_uint(context, 64, value);
63 let constant = Constant::unique(context, constant);
64 Self::new_constant(context, constant)
65 }
66
67 pub fn new_instruction(context: &mut Context, block: Block, instruction: InstOp) -> Value {
69 let content = ValueContent {
70 value: ValueDatum::Instruction(Instruction {
71 op: instruction,
72 parent: block,
73 }),
74 metadata: None,
75 };
76 Value(context.values.insert(content))
77 }
78
79 pub fn add_metadatum(self, context: &mut Context, md_idx: Option<MetadataIndex>) -> Self {
87 if md_idx.is_some() {
88 let orig_md = context.values[self.0].metadata;
89 let new_md = combine(context, &orig_md, &md_idx);
90 context.values[self.0].metadata = new_md;
91 }
92 self
93 }
94
95 pub fn get_metadata(&self, context: &Context) -> Option<MetadataIndex> {
97 context.values[self.0].metadata
98 }
99
100 pub fn is_constant(&self, context: &Context) -> bool {
102 matches!(context.values[self.0].value, ValueDatum::Constant(_))
103 }
104
105 pub fn is_terminator(&self, context: &Context) -> bool {
110 match &context.values[self.0].value {
111 ValueDatum::Instruction(Instruction { op, .. }) => op.is_terminator(),
112 ValueDatum::Argument(..) | ValueDatum::Constant(..) => false,
113 }
114 }
115
116 pub fn replace_instruction_value(&self, context: &mut Context, old_val: Value, new_val: Value) {
119 self.replace_instruction_values(context, &FxHashMap::from_iter([(old_val, new_val)]))
120 }
121
122 pub fn replace_instruction_values(
125 &self,
126 context: &mut Context,
127 replace_map: &FxHashMap<Value, Value>,
128 ) {
129 if let ValueDatum::Instruction(instruction) =
130 &mut context.values.get_mut(self.0).unwrap().value
131 {
132 instruction.op.replace_values(replace_map);
133 }
134 }
135
136 pub fn replace(&self, context: &mut Context, other: ValueDatum) {
138 context.values[self.0].value = other;
139 }
140
141 pub fn get_instruction<'a>(&self, context: &'a Context) -> Option<&'a Instruction> {
143 if let ValueDatum::Instruction(instruction) = &context.values[self.0].value {
144 Some(instruction)
145 } else {
146 None
147 }
148 }
149
150 pub fn get_instruction_mut<'a>(&self, context: &'a mut Context) -> Option<&'a mut Instruction> {
152 if let ValueDatum::Instruction(instruction) =
153 &mut context.values.get_mut(self.0).unwrap().value
154 {
155 Some(instruction)
156 } else {
157 None
158 }
159 }
160
161 pub fn get_constant<'a>(&self, context: &'a Context) -> Option<&'a Constant> {
163 if let ValueDatum::Constant(cn) = &context.values[self.0].value {
164 Some(cn)
165 } else {
166 None
167 }
168 }
169
170 pub fn get_argument<'a>(&self, context: &'a Context) -> Option<&'a BlockArgument> {
172 if let ValueDatum::Argument(arg) = &context.values[self.0].value {
173 Some(arg)
174 } else {
175 None
176 }
177 }
178
179 pub fn get_argument_mut<'a>(&self, context: &'a mut Context) -> Option<&'a mut BlockArgument> {
181 if let ValueDatum::Argument(arg) = &mut context.values[self.0].value {
182 Some(arg)
183 } else {
184 None
185 }
186 }
187
188 pub fn get_type(&self, context: &Context) -> Option<Type> {
192 match &context.values[self.0].value {
193 ValueDatum::Argument(BlockArgument { ty, .. }) => Some(*ty),
194 ValueDatum::Constant(c) => Some(c.get_content(context).ty),
195 ValueDatum::Instruction(ins) => ins.get_type(context),
196 }
197 }
198
199 pub fn match_ptr_type(&self, context: &Context) -> Option<Type> {
201 self.get_type(context)
202 .and_then(|ty| ty.get_pointee_type(context))
203 }
204}