From 2fc964ea35a050d7523095a62c002918cfa13a55 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 19 Dec 2020 16:32:46 +0100 Subject: [PATCH 1/6] Add serde serialization support for the full clif ir --- Cargo.lock | 3 + cranelift/codegen/Cargo.toml | 7 +- cranelift/codegen/meta/src/gen_inst.rs | 6 +- cranelift/codegen/shared/Cargo.toml | 8 ++- cranelift/codegen/shared/src/condcodes.rs | 5 ++ cranelift/codegen/src/ir/constant.rs | 6 ++ cranelift/codegen/src/ir/dfg.rs | 6 ++ cranelift/codegen/src/ir/entities.rs | 11 +++ cranelift/codegen/src/ir/extfunc.rs | 1 + cranelift/codegen/src/ir/extname.rs | 4 ++ cranelift/codegen/src/ir/function.rs | 4 ++ cranelift/codegen/src/ir/globalvalue.rs | 4 ++ cranelift/codegen/src/ir/heap.rs | 5 ++ cranelift/codegen/src/ir/immediates.rs | 6 ++ cranelift/codegen/src/ir/instructions.rs | 3 + cranelift/codegen/src/ir/jumptable.rs | 4 ++ cranelift/codegen/src/ir/layout.rs | 80 +++++++++++++++++++++ cranelift/codegen/src/ir/memflags.rs | 4 ++ cranelift/codegen/src/ir/mod.rs | 2 + cranelift/codegen/src/ir/table.rs | 4 ++ cranelift/codegen/src/isa/encoding.rs | 4 ++ cranelift/codegen/src/regalloc/diversion.rs | 7 ++ cranelift/entity/src/list.rs | 7 +- cranelift/entity/src/packed_option.rs | 4 ++ cranelift/entity/src/sparse.rs | 4 ++ 25 files changed, 195 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f402f5aef9..5948052629 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -550,6 +550,9 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" version = "0.70.0" +dependencies = [ + "serde", +] [[package]] name = "cranelift-entity" diff --git a/cranelift/codegen/Cargo.toml b/cranelift/codegen/Cargo.toml index 0bcdf471b4..5931434130 100644 --- a/cranelift/codegen/Cargo.toml +++ b/cranelift/codegen/Cargo.toml @@ -74,7 +74,12 @@ all-arch = [ ] # For dependent crates that want to serialize some parts of cranelift -enable-serde = ["serde", "regalloc/enable-serde"] +enable-serde = [ + "serde", + "regalloc/enable-serde", + "cranelift-entity/enable-serde", + "cranelift-codegen-shared/enable-serde" +] # Allow snapshotting regalloc test cases. Useful only to report bad register # allocation failures, or for regalloc.rs developers. diff --git a/cranelift/codegen/meta/src/gen_inst.rs b/cranelift/codegen/meta/src/gen_inst.rs index a2760b34d7..13f4776d3b 100644 --- a/cranelift/codegen/meta/src/gen_inst.rs +++ b/cranelift/codegen/meta/src/gen_inst.rs @@ -68,6 +68,7 @@ fn gen_formats(formats: &[&InstructionFormat], fmt: &mut Formatter) { /// `ValueList` to store the additional information out of line. fn gen_instruction_data(formats: &[&InstructionFormat], fmt: &mut Formatter) { fmt.line("#[derive(Clone, Debug)]"); + fmt.line(r#"#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]"#); fmt.line("#[allow(missing_docs)]"); fmt.line("pub enum InstructionData {"); fmt.indent(|fmt| { @@ -410,7 +411,10 @@ fn gen_opcodes(all_inst: &AllInstructions, fmt: &mut Formatter) { fmt.line("#[repr(u16)]"); fmt.line("#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]"); fmt.line( - r#"#[cfg_attr(feature = "enable-peepmatic", derive(serde::Serialize, serde::Deserialize))]"# + r#"#[cfg_attr( + any(feature = "enable-peepmatic", feature = "enable-serde"), + derive(serde::Serialize, serde::Deserialize) + )]"#, ); // We explicitly set the discriminant of the first variant to 1, which allows us to take diff --git a/cranelift/codegen/shared/Cargo.toml b/cranelift/codegen/shared/Cargo.toml index e25a528334..53f864e287 100644 --- a/cranelift/codegen/shared/Cargo.toml +++ b/cranelift/codegen/shared/Cargo.toml @@ -8,4 +8,10 @@ repository = "https://github.com/bytecodealliance/wasmtime" readme = "README.md" edition = "2018" -# Since this is a shared dependency of several packages, please strive to keep this dependency-free. +[dependencies] +# Since this is a shared dependency of several packages, please strive to keep this dependency-free +# when no features are enabled. +serde = { version = "1.0.94", features = ["derive"], optional = true } + +[features] +enable-serde = ["serde"] diff --git a/cranelift/codegen/shared/src/condcodes.rs b/cranelift/codegen/shared/src/condcodes.rs index 03ae865ce4..00e9717ca0 100644 --- a/cranelift/codegen/shared/src/condcodes.rs +++ b/cranelift/codegen/shared/src/condcodes.rs @@ -7,6 +7,9 @@ use core::fmt::{self, Display, Formatter}; use core::str::FromStr; +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + /// Common traits of condition codes. pub trait CondCode: Copy { /// Get the inverse condition code of `self`. @@ -30,6 +33,7 @@ pub trait CondCode: Copy { /// separate codes for comparing the integers as signed or unsigned numbers where it makes a /// difference. #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub enum IntCC { /// `==`. Equal, @@ -187,6 +191,7 @@ impl FromStr for IntCC { /// comparison. The 14 condition codes here cover every possible combination of the relation above /// except the impossible `!UN & !EQ & !LT & !GT` and the always true `UN | EQ | LT | GT`. #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub enum FloatCC { /// EQ | LT | GT Ordered, diff --git a/cranelift/codegen/src/ir/constant.rs b/cranelift/codegen/src/ir/constant.rs index bd84e25ee3..a9aa5d3a64 100644 --- a/cranelift/codegen/src/ir/constant.rs +++ b/cranelift/codegen/src/ir/constant.rs @@ -19,12 +19,16 @@ use core::slice::Iter; use core::str::{from_utf8, FromStr}; use cranelift_entity::EntityRef; +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + /// This type describes the actual constant data. Note that the bytes stored in this structure are /// expected to be in little-endian order; this is due to ease-of-use when interacting with /// WebAssembly values, which are [little-endian by design]. /// /// [little-endian by design]: https://github.com/WebAssembly/design/blob/master/Portability.md #[derive(Clone, Hash, Eq, PartialEq, Debug, Default)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct ConstantData(Vec); impl FromIterator for ConstantData { @@ -173,6 +177,7 @@ pub type ConstantOffset = u32; /// from the beginning of the function is known (see /// `relaxation` in `relaxation.rs`). #[derive(Clone)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct ConstantPoolEntry { data: ConstantData, offset: Option, @@ -197,6 +202,7 @@ impl ConstantPoolEntry { /// Maintains the mapping between a constant handle (i.e. [`Constant`](crate::ir::Constant)) and /// its constant data (i.e. [`ConstantData`](crate::ir::ConstantData)). #[derive(Clone)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct ConstantPool { /// This mapping maintains the insertion order as long as Constants are created with /// sequentially increasing integers. diff --git a/cranelift/codegen/src/ir/dfg.rs b/cranelift/codegen/src/ir/dfg.rs index 58d101aace..861f3147c5 100644 --- a/cranelift/codegen/src/ir/dfg.rs +++ b/cranelift/codegen/src/ir/dfg.rs @@ -21,6 +21,9 @@ use core::mem; use core::ops::{Index, IndexMut}; use core::u16; +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + /// A data flow graph defines all instructions and basic blocks in a function as well as /// the data flow dependencies between them. The DFG also tracks values which can be either /// instruction results or block parameters. @@ -29,6 +32,7 @@ use core::u16; /// `Layout` data structure which forms the other half of the function representation. /// #[derive(Clone)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct DataFlowGraph { /// Data about all of the instructions in the function, including opcodes and operands. /// The instructions in this map are not in program order. That is tracked by `Layout`, along @@ -416,6 +420,7 @@ impl ValueDef { /// Internal table storage for extended values. #[derive(Clone, Debug)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] enum ValueData { /// Value is defined by an instruction. Inst { ty: Type, num: u16, inst: Inst }, @@ -935,6 +940,7 @@ impl DataFlowGraph { /// branches to this block must provide matching arguments, and the arguments to the entry block must /// match the function arguments. #[derive(Clone)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] struct BlockData { /// List of parameters to this block. params: ValueList, diff --git a/cranelift/codegen/src/ir/entities.rs b/cranelift/codegen/src/ir/entities.rs index e629475532..09eaed3bec 100644 --- a/cranelift/codegen/src/ir/entities.rs +++ b/cranelift/codegen/src/ir/entities.rs @@ -33,6 +33,7 @@ use serde::{Deserialize, Serialize}; /// /// While the order is stable, it is arbitrary and does not necessarily resemble the layout order. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct Block(u32); entity_impl!(Block, "block"); @@ -65,6 +66,7 @@ impl Block { /// /// While the order is stable, it is arbitrary. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct Value(u32); entity_impl!(Value, "v"); @@ -97,6 +99,7 @@ impl Value { /// /// While the order is stable, it is arbitrary and does not necessarily resemble the layout order. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct Inst(u32); entity_impl!(Inst, "inst"); @@ -152,6 +155,7 @@ impl StackSlot { /// /// While the order is stable, it is arbitrary. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct GlobalValue(u32); entity_impl!(GlobalValue, "gv"); @@ -177,6 +181,7 @@ impl GlobalValue { /// While the order is stable, it is arbitrary and does not necessarily resemble the order in which /// the constants are written in the constant pool. #[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct Constant(u32); entity_impl!(Constant, "const"); @@ -202,6 +207,7 @@ impl Constant { /// /// While the order is stable, it is arbitrary. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct Immediate(u32); entity_impl!(Immediate, "imm"); @@ -267,6 +273,7 @@ impl JumpTable { /// /// While the order is stable, it is arbitrary. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct FuncRef(u32); entity_impl!(FuncRef, "fn"); @@ -298,6 +305,7 @@ impl FuncRef { /// /// While the order is stable, it is arbitrary. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct SigRef(u32); entity_impl!(SigRef, "sig"); @@ -323,6 +331,7 @@ impl SigRef { /// /// While the order is stable, it is arbitrary. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct Heap(u32); entity_impl!(Heap, "heap"); @@ -349,6 +358,7 @@ impl Heap { /// /// While the order is stable, it is arbitrary. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct Table(u32); entity_impl!(Table, "table"); @@ -367,6 +377,7 @@ impl Table { /// An opaque reference to any of the entities defined in this module that can appear in CLIF IR. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub enum AnyEntity { /// The whole function. Function, diff --git a/cranelift/codegen/src/ir/extfunc.rs b/cranelift/codegen/src/ir/extfunc.rs index 46f1cf2828..6c1d26f4ab 100644 --- a/cranelift/codegen/src/ir/extfunc.rs +++ b/cranelift/codegen/src/ir/extfunc.rs @@ -409,6 +409,7 @@ impl FromStr for ArgumentPurpose { /// /// Information about a function that can be called directly with a direct `call` instruction. #[derive(Clone, Debug)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct ExtFuncData { /// Name of the external function. pub name: ExternalName, diff --git a/cranelift/codegen/src/ir/extname.rs b/cranelift/codegen/src/ir/extname.rs index c12a873d26..362cf8c67e 100644 --- a/cranelift/codegen/src/ir/extname.rs +++ b/cranelift/codegen/src/ir/extname.rs @@ -9,6 +9,9 @@ use core::cmp; use core::fmt::{self, Write}; use core::str::FromStr; +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + const TESTCASE_NAME_LENGTH: usize = 16; /// The name of an external is either a reference to a user-defined symbol @@ -23,6 +26,7 @@ const TESTCASE_NAME_LENGTH: usize = 16; /// In particular, many `.clif` test files use function names to identify /// functions. #[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub enum ExternalName { /// A name in a user-defined symbol table. Cranelift does not interpret /// these numbers in any way. diff --git a/cranelift/codegen/src/ir/function.rs b/cranelift/codegen/src/ir/function.rs index 1833af27f5..f5dc7f916f 100644 --- a/cranelift/codegen/src/ir/function.rs +++ b/cranelift/codegen/src/ir/function.rs @@ -21,11 +21,15 @@ use crate::write::write_function; use alloc::vec::Vec; use core::fmt; +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + /// A function. /// /// Functions can be cloned, but it is not a very fast operation. /// The clone will have all the same entity numbers as the original. #[derive(Clone)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct Function { /// Name of this function. Mostly used by `.clif` files. pub name: ExternalName, diff --git a/cranelift/codegen/src/ir/globalvalue.rs b/cranelift/codegen/src/ir/globalvalue.rs index 6c9b2d7bcf..e70f8221fb 100644 --- a/cranelift/codegen/src/ir/globalvalue.rs +++ b/cranelift/codegen/src/ir/globalvalue.rs @@ -6,8 +6,12 @@ use crate::isa::TargetIsa; use crate::machinst::RelocDistance; use core::fmt; +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + /// Information about a global value declaration. #[derive(Clone)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub enum GlobalValueData { /// Value is the address of the VM context struct. VMContext, diff --git a/cranelift/codegen/src/ir/heap.rs b/cranelift/codegen/src/ir/heap.rs index 8a4b4e84b9..91aabccaa2 100644 --- a/cranelift/codegen/src/ir/heap.rs +++ b/cranelift/codegen/src/ir/heap.rs @@ -4,8 +4,12 @@ use crate::ir::immediates::Uimm64; use crate::ir::{GlobalValue, Type}; use core::fmt; +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + /// Information about a heap declaration. #[derive(Clone)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct HeapData { /// The address of the start of the heap's storage. pub base: GlobalValue, @@ -26,6 +30,7 @@ pub struct HeapData { /// Style of heap including style-specific information. #[derive(Clone)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub enum HeapStyle { /// A dynamic heap can be relocated to a different base address when it is grown. Dynamic { diff --git a/cranelift/codegen/src/ir/immediates.rs b/cranelift/codegen/src/ir/immediates.rs index f575ea361f..9dd317d542 100644 --- a/cranelift/codegen/src/ir/immediates.rs +++ b/cranelift/codegen/src/ir/immediates.rs @@ -48,6 +48,7 @@ impl IntoBytes for Vec { /// An `Imm64` operand can also be used to represent immediate values of smaller integer types by /// sign-extending to `i64`. #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct Imm64(i64); impl Imm64 { @@ -148,6 +149,7 @@ impl FromStr for Imm64 { /// A `Uimm64` operand can also be used to represent immediate values of smaller integer types by /// zero-extending to `i64`. #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct Uimm64(u64); impl Uimm64 { @@ -279,6 +281,7 @@ pub type Uimm8 = u8; /// /// This is used to represent sizes of memory objects. #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct Uimm32(u32); impl Into for Uimm32 { @@ -362,6 +365,7 @@ impl From<&[u8]> for V128Imm { /// This is used to encode an immediate offset for load/store instructions. All supported ISAs have /// a maximum load/store offset that fits in an `i32`. #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct Offset32(i32); impl Offset32 { @@ -451,6 +455,7 @@ impl FromStr for Offset32 { /// /// All bit patterns are allowed. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] #[repr(C)] pub struct Ieee32(u32); @@ -459,6 +464,7 @@ pub struct Ieee32(u32); /// /// All bit patterns are allowed. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] #[repr(C)] pub struct Ieee64(u64); diff --git a/cranelift/codegen/src/ir/instructions.rs b/cranelift/codegen/src/ir/instructions.rs index 13310bc01c..94ce878a97 100644 --- a/cranelift/codegen/src/ir/instructions.rs +++ b/cranelift/codegen/src/ir/instructions.rs @@ -13,6 +13,9 @@ use core::num::NonZeroU32; use core::ops::{Deref, DerefMut}; use core::str::FromStr; +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + use crate::ir::{self, trapcode::TrapCode, types, Block, FuncRef, JumpTable, SigRef, Type, Value}; use crate::isa; diff --git a/cranelift/codegen/src/ir/jumptable.rs b/cranelift/codegen/src/ir/jumptable.rs index a0596728a3..d102617df4 100644 --- a/cranelift/codegen/src/ir/jumptable.rs +++ b/cranelift/codegen/src/ir/jumptable.rs @@ -8,10 +8,14 @@ use alloc::vec::Vec; use core::fmt::{self, Display, Formatter}; use core::slice::{Iter, IterMut}; +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + /// Contents of a jump table. /// /// All jump tables use 0-based indexing and are densely populated. #[derive(Clone)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct JumpTableData { // Table entries. table: Vec, diff --git a/cranelift/codegen/src/ir/layout.rs b/cranelift/codegen/src/ir/layout.rs index 62516325dd..9359c309df 100644 --- a/cranelift/codegen/src/ir/layout.rs +++ b/cranelift/codegen/src/ir/layout.rs @@ -781,6 +781,86 @@ impl<'f> DoubleEndedIterator for Insts<'f> { } } +#[cfg(feature = "enable-serde")] +mod serde { + use ::serde::de::{Deserializer, Error, SeqAccess, Visitor}; + use ::serde::ser::{SerializeSeq, Serializer}; + use ::serde::{Deserialize, Serialize}; + use core::convert::TryFrom; + use core::fmt; + use core::marker::PhantomData; + + use super::*; + + impl Serialize for Layout { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let size = self.blocks().count() * 2 + + self + .blocks() + .map(|block| self.block_insts(block).count()) + .sum::(); + let mut seq = serializer.serialize_seq(Some(size))?; + for block in self.blocks() { + seq.serialize_element(&block)?; + seq.serialize_element(&u32::try_from(self.block_insts(block).count()).unwrap())?; + for inst in self.block_insts(block) { + seq.serialize_element(&inst)?; + } + } + seq.end() + } + } + + impl<'de> Deserialize<'de> for Layout { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_seq(LayoutVisitor { + marker: PhantomData, + }) + } + } + + struct LayoutVisitor { + marker: PhantomData Layout>, + } + + impl<'de> Visitor<'de> for LayoutVisitor { + type Value = Layout; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "a `cranelift_codegen::ir::Layout`") + } + + fn visit_seq(self, mut access: M) -> Result + where + M: SeqAccess<'de>, + { + let mut layout = Layout::new(); + + while let Some(block) = access.next_element::()? { + layout.append_block(block); + + let count = access + .next_element::()? + .ok_or_else(|| Error::missing_field("count"))?; + for _ in 0..count { + let inst = access + .next_element::()? + .ok_or_else(|| Error::missing_field("inst"))?; + layout.append_inst(inst, block); + } + } + + Ok(layout) + } + } +} + #[cfg(test)] mod tests { use super::Layout; diff --git a/cranelift/codegen/src/ir/memflags.rs b/cranelift/codegen/src/ir/memflags.rs index 3c9c8c98ba..4ff76b623c 100644 --- a/cranelift/codegen/src/ir/memflags.rs +++ b/cranelift/codegen/src/ir/memflags.rs @@ -2,6 +2,9 @@ use core::fmt; +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + enum FlagBit { Notrap, Aligned, @@ -32,6 +35,7 @@ pub enum Endianness { /// be overridden for individual accesses by explicitly specifying little- or big-endian /// semantics via the flags. #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct MemFlags { bits: u8, } diff --git a/cranelift/codegen/src/ir/mod.rs b/cranelift/codegen/src/ir/mod.rs index c78dde81de..c075da6824 100644 --- a/cranelift/codegen/src/ir/mod.rs +++ b/cranelift/codegen/src/ir/mod.rs @@ -91,6 +91,7 @@ entity_impl!(ValueLabel, "val"); /// A label of a Value. #[derive(Debug, Clone)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct ValueLabelStart { /// Source location when it is in effect pub from: SourceLoc, @@ -101,6 +102,7 @@ pub struct ValueLabelStart { /// Value label assignements: label starts or value aliases. #[derive(Debug, Clone)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub enum ValueLabelAssignments { /// Original value labels assigned at transform. Starts(alloc::vec::Vec), diff --git a/cranelift/codegen/src/ir/table.rs b/cranelift/codegen/src/ir/table.rs index 9e436cca64..713d1f5df7 100644 --- a/cranelift/codegen/src/ir/table.rs +++ b/cranelift/codegen/src/ir/table.rs @@ -4,8 +4,12 @@ use crate::ir::immediates::Uimm64; use crate::ir::{GlobalValue, Type}; use core::fmt; +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + /// Information about a table declaration. #[derive(Clone)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct TableData { /// Global value giving the address of the start of the table. pub base_gv: GlobalValue, diff --git a/cranelift/codegen/src/isa/encoding.rs b/cranelift/codegen/src/isa/encoding.rs index 99894cab2c..84001c5d36 100644 --- a/cranelift/codegen/src/isa/encoding.rs +++ b/cranelift/codegen/src/isa/encoding.rs @@ -6,6 +6,9 @@ use crate::isa::constraints::{BranchRange, RecipeConstraints}; use crate::regalloc::RegDiversions; use core::fmt; +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + /// Bits needed to encode an instruction as binary machine code. /// /// The encoding consists of two parts, both specific to the target ISA: An encoding *recipe*, and @@ -13,6 +16,7 @@ use core::fmt; /// operands to encoded bits. The encoding bits provide additional information to the recipe, /// typically parts of the opcode. #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct Encoding { recipe: u16, bits: u16, diff --git a/cranelift/codegen/src/regalloc/diversion.rs b/cranelift/codegen/src/regalloc/diversion.rs index be7b7fa1ee..ba91df14a5 100644 --- a/cranelift/codegen/src/regalloc/diversion.rs +++ b/cranelift/codegen/src/regalloc/diversion.rs @@ -15,6 +15,9 @@ use crate::isa::{RegInfo, RegUnit}; use core::fmt; use cranelift_entity::{SparseMap, SparseMapValue}; +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + /// A diversion of a value from its original location to a new register or stack location. /// /// In IR, a diversion is represented by a `regmove` instruction, possibly a chain of them for the @@ -23,6 +26,7 @@ use cranelift_entity::{SparseMap, SparseMapValue}; /// When tracking diversions, the `from` field is the original assigned value location, and `to` is /// the current one. #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct Diversion { /// The original value location. pub from: ValueLoc, @@ -40,18 +44,21 @@ impl Diversion { /// Keep track of diversions in a block. #[derive(Clone)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct RegDiversions { current: FxHashMap, } /// Keep track of diversions at the entry of block. #[derive(Clone)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] struct EntryRegDiversionsValue { key: Block, divert: RegDiversions, } /// Map block to their matching RegDiversions at basic blocks entry. +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct EntryRegDiversions { map: SparseMap, } diff --git a/cranelift/entity/src/list.rs b/cranelift/entity/src/list.rs index dfb8fac646..3e583c5fd7 100644 --- a/cranelift/entity/src/list.rs +++ b/cranelift/entity/src/list.rs @@ -5,6 +5,9 @@ use alloc::vec::Vec; use core::marker::PhantomData; use core::mem; +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + /// A small list of entity references allocated from a pool. /// /// An `EntityList` type provides similar functionality to `Vec`, but with some important @@ -59,7 +62,8 @@ use core::mem; /// /// The index stored in an `EntityList` points to part 2, the list elements. The value 0 is /// reserved for the empty list which isn't allocated in the vector. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct EntityList { index: u32, unused: PhantomData, @@ -77,6 +81,7 @@ impl Default for EntityList { /// A memory pool for storing lists of `T`. #[derive(Clone, Debug)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct ListPool { // The main array containing the lists. data: Vec, diff --git a/cranelift/entity/src/packed_option.rs b/cranelift/entity/src/packed_option.rs index 3bca32f8a0..7f48b0196a 100644 --- a/cranelift/entity/src/packed_option.rs +++ b/cranelift/entity/src/packed_option.rs @@ -10,6 +10,9 @@ use core::fmt; use core::mem; +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + /// Types that have a reserved value which can't be created any other way. pub trait ReservedValue { /// Create an instance of the reserved value. @@ -20,6 +23,7 @@ pub trait ReservedValue { /// Packed representation of `Option`. #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct PackedOption(T); impl PackedOption { diff --git a/cranelift/entity/src/sparse.rs b/cranelift/entity/src/sparse.rs index 57d971b281..a7cad3151c 100644 --- a/cranelift/entity/src/sparse.rs +++ b/cranelift/entity/src/sparse.rs @@ -14,6 +14,9 @@ use core::mem; use core::slice; use core::u32; +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + /// Trait for extracting keys from values stored in a `SparseMap`. /// /// All values stored in a `SparseMap` must keep track of their own key in the map and implement @@ -53,6 +56,7 @@ pub trait SparseMapValue { /// is). /// - `SparseMap` requires the values to implement `SparseMapValue` which means that they must /// contain their own key. +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct SparseMap where K: EntityRef, From 71e468a954e4054fd88d0030146c8009cafc41a2 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 19 Dec 2020 16:38:08 +0100 Subject: [PATCH 2/6] Remove most of cranelift-serde --- cranelift/serde/Cargo.toml | 2 +- cranelift/serde/src/clif-json.rs | 10 +- cranelift/serde/src/serde_clif_json.rs | 978 ------------------------- 3 files changed, 5 insertions(+), 985 deletions(-) delete mode 100644 cranelift/serde/src/serde_clif_json.rs diff --git a/cranelift/serde/Cargo.toml b/cranelift/serde/Cargo.toml index 00eef94a82..7797865ef3 100644 --- a/cranelift/serde/Cargo.toml +++ b/cranelift/serde/Cargo.toml @@ -18,7 +18,7 @@ clap = "2.32.0" serde = "1.0.8" serde_derive = "1.0.75" serde_json = "1.0.26" -cranelift-codegen = { path = "../codegen", version = "0.70.0" } +cranelift-codegen = { path = "../codegen", version = "0.70.0", features = ["enable-serde"] } cranelift-reader = { path = "../reader", version = "0.70.0" } [badges] diff --git a/cranelift/serde/src/clif-json.rs b/cranelift/serde/src/clif-json.rs index 2dedf7dbdc..793b40e68f 100644 --- a/cranelift/serde/src/clif-json.rs +++ b/cranelift/serde/src/clif-json.rs @@ -22,23 +22,21 @@ )] use clap::{App, Arg, SubCommand}; +use cranelift_codegen::ir::Function; use cranelift_reader::parse_functions; use std::fs::File; use std::io::prelude::*; use std::io::{self, Write}; use std::process; -mod serde_clif_json; - fn call_ser(file: &str, pretty: bool) -> Result<(), String> { let ret_of_parse = parse_functions(file); match ret_of_parse { Ok(funcs) => { - let ser_funcs = serde_clif_json::SerObj::new(&funcs); let ser_str = if pretty { - serde_json::to_string_pretty(&ser_funcs).unwrap() + serde_json::to_string_pretty(&funcs).unwrap() } else { - serde_json::to_string(&ser_funcs).unwrap() + serde_json::to_string(&funcs).unwrap() }; println!("{}", ser_str); Ok(()) @@ -48,7 +46,7 @@ fn call_ser(file: &str, pretty: bool) -> Result<(), String> { } fn call_de(file: &File) -> Result<(), String> { - let de: serde_clif_json::SerObj = match serde_json::from_reader(file) { + let de: Vec = match serde_json::from_reader(file) { Result::Ok(val) => val, Result::Err(err) => panic!("{}", err), }; diff --git a/cranelift/serde/src/serde_clif_json.rs b/cranelift/serde/src/serde_clif_json.rs deleted file mode 100644 index 3ec9917553..0000000000 --- a/cranelift/serde/src/serde_clif_json.rs +++ /dev/null @@ -1,978 +0,0 @@ -use cranelift_codegen::ir::{Block, Function, Inst, InstructionData, Signature}; -use serde_derive::{Deserialize, Serialize}; - -/// Serializable version of the original Cranelift IR -#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] -pub enum SerInstData { - Unary { - opcode: String, - arg: String, - }, - UnaryImm { - opcode: String, - imm: String, - }, - UnaryIeee32 { - opcode: String, - imm: String, - }, - UnaryIeee64 { - opcode: String, - imm: String, - }, - UnaryBool { - opcode: String, - imm: bool, - }, - UnaryGlobalValue { - opcode: String, - global_value: String, - }, - Binary { - opcode: String, - args: [String; 2], - }, - BinaryImm8 { - opcode: String, - arg: String, - imm: String, - }, - BinaryImm64 { - opcode: String, - arg: String, - imm: String, - }, - Ternary { - opcode: String, - args: [String; 3], - }, - TernaryImm8 { - opcode: String, - args: [String; 2], - imm: String, - }, - MultiAry { - opcode: String, - args: Vec, - }, - NullAry { - opcode: String, - }, - Shuffle { - opcode: String, - args: [String; 2], - mask: String, - }, - IntCompare { - opcode: String, - args: [String; 2], - cond: String, - }, - IntCompareImm { - opcode: String, - arg: String, - cond: String, - imm: String, - }, - IntCond { - opcode: String, - arg: String, - cond: String, - }, - FloatCompare { - opcode: String, - args: [String; 2], - cond: String, - }, - FloatCond { - opcode: String, - arg: String, - cond: String, - }, - IntSelect { - opcode: String, - args: [String; 3], - cond: String, - }, - Jump { - opcode: String, - args: Vec, - destination: String, - }, - Branch { - opcode: String, - args: Vec, - destination: String, - }, - BranchInt { - opcode: String, - args: Vec, - cond: String, - destination: String, - }, - BranchFloat { - opcode: String, - args: Vec, - cond: String, - destination: String, - }, - BranchIcmp { - opcode: String, - args: Vec, - cond: String, - destination: String, - }, - BranchTable { - opcode: String, - arg: String, - destination: String, - table: String, - }, - BranchTableEntry { - opcode: String, - args: [String; 2], - imm: String, - table: String, - }, - BranchTableBase { - opcode: String, - table: String, - }, - IndirectJump { - opcode: String, - arg: String, - table: String, - }, - Call { - opcode: String, - args: Vec, - func_ref: String, - }, - CallIndirect { - opcode: String, - args: Vec, - sig_ref: String, - }, - FuncAddr { - opcode: String, - func_ref: String, - }, - Load { - opcode: String, - arg: String, - flags: String, - offset: String, - }, - LoadComplex { - opcode: String, - args: Vec, - flags: String, - offset: String, - }, - Store { - opcode: String, - args: [String; 2], - flags: String, - offset: String, - }, - StoreComplex { - opcode: String, - args: Vec, - flags: String, - offset: String, - }, - StackLoad { - opcode: String, - stack_slot: String, - offset: String, - }, - StackStore { - opcode: String, - arg: String, - stack_slot: String, - offset: String, - }, - HeapAddr { - opcode: String, - arg: String, - heap: String, - imm: String, - }, - TableAddr { - opcode: String, - arg: String, - table: String, - offset: String, - }, - RegMove { - opcode: String, - arg: String, - src: String, - dst: String, - }, - CopySpecial { - opcode: String, - src: String, - dst: String, - }, - CopyToSsa { - opcode: String, - src: String, - }, - RegSpill { - opcode: String, - arg: String, - src: String, - dst: String, - }, - RegFill { - opcode: String, - arg: String, - src: String, - dst: String, - }, - Trap { - opcode: String, - code: String, - }, - CondTrap { - opcode: String, - arg: String, - code: String, - }, - IntCondTrap { - opcode: String, - arg: String, - cond: String, - code: String, - }, - FloatCondTrap { - opcode: String, - arg: String, - cond: String, - code: String, - }, - AtomicCas { - opcode: String, - args: [String; 3], - flags: String, - }, - AtomicRmw { - opcode: String, - args: [String; 2], - flags: String, - op: String, - }, - LoadNoOffset { - opcode: String, - arg: String, - flags: String, - }, - StoreNoOffset { - opcode: String, - args: [String; 2], - flags: String, - }, -} - -/// Convert Cranelift IR instructions to JSON format. -pub fn get_inst_data(inst_index: Inst, func: &Function) -> SerInstData { - let inst = &func.dfg[inst_index]; - match *inst { - InstructionData::Unary { opcode, arg } => SerInstData::Unary { - opcode: opcode.to_string(), - arg: arg.to_string(), - }, - InstructionData::UnaryImm { opcode, imm } => SerInstData::UnaryImm { - opcode: opcode.to_string(), - imm: imm.to_string(), - }, - InstructionData::UnaryIeee32 { opcode, imm } => SerInstData::UnaryIeee32 { - opcode: opcode.to_string(), - imm: imm.to_string(), - }, - InstructionData::UnaryIeee64 { opcode, imm } => SerInstData::UnaryIeee64 { - opcode: opcode.to_string(), - imm: imm.to_string(), - }, - InstructionData::UnaryBool { opcode, imm } => SerInstData::UnaryBool { - opcode: opcode.to_string(), - imm, - }, - InstructionData::UnaryGlobalValue { - opcode, - global_value, - } => SerInstData::UnaryGlobalValue { - opcode: opcode.to_string(), - global_value: global_value.to_string(), - }, - InstructionData::Binary { opcode, args } => { - let hold_args = [args[0].to_string(), args[1].to_string()]; - SerInstData::Binary { - opcode: opcode.to_string(), - args: hold_args, - } - } - InstructionData::BinaryImm8 { opcode, arg, imm } => SerInstData::BinaryImm8 { - opcode: opcode.to_string(), - arg: arg.to_string(), - imm: imm.to_string(), - }, - InstructionData::BinaryImm64 { opcode, arg, imm } => SerInstData::BinaryImm64 { - opcode: opcode.to_string(), - arg: arg.to_string(), - imm: imm.to_string(), - }, - InstructionData::Ternary { opcode, args } => { - let hold_args = [ - args[0].to_string(), - args[1].to_string(), - args[2].to_string(), - ]; - SerInstData::Ternary { - opcode: opcode.to_string(), - args: hold_args, - } - } - InstructionData::MultiAry { opcode, ref args } => { - let mut hold_args = Vec::new(); - let args_iter = args.as_slice(&func.dfg.value_lists); - for arg in args_iter { - hold_args.push(arg.to_string()); - } - - SerInstData::MultiAry { - opcode: opcode.to_string(), - args: hold_args, - } - } - InstructionData::NullAry { opcode } => SerInstData::NullAry { - opcode: opcode.to_string(), - }, - InstructionData::TernaryImm8 { opcode, args, imm } => { - let hold_args = [args[0].to_string(), args[1].to_string()]; - SerInstData::TernaryImm8 { - opcode: opcode.to_string(), - args: hold_args, - imm: imm.to_string(), - } - } - InstructionData::UnaryConst { - opcode, - constant_handle, - } => { - let constant = func.dfg.constants.get(constant_handle); - SerInstData::UnaryImm { - opcode: opcode.to_string(), - imm: format!("{:?}", constant), - } - } - InstructionData::Shuffle { opcode, args, mask } => { - let mask = func - .dfg - .immediates - .get(mask) - .expect("Expected shuffle mask to already be inserted in immediate mapping"); - SerInstData::Shuffle { - opcode: opcode.to_string(), - args: [args[0].to_string(), args[1].to_string()], - mask: format!("{:?}", mask), - } - } - InstructionData::IntCompare { opcode, args, cond } => { - let hold_args = [args[0].to_string(), args[1].to_string()]; - SerInstData::IntCompare { - opcode: opcode.to_string(), - args: hold_args, - cond: cond.to_string(), - } - } - InstructionData::IntCompareImm { - opcode, - arg, - cond, - imm, - } => SerInstData::IntCompareImm { - opcode: opcode.to_string(), - arg: arg.to_string(), - cond: cond.to_string(), - imm: imm.to_string(), - }, - InstructionData::IntCond { opcode, arg, cond } => SerInstData::IntCond { - opcode: opcode.to_string(), - arg: arg.to_string(), - cond: cond.to_string(), - }, - InstructionData::FloatCompare { opcode, args, cond } => { - let hold_args = [args[0].to_string(), args[1].to_string()]; - SerInstData::FloatCompare { - opcode: opcode.to_string(), - args: hold_args, - cond: cond.to_string(), - } - } - InstructionData::FloatCond { opcode, arg, cond } => SerInstData::FloatCond { - opcode: opcode.to_string(), - arg: arg.to_string(), - cond: cond.to_string(), - }, - InstructionData::IntSelect { opcode, args, cond } => { - let hold_args = [ - args[0].to_string(), - args[1].to_string(), - args[2].to_string(), - ]; - SerInstData::IntSelect { - opcode: opcode.to_string(), - args: hold_args, - cond: cond.to_string(), - } - } - InstructionData::Jump { - opcode, - ref args, - destination, - } => { - let mut hold_args = Vec::new(); - let args_iter = args.as_slice(&func.dfg.value_lists); - for arg in args_iter { - hold_args.push(arg.to_string()); - } - SerInstData::Jump { - opcode: opcode.to_string(), - args: hold_args, - destination: destination.to_string(), - } - } - InstructionData::Branch { - opcode, - ref args, - destination, - } => { - let mut hold_args = Vec::new(); - let args_iter = args.as_slice(&func.dfg.value_lists); - for arg in args_iter { - hold_args.push(arg.to_string()); - } - SerInstData::Branch { - opcode: opcode.to_string(), - args: hold_args, - destination: destination.to_string(), - } - } - InstructionData::BranchInt { - opcode, - ref args, - cond, - destination, - } => { - let mut hold_args = Vec::new(); - let args_iter = args.as_slice(&func.dfg.value_lists); - for arg in args_iter { - hold_args.push(arg.to_string()); - } - SerInstData::BranchInt { - opcode: opcode.to_string(), - args: hold_args, - cond: cond.to_string(), - destination: destination.to_string(), - } - } - InstructionData::BranchFloat { - opcode, - ref args, - cond, - destination, - } => { - let mut hold_args = Vec::new(); - let args_iter = args.as_slice(&func.dfg.value_lists); - for arg in args_iter { - hold_args.push(arg.to_string()); - } - SerInstData::BranchFloat { - opcode: opcode.to_string(), - args: hold_args, - cond: cond.to_string(), - destination: destination.to_string(), - } - } - InstructionData::BranchIcmp { - opcode, - ref args, - cond, - destination, - } => { - let mut hold_args = Vec::new(); - let args_iter = args.as_slice(&func.dfg.value_lists); - for arg in args_iter { - hold_args.push(arg.to_string()); - } - SerInstData::BranchIcmp { - opcode: opcode.to_string(), - args: hold_args, - cond: cond.to_string(), - destination: destination.to_string(), - } - } - InstructionData::BranchTable { - opcode, - arg, - destination, - table, - } => SerInstData::BranchTable { - opcode: opcode.to_string(), - arg: arg.to_string(), - destination: destination.to_string(), - table: table.to_string(), - }, - InstructionData::BranchTableBase { opcode, table } => SerInstData::BranchTableBase { - opcode: opcode.to_string(), - table: table.to_string(), - }, - InstructionData::BranchTableEntry { - opcode, - args, - imm, - table, - } => { - let hold_args = [args[0].to_string(), args[1].to_string()]; - SerInstData::BranchTableEntry { - opcode: opcode.to_string(), - args: hold_args, - imm: imm.to_string(), - table: table.to_string(), - } - } - InstructionData::IndirectJump { opcode, arg, table } => SerInstData::IndirectJump { - opcode: opcode.to_string(), - arg: arg.to_string(), - table: table.to_string(), - }, - InstructionData::Call { - opcode, - ref args, - func_ref, - } => { - let mut hold_args = Vec::new(); - let args_iter = args.as_slice(&func.dfg.value_lists); - for arg in args_iter { - hold_args.push(arg.to_string()); - } - SerInstData::Call { - opcode: opcode.to_string(), - args: hold_args, - func_ref: func_ref.to_string(), - } - } - InstructionData::CallIndirect { - opcode, - ref args, - sig_ref, - } => { - let mut hold_args = Vec::new(); - let args_iter = args.as_slice(&func.dfg.value_lists); - for arg in args_iter { - hold_args.push(arg.to_string()); - } - SerInstData::CallIndirect { - opcode: opcode.to_string(), - args: hold_args, - sig_ref: sig_ref.to_string(), - } - } - InstructionData::FuncAddr { opcode, func_ref } => SerInstData::FuncAddr { - opcode: opcode.to_string(), - func_ref: func_ref.to_string(), - }, - InstructionData::Load { - opcode, - arg, - flags, - offset, - } => SerInstData::Load { - opcode: opcode.to_string(), - arg: arg.to_string(), - flags: flags.to_string(), - offset: offset.to_string(), - }, - InstructionData::LoadComplex { - opcode, - ref args, - flags, - offset, - } => { - let mut hold_args = Vec::new(); - let args_iter = args.as_slice(&func.dfg.value_lists); - for arg in args_iter { - hold_args.push(arg.to_string()); - } - SerInstData::LoadComplex { - opcode: opcode.to_string(), - args: hold_args, - flags: flags.to_string(), - offset: offset.to_string(), - } - } - InstructionData::Store { - opcode, - args, - flags, - offset, - } => { - let hold_args = [args[0].to_string(), args[1].to_string()]; - SerInstData::Store { - opcode: opcode.to_string(), - args: hold_args, - flags: flags.to_string(), - offset: offset.to_string(), - } - } - InstructionData::StoreComplex { - opcode, - ref args, - flags, - offset, - } => { - let mut hold_args = Vec::new(); - let args_iter = args.as_slice(&func.dfg.value_lists); - for arg in args_iter { - hold_args.push(arg.to_string()); - } - SerInstData::StoreComplex { - opcode: opcode.to_string(), - args: hold_args, - flags: flags.to_string(), - offset: offset.to_string(), - } - } - InstructionData::StackLoad { - opcode, - stack_slot, - offset, - } => SerInstData::StackLoad { - opcode: opcode.to_string(), - stack_slot: stack_slot.to_string(), - offset: offset.to_string(), - }, - InstructionData::StackStore { - opcode, - arg, - stack_slot, - offset, - } => SerInstData::StackStore { - opcode: opcode.to_string(), - arg: arg.to_string(), - stack_slot: stack_slot.to_string(), - offset: offset.to_string(), - }, - InstructionData::HeapAddr { - opcode, - arg, - heap, - imm, - } => SerInstData::HeapAddr { - opcode: opcode.to_string(), - arg: arg.to_string(), - heap: heap.to_string(), - imm: imm.to_string(), - }, - InstructionData::TableAddr { - opcode, - arg, - table, - offset, - } => SerInstData::TableAddr { - opcode: opcode.to_string(), - arg: arg.to_string(), - table: table.to_string(), - offset: offset.to_string(), - }, - InstructionData::RegMove { - opcode, - arg, - src, - dst, - } => SerInstData::RegMove { - opcode: opcode.to_string(), - arg: arg.to_string(), - src: src.to_string(), - dst: dst.to_string(), - }, - InstructionData::CopySpecial { opcode, src, dst } => SerInstData::CopySpecial { - opcode: opcode.to_string(), - src: src.to_string(), - dst: dst.to_string(), - }, - InstructionData::CopyToSsa { opcode, src } => SerInstData::CopyToSsa { - opcode: opcode.to_string(), - src: src.to_string(), - }, - InstructionData::RegSpill { - opcode, - arg, - src, - dst, - } => SerInstData::RegSpill { - opcode: opcode.to_string(), - arg: arg.to_string(), - src: src.to_string(), - dst: dst.to_string(), - }, - InstructionData::RegFill { - opcode, - arg, - src, - dst, - } => SerInstData::RegFill { - opcode: opcode.to_string(), - arg: arg.to_string(), - src: src.to_string(), - dst: dst.to_string(), - }, - InstructionData::Trap { opcode, code } => SerInstData::Trap { - opcode: opcode.to_string(), - code: code.to_string(), - }, - InstructionData::CondTrap { opcode, arg, code } => SerInstData::CondTrap { - opcode: opcode.to_string(), - arg: arg.to_string(), - code: code.to_string(), - }, - InstructionData::IntCondTrap { - opcode, - arg, - cond, - code, - } => SerInstData::IntCondTrap { - opcode: opcode.to_string(), - arg: arg.to_string(), - cond: cond.to_string(), - code: code.to_string(), - }, - InstructionData::FloatCondTrap { - opcode, - arg, - cond, - code, - } => SerInstData::FloatCondTrap { - opcode: opcode.to_string(), - arg: arg.to_string(), - cond: cond.to_string(), - code: code.to_string(), - }, - InstructionData::AtomicCas { - opcode, - args, - flags, - } => { - let hold_args = [ - args[0].to_string(), - args[1].to_string(), - args[2].to_string(), - ]; - SerInstData::AtomicCas { - opcode: opcode.to_string(), - args: hold_args, - flags: flags.to_string(), - } - } - InstructionData::AtomicRmw { - opcode, - args, - flags, - op, - } => { - let hold_args = [args[0].to_string(), args[1].to_string()]; - SerInstData::AtomicRmw { - opcode: opcode.to_string(), - args: hold_args, - flags: flags.to_string(), - op: op.to_string(), - } - } - InstructionData::LoadNoOffset { opcode, arg, flags } => SerInstData::LoadNoOffset { - opcode: opcode.to_string(), - arg: arg.to_string(), - flags: flags.to_string(), - }, - InstructionData::StoreNoOffset { - opcode, - args, - flags, - } => { - let hold_args = [args[0].to_string(), args[1].to_string()]; - SerInstData::StoreNoOffset { - opcode: opcode.to_string(), - args: hold_args, - flags: flags.to_string(), - } - } - } -} - -/// Serializable version of Cranelift IR instructions. -#[derive(Clone, Deserialize, Serialize, Debug)] -pub struct SerInst { - pub inst_name: String, - pub inst_data: SerInstData, -} - -impl SerInst { - pub fn new(inst: Inst, func: &Function) -> Self { - Self { - inst_name: inst.to_string(), - inst_data: get_inst_data(inst, func), - } - } -} - -/// Serializable version of Cranelift IR Blocks. -#[derive(Clone, Deserialize, Serialize, Debug)] -pub struct SerBlock { - pub block: String, - pub params: Vec, - pub insts: Vec, -} - -impl SerBlock { - pub fn new(name: String) -> Self { - Self { - block: name, - params: Vec::new(), - insts: Vec::new(), - } - } -} - -pub fn populate_inst(func: &Function, block: Block) -> Vec { - let mut ser_vec: Vec = Vec::new(); - let ret_iter = func.layout.block_insts(block); - for inst in ret_iter { - let ser_inst: SerInst = SerInst::new(inst, &func); - ser_vec.push(ser_inst); - } - ser_vec -} - -/// Translating Block parameters into serializable parameters. -pub fn populate_params(func: &Function, block: Block) -> Vec { - let mut ser_vec: Vec = Vec::new(); - let parameters = func.dfg.block_params(block); - for param in parameters { - ser_vec.push(param.to_string()); - } - ser_vec -} - -/// Serializable Data Flow Graph. -#[derive(Deserialize, Serialize, Debug)] -pub struct SerDataFlowGraph { - blocks: Vec, -} - -/// Serialize all parts of the Cranelift Block data structure, this includes name, parameters, and -/// instructions. -pub fn populate_blocks(func: &Function) -> Vec { - let mut block_vec: Vec = Vec::new(); - for block in func.layout.blocks() { - let mut ser_block: SerBlock = SerBlock::new(block.to_string()); - ser_block.params = populate_params(&func, block); - ser_block.insts = populate_inst(&func, block); - block_vec.push(ser_block); - } - block_vec -} - -/// Serializable Cranelift IR data flow graph, including all blocks. -impl SerDataFlowGraph { - pub fn create_new(func: &Function) -> Self { - Self { - blocks: populate_blocks(func), - } - } - - pub fn new(func: &Function) -> Self { - Self::create_new(func) - } -} - -/// Serializable signature including function parameters and returns. -#[derive(Serialize, Deserialize, Debug)] -pub struct SerSignature { - pub func_params: Vec, - pub func_returns: Vec, -} - -impl SerSignature { - /// Creating serializable signature data structure from all Cranelift IR functions. - fn create_new(sig: &Signature) -> Self { - let mut params_vec: Vec = Vec::new(); - let mut returns_vec: Vec = Vec::new(); - for param in &sig.params { - params_vec.push(param.to_string()); - } - for ret in &sig.returns { - returns_vec.push(ret.to_string()); - } - Self { - func_params: params_vec, - func_returns: returns_vec, - } - } - - pub fn new(func: &Function) -> Self { - Self::create_new(&func.signature) - } -} - -/// Serializable Function type, including name, signature, global values, and data flow graph. -#[derive(Serialize, Deserialize, Debug)] -pub struct SerFunction { - pub name: String, - pub signature: SerSignature, - pub globals: Vec, - pub dfg: SerDataFlowGraph, -} - -impl SerFunction { - /// Creates serializable global values, as well as the functions signature, name, and data flow - /// graph. - fn create_new(func: &Function) -> Self { - let mut global_vec: Vec = Vec::new(); - for (glob_name, _) in func.global_values.iter() { - global_vec.push(glob_name.to_string()); - } - Self { - name: func.name.to_string(), - signature: SerSignature::new(&func), - globals: global_vec, - dfg: SerDataFlowGraph::new(&func), - } - } - - pub fn new(func: &Function) -> Self { - Self::create_new(func) - } -} - -/// Must have SerObj for deserialization, contains all of the functions from inside the file to be -/// serialized. Files have one SerObj each, with all SerFunctions contained inside that SerObj. -#[derive(Serialize, Deserialize, Debug)] -pub struct SerObj { - pub functions: Vec, -} - -impl SerObj { - fn create_new(funcs: Vec) -> Self { - Self { functions: funcs } - } - - pub fn new(funcs: &[Function]) -> Self { - let mut func_vec: Vec = Vec::new(); - for func in funcs { - let ser_func: SerFunction = SerFunction::new(&func); - func_vec.push(ser_func); - } - Self::create_new(func_vec) - } -} From a0c2276ee7bd71a619f0f66c7a875cb8c54409ac Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 8 Feb 2021 11:48:54 +0100 Subject: [PATCH 3/6] Add a version marker This prevents deserializing a function with a different Cranelift version --- cranelift/codegen/src/ir/function.rs | 47 +++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/cranelift/codegen/src/ir/function.rs b/cranelift/codegen/src/ir/function.rs index f5dc7f916f..1b579e18a1 100644 --- a/cranelift/codegen/src/ir/function.rs +++ b/cranelift/codegen/src/ir/function.rs @@ -18,19 +18,63 @@ use crate::isa::{CallConv, EncInfo, Encoding, Legalize, TargetIsa}; use crate::regalloc::{EntryRegDiversions, RegDiversions}; use crate::value_label::ValueLabelsRanges; use crate::write::write_function; +#[cfg(feature = "enable-serde")] +use alloc::string::String; use alloc::vec::Vec; use core::fmt; +#[cfg(feature = "enable-serde")] +use serde::de::{Deserializer, Error}; +#[cfg(feature = "enable-serde")] +use serde::ser::Serializer; #[cfg(feature = "enable-serde")] use serde::{Deserialize, Serialize}; -/// A function. +/// A version marker used to ensure that serialized clif ir is never deserialized with a +/// different version of Cranelift. +#[derive(Copy, Clone, Debug)] +pub struct VersionMarker; + +#[cfg(feature = "enable-serde")] +impl Serialize for VersionMarker { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + crate::VERSION.serialize(serializer) + } +} + +#[cfg(feature = "enable-serde")] +impl<'de> Deserialize<'de> for VersionMarker { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let version = String::deserialize(deserializer)?; + if version != crate::VERSION { + return Err(D::Error::custom(&format!( + "Expected a clif ir function for version {}, found one for version {}", + crate::VERSION, + version, + ))); + } + Ok(VersionMarker) + } +} + /// /// Functions can be cloned, but it is not a very fast operation. /// The clone will have all the same entity numbers as the original. #[derive(Clone)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct Function { + /// A version marker used to ensure that serialized clif ir is never deserialized with a + /// different version of Cranelift. + // Note: This must be the first field to ensure that Serde will deserialize it before + // attempting to deserialize other fields that are potentially changed between versions. + pub version_marker: VersionMarker, + /// Name of this function. Mostly used by `.clif` files. pub name: ExternalName, @@ -113,6 +157,7 @@ impl Function { /// Create a function with the given name and signature. pub fn with_name_signature(name: ExternalName, sig: Signature) -> Self { Self { + version_marker: VersionMarker, name, signature: sig, old_signature: None, From 720da20588e0e984b1c1ff5eb63b84206b026d65 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Thu, 11 Feb 2021 11:08:54 +0100 Subject: [PATCH 4/6] Describe serialization format --- cranelift/codegen/src/ir/layout.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/cranelift/codegen/src/ir/layout.rs b/cranelift/codegen/src/ir/layout.rs index 9359c309df..f6272199bb 100644 --- a/cranelift/codegen/src/ir/layout.rs +++ b/cranelift/codegen/src/ir/layout.rs @@ -781,6 +781,17 @@ impl<'f> DoubleEndedIterator for Insts<'f> { } } +/// A custom serialize and deserialize implementation for [`Layout`]. +/// +/// This doesn't use a derived implementation as [`Layout`] is a manual implementation of a linked +/// list. Storing it directly as a regular list saves a lot of space. +/// +/// The following format is used. (notated in EBNF form) +/// +/// ```plain +/// data = block_data * ; +/// block_data = "block_id" , "inst_count" , ( "inst_id" * ) ; +/// ``` #[cfg(feature = "enable-serde")] mod serde { use ::serde::de::{Deserializer, Error, SeqAccess, Visitor}; From 0693b7dade171b25f0957c5c75e18e3d8c4cdd14 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 16 Feb 2021 19:01:02 +0100 Subject: [PATCH 5/6] Include git rev in the version number --- cranelift/codegen/build.rs | 37 ++++++++++++++++++++++++++++++++++++ cranelift/codegen/src/lib.rs | 3 +-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/cranelift/codegen/build.rs b/cranelift/codegen/build.rs index c456908845..dd6cfc999c 100644 --- a/cranelift/codegen/build.rs +++ b/cranelift/codegen/build.rs @@ -17,6 +17,7 @@ use cranelift_codegen_meta as meta; use std::env; +use std::io::Read; use std::process; use std::time::Instant; @@ -97,4 +98,40 @@ fn main() { ) .unwrap() } + + let pkg_version = env::var("CARGO_PKG_VERSION").unwrap(); + let mut cmd = std::process::Command::new("git"); + cmd.arg("rev-parse") + .arg("HEAD") + .stdout(std::process::Stdio::piped()) + .current_dir(env::var("CARGO_MANIFEST_DIR").unwrap()); + let version = if let Ok(mut child) = cmd.spawn() { + let mut git_rev = String::new(); + child + .stdout + .as_mut() + .unwrap() + .read_to_string(&mut git_rev) + .unwrap(); + let status = child.wait().unwrap(); + if status.success() { + let git_rev = git_rev.trim().chars().take(9).collect::(); + format!("{}-{}", pkg_version, git_rev) + } else { + // not a git repo + pkg_version + } + } else { + // git not available + pkg_version + }; + std::fs::write( + std::path::Path::new(&out_dir).join("version.rs"), + format!( + "/// Version number of this crate. \n\ + pub const VERSION: &str = \"{}\";", + version + ), + ) + .unwrap(); } diff --git a/cranelift/codegen/src/lib.rs b/cranelift/codegen/src/lib.rs index e3be3e0aaf..5b80073b7f 100644 --- a/cranelift/codegen/src/lib.rs +++ b/cranelift/codegen/src/lib.rs @@ -121,5 +121,4 @@ mod souper_harvest; pub use crate::result::{CodegenError, CodegenResult}; -/// Version number of this crate. -pub const VERSION: &str = env!("CARGO_PKG_VERSION"); +include!(concat!(env!("OUT_DIR"), "/version.rs")); From 08f72d708493b80c48c44730a01183a3ebf68340 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Thu, 18 Feb 2021 12:16:13 +0100 Subject: [PATCH 6/6] Fix ensure_deterministic_build.sh --- ci/ensure_deterministic_build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/ensure_deterministic_build.sh b/ci/ensure_deterministic_build.sh index ebed6cd1c7..7c80062ec5 100755 --- a/ci/ensure_deterministic_build.sh +++ b/ci/ensure_deterministic_build.sh @@ -11,7 +11,7 @@ BUILD_SCRIPT=$(find -wholename "./target/debug/build/cranelift-codegen-*/build-s # First, run the script to generate a reference comparison. rm -rf /tmp/reference mkdir /tmp/reference -OUT_DIR=/tmp/reference TARGET=x86_64 $BUILD_SCRIPT +OUT_DIR=/tmp/reference TARGET=x86_64 CARGO_PKG_VERSION=0.1.0 CARGO_MANIFEST_DIR=/tmp $BUILD_SCRIPT # To make sure the build script doesn't depend on the current directory, we'll # change the current working directory on every iteration. Make this easy to @@ -36,6 +36,6 @@ do rm -rf /tmp/try mkdir /tmp/try - OUT_DIR=/tmp/try TARGET=x86_64 $BUILD_SCRIPT + OUT_DIR=/tmp/try TARGET=x86_64 CARGO_PKG_VERSION=0.1.0 CARGO_MANIFEST_DIR=/tmp/src$i $BUILD_SCRIPT diff -qr /tmp/reference /tmp/try done