Start a very simple GVN pass (#79)
* Skeleton simple_gvn pass. * Basic testing infrastructure for simple-gvn. * Add can_load and can_store flags to instructions. * Move the replace_values function into the DataFlowGraph. * Make InstructionData derive from Hash, PartialEq, and Eq. * Make EntityList's hash and eq functions panic. * Change Ieee32 and Ieee64 to store u32 and u64, respectively.
This commit is contained in:
committed by
Jakob Stoklund Olesen
parent
0c7b2c7b68
commit
dc809628f4
@@ -27,7 +27,7 @@ pub trait CondCode: Copy {
|
||||
/// This condition code is used by the `icmp` instruction to compare integer values. There are
|
||||
/// separate codes for comparing the integers as signed or unsigned numbers where it makes a
|
||||
/// difference.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum IntCC {
|
||||
/// `==`.
|
||||
Equal,
|
||||
@@ -139,7 +139,7 @@ impl FromStr for IntCC {
|
||||
/// The condition codes described here are used to produce a single boolean value from the
|
||||
/// 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)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum FloatCC {
|
||||
/// EQ | LT | GT
|
||||
Ordered,
|
||||
|
||||
@@ -243,6 +243,46 @@ impl DataFlowGraph {
|
||||
self.values[dest] = ValueData::Alias { ty, original };
|
||||
}
|
||||
|
||||
/// Replace the results of one instruction with aliases to the results of another.
|
||||
///
|
||||
/// Change all the results of `dest_inst` to behave as aliases of
|
||||
/// corresponding results of `src_inst`, as if calling change_to_alias for
|
||||
/// each.
|
||||
///
|
||||
/// After calling this instruction, `dest_inst` will have had its results
|
||||
/// cleared, so it likely needs to be removed from the graph.
|
||||
///
|
||||
pub fn replace_with_aliases(&mut self, dest_inst: Inst, src_inst: Inst) {
|
||||
debug_assert_ne!(dest_inst,
|
||||
src_inst,
|
||||
"Replacing {} with itself would create a loop",
|
||||
dest_inst);
|
||||
debug_assert_eq!(self.results[dest_inst].len(&self.value_lists),
|
||||
self.results[src_inst].len(&self.value_lists),
|
||||
"Replacing {} with {} would produce a different number of results.",
|
||||
dest_inst,
|
||||
src_inst);
|
||||
|
||||
for (&dest, &src) in self.results[dest_inst]
|
||||
.as_slice(&self.value_lists)
|
||||
.iter()
|
||||
.zip(self.results[src_inst].as_slice(&self.value_lists)) {
|
||||
let original = src;
|
||||
let ty = self.value_type(original);
|
||||
assert_eq!(self.value_type(dest),
|
||||
ty,
|
||||
"Aliasing {} to {} would change its type {} to {}",
|
||||
dest,
|
||||
src,
|
||||
self.value_type(dest),
|
||||
ty);
|
||||
|
||||
self.values[dest] = ValueData::Alias { ty, original };
|
||||
}
|
||||
|
||||
self.clear_results(dest_inst);
|
||||
}
|
||||
|
||||
/// Create a new value alias.
|
||||
///
|
||||
/// Note that this function should only be called by the parser.
|
||||
|
||||
@@ -14,7 +14,7 @@ use std::str::FromStr;
|
||||
///
|
||||
/// 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)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct Imm64(i64);
|
||||
|
||||
impl Imm64 {
|
||||
@@ -153,7 +153,7 @@ pub type Uimm8 = u8;
|
||||
///
|
||||
/// 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)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct Offset32(i32);
|
||||
|
||||
impl Offset32 {
|
||||
@@ -220,7 +220,7 @@ impl FromStr for Offset32 {
|
||||
/// 32-bit unsigned immediate offset.
|
||||
///
|
||||
/// This is used to encode an immediate offset for WebAssembly heap_load/heap_store instructions.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct Uoffset32(u32);
|
||||
|
||||
impl Uoffset32 {
|
||||
@@ -282,17 +282,19 @@ impl FromStr for Uoffset32 {
|
||||
}
|
||||
}
|
||||
|
||||
/// An IEEE binary32 immediate floating point value.
|
||||
/// An IEEE binary32 immediate floating point value, represented as a u32
|
||||
/// containing the bitpattern.
|
||||
///
|
||||
/// All bit patterns are allowed.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Ieee32(f32);
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct Ieee32(u32);
|
||||
|
||||
/// An IEEE binary64 immediate floating point value.
|
||||
/// An IEEE binary64 immediate floating point value, represented as a u64
|
||||
/// containing the bitpattern.
|
||||
///
|
||||
/// All bit patterns are allowed.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Ieee64(f64);
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct Ieee64(u64);
|
||||
|
||||
// Format a floating point number in a way that is reasonably human-readable, and that can be
|
||||
// converted back to binary without any rounding issues. The hexadecimal formatting of normal and
|
||||
@@ -531,18 +533,13 @@ fn parse_float(s: &str, w: u8, t: u8) -> Result<u64, &'static str> {
|
||||
impl Ieee32 {
|
||||
/// Create a new `Ieee32` representing the number `x`.
|
||||
pub fn new(x: f32) -> Ieee32 {
|
||||
Ieee32(x)
|
||||
}
|
||||
|
||||
/// Construct `Ieee32` immediate from raw bits.
|
||||
pub fn from_bits(x: u32) -> Ieee32 {
|
||||
Ieee32(unsafe { mem::transmute(x) })
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Ieee32 {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
let bits: u32 = unsafe { mem::transmute(self.0) };
|
||||
let bits: u32 = self.0;
|
||||
format_float(bits as u64, 8, 23, f)
|
||||
}
|
||||
}
|
||||
@@ -552,7 +549,7 @@ impl FromStr for Ieee32 {
|
||||
|
||||
fn from_str(s: &str) -> Result<Ieee32, &'static str> {
|
||||
match parse_float(s, 8, 23) {
|
||||
Ok(b) => Ok(Ieee32::from_bits(b as u32)),
|
||||
Ok(b) => Ok(Ieee32(b as u32)),
|
||||
Err(s) => Err(s),
|
||||
}
|
||||
}
|
||||
@@ -561,18 +558,13 @@ impl FromStr for Ieee32 {
|
||||
impl Ieee64 {
|
||||
/// Create a new `Ieee64` representing the number `x`.
|
||||
pub fn new(x: f64) -> Ieee64 {
|
||||
Ieee64(x)
|
||||
}
|
||||
|
||||
/// Construct `Ieee64` immediate from raw bits.
|
||||
pub fn from_bits(x: u64) -> Ieee64 {
|
||||
Ieee64(unsafe { mem::transmute(x) })
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Ieee64 {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
let bits: u64 = unsafe { mem::transmute(self.0) };
|
||||
let bits: u64 = self.0;
|
||||
format_float(bits, 11, 52, f)
|
||||
}
|
||||
}
|
||||
@@ -582,7 +574,7 @@ impl FromStr for Ieee64 {
|
||||
|
||||
fn from_str(s: &str) -> Result<Ieee64, &'static str> {
|
||||
match parse_float(s, 11, 52) {
|
||||
Ok(b) => Ok(Ieee64::from_bits(b)),
|
||||
Ok(b) => Ok(Ieee64(b)),
|
||||
Err(s) => Err(s),
|
||||
}
|
||||
}
|
||||
@@ -743,11 +735,11 @@ mod tests {
|
||||
assert_eq!(Ieee32::new(f32::NAN).to_string(), "+NaN");
|
||||
assert_eq!(Ieee32::new(-f32::NAN).to_string(), "-NaN");
|
||||
// Construct some qNaNs with payloads.
|
||||
assert_eq!(Ieee32::from_bits(0x7fc00001).to_string(), "+NaN:0x1");
|
||||
assert_eq!(Ieee32::from_bits(0x7ff00001).to_string(), "+NaN:0x300001");
|
||||
assert_eq!(Ieee32(0x7fc00001).to_string(), "+NaN:0x1");
|
||||
assert_eq!(Ieee32(0x7ff00001).to_string(), "+NaN:0x300001");
|
||||
// Signaling NaNs.
|
||||
assert_eq!(Ieee32::from_bits(0x7f800001).to_string(), "+sNaN:0x1");
|
||||
assert_eq!(Ieee32::from_bits(0x7fa00001).to_string(), "+sNaN:0x200001");
|
||||
assert_eq!(Ieee32(0x7f800001).to_string(), "+sNaN:0x1");
|
||||
assert_eq!(Ieee32(0x7fa00001).to_string(), "+sNaN:0x200001");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -845,14 +837,12 @@ mod tests {
|
||||
assert_eq!(Ieee64::new(f64::NAN).to_string(), "+NaN");
|
||||
assert_eq!(Ieee64::new(-f64::NAN).to_string(), "-NaN");
|
||||
// Construct some qNaNs with payloads.
|
||||
assert_eq!(Ieee64::from_bits(0x7ff8000000000001).to_string(),
|
||||
"+NaN:0x1");
|
||||
assert_eq!(Ieee64::from_bits(0x7ffc000000000001).to_string(),
|
||||
assert_eq!(Ieee64(0x7ff8000000000001).to_string(), "+NaN:0x1");
|
||||
assert_eq!(Ieee64(0x7ffc000000000001).to_string(),
|
||||
"+NaN:0x4000000000001");
|
||||
// Signaling NaNs.
|
||||
assert_eq!(Ieee64::from_bits(0x7ff0000000000001).to_string(),
|
||||
"+sNaN:0x1");
|
||||
assert_eq!(Ieee64::from_bits(0x7ff4000000000001).to_string(),
|
||||
assert_eq!(Ieee64(0x7ff0000000000001).to_string(), "+sNaN:0x1");
|
||||
assert_eq!(Ieee64(0x7ff4000000000001).to_string(),
|
||||
"+sNaN:0x4000000000001");
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ impl FromStr for Opcode {
|
||||
/// value should have its `ty` field set to `VOID`. The size of `InstructionData` should be kept at
|
||||
/// 16 bytes on 64-bit architectures. If more space is needed to represent an instruction, use a
|
||||
/// `Box<AuxData>` to store the additional information out of line.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum InstructionData {
|
||||
Nullary { opcode: Opcode },
|
||||
|
||||
@@ -14,7 +14,7 @@ const NAMES: [&str; 2] = ["notrap", "aligned"];
|
||||
/// Each of these flags introduce a limited form of undefined behavior. The flags each enable
|
||||
/// certain optimizations that need to make additional assumptions. Generally, the semantics of a
|
||||
/// program does not change when a flag is removed, but adding a flag will.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
||||
pub struct MemFlags {
|
||||
bits: u8,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user