Merge pull request #2527 from bjorn3/serialize_ir
Add serde serialization support for the full clif ir
This commit is contained in:
3
Cargo.lock
generated
3
Cargo.lock
generated
@@ -550,6 +550,9 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-codegen-shared"
|
name = "cranelift-codegen-shared"
|
||||||
version = "0.70.0"
|
version = "0.70.0"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-entity"
|
name = "cranelift-entity"
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ BUILD_SCRIPT=$(find -wholename "./target/debug/build/cranelift-codegen-*/build-s
|
|||||||
# First, run the script to generate a reference comparison.
|
# First, run the script to generate a reference comparison.
|
||||||
rm -rf /tmp/reference
|
rm -rf /tmp/reference
|
||||||
mkdir /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
|
# 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
|
# change the current working directory on every iteration. Make this easy to
|
||||||
@@ -36,6 +36,6 @@ do
|
|||||||
|
|
||||||
rm -rf /tmp/try
|
rm -rf /tmp/try
|
||||||
mkdir /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
|
diff -qr /tmp/reference /tmp/try
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -74,7 +74,12 @@ all-arch = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
# For dependent crates that want to serialize some parts of cranelift
|
# 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
|
# Allow snapshotting regalloc test cases. Useful only to report bad register
|
||||||
# allocation failures, or for regalloc.rs developers.
|
# allocation failures, or for regalloc.rs developers.
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
use cranelift_codegen_meta as meta;
|
use cranelift_codegen_meta as meta;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::io::Read;
|
||||||
use std::process;
|
use std::process;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
@@ -97,4 +98,40 @@ fn main() {
|
|||||||
)
|
)
|
||||||
.unwrap()
|
.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::<String>();
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ fn gen_formats(formats: &[&InstructionFormat], fmt: &mut Formatter) {
|
|||||||
/// `ValueList` to store the additional information out of line.
|
/// `ValueList` to store the additional information out of line.
|
||||||
fn gen_instruction_data(formats: &[&InstructionFormat], fmt: &mut Formatter) {
|
fn gen_instruction_data(formats: &[&InstructionFormat], fmt: &mut Formatter) {
|
||||||
fmt.line("#[derive(Clone, Debug)]");
|
fmt.line("#[derive(Clone, Debug)]");
|
||||||
|
fmt.line(r#"#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]"#);
|
||||||
fmt.line("#[allow(missing_docs)]");
|
fmt.line("#[allow(missing_docs)]");
|
||||||
fmt.line("pub enum InstructionData {");
|
fmt.line("pub enum InstructionData {");
|
||||||
fmt.indent(|fmt| {
|
fmt.indent(|fmt| {
|
||||||
@@ -410,7 +411,10 @@ fn gen_opcodes(all_inst: &AllInstructions, fmt: &mut Formatter) {
|
|||||||
fmt.line("#[repr(u16)]");
|
fmt.line("#[repr(u16)]");
|
||||||
fmt.line("#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]");
|
fmt.line("#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]");
|
||||||
fmt.line(
|
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
|
// We explicitly set the discriminant of the first variant to 1, which allows us to take
|
||||||
|
|||||||
@@ -8,4 +8,10 @@ repository = "https://github.com/bytecodealliance/wasmtime"
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
edition = "2018"
|
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"]
|
||||||
|
|||||||
@@ -7,6 +7,9 @@
|
|||||||
use core::fmt::{self, Display, Formatter};
|
use core::fmt::{self, Display, Formatter};
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
|
|
||||||
|
#[cfg(feature = "enable-serde")]
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Common traits of condition codes.
|
/// Common traits of condition codes.
|
||||||
pub trait CondCode: Copy {
|
pub trait CondCode: Copy {
|
||||||
/// Get the inverse condition code of `self`.
|
/// 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
|
/// separate codes for comparing the integers as signed or unsigned numbers where it makes a
|
||||||
/// difference.
|
/// difference.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub enum IntCC {
|
pub enum IntCC {
|
||||||
/// `==`.
|
/// `==`.
|
||||||
Equal,
|
Equal,
|
||||||
@@ -187,6 +191,7 @@ impl FromStr for IntCC {
|
|||||||
/// comparison. The 14 condition codes here cover every possible combination of the relation above
|
/// 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`.
|
/// except the impossible `!UN & !EQ & !LT & !GT` and the always true `UN | EQ | LT | GT`.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub enum FloatCC {
|
pub enum FloatCC {
|
||||||
/// EQ | LT | GT
|
/// EQ | LT | GT
|
||||||
Ordered,
|
Ordered,
|
||||||
|
|||||||
@@ -19,12 +19,16 @@ use core::slice::Iter;
|
|||||||
use core::str::{from_utf8, FromStr};
|
use core::str::{from_utf8, FromStr};
|
||||||
use cranelift_entity::EntityRef;
|
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
|
/// 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
|
/// 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].
|
/// WebAssembly values, which are [little-endian by design].
|
||||||
///
|
///
|
||||||
/// [little-endian by design]: https://github.com/WebAssembly/design/blob/master/Portability.md
|
/// [little-endian by design]: https://github.com/WebAssembly/design/blob/master/Portability.md
|
||||||
#[derive(Clone, Hash, Eq, PartialEq, Debug, Default)]
|
#[derive(Clone, Hash, Eq, PartialEq, Debug, Default)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct ConstantData(Vec<u8>);
|
pub struct ConstantData(Vec<u8>);
|
||||||
|
|
||||||
impl FromIterator<u8> for ConstantData {
|
impl FromIterator<u8> for ConstantData {
|
||||||
@@ -173,6 +177,7 @@ pub type ConstantOffset = u32;
|
|||||||
/// from the beginning of the function is known (see
|
/// from the beginning of the function is known (see
|
||||||
/// `relaxation` in `relaxation.rs`).
|
/// `relaxation` in `relaxation.rs`).
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct ConstantPoolEntry {
|
pub struct ConstantPoolEntry {
|
||||||
data: ConstantData,
|
data: ConstantData,
|
||||||
offset: Option<ConstantOffset>,
|
offset: Option<ConstantOffset>,
|
||||||
@@ -197,6 +202,7 @@ impl ConstantPoolEntry {
|
|||||||
/// Maintains the mapping between a constant handle (i.e. [`Constant`](crate::ir::Constant)) and
|
/// Maintains the mapping between a constant handle (i.e. [`Constant`](crate::ir::Constant)) and
|
||||||
/// its constant data (i.e. [`ConstantData`](crate::ir::ConstantData)).
|
/// its constant data (i.e. [`ConstantData`](crate::ir::ConstantData)).
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct ConstantPool {
|
pub struct ConstantPool {
|
||||||
/// This mapping maintains the insertion order as long as Constants are created with
|
/// This mapping maintains the insertion order as long as Constants are created with
|
||||||
/// sequentially increasing integers.
|
/// sequentially increasing integers.
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ use core::mem;
|
|||||||
use core::ops::{Index, IndexMut};
|
use core::ops::{Index, IndexMut};
|
||||||
use core::u16;
|
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
|
/// 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
|
/// the data flow dependencies between them. The DFG also tracks values which can be either
|
||||||
/// instruction results or block parameters.
|
/// instruction results or block parameters.
|
||||||
@@ -29,6 +32,7 @@ use core::u16;
|
|||||||
/// `Layout` data structure which forms the other half of the function representation.
|
/// `Layout` data structure which forms the other half of the function representation.
|
||||||
///
|
///
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct DataFlowGraph {
|
pub struct DataFlowGraph {
|
||||||
/// Data about all of the instructions in the function, including opcodes and operands.
|
/// 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
|
/// 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.
|
/// Internal table storage for extended values.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
enum ValueData {
|
enum ValueData {
|
||||||
/// Value is defined by an instruction.
|
/// Value is defined by an instruction.
|
||||||
Inst { ty: Type, num: u16, inst: Inst },
|
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
|
/// branches to this block must provide matching arguments, and the arguments to the entry block must
|
||||||
/// match the function arguments.
|
/// match the function arguments.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
struct BlockData {
|
struct BlockData {
|
||||||
/// List of parameters to this block.
|
/// List of parameters to this block.
|
||||||
params: ValueList,
|
params: ValueList,
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
///
|
///
|
||||||
/// While the order is stable, it is arbitrary and does not necessarily resemble the layout order.
|
/// While the order is stable, it is arbitrary and does not necessarily resemble the layout order.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct Block(u32);
|
pub struct Block(u32);
|
||||||
entity_impl!(Block, "block");
|
entity_impl!(Block, "block");
|
||||||
|
|
||||||
@@ -65,6 +66,7 @@ impl Block {
|
|||||||
///
|
///
|
||||||
/// While the order is stable, it is arbitrary.
|
/// While the order is stable, it is arbitrary.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct Value(u32);
|
pub struct Value(u32);
|
||||||
entity_impl!(Value, "v");
|
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.
|
/// While the order is stable, it is arbitrary and does not necessarily resemble the layout order.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct Inst(u32);
|
pub struct Inst(u32);
|
||||||
entity_impl!(Inst, "inst");
|
entity_impl!(Inst, "inst");
|
||||||
|
|
||||||
@@ -152,6 +155,7 @@ impl StackSlot {
|
|||||||
///
|
///
|
||||||
/// While the order is stable, it is arbitrary.
|
/// While the order is stable, it is arbitrary.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct GlobalValue(u32);
|
pub struct GlobalValue(u32);
|
||||||
entity_impl!(GlobalValue, "gv");
|
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
|
/// 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.
|
/// the constants are written in the constant pool.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct Constant(u32);
|
pub struct Constant(u32);
|
||||||
entity_impl!(Constant, "const");
|
entity_impl!(Constant, "const");
|
||||||
|
|
||||||
@@ -202,6 +207,7 @@ impl Constant {
|
|||||||
///
|
///
|
||||||
/// While the order is stable, it is arbitrary.
|
/// While the order is stable, it is arbitrary.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct Immediate(u32);
|
pub struct Immediate(u32);
|
||||||
entity_impl!(Immediate, "imm");
|
entity_impl!(Immediate, "imm");
|
||||||
|
|
||||||
@@ -267,6 +273,7 @@ impl JumpTable {
|
|||||||
///
|
///
|
||||||
/// While the order is stable, it is arbitrary.
|
/// While the order is stable, it is arbitrary.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct FuncRef(u32);
|
pub struct FuncRef(u32);
|
||||||
entity_impl!(FuncRef, "fn");
|
entity_impl!(FuncRef, "fn");
|
||||||
|
|
||||||
@@ -298,6 +305,7 @@ impl FuncRef {
|
|||||||
///
|
///
|
||||||
/// While the order is stable, it is arbitrary.
|
/// While the order is stable, it is arbitrary.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct SigRef(u32);
|
pub struct SigRef(u32);
|
||||||
entity_impl!(SigRef, "sig");
|
entity_impl!(SigRef, "sig");
|
||||||
|
|
||||||
@@ -323,6 +331,7 @@ impl SigRef {
|
|||||||
///
|
///
|
||||||
/// While the order is stable, it is arbitrary.
|
/// While the order is stable, it is arbitrary.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct Heap(u32);
|
pub struct Heap(u32);
|
||||||
entity_impl!(Heap, "heap");
|
entity_impl!(Heap, "heap");
|
||||||
|
|
||||||
@@ -349,6 +358,7 @@ impl Heap {
|
|||||||
///
|
///
|
||||||
/// While the order is stable, it is arbitrary.
|
/// While the order is stable, it is arbitrary.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct Table(u32);
|
pub struct Table(u32);
|
||||||
entity_impl!(Table, "table");
|
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.
|
/// 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)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub enum AnyEntity {
|
pub enum AnyEntity {
|
||||||
/// The whole function.
|
/// The whole function.
|
||||||
Function,
|
Function,
|
||||||
|
|||||||
@@ -409,6 +409,7 @@ impl FromStr for ArgumentPurpose {
|
|||||||
///
|
///
|
||||||
/// Information about a function that can be called directly with a direct `call` instruction.
|
/// Information about a function that can be called directly with a direct `call` instruction.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct ExtFuncData {
|
pub struct ExtFuncData {
|
||||||
/// Name of the external function.
|
/// Name of the external function.
|
||||||
pub name: ExternalName,
|
pub name: ExternalName,
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ use core::cmp;
|
|||||||
use core::fmt::{self, Write};
|
use core::fmt::{self, Write};
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
|
|
||||||
|
#[cfg(feature = "enable-serde")]
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
const TESTCASE_NAME_LENGTH: usize = 16;
|
const TESTCASE_NAME_LENGTH: usize = 16;
|
||||||
|
|
||||||
/// The name of an external is either a reference to a user-defined symbol
|
/// 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
|
/// In particular, many `.clif` test files use function names to identify
|
||||||
/// functions.
|
/// functions.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub enum ExternalName {
|
pub enum ExternalName {
|
||||||
/// A name in a user-defined symbol table. Cranelift does not interpret
|
/// A name in a user-defined symbol table. Cranelift does not interpret
|
||||||
/// these numbers in any way.
|
/// these numbers in any way.
|
||||||
|
|||||||
@@ -18,15 +18,63 @@ use crate::isa::{CallConv, EncInfo, Encoding, Legalize, TargetIsa};
|
|||||||
use crate::regalloc::{EntryRegDiversions, RegDiversions};
|
use crate::regalloc::{EntryRegDiversions, RegDiversions};
|
||||||
use crate::value_label::ValueLabelsRanges;
|
use crate::value_label::ValueLabelsRanges;
|
||||||
use crate::write::write_function;
|
use crate::write::write_function;
|
||||||
|
#[cfg(feature = "enable-serde")]
|
||||||
|
use alloc::string::String;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
/// A function.
|
#[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 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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
crate::VERSION.serialize(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "enable-serde")]
|
||||||
|
impl<'de> Deserialize<'de> for VersionMarker {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
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.
|
/// Functions can be cloned, but it is not a very fast operation.
|
||||||
/// The clone will have all the same entity numbers as the original.
|
/// The clone will have all the same entity numbers as the original.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct Function {
|
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.
|
/// Name of this function. Mostly used by `.clif` files.
|
||||||
pub name: ExternalName,
|
pub name: ExternalName,
|
||||||
|
|
||||||
@@ -109,6 +157,7 @@ impl Function {
|
|||||||
/// Create a function with the given name and signature.
|
/// Create a function with the given name and signature.
|
||||||
pub fn with_name_signature(name: ExternalName, sig: Signature) -> Self {
|
pub fn with_name_signature(name: ExternalName, sig: Signature) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
version_marker: VersionMarker,
|
||||||
name,
|
name,
|
||||||
signature: sig,
|
signature: sig,
|
||||||
old_signature: None,
|
old_signature: None,
|
||||||
|
|||||||
@@ -6,8 +6,12 @@ use crate::isa::TargetIsa;
|
|||||||
use crate::machinst::RelocDistance;
|
use crate::machinst::RelocDistance;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
|
#[cfg(feature = "enable-serde")]
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Information about a global value declaration.
|
/// Information about a global value declaration.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub enum GlobalValueData {
|
pub enum GlobalValueData {
|
||||||
/// Value is the address of the VM context struct.
|
/// Value is the address of the VM context struct.
|
||||||
VMContext,
|
VMContext,
|
||||||
|
|||||||
@@ -4,8 +4,12 @@ use crate::ir::immediates::Uimm64;
|
|||||||
use crate::ir::{GlobalValue, Type};
|
use crate::ir::{GlobalValue, Type};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
|
#[cfg(feature = "enable-serde")]
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Information about a heap declaration.
|
/// Information about a heap declaration.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct HeapData {
|
pub struct HeapData {
|
||||||
/// The address of the start of the heap's storage.
|
/// The address of the start of the heap's storage.
|
||||||
pub base: GlobalValue,
|
pub base: GlobalValue,
|
||||||
@@ -26,6 +30,7 @@ pub struct HeapData {
|
|||||||
|
|
||||||
/// Style of heap including style-specific information.
|
/// Style of heap including style-specific information.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub enum HeapStyle {
|
pub enum HeapStyle {
|
||||||
/// A dynamic heap can be relocated to a different base address when it is grown.
|
/// A dynamic heap can be relocated to a different base address when it is grown.
|
||||||
Dynamic {
|
Dynamic {
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ impl IntoBytes for Vec<u8> {
|
|||||||
/// An `Imm64` operand can also be used to represent immediate values of smaller integer types by
|
/// An `Imm64` operand can also be used to represent immediate values of smaller integer types by
|
||||||
/// sign-extending to `i64`.
|
/// sign-extending to `i64`.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct Imm64(i64);
|
pub struct Imm64(i64);
|
||||||
|
|
||||||
impl Imm64 {
|
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
|
/// A `Uimm64` operand can also be used to represent immediate values of smaller integer types by
|
||||||
/// zero-extending to `i64`.
|
/// zero-extending to `i64`.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct Uimm64(u64);
|
pub struct Uimm64(u64);
|
||||||
|
|
||||||
impl Uimm64 {
|
impl Uimm64 {
|
||||||
@@ -279,6 +281,7 @@ pub type Uimm8 = u8;
|
|||||||
///
|
///
|
||||||
/// This is used to represent sizes of memory objects.
|
/// This is used to represent sizes of memory objects.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct Uimm32(u32);
|
pub struct Uimm32(u32);
|
||||||
|
|
||||||
impl Into<u32> for Uimm32 {
|
impl Into<u32> 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
|
/// 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`.
|
/// a maximum load/store offset that fits in an `i32`.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct Offset32(i32);
|
pub struct Offset32(i32);
|
||||||
|
|
||||||
impl Offset32 {
|
impl Offset32 {
|
||||||
@@ -451,6 +455,7 @@ impl FromStr for Offset32 {
|
|||||||
///
|
///
|
||||||
/// All bit patterns are allowed.
|
/// All bit patterns are allowed.
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Ieee32(u32);
|
pub struct Ieee32(u32);
|
||||||
|
|
||||||
@@ -459,6 +464,7 @@ pub struct Ieee32(u32);
|
|||||||
///
|
///
|
||||||
/// All bit patterns are allowed.
|
/// All bit patterns are allowed.
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Ieee64(u64);
|
pub struct Ieee64(u64);
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ use core::num::NonZeroU32;
|
|||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
use core::str::FromStr;
|
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::ir::{self, trapcode::TrapCode, types, Block, FuncRef, JumpTable, SigRef, Type, Value};
|
||||||
use crate::isa;
|
use crate::isa;
|
||||||
|
|
||||||
|
|||||||
@@ -8,10 +8,14 @@ use alloc::vec::Vec;
|
|||||||
use core::fmt::{self, Display, Formatter};
|
use core::fmt::{self, Display, Formatter};
|
||||||
use core::slice::{Iter, IterMut};
|
use core::slice::{Iter, IterMut};
|
||||||
|
|
||||||
|
#[cfg(feature = "enable-serde")]
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Contents of a jump table.
|
/// Contents of a jump table.
|
||||||
///
|
///
|
||||||
/// All jump tables use 0-based indexing and are densely populated.
|
/// All jump tables use 0-based indexing and are densely populated.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct JumpTableData {
|
pub struct JumpTableData {
|
||||||
// Table entries.
|
// Table entries.
|
||||||
table: Vec<Block>,
|
table: Vec<Block>,
|
||||||
|
|||||||
@@ -781,6 +781,97 @@ 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};
|
||||||
|
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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
let size = self.blocks().count() * 2
|
||||||
|
+ self
|
||||||
|
.blocks()
|
||||||
|
.map(|block| self.block_insts(block).count())
|
||||||
|
.sum::<usize>();
|
||||||
|
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<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserializer.deserialize_seq(LayoutVisitor {
|
||||||
|
marker: PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LayoutVisitor {
|
||||||
|
marker: PhantomData<fn() -> 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<M>(self, mut access: M) -> Result<Self::Value, M::Error>
|
||||||
|
where
|
||||||
|
M: SeqAccess<'de>,
|
||||||
|
{
|
||||||
|
let mut layout = Layout::new();
|
||||||
|
|
||||||
|
while let Some(block) = access.next_element::<Block>()? {
|
||||||
|
layout.append_block(block);
|
||||||
|
|
||||||
|
let count = access
|
||||||
|
.next_element::<u32>()?
|
||||||
|
.ok_or_else(|| Error::missing_field("count"))?;
|
||||||
|
for _ in 0..count {
|
||||||
|
let inst = access
|
||||||
|
.next_element::<Inst>()?
|
||||||
|
.ok_or_else(|| Error::missing_field("inst"))?;
|
||||||
|
layout.append_inst(inst, block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(layout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::Layout;
|
use super::Layout;
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
|
#[cfg(feature = "enable-serde")]
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
enum FlagBit {
|
enum FlagBit {
|
||||||
Notrap,
|
Notrap,
|
||||||
Aligned,
|
Aligned,
|
||||||
@@ -32,6 +35,7 @@ pub enum Endianness {
|
|||||||
/// be overridden for individual accesses by explicitly specifying little- or big-endian
|
/// be overridden for individual accesses by explicitly specifying little- or big-endian
|
||||||
/// semantics via the flags.
|
/// semantics via the flags.
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct MemFlags {
|
pub struct MemFlags {
|
||||||
bits: u8,
|
bits: u8,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ entity_impl!(ValueLabel, "val");
|
|||||||
|
|
||||||
/// A label of a Value.
|
/// A label of a Value.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct ValueLabelStart {
|
pub struct ValueLabelStart {
|
||||||
/// Source location when it is in effect
|
/// Source location when it is in effect
|
||||||
pub from: SourceLoc,
|
pub from: SourceLoc,
|
||||||
@@ -101,6 +102,7 @@ pub struct ValueLabelStart {
|
|||||||
|
|
||||||
/// Value label assignements: label starts or value aliases.
|
/// Value label assignements: label starts or value aliases.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub enum ValueLabelAssignments {
|
pub enum ValueLabelAssignments {
|
||||||
/// Original value labels assigned at transform.
|
/// Original value labels assigned at transform.
|
||||||
Starts(alloc::vec::Vec<ValueLabelStart>),
|
Starts(alloc::vec::Vec<ValueLabelStart>),
|
||||||
|
|||||||
@@ -4,8 +4,12 @@ use crate::ir::immediates::Uimm64;
|
|||||||
use crate::ir::{GlobalValue, Type};
|
use crate::ir::{GlobalValue, Type};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
|
#[cfg(feature = "enable-serde")]
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Information about a table declaration.
|
/// Information about a table declaration.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct TableData {
|
pub struct TableData {
|
||||||
/// Global value giving the address of the start of the table.
|
/// Global value giving the address of the start of the table.
|
||||||
pub base_gv: GlobalValue,
|
pub base_gv: GlobalValue,
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ use crate::isa::constraints::{BranchRange, RecipeConstraints};
|
|||||||
use crate::regalloc::RegDiversions;
|
use crate::regalloc::RegDiversions;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
|
#[cfg(feature = "enable-serde")]
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Bits needed to encode an instruction as binary machine code.
|
/// 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
|
/// 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,
|
/// operands to encoded bits. The encoding bits provide additional information to the recipe,
|
||||||
/// typically parts of the opcode.
|
/// typically parts of the opcode.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct Encoding {
|
pub struct Encoding {
|
||||||
recipe: u16,
|
recipe: u16,
|
||||||
bits: u16,
|
bits: u16,
|
||||||
|
|||||||
@@ -121,5 +121,4 @@ mod souper_harvest;
|
|||||||
|
|
||||||
pub use crate::result::{CodegenError, CodegenResult};
|
pub use crate::result::{CodegenError, CodegenResult};
|
||||||
|
|
||||||
/// Version number of this crate.
|
include!(concat!(env!("OUT_DIR"), "/version.rs"));
|
||||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ use crate::isa::{RegInfo, RegUnit};
|
|||||||
use core::fmt;
|
use core::fmt;
|
||||||
use cranelift_entity::{SparseMap, SparseMapValue};
|
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.
|
/// 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
|
/// 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
|
/// When tracking diversions, the `from` field is the original assigned value location, and `to` is
|
||||||
/// the current one.
|
/// the current one.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct Diversion {
|
pub struct Diversion {
|
||||||
/// The original value location.
|
/// The original value location.
|
||||||
pub from: ValueLoc,
|
pub from: ValueLoc,
|
||||||
@@ -40,18 +44,21 @@ impl Diversion {
|
|||||||
|
|
||||||
/// Keep track of diversions in a block.
|
/// Keep track of diversions in a block.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct RegDiversions {
|
pub struct RegDiversions {
|
||||||
current: FxHashMap<Value, Diversion>,
|
current: FxHashMap<Value, Diversion>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Keep track of diversions at the entry of block.
|
/// Keep track of diversions at the entry of block.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
struct EntryRegDiversionsValue {
|
struct EntryRegDiversionsValue {
|
||||||
key: Block,
|
key: Block,
|
||||||
divert: RegDiversions,
|
divert: RegDiversions,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Map block to their matching RegDiversions at basic blocks entry.
|
/// Map block to their matching RegDiversions at basic blocks entry.
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct EntryRegDiversions {
|
pub struct EntryRegDiversions {
|
||||||
map: SparseMap<Block, EntryRegDiversionsValue>,
|
map: SparseMap<Block, EntryRegDiversionsValue>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ use alloc::vec::Vec;
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::mem;
|
use core::mem;
|
||||||
|
|
||||||
|
#[cfg(feature = "enable-serde")]
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// A small list of entity references allocated from a pool.
|
/// A small list of entity references allocated from a pool.
|
||||||
///
|
///
|
||||||
/// An `EntityList<T>` type provides similar functionality to `Vec<T>`, but with some important
|
/// An `EntityList<T>` type provides similar functionality to `Vec<T>`, 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
|
/// 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.
|
/// 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<T: EntityRef + ReservedValue> {
|
pub struct EntityList<T: EntityRef + ReservedValue> {
|
||||||
index: u32,
|
index: u32,
|
||||||
unused: PhantomData<T>,
|
unused: PhantomData<T>,
|
||||||
@@ -77,6 +81,7 @@ impl<T: EntityRef + ReservedValue> Default for EntityList<T> {
|
|||||||
|
|
||||||
/// A memory pool for storing lists of `T`.
|
/// A memory pool for storing lists of `T`.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct ListPool<T: EntityRef + ReservedValue> {
|
pub struct ListPool<T: EntityRef + ReservedValue> {
|
||||||
// The main array containing the lists.
|
// The main array containing the lists.
|
||||||
data: Vec<T>,
|
data: Vec<T>,
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::mem;
|
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.
|
/// Types that have a reserved value which can't be created any other way.
|
||||||
pub trait ReservedValue {
|
pub trait ReservedValue {
|
||||||
/// Create an instance of the reserved value.
|
/// Create an instance of the reserved value.
|
||||||
@@ -20,6 +23,7 @@ pub trait ReservedValue {
|
|||||||
|
|
||||||
/// Packed representation of `Option<T>`.
|
/// Packed representation of `Option<T>`.
|
||||||
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct PackedOption<T: ReservedValue>(T);
|
pub struct PackedOption<T: ReservedValue>(T);
|
||||||
|
|
||||||
impl<T: ReservedValue> PackedOption<T> {
|
impl<T: ReservedValue> PackedOption<T> {
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ use core::mem;
|
|||||||
use core::slice;
|
use core::slice;
|
||||||
use core::u32;
|
use core::u32;
|
||||||
|
|
||||||
|
#[cfg(feature = "enable-serde")]
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Trait for extracting keys from values stored in a `SparseMap`.
|
/// 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
|
/// 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<K> {
|
|||||||
/// is).
|
/// is).
|
||||||
/// - `SparseMap` requires the values to implement `SparseMapValue<K>` which means that they must
|
/// - `SparseMap` requires the values to implement `SparseMapValue<K>` which means that they must
|
||||||
/// contain their own key.
|
/// contain their own key.
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct SparseMap<K, V>
|
pub struct SparseMap<K, V>
|
||||||
where
|
where
|
||||||
K: EntityRef,
|
K: EntityRef,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ clap = "2.32.0"
|
|||||||
serde = "1.0.8"
|
serde = "1.0.8"
|
||||||
serde_derive = "1.0.75"
|
serde_derive = "1.0.75"
|
||||||
serde_json = "1.0.26"
|
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" }
|
cranelift-reader = { path = "../reader", version = "0.70.0" }
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
|
|||||||
@@ -22,23 +22,21 @@
|
|||||||
)]
|
)]
|
||||||
|
|
||||||
use clap::{App, Arg, SubCommand};
|
use clap::{App, Arg, SubCommand};
|
||||||
|
use cranelift_codegen::ir::Function;
|
||||||
use cranelift_reader::parse_functions;
|
use cranelift_reader::parse_functions;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
mod serde_clif_json;
|
|
||||||
|
|
||||||
fn call_ser(file: &str, pretty: bool) -> Result<(), String> {
|
fn call_ser(file: &str, pretty: bool) -> Result<(), String> {
|
||||||
let ret_of_parse = parse_functions(file);
|
let ret_of_parse = parse_functions(file);
|
||||||
match ret_of_parse {
|
match ret_of_parse {
|
||||||
Ok(funcs) => {
|
Ok(funcs) => {
|
||||||
let ser_funcs = serde_clif_json::SerObj::new(&funcs);
|
|
||||||
let ser_str = if pretty {
|
let ser_str = if pretty {
|
||||||
serde_json::to_string_pretty(&ser_funcs).unwrap()
|
serde_json::to_string_pretty(&funcs).unwrap()
|
||||||
} else {
|
} else {
|
||||||
serde_json::to_string(&ser_funcs).unwrap()
|
serde_json::to_string(&funcs).unwrap()
|
||||||
};
|
};
|
||||||
println!("{}", ser_str);
|
println!("{}", ser_str);
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -48,7 +46,7 @@ fn call_ser(file: &str, pretty: bool) -> Result<(), String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn call_de(file: &File) -> Result<(), String> {
|
fn call_de(file: &File) -> Result<(), String> {
|
||||||
let de: serde_clif_json::SerObj = match serde_json::from_reader(file) {
|
let de: Vec<Function> = match serde_json::from_reader(file) {
|
||||||
Result::Ok(val) => val,
|
Result::Ok(val) => val,
|
||||||
Result::Err(err) => panic!("{}", err),
|
Result::Err(err) => panic!("{}", err),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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<String>,
|
|
||||||
},
|
|
||||||
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<String>,
|
|
||||||
destination: String,
|
|
||||||
},
|
|
||||||
Branch {
|
|
||||||
opcode: String,
|
|
||||||
args: Vec<String>,
|
|
||||||
destination: String,
|
|
||||||
},
|
|
||||||
BranchInt {
|
|
||||||
opcode: String,
|
|
||||||
args: Vec<String>,
|
|
||||||
cond: String,
|
|
||||||
destination: String,
|
|
||||||
},
|
|
||||||
BranchFloat {
|
|
||||||
opcode: String,
|
|
||||||
args: Vec<String>,
|
|
||||||
cond: String,
|
|
||||||
destination: String,
|
|
||||||
},
|
|
||||||
BranchIcmp {
|
|
||||||
opcode: String,
|
|
||||||
args: Vec<String>,
|
|
||||||
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<String>,
|
|
||||||
func_ref: String,
|
|
||||||
},
|
|
||||||
CallIndirect {
|
|
||||||
opcode: String,
|
|
||||||
args: Vec<String>,
|
|
||||||
sig_ref: String,
|
|
||||||
},
|
|
||||||
FuncAddr {
|
|
||||||
opcode: String,
|
|
||||||
func_ref: String,
|
|
||||||
},
|
|
||||||
Load {
|
|
||||||
opcode: String,
|
|
||||||
arg: String,
|
|
||||||
flags: String,
|
|
||||||
offset: String,
|
|
||||||
},
|
|
||||||
LoadComplex {
|
|
||||||
opcode: String,
|
|
||||||
args: Vec<String>,
|
|
||||||
flags: String,
|
|
||||||
offset: String,
|
|
||||||
},
|
|
||||||
Store {
|
|
||||||
opcode: String,
|
|
||||||
args: [String; 2],
|
|
||||||
flags: String,
|
|
||||||
offset: String,
|
|
||||||
},
|
|
||||||
StoreComplex {
|
|
||||||
opcode: String,
|
|
||||||
args: Vec<String>,
|
|
||||||
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<String>,
|
|
||||||
pub insts: Vec<SerInst>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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<SerInst> {
|
|
||||||
let mut ser_vec: Vec<SerInst> = 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<String> {
|
|
||||||
let mut ser_vec: Vec<String> = 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<SerBlock>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Serialize all parts of the Cranelift Block data structure, this includes name, parameters, and
|
|
||||||
/// instructions.
|
|
||||||
pub fn populate_blocks(func: &Function) -> Vec<SerBlock> {
|
|
||||||
let mut block_vec: Vec<SerBlock> = 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<String>,
|
|
||||||
pub func_returns: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SerSignature {
|
|
||||||
/// Creating serializable signature data structure from all Cranelift IR functions.
|
|
||||||
fn create_new(sig: &Signature) -> Self {
|
|
||||||
let mut params_vec: Vec<String> = Vec::new();
|
|
||||||
let mut returns_vec: Vec<String> = 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<String>,
|
|
||||||
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<String> = 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<SerFunction>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SerObj {
|
|
||||||
fn create_new(funcs: Vec<SerFunction>) -> Self {
|
|
||||||
Self { functions: funcs }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new(funcs: &[Function]) -> Self {
|
|
||||||
let mut func_vec: Vec<SerFunction> = Vec::new();
|
|
||||||
for func in funcs {
|
|
||||||
let ser_func: SerFunction = SerFunction::new(&func);
|
|
||||||
func_vec.push(ser_func);
|
|
||||||
}
|
|
||||||
Self::create_new(func_vec)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user