1use crate::naming::{FunctionNames, ProgramNames};
2use crate::{MirAggregateArg, MirFunction, MirInstr};
3
4use super::formatting::{
5 format_aggregate_arg, format_call_arg_mode, format_local, format_local_repr,
6};
7
8pub(super) fn format_instr(
10 function: &MirFunction,
11 instr: &MirInstr,
12 function_names: &FunctionNames,
13 program_names: &ProgramNames,
14) -> String {
15 match instr {
16 MirInstr::ConstUnit { dst } => {
17 format!("{} = const unit", format_local(*dst, function_names))
18 }
19 MirInstr::ConstInt { dst, value } => {
20 format!("{} = const {value}", format_local(*dst, function_names))
21 }
22 MirInstr::ConstFloat { dst, value } => {
23 format!("{} = const {value}", format_local(*dst, function_names))
24 }
25 MirInstr::ConstString { dst, value } => {
26 format!("{} = const \"{value}\"", format_local(*dst, function_names))
27 }
28 MirInstr::ConstBool { dst, value } => {
29 format!("{} = const {value}", format_local(*dst, function_names))
30 }
31 MirInstr::ConstNull { dst } => {
32 format!("{} = const null", format_local(*dst, function_names))
33 }
34 MirInstr::ReleaseHeap { local } => {
35 format!("release_heap {}", format_local(*local, function_names))
36 }
37 MirInstr::PointerNew { src, dst } => {
38 format!(
39 "{} = pointer_new {}",
40 format_local(*dst, function_names),
41 format_local(*src, function_names)
42 )
43 }
44 MirInstr::MakeArray { items, dst, .. } => {
45 format!(
46 "{} = array [{}]",
47 format_local(*dst, function_names),
48 format_aggregate_arg_list(items, function_names)
49 )
50 }
51 MirInstr::MakeTuple { items, dst, .. } => {
52 format!(
53 "{} = tuple ({})",
54 format_local(*dst, function_names),
55 format_aggregate_arg_list(items, function_names)
56 )
57 }
58 MirInstr::MakeStruct {
59 name, fields, dst, ..
60 } => {
61 let rendered_fields = fields
62 .iter()
63 .map(|(field_name, value)| {
64 format!("{field_name}: {}", format_local(*value, function_names))
65 })
66 .collect::<Vec<_>>()
67 .join(", ");
68 format!(
69 "{} = struct {} {{ {} }}",
70 format_local(*dst, function_names),
71 name,
72 rendered_fields
73 )
74 }
75 MirInstr::MakeEnum {
76 enum_name,
77 variant,
78 payload,
79 dst,
80 ..
81 } => {
82 format!(
83 "{} = enum {}::{}({})",
84 format_local(*dst, function_names),
85 enum_name,
86 variant,
87 format_aggregate_arg_list(payload, function_names)
88 )
89 }
90 MirInstr::ReadField { base, field, dst } => {
91 format!(
92 "{} = field {}.{}",
93 format_local(*dst, function_names),
94 format_local(*base, function_names),
95 field
96 )
97 }
98 MirInstr::FieldBorrowRo { base, field, dst } => {
99 format!(
100 "{} = field_borrow_ro {}.{}",
101 format_local(*dst, function_names),
102 format_local(*base, function_names),
103 field
104 )
105 }
106 MirInstr::FieldBorrowMut { base, field, dst } => {
107 format!(
108 "{} = field_borrow_mut {}.{}",
109 format_local(*dst, function_names),
110 format_local(*base, function_names),
111 field
112 )
113 }
114 MirInstr::EnumIsVariant {
115 value,
116 enum_name,
117 variant,
118 payload_len: _,
119 dst,
120 } => {
121 format!(
122 "{} = enum_is_variant {} {}::{}",
123 format_local(*dst, function_names),
124 format_local(*value, function_names),
125 enum_name,
126 variant
127 )
128 }
129 MirInstr::EnumGetField {
130 value,
131 enum_name,
132 variant,
133 index,
134 dst,
135 } => {
136 format!(
137 "{} = enum_get_field {} {}::{}[{}]",
138 format_local(*dst, function_names),
139 format_local(*value, function_names),
140 enum_name,
141 variant,
142 index
143 )
144 }
145 MirInstr::Copy { src, dst } => format!(
146 "{} = copy {}",
147 format_local(*dst, function_names),
148 format_local(*src, function_names)
149 ),
150 MirInstr::Move { src, dst } => format!(
151 "{} = move {}",
152 format_local(*dst, function_names),
153 format_local(*src, function_names)
154 ),
155 MirInstr::AssignLocal { src, dst } => format!(
156 "assign {} <- {}",
157 format_local(*dst, function_names),
158 format_local(*src, function_names)
159 ),
160 MirInstr::StoreRef { src, dst_ref } => format!(
161 "store_ref {} <- {}",
162 format_local(*dst_ref, function_names),
163 format_local(*src, function_names)
164 ),
165 MirInstr::AssignFieldPath { base, fields, src } => {
166 let mut path = format_local(*base, function_names);
167 for field in fields {
168 path.push('.');
169 path.push_str(field);
170 }
171 format!(
172 "assign_field {} <- {}",
173 path,
174 format_local(*src, function_names)
175 )
176 }
177 MirInstr::Call { callee, args, dst } => {
178 let args = args
179 .iter()
180 .map(|arg| format_call_arg(function, arg, function_names))
181 .collect::<Vec<_>>()
182 .join(", ");
183 format!(
184 "{} = call {}({args})",
185 format_local(*dst, function_names),
186 program_names.function_ident(*callee)
187 )
188 }
189 MirInstr::CallExtern { symbol, args, dst } => {
190 let args = args
191 .iter()
192 .map(|arg| format_call_arg(function, arg, function_names))
193 .collect::<Vec<_>>()
194 .join(", ");
195 format!(
196 "{} = extern {}({args})",
197 format_local(*dst, function_names),
198 symbol,
199 )
200 }
201 MirInstr::CallIntrinsic {
202 intrinsic,
203 args,
204 dst,
205 ..
206 } => {
207 let args = args
208 .iter()
209 .map(|arg| format_call_arg(function, arg, function_names))
210 .collect::<Vec<_>>()
211 .join(", ");
212 let name = match intrinsic {
213 crate::MirIntrinsic::Ptr => "@box",
214 crate::MirIntrinsic::Array => "@array",
215 };
216 format!(
217 "{} = intrinsic {}({args})",
218 format_local(*dst, function_names),
219 name,
220 )
221 }
222 MirInstr::CollectionLen { collection, dst } => format!(
223 "{} = len {}",
224 format_local(*dst, function_names),
225 format_local(*collection, function_names)
226 ),
227 MirInstr::IndexBorrowRo {
228 collection,
229 index,
230 dst,
231 } => {
232 format!(
233 "{} = index_borrow_ro {}, {}",
234 format_local(*dst, function_names),
235 format_local(*collection, function_names),
236 format_local(*index, function_names)
237 )
238 }
239 MirInstr::IndexBorrowMut {
240 collection,
241 index,
242 dst,
243 } => {
244 format!(
245 "{} = index_borrow_mut {}, {}",
246 format_local(*dst, function_names),
247 format_local(*collection, function_names),
248 format_local(*index, function_names)
249 )
250 }
251 MirInstr::SliceBorrowRo {
252 collection,
253 start,
254 end,
255 dst,
256 } => {
257 let start = start
258 .map(|value| format_local(value, function_names))
259 .unwrap_or_default();
260 let end = end
261 .map(|value| format_local(value, function_names))
262 .unwrap_or_default();
263 format!(
264 "{} = slice_borrow_ro {} [{}..{}]",
265 format_local(*dst, function_names),
266 format_local(*collection, function_names),
267 start,
268 end
269 )
270 }
271 MirInstr::SliceBorrowMut {
272 collection,
273 start,
274 end,
275 dst,
276 } => {
277 let start = start
278 .map(|value| format_local(value, function_names))
279 .unwrap_or_default();
280 let end = end
281 .map(|value| format_local(value, function_names))
282 .unwrap_or_default();
283 format!(
284 "{} = slice_borrow_mut {} [{}..{}]",
285 format_local(*dst, function_names),
286 format_local(*collection, function_names),
287 start,
288 end
289 )
290 }
291 MirInstr::PointerIsSome { pointer, dst } => {
292 format!(
293 "{} = pointer_is_some {}",
294 format_local(*dst, function_names),
295 format_local(*pointer, function_names)
296 )
297 }
298 MirInstr::PointerBorrowRo { pointer, dst } => {
299 format!(
300 "{} = pointer_borrow_ro {}",
301 format_local(*dst, function_names),
302 format_local(*pointer, function_names)
303 )
304 }
305 MirInstr::PointerBorrowMut { pointer, dst } => {
306 format!(
307 "{} = pointer_borrow_mut {}",
308 format_local(*dst, function_names),
309 format_local(*pointer, function_names)
310 )
311 }
312 MirInstr::DerefCopy { src, dst } => format!(
313 "{} = deref_copy {}",
314 format_local(*dst, function_names),
315 format_local(*src, function_names)
316 ),
317 MirInstr::NumCast { src, dst } => format!(
318 "{} = num_cast {}",
319 format_local(*dst, function_names),
320 format_local(*src, function_names)
321 ),
322 MirInstr::CheckedIntCast { src, dst } => format!(
323 "{} = checked_int_cast {}",
324 format_local(*dst, function_names),
325 format_local(*src, function_names)
326 ),
327 MirInstr::IntLt { lhs, rhs, dst } => {
328 format!(
329 "{} = int_lt {}, {}",
330 format_local(*dst, function_names),
331 format_local(*lhs, function_names),
332 format_local(*rhs, function_names)
333 )
334 }
335 MirInstr::IntGt { lhs, rhs, dst } => {
336 format!(
337 "{} = int_gt {}, {}",
338 format_local(*dst, function_names),
339 format_local(*lhs, function_names),
340 format_local(*rhs, function_names)
341 )
342 }
343 MirInstr::IntLtEq { lhs, rhs, dst } => {
344 format!(
345 "{} = int_lteq {}, {}",
346 format_local(*dst, function_names),
347 format_local(*lhs, function_names),
348 format_local(*rhs, function_names)
349 )
350 }
351 MirInstr::IntGtEq { lhs, rhs, dst } => {
352 format!(
353 "{} = int_gteq {}, {}",
354 format_local(*dst, function_names),
355 format_local(*lhs, function_names),
356 format_local(*rhs, function_names)
357 )
358 }
359 MirInstr::IntEq { lhs, rhs, dst } => {
360 format!(
361 "{} = int_eq {}, {}",
362 format_local(*dst, function_names),
363 format_local(*lhs, function_names),
364 format_local(*rhs, function_names)
365 )
366 }
367 MirInstr::IntNeq { lhs, rhs, dst } => {
368 format!(
369 "{} = int_neq {}, {}",
370 format_local(*dst, function_names),
371 format_local(*lhs, function_names),
372 format_local(*rhs, function_names)
373 )
374 }
375 MirInstr::IntAdd { lhs, rhs, dst } => {
376 format!(
377 "{} = int_add {}, {}",
378 format_local(*dst, function_names),
379 format_local(*lhs, function_names),
380 format_local(*rhs, function_names)
381 )
382 }
383 MirInstr::IntSub { lhs, rhs, dst } => {
384 format!(
385 "{} = int_sub {}, {}",
386 format_local(*dst, function_names),
387 format_local(*lhs, function_names),
388 format_local(*rhs, function_names)
389 )
390 }
391 MirInstr::IntMul { lhs, rhs, dst } => {
392 format!(
393 "{} = int_mul {}, {}",
394 format_local(*dst, function_names),
395 format_local(*lhs, function_names),
396 format_local(*rhs, function_names)
397 )
398 }
399 MirInstr::IntDiv { lhs, rhs, dst } => {
400 format!(
401 "{} = int_div {}, {}",
402 format_local(*dst, function_names),
403 format_local(*lhs, function_names),
404 format_local(*rhs, function_names)
405 )
406 }
407 MirInstr::IntMod { lhs, rhs, dst } => {
408 format!(
409 "{} = int_mod {}, {}",
410 format_local(*dst, function_names),
411 format_local(*lhs, function_names),
412 format_local(*rhs, function_names)
413 )
414 }
415 }
416}
417
418fn format_aggregate_arg_list(args: &[MirAggregateArg], function_names: &FunctionNames) -> String {
420 if args.is_empty() {
421 "-".to_string()
422 } else {
423 args.iter()
424 .map(|arg| format_aggregate_arg(arg, function_names))
425 .collect::<Vec<_>>()
426 .join(", ")
427 }
428}
429
430fn format_call_arg(
432 function: &MirFunction,
433 arg: &crate::MirCallArg,
434 function_names: &FunctionNames,
435) -> String {
436 let binding = function.call_arg_binding(arg);
437 let materialization = if binding.requires_deref_read() {
438 ":deref"
439 } else {
440 ""
441 };
442 format!(
443 "{} {}:{}{}",
444 format_call_arg_mode(arg.mode),
445 format_local(arg.local, function_names),
446 format_local_repr(binding.local.repr),
447 materialization,
448 )
449}