Skip to main content

vicis_core/ir/value/
mod.rs

1pub mod parser;
2
3pub use parser::parse;
4
5use super::{
6    function::{data::Data, instruction::InstructionId},
7    module::name::Name,
8    types::{Type, Types},
9    util::escape,
10};
11use id_arena::Id;
12use std::{fmt, str};
13
14pub type ValueId = Id<Value>;
15
16/// A value in LLVM IR.
17///
18/// The original LLVM Value class has information about its uses and users.
19/// However, `Value` here does not have such information.
20/// Instead, only for [`Instruction`](super::function::instruction::Instruction)s
21/// we track uses & users. (See [`Data`](Data) for details.)
22#[derive(Debug, Clone, PartialEq)]
23pub enum Value {
24    Instruction(InstructionId),
25    Argument(usize),
26    Constant(ConstantData),
27    InlineAsm(InlineAsm),
28}
29
30#[derive(Debug, Clone, PartialEq)]
31pub enum ConstantData {
32    Undef,
33    AggregateZero,
34    Null,
35    Int(ConstantInt),
36    Array(ConstantArray),
37    Struct(ConstantStruct),
38    Expr(ConstantExpr), // TODO: Boxing?
39    GlobalRef(Name),
40}
41
42#[derive(Debug, Clone, Copy, PartialEq)]
43pub enum ConstantInt {
44    Int1(bool),
45    Int8(i8),
46    Int32(i32),
47    Int64(i64),
48}
49
50#[derive(Debug, Clone, PartialEq)]
51pub struct ConstantArray {
52    pub elem_ty: Type,
53    pub elems: Vec<ConstantData>,
54    pub is_string: bool,
55}
56
57#[derive(Debug, Clone, PartialEq)]
58pub struct ConstantStruct {
59    pub elems_ty: Vec<Type>,
60    pub elems: Vec<ConstantData>,
61    pub is_packed: bool,
62}
63
64#[derive(Debug, Clone, PartialEq)]
65pub enum ConstantExpr {
66    GetElementPtr {
67        inbounds: bool,
68        tys: Vec<Type>,
69        args: Vec<ConstantData>,
70    },
71    Bitcast {
72        tys: [Type; 2],
73        arg: Box<ConstantData>,
74    },
75}
76
77#[derive(Debug, Clone, PartialEq)]
78pub struct InlineAsm {
79    pub body: String,
80    pub constraints: String,
81    pub sideeffect: bool,
82}
83
84impl Value {
85    pub fn undef() -> Self {
86        Self::Constant(ConstantData::Undef)
87    }
88
89    pub fn as_inst(&self) -> &InstructionId {
90        match self {
91            Self::Instruction(id) => id,
92            _ => panic!(),
93        }
94    }
95
96    pub fn to_string(&self, _data: &Data, types: &Types) -> String {
97        match self {
98            Self::Constant(c) => c.to_string(types),
99            Self::Instruction(id) => {
100                format!("%I{}", id.index())
101            }
102            Self::Argument(n) => format!("%A{}", n),
103            Self::InlineAsm(InlineAsm {
104                body,
105                constraints,
106                sideeffect,
107            }) => {
108                format!(
109                    "asm {}\"{}\", \"{}\"",
110                    if *sideeffect { "sideeffect " } else { "" },
111                    constraints,
112                    body
113                )
114            }
115        }
116    }
117}
118
119impl ConstantData {
120    pub fn to_string(&self, types: &Types) -> String {
121        match self {
122            Self::Undef => "undef".to_string(),
123            Self::AggregateZero => "zeroinitializer".to_string(),
124            Self::Null => "null".to_string(),
125            Self::Int(i) => i.to_string(),
126            Self::Array(a) => a.to_string(types),
127            Self::Struct(s) => s.to_string(types),
128            Self::Expr(e) => e.to_string(types),
129            Self::GlobalRef(name) => format!("@{:?}", name),
130        }
131    }
132
133    pub fn as_int(&self) -> &ConstantInt {
134        match self {
135            Self::Int(i) => i,
136            _ => panic!(),
137        }
138    }
139
140    pub fn as_global_ref(&self) -> &Name {
141        match self {
142            Self::GlobalRef(name) => name,
143            _ => panic!(),
144        }
145    }
146
147    pub fn as_array(&self) -> &ConstantArray {
148        match self {
149            Self::Array(a) => a,
150            _ => panic!(),
151        }
152    }
153}
154
155impl ConstantInt {
156    pub fn as_i8(&self) -> &i8 {
157        match self {
158            Self::Int8(i) => i,
159            _ => panic!(),
160        }
161    }
162
163    // TODO: Generics?
164    pub fn cast_to_usize(self) -> usize {
165        match self {
166            Self::Int1(i) => i as usize,
167            Self::Int8(i) => i as usize,
168            Self::Int32(i) => i as usize,
169            Self::Int64(i) => i as usize,
170        }
171    }
172}
173
174impl ConstantArray {
175    pub fn to_string(&self, types: &Types) -> String {
176        if self.is_string {
177            return format!(
178                "c\"{}\"",
179                escape(
180                    str::from_utf8(
181                        self.elems
182                            .iter()
183                            .map(|i| *i.as_int().as_i8() as u8)
184                            .collect::<Vec<u8>>()
185                            .as_slice(),
186                    )
187                    .unwrap()
188                )
189            );
190        }
191
192        format!(
193            "{}]",
194            self.elems
195                .iter()
196                .fold("[".to_string(), |acc, e| {
197                    format!(
198                        "{}{} {}, ",
199                        acc,
200                        types.to_string(self.elem_ty),
201                        e.to_string(types)
202                    )
203                })
204                .trim_end_matches(", ")
205        )
206    }
207}
208
209impl ConstantStruct {
210    pub fn to_string(&self, types: &Types) -> String {
211        format!(
212            "{}{{ {} }}{}",
213            if self.is_packed { "<" } else { "" },
214            self.elems
215                .iter()
216                .zip(self.elems_ty.iter())
217                .fold("".to_string(), |acc, (e, &et)| {
218                    format!("{}{} {}, ", acc, types.to_string(et), e.to_string(types))
219                })
220                .trim_end_matches(", "),
221            if self.is_packed { ">" } else { "" }
222        )
223    }
224}
225
226impl ConstantExpr {
227    pub fn to_string(&self, types: &Types) -> String {
228        match self {
229            Self::GetElementPtr {
230                inbounds,
231                tys,
232                args,
233            } => {
234                format!(
235                    "getelementptr {}({}, {})",
236                    if *inbounds { "inbounds " } else { "" },
237                    types.to_string(tys[0]),
238                    tys[1..]
239                        .iter()
240                        .zip(args.iter())
241                        .fold("".to_string(), |acc, (ty, arg)| {
242                            format!("{}{} {}, ", acc, types.to_string(*ty), arg.to_string(types))
243                        })
244                        .trim_end_matches(", ")
245                )
246            }
247            Self::Bitcast { tys, arg } => {
248                format!(
249                    "bitcast ({} {} to {})",
250                    types.to_string(tys[0]),
251                    arg.to_string(types),
252                    types.to_string(tys[1]),
253                )
254            }
255        }
256    }
257}
258
259impl From<i32> for Value {
260    fn from(i: i32) -> Self {
261        Self::Constant(ConstantInt::Int32(i).into())
262    }
263}
264
265impl From<i64> for Value {
266    fn from(i: i64) -> Self {
267        Self::Constant(ConstantInt::Int64(i).into())
268    }
269}
270
271impl From<ConstantInt> for ConstantData {
272    fn from(i: ConstantInt) -> Self {
273        Self::Int(i)
274    }
275}
276
277impl From<ConstantInt> for Value {
278    fn from(i: ConstantInt) -> Self {
279        Self::Constant(i.into())
280    }
281}
282
283impl fmt::Display for ConstantInt {
284    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
285        match self {
286            Self::Int1(i) => write!(f, "{}", i),
287            Self::Int8(i) => write!(f, "{}", i),
288            Self::Int32(i) => write!(f, "{}", i),
289            Self::Int64(i) => write!(f, "{}", i),
290        }
291    }
292}