Skip to content

Commit 5233f51

Browse files
committed
Auto merge of #126963 - runtimeverification:smir_serde_derive, r=oli-obk
Add basic Serde serialization capabilities to Stable MIR This PR adds basic Serde serialization capabilities to Stable MIR. It is intentionally minimal (just wrapping all stable MIR types with a Serde `derive`), so that any important design decisions can be discussed before going further. A simple test is included with this PR to validate that JSON can actually be emitted. ## Notes When I wrapped the Stable MIR error types in `compiler/stable_mir/src/error.rs`, it caused test failures (though I'm not sure why) so I backed those out. ## Future Work So, this PR will support serializing basic stable MIR, but it _does not_ support serializing interned values beneath `Ty`s and `AllocId`s, etc... My current thinking about how to handle this is as follows: 1. Add new `visited_X` fields to the `Tables` struct for each interned category of interest. 2. As serialization is occuring, serialize interned values as usual _and_ also record the interned value we referenced in `visited_X`. (Possibly) In addition, if an interned value recursively references other interned values, record those interned values as well. 3. Teach the stable MIR `Context` how to access the `visited_X` values and expose them with wrappers in `stable_mir/src/lib.rs` to users (e.g. to serialize and/or further analyze them). ### Pros This approach does not commit to any specific serialization format regarding interned values or other more complex cases, which avoids us locking into any behaviors that may not be desired long-term. ### Cons The user will need to manually handle serializing interned values. ### Alternatives 1. We can directly provide access to the underlying `Tables` maps for interned values; the disadvantage of this approach is that it either requires extra processing for users to filter out to only use the values that they need _or_ users may serialize extra values that they don't need. The advantage is that the implementation is even simpler. The other pros/cons are similar to the above. 2. We can directly serialize interned values by expanding them in-place. The pro is that this may make some basic inputs easier to consume. However, the cons are that there will need to be special provisions for dealing with cyclical values on both the producer and consumer _and_ global values will possibly need to be de-duplicated on the consumer side.
2 parents 99f77a2 + 414ebea commit 5233f51

File tree

11 files changed

+242
-139
lines changed

11 files changed

+242
-139
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -5263,6 +5263,7 @@ name = "stable_mir"
52635263
version = "0.1.0-preview"
52645264
dependencies = [
52655265
"scoped-tls",
5266+
"serde",
52665267
]
52675268

52685269
[[package]]

compiler/stable_mir/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ edition = "2021"
55

66
[dependencies]
77
scoped-tls = "1.0"
8+
serde = { version = "1.0.125", features = [ "derive" ] }

compiler/stable_mir/src/abi.rs

+18-17
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ use crate::target::{MachineInfo, MachineSize as Size};
55
use crate::ty::{Align, IndexedVal, Ty, VariantIdx};
66
use crate::Error;
77
use crate::Opaque;
8+
use serde::Serialize;
89
use std::fmt::{self, Debug};
910
use std::num::NonZero;
1011
use std::ops::RangeInclusive;
1112

