peepmatic: Make the results of match operations a smaller and more cache friendly

This commit is contained in:
Nick Fitzgerald
2020-05-07 12:15:50 -07:00
parent 9a1f8038b7
commit 469104c4d3
14 changed files with 580 additions and 149 deletions

View File

@@ -6,10 +6,10 @@ use peepmatic_runtime::linear;
/// Construct an automaton from a set of linear optimizations.
pub fn automatize(
opts: &linear::Optimizations,
) -> Automaton<Option<u32>, linear::MatchOp, Vec<linear::Action>> {
) -> Automaton<linear::MatchResult, linear::MatchOp, Vec<linear::Action>> {
debug_assert!(crate::linear_passes::is_sorted_lexicographically(opts));
let mut builder = Builder::<Option<u32>, linear::MatchOp, Vec<linear::Action>>::new();
let mut builder = Builder::<linear::MatchResult, linear::MatchOp, Vec<linear::Action>>::new();
for opt in &opts.optimizations {
let mut insertion = builder.insert();

View File

@@ -12,36 +12,37 @@ use peepmatic_runtime::{
};
use std::convert::TryFrom;
use std::io::{self, Write};
use std::num::NonZeroU32;
#[derive(Debug)]
pub(crate) struct PeepholeDotFmt<'a>(pub(crate) &'a PathInterner, pub(crate) &'a IntegerInterner);
impl DotFmt<Option<u32>, linear::MatchOp, Vec<linear::Action>> for PeepholeDotFmt<'_> {
impl DotFmt<linear::MatchResult, linear::MatchOp, Vec<linear::Action>> for PeepholeDotFmt<'_> {
fn fmt_transition(
&self,
w: &mut impl Write,
from: Option<&linear::MatchOp>,
input: &Option<u32>,
input: &linear::MatchResult,
_to: Option<&linear::MatchOp>,
) -> io::Result<()> {
let from = from.expect("we should have match op for every state");
if let Some(x) = input {
if let Some(x) = input.ok().map(|x| x.get()) {
match from {
linear::MatchOp::Opcode { .. } => {
let opcode =
Operator::try_from(*x).expect("we shouldn't generate non-opcode edges");
Operator::try_from(x).expect("we shouldn't generate non-opcode edges");
write!(w, "{}", opcode)
}
linear::MatchOp::ConditionCode { .. } => {
let cc =
ConditionCode::try_from(*x).expect("we shouldn't generate non-CC edges");
ConditionCode::try_from(x).expect("we shouldn't generate non-CC edges");
write!(w, "{}", cc)
}
linear::MatchOp::IntegerValue { .. } => {
let x = self.1.lookup(IntegerId(*x));
let x = self.1.lookup(IntegerId(NonZeroU32::new(x).unwrap()));
write!(w, "{}", x)
}
_ => write!(w, "{}", x),
_ => write!(w, "Ok({})", x),
}
} else {
write!(w, "(else)")

View File

@@ -65,7 +65,12 @@ fn compare_optimizations(
return c;
}
let c = a.expected.cmp(&b.expected).reverse();
let c = match (a.expected, b.expected) {
(Ok(a), Ok(b)) => a.cmp(&b).reverse(),
(Err(_), Ok(_)) => Ordering::Greater,
(Ok(_), Err(_)) => Ordering::Less,
(Err(linear::Else), Err(linear::Else)) => Ordering::Equal,
};
if c != Ordering::Equal {
return c;
}
@@ -228,10 +233,10 @@ pub fn match_in_same_order(opts: &mut linear::Optimizations) {
Some(_) => {
new_increments.push(linear::Increment {
operation: *last_op,
expected: None,
expected: Err(linear::Else),
actions: vec![],
});
if last_expected.is_some() {
if last_expected.is_ok() {
break;
}
}
@@ -282,12 +287,99 @@ pub fn remove_unnecessary_nops(opts: &mut linear::Optimizations) {
mod tests {
use super::*;
use crate::ast::*;
use linear::MatchOp::*;
use peepmatic_runtime::{operator::Operator, paths::*};
use peepmatic_runtime::{
linear::{bool_to_match_result, Else, MatchOp::*, MatchResult},
operator::Operator,
paths::*,
};
use std::num::NonZeroU32;
#[test]
fn ok_non_zero_less_than_err_else() {
assert!(Ok(NonZeroU32::new(1).unwrap()) < Err(Else));
}
macro_rules! sorts_to {
($test_name:ident, $source:expr, $make_expected:expr) => {
#[test]
#[allow(unused_variables)]
fn $test_name() {
let buf = wast::parser::ParseBuffer::new($source).expect("should lex OK");
let opts = match wast::parser::parse::<Optimizations>(&buf) {
Ok(opts) => opts,
Err(mut e) => {
e.set_path(std::path::Path::new(stringify!($test_name)));
e.set_text($source);
eprintln!("{}", e);
panic!("should parse OK")
}
};
if let Err(mut e) = crate::verify(&opts) {
e.set_path(std::path::Path::new(stringify!($test_name)));
e.set_text($source);
eprintln!("{}", e);
panic!("should verify OK")
}
let mut opts = crate::linearize(&opts);
let before = opts
.optimizations
.iter()
.map(|o| {
o.increments
.iter()
.map(|i| format!("{:?} == {:?}", i.operation, i.expected))
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
eprintln!("before = {:#?}", before);
sort_least_to_most_general(&mut opts);
let after = opts
.optimizations
.iter()
.map(|o| {
o.increments
.iter()
.map(|i| format!("{:?} == {:?}", i.operation, i.expected))
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
eprintln!("after = {:#?}", before);
let linear::Optimizations {
mut paths,
mut integers,
optimizations,
} = opts;
let actual: Vec<Vec<_>> = optimizations
.iter()
.map(|o| {
o.increments
.iter()
.map(|i| (i.operation, i.expected))
.collect()
})
.collect();
let mut p = |p: &[u8]| paths.intern(Path::new(&p));
let mut i = |i: u64| Ok(integers.intern(i).into());
let expected = $make_expected(&mut p, &mut i);
assert_eq!(expected, actual);
}
};
}
macro_rules! match_in_same_order {
($test_name:ident, $source:expr, $make_expected:expr) => {
#[test]
#[allow(unused_variables)]
fn $test_name() {
let buf = wast::parser::ParseBuffer::new($source).expect("should lex OK");
@@ -311,6 +403,32 @@ mod tests {
let mut opts = crate::linearize(&opts);
sort_least_to_most_general(&mut opts);
let before = opts
.optimizations
.iter()
.map(|o| {
o.increments
.iter()
.map(|i| format!("{:?} == {:?}", i.operation, i.expected))
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
eprintln!("before = {:#?}", before);
match_in_same_order(&mut opts);
let after = opts
.optimizations
.iter()
.map(|o| {
o.increments
.iter()
.map(|i| format!("{:?} == {:?}", i.operation, i.expected))
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
eprintln!("after = {:#?}", before);
let linear::Optimizations {
mut paths,
mut integers,
@@ -328,7 +446,7 @@ mod tests {
.collect();
let mut p = |p: &[u8]| paths.intern(Path::new(&p));
let mut i = |i: u64| Some(integers.intern(i).into());
let mut i = |i: u64| Ok(integers.intern(i).into());
let expected = $make_expected(&mut p, &mut i);
assert_eq!(expected, actual);
@@ -348,53 +466,83 @@ mod tests {
(=> (iadd $x 42) 0)
(=> (iadd $x (iadd $y $z)) 0)
",
|p: &mut dyn FnMut(&[u8]) -> PathId, i: &mut dyn FnMut(u64) -> Option<u32>| vec![
|p: &mut dyn FnMut(&[u8]) -> PathId, i: &mut dyn FnMut(u64) -> MatchResult| vec![
vec![
(Opcode { path: p(&[0]) }, Some(Operator::Iadd as _)),
(Nop, None),
(Opcode { path: p(&[0, 1]) }, Some(Operator::Iadd as _)),
(Nop, None),
(Nop, None),
(
Opcode { path: p(&[0]) },
Ok(NonZeroU32::new(Operator::Iadd as _).unwrap())
),
(Nop, Err(Else)),
(
Opcode { path: p(&[0, 1]) },
Ok(NonZeroU32::new(Operator::Iadd as _).unwrap())
),
(Nop, Err(Else)),
(Nop, Err(Else)),
],
vec![
(Opcode { path: p(&[0]) }, Some(Operator::Iadd as _)),
(Nop, None),
(
Opcode { path: p(&[0]) },
Ok(NonZeroU32::new(Operator::Iadd as _).unwrap())
),
(Nop, Err(Else)),
(IntegerValue { path: p(&[0, 1]) }, i(42))
],
vec![
(Opcode { path: p(&[0]) }, Some(Operator::Iadd as _)),
(Nop, None),
(IsConst { path: p(&[0, 1]) }, Some(1)),
(IsPowerOfTwo { path: p(&[0, 1]) }, Some(1))
(
Opcode { path: p(&[0]) },
Ok(NonZeroU32::new(Operator::Iadd as _).unwrap())
),
(Nop, Err(Else)),
(IsConst { path: p(&[0, 1]) }, bool_to_match_result(true)),
(
IsPowerOfTwo { path: p(&[0, 1]) },
bool_to_match_result(true)
)
],
vec![
(Opcode { path: p(&[0]) }, Some(Operator::Iadd as _)),
(Nop, None),
(IsConst { path: p(&[0, 1]) }, Some(1)),
(BitWidth { path: p(&[0, 0]) }, Some(32))
(
Opcode { path: p(&[0]) },
Ok(NonZeroU32::new(Operator::Iadd as _).unwrap())
),
(Nop, Err(Else)),
(IsConst { path: p(&[0, 1]) }, bool_to_match_result(true)),
(
BitWidth { path: p(&[0, 0]) },
Ok(NonZeroU32::new(32).unwrap())
)
],
vec![
(Opcode { path: p(&[0]) }, Some(Operator::Iadd as _)),
(Nop, None),
(IsConst { path: p(&[0, 1]) }, Some(1))
(
Opcode { path: p(&[0]) },
Ok(NonZeroU32::new(Operator::Iadd as _).unwrap())
),
(Nop, Err(Else)),
(IsConst { path: p(&[0, 1]) }, bool_to_match_result(true))
],
vec![
(Opcode { path: p(&[0]) }, Some(Operator::Iadd as _)),
(Nop, None),
(
Opcode { path: p(&[0]) },
Ok(NonZeroU32::new(Operator::Iadd as _).unwrap())
),
(Nop, Err(Else)),
(
Eq {
path_a: p(&[0, 1]),
path_b: p(&[0, 0]),
},
Some(1)
bool_to_match_result(true)
)
],
vec![
(Opcode { path: p(&[0]) }, Some(Operator::Iadd as _)),
(Nop, None),
(Nop, None),
(
Opcode { path: p(&[0]) },
Ok(NonZeroU32::new(Operator::Iadd as _).unwrap())
),
(Nop, Err(Else)),
(Nop, Err(Else)),
],
vec![(Nop, None)]
vec![(Nop, Err(Else))]
]
);
@@ -408,37 +556,164 @@ mod tests {
(=> (imul 2 $x) (ishl $x 1))
(=> (imul $x 2) (ishl $x 1))
",
|p: &mut dyn FnMut(&[u8]) -> PathId, i: &mut dyn FnMut(u64) -> Option<u32>| vec![
|p: &mut dyn FnMut(&[u8]) -> PathId, i: &mut dyn FnMut(u64) -> MatchResult| vec![
vec![
(Opcode { path: p(&[0]) }, Some(Operator::Imul as _)),
(
Opcode { path: p(&[0]) },
Ok(NonZeroU32::new(Operator::Imul as _).unwrap())
),
(IntegerValue { path: p(&[0, 0]) }, i(2)),
(Nop, None)
(Nop, Err(Else))
],
vec![
(Opcode { path: p(&[0]) }, Some(Operator::Imul as _)),
(
Opcode { path: p(&[0]) },
Ok(NonZeroU32::new(Operator::Imul as _).unwrap())
),
(IntegerValue { path: p(&[0, 0]) }, i(1)),
(Nop, None)
(Nop, Err(Else))
],
vec![
(Opcode { path: p(&[0]) }, Some(Operator::Imul as _)),
(Nop, None),
(
Opcode { path: p(&[0]) },
Ok(NonZeroU32::new(Operator::Imul as _).unwrap())
),
(Nop, Err(Else)),
(IntegerValue { path: p(&[0, 1]) }, i(2))
],
vec![
(Opcode { path: p(&[0]) }, Some(Operator::Imul as _)),
(Nop, None),
(
Opcode { path: p(&[0]) },
Ok(NonZeroU32::new(Operator::Imul as _).unwrap())
),
(Nop, Err(Else)),
(IntegerValue { path: p(&[0, 1]) }, i(1))
],
vec![
(Opcode { path: p(&[0]) }, Some(Operator::Iadd as _)),
(
Opcode { path: p(&[0]) },
Ok(NonZeroU32::new(Operator::Iadd as _).unwrap())
),
(IntegerValue { path: p(&[0, 0]) }, i(0)),
(Nop, None)
(Nop, Err(Else))
],
vec![
(Opcode { path: p(&[0]) }, Some(Operator::Iadd as _)),
(Nop, None),
(
Opcode { path: p(&[0]) },
Ok(NonZeroU32::new(Operator::Iadd as _).unwrap())
),
(Nop, Err(Else)),
(IntegerValue { path: p(&[0, 1]) }, i(0))
]
]
);
sorts_to!(
sort_redundant_bor,
"
(=> (bor (bor $x $y) $x)
(bor $x $y))
(=> (bor (bor $x $y) $y)
(bor $x $y))
",
|p: &mut dyn FnMut(&[u8]) -> PathId, i: &mut dyn FnMut(u64) -> MatchResult| vec![
vec![
(
Opcode { path: p(&[0]) },
Ok(NonZeroU32::new(Operator::Bor as _).unwrap())
),
(
Opcode { path: p(&[0, 0]) },
Ok(NonZeroU32::new(Operator::Bor as _).unwrap())
),
(Nop, Err(Else)),
(Nop, Err(Else)),
(
Eq {
path_a: p(&[0, 1]),
path_b: p(&[0, 0, 0]),
},
bool_to_match_result(true)
),
],
vec![
(
Opcode { path: p(&[0]) },
Ok(NonZeroU32::new(Operator::Bor as _).unwrap())
),
(
Opcode { path: p(&[0, 0]) },
Ok(NonZeroU32::new(Operator::Bor as _).unwrap())
),
(Nop, Err(Else)),
(Nop, Err(Else)),
(
Eq {
path_a: p(&[0, 1]),
path_b: p(&[0, 0, 1]),
},
bool_to_match_result(true)
),
],
]
);
match_in_same_order!(
match_in_same_order_redundant_bor,
"
(=> (bor (bor $x $y) $x)
(bor $x $y))
(=> (bor (bor $x $y) $y)
(bor $x $y))
",
|p: &mut dyn FnMut(&[u8]) -> PathId, i: &mut dyn FnMut(u64) -> MatchResult| vec![
vec![
(
Opcode { path: p(&[0]) },
Ok(NonZeroU32::new(Operator::Bor as _).unwrap())
),
(
Opcode { path: p(&[0, 0]) },
Ok(NonZeroU32::new(Operator::Bor as _).unwrap())
),
(Nop, Err(Else)),
(Nop, Err(Else)),
(
Eq {
path_a: p(&[0, 1]),
path_b: p(&[0, 0, 0]),
},
bool_to_match_result(true)
),
],
vec![
(
Opcode { path: p(&[0]) },
Ok(NonZeroU32::new(Operator::Bor as _).unwrap())
),
(
Opcode { path: p(&[0, 0]) },
Ok(NonZeroU32::new(Operator::Bor as _).unwrap())
),
(Nop, Err(Else)),
(Nop, Err(Else)),
(
Eq {
path_a: p(&[0, 1]),
path_b: p(&[0, 0, 0]),
},
Err(Else),
),
(
Eq {
path_a: p(&[0, 1]),
path_b: p(&[0, 0, 1]),
},
bool_to_match_result(true)
),
],
]
);
}

View File

@@ -92,6 +92,7 @@ use peepmatic_runtime::{
paths::{Path, PathId, PathInterner},
};
use std::collections::BTreeMap;
use std::num::NonZeroU32;
use wast::Id;
/// Translate the given AST optimizations into linear optimizations.
@@ -142,9 +143,12 @@ fn linearize_optimization(
// increment that checks the instruction-being-matched's bit width.
if let Pattern::Operation(Operation { r#type, .. }) = pattern {
if let Some(w) = r#type.get().and_then(|ty| ty.bit_width.fixed_width()) {
debug_assert!(w != 0, "All fixed-width bit widths are non-zero");
let expected = Ok(unsafe { NonZeroU32::new_unchecked(w as u32) });
increments.push(linear::Increment {
operation: linear::MatchOp::BitWidth { path },
expected: Some(w as u32),
expected,
actions: vec![],
});
}
@@ -432,7 +436,7 @@ impl Precondition<'_> {
let path = lhs_id_to_path.unwrap_first_occurrence(&id);
linear::Increment {
operation: linear::MatchOp::IsPowerOfTwo { path },
expected: Some(1),
expected: linear::bool_to_match_result(true),
actions: vec![],
}
}
@@ -451,12 +455,14 @@ impl Precondition<'_> {
})) => *value,
_ => unreachable!("checked in verification"),
};
debug_assert!(width <= 128);
debug_assert!((width as u8).is_power_of_two());
assert!(0 < width && width <= 128);
assert!((width as u8).is_power_of_two());
let expected = Ok(unsafe { NonZeroU32::new_unchecked(width as u32) });
linear::Increment {
operation: linear::MatchOp::BitWidth { path },
expected: Some(width as u32),
expected,
actions: vec![],
}
}
@@ -469,7 +475,7 @@ impl Precondition<'_> {
let path = lhs_id_to_path.unwrap_first_occurrence(&id);
linear::Increment {
operation: linear::MatchOp::FitsInNativeWord { path },
expected: Some(1),
expected: linear::bool_to_match_result(true),
actions: vec![],
}
}
@@ -488,17 +494,21 @@ impl Pattern<'_> {
integers: &mut IntegerInterner,
lhs_id_to_path: &LhsIdToPath,
path: PathId,
) -> (linear::MatchOp, Option<u32>) {
) -> (linear::MatchOp, linear::MatchResult) {
match self {
Pattern::ValueLiteral(ValueLiteral::Integer(Integer { value, .. })) => (
linear::MatchOp::IntegerValue { path },
Some(integers.intern(*value as u64).into()),
Ok(integers.intern(*value as u64).into()),
),
Pattern::ValueLiteral(ValueLiteral::Boolean(Boolean { value, .. })) => (
linear::MatchOp::BooleanValue { path },
linear::bool_to_match_result(*value),
),
Pattern::ValueLiteral(ValueLiteral::Boolean(Boolean { value, .. })) => {
(linear::MatchOp::BooleanValue { path }, Some(*value as u32))
}
Pattern::ValueLiteral(ValueLiteral::ConditionCode(ConditionCode { cc, .. })) => {
(linear::MatchOp::ConditionCode { path }, Some(*cc as u32))
let cc = *cc as u32;
debug_assert!(cc != 0, "no `ConditionCode` variants are zero");
let expected = Ok(unsafe { NonZeroU32::new_unchecked(cc) });
(linear::MatchOp::ConditionCode { path }, expected)
}
Pattern::Constant(Constant { id, .. }) => {
if let Some(path_b) = lhs_id_to_path.get_first_occurrence(id) {
@@ -508,10 +518,13 @@ impl Pattern<'_> {
path_a: path,
path_b,
},
Some(1),
linear::bool_to_match_result(true),
)
} else {
(linear::MatchOp::IsConst { path }, Some(1))
(
linear::MatchOp::IsConst { path },
linear::bool_to_match_result(true),
)
}
}
Pattern::Variable(Variable { id, .. }) => {
@@ -522,13 +535,18 @@ impl Pattern<'_> {
path_a: path,
path_b,
},
Some(1),
linear::bool_to_match_result(true),
)
} else {
(linear::MatchOp::Nop, None)
(linear::MatchOp::Nop, Err(linear::Else))
}
}
Pattern::Operation(op) => (linear::MatchOp::Opcode { path }, Some(op.operator as u32)),
Pattern::Operation(op) => {
let op = op.operator as u32;
debug_assert!(op != 0, "no `Operator` variants are zero");
let expected = Ok(unsafe { NonZeroU32::new_unchecked(op) });
(linear::MatchOp::Opcode { path }, expected)
}
}
}
}
@@ -538,7 +556,7 @@ mod tests {
use super::*;
use peepmatic_runtime::{
integer_interner::IntegerId,
linear::{Action::*, MatchOp::*},
linear::{bool_to_match_result, Action::*, Else, MatchOp::*},
operator::Operator,
r#type::{BitWidth, Kind, Type},
};
@@ -603,7 +621,7 @@ mod tests {
increments: vec![
linear::Increment {
operation: Opcode { path: p(&[0]) },
expected: Some(Operator::Imul as _),
expected: Ok(NonZeroU32::new(Operator::Imul as _).unwrap()),
actions: vec![
GetLhs { path: p(&[0, 0]) },
GetLhs { path: p(&[0, 1]) },
@@ -619,17 +637,17 @@ mod tests {
},
linear::Increment {
operation: Nop,
expected: None,
expected: Err(Else),
actions: vec![],
},
linear::Increment {
operation: IsConst { path: p(&[0, 1]) },
expected: Some(1),
expected: bool_to_match_result(true),
actions: vec![],
},
linear::Increment {
operation: IsPowerOfTwo { path: p(&[0, 1]) },
expected: Some(1),
expected: bool_to_match_result(true),
actions: vec![],
},
],
@@ -644,7 +662,7 @@ mod tests {
linear::Optimization {
increments: vec![linear::Increment {
operation: Nop,
expected: None,
expected: Err(Else),
actions: vec![GetLhs { path: p(&[0]) }],
}],
}
@@ -658,7 +676,7 @@ mod tests {
linear::Optimization {
increments: vec![linear::Increment {
operation: IsConst { path: p(&[0]) },
expected: Some(1),
expected: bool_to_match_result(true),
actions: vec![GetLhs { path: p(&[0]) }],
}],
}
@@ -672,7 +690,7 @@ mod tests {
linear::Optimization {
increments: vec![linear::Increment {
operation: BooleanValue { path: p(&[0]) },
expected: Some(1),
expected: bool_to_match_result(true),
actions: vec![MakeBooleanConst {
value: true,
bit_width: BitWidth::Polymorphic,
@@ -689,7 +707,7 @@ mod tests {
linear::Optimization {
increments: vec![linear::Increment {
operation: IntegerValue { path: p(&[0]) },
expected: Some(i(5).into()),
expected: Ok(i(5).into()),
actions: vec![MakeIntegerConst {
value: i(5),
bit_width: BitWidth::Polymorphic,
@@ -707,7 +725,7 @@ mod tests {
increments: vec![
linear::Increment {
operation: Opcode { path: p(&[0]) },
expected: Some(Operator::Iconst as _),
expected: Ok(NonZeroU32::new(Operator::Iconst as _).unwrap()),
actions: vec![
GetLhs { path: p(&[0, 0]) },
MakeUnaryInst {
@@ -722,7 +740,7 @@ mod tests {
},
linear::Increment {
operation: IsConst { path: p(&[0, 0]) },
expected: Some(1),
expected: bool_to_match_result(true),
actions: vec![],
},
],
@@ -738,7 +756,7 @@ mod tests {
increments: vec![
linear::Increment {
operation: Opcode { path: p(&[0]) },
expected: Some(Operator::Bor as _),
expected: Ok(NonZeroU32::new(Operator::Bor as _).unwrap()),
actions: vec![
GetLhs { path: p(&[0, 0]) },
GetLhs {
@@ -756,12 +774,12 @@ mod tests {
},
linear::Increment {
operation: Nop,
expected: None,
expected: Err(Else),
actions: vec![],
},
linear::Increment {
operation: Opcode { path: p(&[0, 1]) },
expected: Some(Operator::Bor as _),
expected: Ok(NonZeroU32::new(Operator::Bor as _).unwrap()),
actions: vec![],
},
linear::Increment {
@@ -769,12 +787,12 @@ mod tests {
path_a: p(&[0, 1, 0]),
path_b: p(&[0, 0]),
},
expected: Some(1),
expected: bool_to_match_result(true),
actions: vec![],
},
linear::Increment {
operation: Nop,
expected: None,
expected: Err(Else),
actions: vec![],
},
],
@@ -790,7 +808,7 @@ mod tests {
linear::Optimization {
increments: vec![linear::Increment {
operation: IntegerValue { path: p(&[0]) },
expected: Some(i(std::u64::MAX).into()),
expected: Ok(i(std::u64::MAX).into()),
actions: vec![MakeIntegerConst {
value: i(0),
bit_width: BitWidth::Polymorphic,
@@ -808,7 +826,7 @@ mod tests {
increments: vec![
linear::Increment {
operation: Opcode { path: p(&[0]) },
expected: Some(Operator::Ireduce as _),
expected: Ok(NonZeroU32::new(Operator::Ireduce as _).unwrap()),
actions: vec![MakeIntegerConst {
value: i(0),
bit_width: BitWidth::ThirtyTwo,
@@ -816,12 +834,12 @@ mod tests {
},
linear::Increment {
operation: linear::MatchOp::BitWidth { path: p(&[0]) },
expected: Some(32),
expected: Ok(NonZeroU32::new(32).unwrap()),
actions: vec![],
},
linear::Increment {
operation: Nop,
expected: None,
expected: Err(Else),
actions: vec![],
},
],