Skip to content

Commit bb08f56

Browse files
committed
[StableMIR] A few fixes to pretty printing
Improve identation, and a few other rvalue printing
1 parent f61306d commit bb08f56

File tree

3 files changed

+293
-21
lines changed

3 files changed

+293
-21
lines changed

compiler/stable_mir/src/mir/pretty.rs

+71-21
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1+
//! Implement methods to pretty print stable MIR body.
12
use std::fmt::Debug;
23
use std::io::Write;
34
use std::{fmt, io, iter};
45

56
use fmt::{Display, Formatter};
67

7-
use super::{AssertMessage, BinOp, BorrowKind, FakeBorrowKind, TerminatorKind};
8+
use super::{AggregateKind, AssertMessage, BinOp, BorrowKind, FakeBorrowKind, TerminatorKind};
89
use crate::mir::{Operand, Place, Rvalue, StatementKind, UnwindAction, VarDebugInfoContents};
9-
use crate::ty::{IndexedVal, MirConst, Ty, TyConst};
10-
use crate::{Body, Mutability, with};
10+
use crate::ty::{AdtKind, IndexedVal, MirConst, Ty, TyConst};
11+
use crate::{Body, CrateDef, Mutability, with};
1112

1213
impl Display for Ty {
1314
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
@@ -73,39 +74,40 @@ pub(crate) fn function_body<W: Write>(writer: &mut W, body: &Body, name: &str) -
7374
}
7475

