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#[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), 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 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}