ruka_mir/browser_graph/
instr_format.rs

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
8/// Render one MIR instruction into a compact viewer-facing line.
9pub(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
418/// Render a list of MIR aggregate arguments into a compact label.
419fn 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
430/// Render one MIR call argument into a compact label.
431fn 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}