7576
fn pretty_statement<W: Write>(writer: &mut W, statement: &StatementKind) -> io::Result<()> {
77+
const INDENT: &str = " ";
7678
match statement {
7779
StatementKind::Assign(place, rval) => {
78-
write!(writer, " {place:?} = ")?;
80+
write!(writer, "{INDENT}{place:?} = ")?;
7981
pretty_rvalue(writer, rval)?;
8082
writeln!(writer, ";")
8183
}
8284
// FIXME: Add rest of the statements
8385
StatementKind::FakeRead(cause, place) => {
84-
writeln!(writer, "FakeRead({cause:?}, {place:?});")
86+
writeln!(writer, "{INDENT}FakeRead({cause:?}, {place:?});")
8587
}
8688
StatementKind::SetDiscriminant { place, variant_index } => {
87-
writeln!(writer, "discriminant({place:?} = {};", variant_index.to_index())
89+
writeln!(writer, "{INDENT}discriminant({place:?} = {};", variant_index.to_index())
8890
}
8991
StatementKind::Deinit(place) => writeln!(writer, "Deinit({place:?};"),
9092
StatementKind::StorageLive(local) => {
91-
writeln!(writer, "StorageLive(_{local});")
93+
writeln!(writer, "{INDENT}StorageLive(_{local});")
9294
}
9395
StatementKind::StorageDead(local) => {
94-
writeln!(writer, "StorageDead(_{local});")
96+
writeln!(writer, "{INDENT}StorageDead(_{local});")
9597
}
9698
StatementKind::Retag(kind, place) => writeln!(writer, "Retag({kind:?}, {place:?});"),
9799
StatementKind::PlaceMention(place) => {
98-
writeln!(writer, "PlaceMention({place:?};")
100+
writeln!(writer, "{INDENT}PlaceMention({place:?};")
99101
}
100102
StatementKind::ConstEvalCounter => {
101-
writeln!(writer, "ConstEvalCounter;")
103+
writeln!(writer, "{INDENT}ConstEvalCounter;")
102104
}
103-
StatementKind::Nop => writeln!(writer, "nop;"),
105+
StatementKind::Nop => writeln!(writer, "{INDENT}nop;"),
104106
StatementKind::AscribeUserType { .. }
105107
| StatementKind::Coverage(_)
106108
| StatementKind::Intrinsic(_) => {
107109
// FIX-ME: Make them pretty.
108-
writeln!(writer, "{statement:?};")
110+
writeln!(writer, "{INDENT}{statement:?};")
109111
}
110112
}
111113
}
@@ -322,15 +324,11 @@ fn pretty_ty_const(ct: &TyConst) -> String {
322324
fn pretty_rvalue<W: Write>(writer: &mut W, rval: &Rvalue) -> io::Result<()> {
323325
match rval {
324326
Rvalue::AddressOf(mutability, place) => {
325-
write!(writer, "&raw {}(*{:?})", pretty_mut(*mutability), place)
327+
write!(writer, "&raw {} {:?}", pretty_mut(*mutability), place)
326328
}
327329
Rvalue::Aggregate(aggregate_kind, operands) => {
328330
// FIXME: Add pretty_aggregate function that returns a pretty string
329-
write!(writer, "{aggregate_kind:?} (")?;
330-
let mut op_iter = operands.iter();
331-
op_iter.next().map_or(Ok(()), |op| write!(writer, "{}", pretty_operand(op)))?;
332-
op_iter.try_for_each(|op| write!(writer, ", {}", pretty_operand(op)))?;
333-
write!(writer, ")")
331+
pretty_aggregate(writer, aggregate_kind, operands)
334332
}
335333
Rvalue::BinaryOp(bin, op1, op2) => {
336334
write!(writer, "{:?}({}, {})", bin, pretty_operand(op1), pretty_operand(op2))
@@ -360,22 +358,74 @@ fn pretty_rvalue<W: Write>(writer: &mut W, rval: &Rvalue) -> io::Result<()> {
360358
write!(writer, "{kind}{place:?}")
361359
}
362360
Rvalue::Repeat(op, cnst) => {
363-
write!(writer, "{} \" \" {}", pretty_operand(op), pretty_ty_const(cnst))
361+
write!(writer, "[{}; {}]", pretty_operand(op), pretty_ty_const(cnst))
364362
}
365363
Rvalue::ShallowInitBox(_, _) => Ok(()),
366364
Rvalue::ThreadLocalRef(item) => {
367365
write!(writer, "thread_local_ref{item:?}")
368366
}
369367
Rvalue::NullaryOp(nul, ty) => {
370-
write!(writer, "{nul:?} {ty} \" \"")
368+
write!(writer, "{nul:?}::<{ty}>() \" \"")
371369
}
372370
Rvalue::UnaryOp(un, op) => {
373-
write!(writer, "{} \" \" {:?}", pretty_operand(op), un)
371+
write!(writer, "{:?}({})", un, pretty_operand(op))
374372
}
375373
Rvalue::Use(op) => write!(writer, "{}", pretty_operand(op)),
376374
}
377375
}
378376

377+
fn pretty_aggregate<W: Write>(
378+
writer: &mut W,
379+
aggregate_kind: &AggregateKind,
380+
operands: &Vec<Operand>,
381+
) -> io::Result<()> {
382+
let suffix = match aggregate_kind {
383+
AggregateKind::Array(_) => {
384+
write!(writer, "[")?;
385+
"]"
386+
}
387+
AggregateKind::Tuple => {
388+
write!(writer, "(")?;
389+
")"
390+
}
391+
AggregateKind::Adt(def, var, _, _, _) => {
392+
if def.kind() == AdtKind::Enum {
393+
write!(writer, "{}::{}", def.name(), def.variant(*var).unwrap().name())?;
394+
} else {
395+
write!(writer, "{}", def.variant(*var).unwrap().name())?;
396+
}
397+
if operands.is_empty() {
398+
return Ok(());
399+
}
400+
// FIXME: Change this once we have CtorKind in StableMIR.
401+
write!(writer, "(")?;
402+
")"
403+
}
404+
AggregateKind::Closure(def, _) => {
405+
write!(writer, "{{closure@{:?}}}(", def.span())?;
406+
")"
407+
}
408+
AggregateKind::Coroutine(def, _, _) => {
409+
write!(writer, "{{coroutine@{:?}}}(", def.span())?;
410+
")"
411+
}
412+
AggregateKind::RawPtr(ty, mutability) => {
413+
write!(
414+
writer,
415+
"*{} {ty} from (",
416+
if *mutability == Mutability::Mut { "mut" } else { "const" }
417+
)?;
418+
")"
419+
}
420+
};
421+
let mut separator = "";
422+
for op in operands {
423+
write!(writer, "{}{}", separator, pretty_operand(op))?;
424+
separator = ", ";
425+
}
426+
write!(writer, "{suffix}")
427+
}
428+
379429
fn pretty_mut(mutability: Mutability) -> &'static str {
380430
match mutability {
381431
Mutability::Not => " ",

tests/ui/stable-mir-print/operands.rs

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//@ compile-flags: -Z unpretty=stable-mir --crate-type lib -C panic=abort
2+
//@ check-pass
3+
//@ only-x86_64
4+
//@ needs-unwind unwind edges are different with panic=abort
5+
//! Check how stable mir pretty printer prints different operands and abort strategy.
6+
7+
pub fn operands(val: u8) {
8+
let array = [val; 10];
9+
let first = array[0];
10+
let last = array[10 - 1];
11+
assert_eq!(first, last);
12+
13+
let reference = &first;
14+
let dereferenced = *reference;
15+
assert_eq!(dereferenced, first);
16+
17+
let tuple = (first, last);
18+
let (first_again, _) = tuple;
19+
let first_again_again = tuple.0;
20+
assert_eq!(first_again, first_again_again);
21+
22+
let length = array.len();
23+
let size_of = std::mem::size_of_val(&length);
24+
assert_eq!(length, size_of);
25+
}
+197
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
// WARNING: This is highly experimental output it's intended for stable-mir developers only.
2+
// If you find a bug or want to improve the output open a issue at https://github.com/rust-lang/project-stable-mir.
3+
fn operands(_1: u8) -> () {
4+
let mut _0: ();
5+
let _2: [u8; 10];
6+
let _3: u8;
7+
let _4: usize;
8+
let mut _5: usize;
9+
let mut _6: bool;
10+
let _7: u8;
11+
let _8: usize;
12+
let mut _9: (usize, bool);
13+
let mut _10: usize;
14+
let mut _11: bool;
15+
let mut _12: (&u8, &u8);
16+
let mut _13: &u8;
17+
let mut _14: &u8;
18+
let _15: &u8;
19+
let _16: &u8;
20+
let mut _17: bool;
21+
let mut _18: u8;
22+
let mut _19: u8;
23+
let _20: core::panicking::AssertKind;
24+
let _21: !;
25+
let mut _22: Option<Arguments<'_>>;
26+
let _23: &u8;
27+
let _24: u8;
28+
let mut _25: (&u8, &u8);
29+
let mut _26: &u8;
30+
let mut _27: &u8;
31+
let _28: &u8;
32+
let _29: &u8;
33+
let mut _30: bool;
34+
let mut _31: u8;
35+
let mut _32: u8;
36+
let _33: core::panicking::AssertKind;
37+
let _34: !;
38+
let mut _35: Option<Arguments<'_>>;
39+
let _36: (u8, u8);
40+
let _37: u8;
41+
let _38: u8;
42+
let mut _39: (&u8, &u8);
43+
let mut _40: &u8;
44+
let mut _41: &u8;
45+
let _42: &u8;
46+
let _43: &u8;
47+
let mut _44: bool;
48+
let mut _45: u8;
49+
let mut _46: u8;
50+
let _47: core::panicking::AssertKind;
51+
let _48: !;
52+
let mut _49: Option<Arguments<'_>>;
53+
let _50: usize;
54+
let mut _51: &[u8];
55+
let mut _52: &[u8; 10];
56+
let _53: usize;
57+
let _54: &usize;
58+
let mut _55: (&usize, &usize);
59+
let mut _56: &usize;
60+
let mut _57: &usize;
61+
let _58: &usize;
62+
let _59: &usize;
63+
let mut _60: bool;
64+
let mut _61: usize;
65+
let mut _62: usize;
66+
let _63: core::panicking::AssertKind;
67+
let _64: !;
68+
let mut _65: Option<Arguments<'_>>;
69+
debug val => _1;
70+
debug array => _2;
71+
debug first => _3;
72+
debug last => _7;
73+
debug left_val => _15;
74+
debug right_val => _16;
75+
debug kind => _20;
76+
debug reference => _23;
77+
debug dereferenced => _24;
78+
debug left_val => _28;
79+
debug right_val => _29;
80+
debug kind => _33;
81+
debug tuple => _36;
82+
debug first_again => _37;
83+
debug first_again_again => _38;
84+
debug left_val => _42;
85+
debug right_val => _43;
86+
debug kind => _47;
87+
debug length => _50;
88+
debug size_of => _53;
89+
debug left_val => _58;
90+
debug right_val => _59;
91+
debug kind => _63;
92+
bb0: {
93+
_2 = [_1; 10];
94+
_4 = 0_usize;
95+
_5 = 10_usize;
96+
_6 = Lt(_4, _5);
97+
assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable];
98+
}
99+
bb1: {
100+
_3 = _2[_4];
101+
_9 = CheckedSub(10_usize, 1_usize);
102+
assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", 10_usize, 1_usize) -> [success: bb2, unwind unreachable];
103+
}
104+
bb2: {
105+
_8 = move (_9.0: usize);
106+
_10 = 10_usize;
107+
_11 = Lt(_8, _10);
108+
assert(move _11, "index out of bounds: the length is {} but the index is {}", move _10, _8) -> [success: bb3, unwind unreachable];
109+
}
110+
bb3: {
111+
_7 = _2[_8];
112+
_13 = &_3;
113+
_14 = &_7;
114+
_12 = (move _13, move _14);
115+
_15 = (_12.0: &u8);
116+
_16 = (_12.1: &u8);
117+
_18 = (*_15);
118+
_19 = (*_16);
119+
_17 = Eq(move _18, move _19);
120+
switchInt(move _17) -> [0: bb5, otherwise: bb4];
121+
}
122+
bb4: {
123+
_23 = &_3;
124+
_24 = (*_23);
125+
_26 = &_24;
126+
_27 = &_3;
127+
_25 = (move _26, move _27);
128+
_28 = (_25.0: &u8);
129+
_29 = (_25.1: &u8);
130+
_31 = (*_28);
131+
_32 = (*_29);
132+
_30 = Eq(move _31, move _32);
133+
switchInt(move _30) -> [0: bb7, otherwise: bb6];
134+
}
135+
bb5: {
136+
_20 = core::panicking::AssertKind::Eq;
137+
_22 = std::option::Option::None;
138+
_21 = core::panicking::assert_failed::<u8, u8>(move _20, _15, _16, move _22) -> unwind unreachable;
139+
}
140+
bb6: {
141+
_36 = (_3, _7);
142+
_37 = (_36.0: u8);
143+
_38 = (_36.0: u8);
144+
_40 = &_37;
145+
_41 = &_38;
146+
_39 = (move _40, move _41);
147+
_42 = (_39.0: &u8);
148+
_43 = (_39.1: &u8);
149+
_45 = (*_42);
150+
_46 = (*_43);
151+
_44 = Eq(move _45, move _46);
152+
switchInt(move _44) -> [0: bb9, otherwise: bb8];
153+
}
154+
bb7: {
155+
_33 = core::panicking::AssertKind::Eq;
156+
_35 = std::option::Option::None;
157+
_34 = core::panicking::assert_failed::<u8, u8>(move _33, _28, _29, move _35) -> unwind unreachable;
158+
}
159+
bb8: {
160+
_52 = &_2;
161+
_51 = move _52 as &[u8];
162+
_50 = PtrMetadata(move _51);
163+
_54 = &_50;
164+
_53 = std::mem::size_of_val::<usize>(_54) -> [return: bb10, unwind unreachable];
165+
}
166+
bb9: {
167+
_47 = core::panicking::AssertKind::Eq;
168+
_49 = std::option::Option::None;
169+
_48 = core::panicking::assert_failed::<u8, u8>(move _47, _42, _43, move _49) -> unwind unreachable;
170+
}
171+
bb10: {
172+
_56 = &_50;
173+
_57 = &_53;
174+
_55 = (move _56, move _57);
175+
_58 = (_55.0: &usize);
176+
_59 = (_55.1: &usize);
177+
_61 = (*_58);
178+
_62 = (*_59);
179+
_60 = Eq(move _61, move _62);
180+
switchInt(move _60) -> [0: bb12, otherwise: bb11];
181+
}
182+
bb11: {
183+
return;
184+
}
185+
bb12: {
186+
_63 = core::panicking::AssertKind::Eq;
187+
_65 = std::option::Option::None;
188+
_64 = core::panicking::assert_failed::<usize, usize>(move _63, _58, _59, move _65) -> unwind unreachable;
189+
}
190+
}
191+
fn operands::{constant#0}() -> usize {
192+
let mut _0: usize;
193+
bb0: {
194+
_0 = 10_usize;
195+
return;
196+
}
197+
}

0 commit comments

Comments
 (0)