1213
/// A function ABI definition.
13-
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
14+
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
1415
pub struct FnAbi {
1516
/// The types of each argument.
1617
pub args: Vec<ArgAbi>,
@@ -31,15 +32,15 @@ pub struct FnAbi {
3132
}
3233

3334
/// Information about the ABI of a function's argument, or return value.
34-
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
35+
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
3536
pub struct ArgAbi {
3637
pub ty: Ty,
3738
pub layout: Layout,
3839
pub mode: PassMode,
3940
}
4041

4142
/// How a function argument should be passed in to the target function.
42-
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
43+
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
4344
pub enum PassMode {
4445
/// Ignore the argument.
4546
///
@@ -60,14 +61,14 @@ pub enum PassMode {
6061
}
6162

6263
/// The layout of a type, alongside the type itself.
63-
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
64+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
6465
pub struct TyAndLayout {
6566
pub ty: Ty,
6667
pub layout: Layout,
6768
}
6869

6970
/// The layout of a type in memory.
70-
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
71+
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
7172
pub struct LayoutShape {
7273
/// The fields location withing the layout
7374
pub fields: FieldsShape,
@@ -108,7 +109,7 @@ impl LayoutShape {
108109
}
109110
}
110111

111-
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
112+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
112113
pub struct Layout(usize);
113114

114115
impl Layout {
@@ -127,7 +128,7 @@ impl IndexedVal for Layout {
127128
}
128129

129130
/// Describes how the fields of a type are shaped in memory.
130-
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
131+
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
131132
pub enum FieldsShape {
132133
/// Scalar primitives and `!`, which never have fields.
133134
Primitive,
@@ -177,7 +178,7 @@ impl FieldsShape {
177178
}
178179
}
179180

180-
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
181+
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
181182
pub enum VariantsShape {
182183
/// Single enum variants, structs/tuples, unions, and all non-ADTs.
183184
Single { index: VariantIdx },
@@ -196,7 +197,7 @@ pub enum VariantsShape {
196197
},
197198
}
198199

199-
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
200+
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
200201
pub enum TagEncoding {
201202
/// The tag directly stores the discriminant, but possibly with a smaller layout
202203
/// (so converting the tag to the discriminant can require sign extension).
@@ -221,7 +222,7 @@ pub enum TagEncoding {
221222

222223
/// Describes how values of the type are passed by target ABIs,
223224
/// in terms of categories of C types there are ABI rules for.
224-
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
225+
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
225226
pub enum ValueAbi {
226227
Uninhabited,
227228
Scalar(Scalar),
@@ -250,7 +251,7 @@ impl ValueAbi {
250251
}
251252

252253
/// Information about one scalar component of a Rust type.
253-
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
254+
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize)]
254255
pub enum Scalar {
255256
Initialized {
256257
/// The primitive type used to represent this value.
@@ -280,7 +281,7 @@ impl Scalar {
280281
}
281282

282283
/// Fundamental unit of memory access and layout.
283-
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
284+
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize)]
284285
pub enum Primitive {
285286
/// The `bool` is the signedness of the `Integer` type.
286287
///
@@ -310,7 +311,7 @@ impl Primitive {
310311
}
311312

312313
/// Enum representing the existing integer lengths.
313-
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
314+
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
314315
pub enum IntegerLength {
315316
I8,
316317
I16,
@@ -320,7 +321,7 @@ pub enum IntegerLength {
320321
}
321322

322323
/// Enum representing the existing float lengths.
323-
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
324+
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
324325
pub enum FloatLength {
325326
F16,
326327
F32,
@@ -354,7 +355,7 @@ impl FloatLength {
354355
/// An identifier that specifies the address space that some operation
355356
/// should operate on. Special address spaces have an effect on code generation,
356357
/// depending on the target and the address spaces it implements.
357-
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
358+
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
358359
pub struct AddressSpace(pub u32);
359360

360361
impl AddressSpace {
@@ -369,7 +370,7 @@ impl AddressSpace {
369370
/// sequence:
370371
///
371372
/// 254 (-2), 255 (-1), 0, 1, 2
372-
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
373+
#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize)]
373374
pub struct WrappingRange {
374375
pub start: u128,
375376
pub end: u128,
@@ -420,7 +421,7 @@ impl Debug for WrappingRange {
420421
}
421422

422423
/// General language calling conventions.
423-
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
424+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
424425
pub enum CallConvention {
425426
C,
426427
Rust,

compiler/stable_mir/src/crate_def.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
44
use crate::ty::{GenericArgs, Span, Ty};
55
use crate::{with, Crate, Symbol};
6+
use serde::Serialize;
67

78
/// A unique identification number for each item accessible for the current compilation unit.
8-
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
9+
#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize)]
910
pub struct DefId(pub(crate) usize);
1011

1112
/// A trait for retrieving information about a particular definition.

compiler/stable_mir/src/lib.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub use crate::error::*;
2727
use crate::mir::Body;
2828
use crate::mir::Mutability;
2929
use crate::ty::{ForeignModuleDef, ImplDef, IndexedVal, Span, TraitDef, Ty};
30+
use serde::Serialize;
3031

3132
pub mod abi;
3233
#[macro_use]
@@ -74,7 +75,7 @@ pub type TraitDecls = Vec<TraitDef>;
7475
pub type ImplTraitDecls = Vec<ImplDef>;
7576

7677
/// Holds information about a crate.
77-
#[derive(Clone, PartialEq, Eq, Debug)]
78+
#[derive(Clone, PartialEq, Eq, Debug, Serialize)]
7879
pub struct Crate {
7980
pub id: CrateNum,
8081
pub name: Symbol,
@@ -98,15 +99,15 @@ impl Crate {
9899
}
99100
}
100101

101-
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
102+
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize)]
102103
pub enum ItemKind {
103104
Fn,
104105
Static,
105106
Const,
106107
Ctor(CtorKind),
107108
}
108109

109-
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
110+
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize)]
110111
pub enum CtorKind {
111112
Const,
112113
Fn,
@@ -116,6 +117,7 @@ pub type Filename = String;
116117

117118
crate_def_with_ty! {
118119
/// Holds information about an item in a crate.
120+
#[derive(Serialize)]
119121
pub CrateItem;
120122
}
121123

@@ -188,7 +190,7 @@ pub fn all_trait_impls() -> ImplTraitDecls {
188190
}
189191

190192
/// A type that provides internal information but that can still be used for debug purpose.
191-
#[derive(Clone, PartialEq, Eq, Hash)]
193+
#[derive(Clone, PartialEq, Eq, Hash, Serialize)]
192194
pub struct Opaque(String);
193195

194196
impl std::fmt::Display for Opaque {

compiler/stable_mir/src/mir/alloc.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ use crate::mir::mono::{Instance, StaticDef};
44
use crate::target::{Endian, MachineInfo};
55
use crate::ty::{Allocation, Binder, ExistentialTraitRef, IndexedVal, Ty};
66
use crate::{with, Error};
7+
use serde::Serialize;
78
use std::io::Read;
89

910
/// An allocation in the SMIR global memory can be either a function pointer,
1011
/// a static, or a "real" allocation with some data in it.
11-
#[derive(Debug, Clone, Eq, PartialEq)]
12+
#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
1213
pub enum GlobalAlloc {
1314
/// The alloc ID is used as a function pointer.
1415
Function(Instance),
@@ -41,7 +42,7 @@ impl GlobalAlloc {
4142
}
4243

4344
/// A unique identification number for each provenance
44-
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
45+
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)]
4546
pub struct AllocId(usize);
4647

4748
impl IndexedVal for AllocId {

0 commit comments

Comments
 (0)