diff --git a/hercules_ir/src/ir.rs b/hercules_ir/src/ir.rs index bf9698b32125832b047ee9a94668bd0a09b93ac9..f91efe584c7422e2d7e1e542fed7141fcf684f53 100644 --- a/hercules_ir/src/ir.rs +++ b/hercules_ir/src/ir.rs @@ -1050,6 +1050,38 @@ impl Constant { _ => false, } } + + pub fn is_largest(&self) -> bool { + match self { + Constant::Integer8(i8::MAX) => true, + Constant::Integer16(i16::MAX) => true, + Constant::Integer32(i32::MAX) => true, + Constant::Integer64(i64::MAX) => true, + Constant::UnsignedInteger8(u8::MAX) => true, + Constant::UnsignedInteger16(u16::MAX) => true, + Constant::UnsignedInteger32(u32::MAX) => true, + Constant::UnsignedInteger64(u64::MAX) => true, + Constant::Float32(ord) => *ord == OrderedFloat::<f32>(f32::INFINITY), + Constant::Float64(ord) => *ord == OrderedFloat::<f64>(f64::INFINITY), + _ => false, + } + } + + pub fn is_smallest(&self) -> bool { + match self { + Constant::Integer8(i8::MIN) => true, + Constant::Integer16(i16::MIN) => true, + Constant::Integer32(i32::MIN) => true, + Constant::Integer64(i64::MIN) => true, + Constant::UnsignedInteger8(u8::MIN) => true, + Constant::UnsignedInteger16(u16::MIN) => true, + Constant::UnsignedInteger32(u32::MIN) => true, + Constant::UnsignedInteger64(u64::MIN) => true, + Constant::Float32(ord) => *ord == OrderedFloat::<f32>(f32::NEG_INFINITY), + Constant::Float64(ord) => *ord == OrderedFloat::<f64>(f64::NEG_INFINITY), + _ => false, + } + } } impl DynamicConstant { @@ -1098,19 +1130,19 @@ impl DynamicConstant { } pub fn is_zero(&self) -> bool { - if *self == DynamicConstant::Constant(0) { - true - } else { - false - } + *self == DynamicConstant::Constant(0) } pub fn is_one(&self) -> bool { - if *self == DynamicConstant::Constant(1) { - true - } else { - false - } + *self == DynamicConstant::Constant(1) + } + + pub fn is_largest(&self) -> bool { + *self == DynamicConstant::Constant(usize::MAX) + } + + pub fn is_smallest(&self) -> bool { + *self == DynamicConstant::Constant(usize::MIN) } pub fn try_parameter(&self) -> Option<usize> { diff --git a/hercules_opt/src/editor.rs b/hercules_opt/src/editor.rs index b33dc956ecc65d5bef67b804a4ca5a543793b242..57fe204245fc0adf75c8a046cfd9db25ebed119e 100644 --- a/hercules_opt/src/editor.rs +++ b/hercules_opt/src/editor.rs @@ -795,22 +795,48 @@ impl<'a, 'b> FunctionEdit<'a, 'b> { self.add_constant(constant_to_construct) } - pub fn add_pos_inf_constant(&mut self, id: TypeID) -> ConstantID { + pub fn add_largest_constant(&mut self, id: TypeID) -> ConstantID { let ty = self.get_type(id).clone(); let constant_to_construct = match ty { + Type::Boolean => Constant::Boolean(true), + Type::Integer8 => Constant::Integer8(i8::MAX), + Type::Integer16 => Constant::Integer16(i16::MAX), + Type::Integer32 => Constant::Integer32(i32::MAX), + Type::Integer64 => Constant::Integer64(i64::MAX), + Type::UnsignedInteger8 => Constant::UnsignedInteger8(u8::MAX), + Type::UnsignedInteger16 => Constant::UnsignedInteger16(u16::MAX), + Type::UnsignedInteger32 => Constant::UnsignedInteger32(u32::MAX), + Type::UnsignedInteger64 => Constant::UnsignedInteger64(u64::MAX), + Type::Float8 | Type::BFloat16 => panic!(), Type::Float32 => Constant::Float32(ordered_float::OrderedFloat(f32::INFINITY)), Type::Float64 => Constant::Float64(ordered_float::OrderedFloat(f64::INFINITY)), - _ => panic!(), + Type::Control => panic!("PANIC: Can't create largest constant for the control type."), + Type::Product(_) | Type::Summation(_) | Type::Array(_, _) => { + panic!("PANIC: Can't create largest constant of a collection type.") + } }; self.add_constant(constant_to_construct) } - pub fn add_neg_inf_constant(&mut self, id: TypeID) -> ConstantID { + pub fn add_smallest_constant(&mut self, id: TypeID) -> ConstantID { let ty = self.get_type(id).clone(); let constant_to_construct = match ty { + Type::Boolean => Constant::Boolean(true), + Type::Integer8 => Constant::Integer8(i8::MIN), + Type::Integer16 => Constant::Integer16(i16::MIN), + Type::Integer32 => Constant::Integer32(i32::MIN), + Type::Integer64 => Constant::Integer64(i64::MIN), + Type::UnsignedInteger8 => Constant::UnsignedInteger8(u8::MIN), + Type::UnsignedInteger16 => Constant::UnsignedInteger16(u16::MIN), + Type::UnsignedInteger32 => Constant::UnsignedInteger32(u32::MIN), + Type::UnsignedInteger64 => Constant::UnsignedInteger64(u64::MIN), + Type::Float8 | Type::BFloat16 => panic!(), Type::Float32 => Constant::Float32(ordered_float::OrderedFloat(f32::NEG_INFINITY)), Type::Float64 => Constant::Float64(ordered_float::OrderedFloat(f64::NEG_INFINITY)), - _ => panic!(), + Type::Control => panic!("PANIC: Can't create smallest constant for the control type."), + Type::Product(_) | Type::Summation(_) | Type::Array(_, _) => { + panic!("PANIC: Can't create smallest constant of a collection type.") + } }; self.add_constant(constant_to_construct) } diff --git a/hercules_opt/src/fork_transforms.rs b/hercules_opt/src/fork_transforms.rs index 283734a009ab3f619910b02465bf9d4d05856bef..e635b3c00d7bfa0090376d8056e65d8d01e60ce2 100644 --- a/hercules_opt/src/fork_transforms.rs +++ b/hercules_opt/src/fork_transforms.rs @@ -1556,6 +1556,44 @@ pub fn clean_monoid_reduces(editor: &mut FunctionEditor, typing: &Vec<TypeID>) { edit.replace_all_uses_where(id, final_op, |u| *u != reduct && *u != final_op) }); } + Node::IntrinsicCall { + intrinsic: Intrinsic::Max, + args: _, + } if !is_smallest(editor, init) => { + editor.edit(|mut edit| { + let smallest = edit.add_smallest_constant(typing[init.idx()]); + let smallest = edit.add_node(Node::Constant { id: smallest }); + edit.sub_edit(id, smallest); + edit = edit.replace_all_uses_where(init, smallest, |u| *u == id)?; + let final_op = edit.add_node(Node::IntrinsicCall { + intrinsic: Intrinsic::Max, + args: Box::new([init, id]), + }); + for u in out_uses { + edit.sub_edit(u, final_op); + } + edit.replace_all_uses_where(id, final_op, |u| *u != reduct && *u != final_op) + }); + } + Node::IntrinsicCall { + intrinsic: Intrinsic::Min, + args: _, + } if !is_largest(editor, init) => { + editor.edit(|mut edit| { + let largest = edit.add_largest_constant(typing[init.idx()]); + let largest = edit.add_node(Node::Constant { id: largest }); + edit.sub_edit(id, largest); + edit = edit.replace_all_uses_where(init, largest, |u| *u == id)?; + let final_op = edit.add_node(Node::IntrinsicCall { + intrinsic: Intrinsic::Min, + args: Box::new([init, id]), + }); + for u in out_uses { + edit.sub_edit(u, final_op); + } + edit.replace_all_uses_where(id, final_op, |u| *u != reduct && *u != final_op) + }); + } _ => {} } } diff --git a/hercules_opt/src/utils.rs b/hercules_opt/src/utils.rs index 1806d5c740e57a666f98ebf6c0ba40ee9a6461bd..793fe9fabfee830eef97687097aa5e40177a369d 100644 --- a/hercules_opt/src/utils.rs +++ b/hercules_opt/src/utils.rs @@ -567,3 +567,29 @@ pub fn is_one(editor: &FunctionEditor, id: NodeID) -> bool { .unwrap_or(false) || nodes[id.idx()].is_undef() } + +pub fn is_largest(editor: &FunctionEditor, id: NodeID) -> bool { + let nodes = &editor.func().nodes; + nodes[id.idx()] + .try_constant() + .map(|id| editor.get_constant(id).is_largest()) + .unwrap_or(false) + || nodes[id.idx()] + .try_dynamic_constant() + .map(|id| editor.get_dynamic_constant(id).is_largest()) + .unwrap_or(false) + || nodes[id.idx()].is_undef() +} + +pub fn is_smallest(editor: &FunctionEditor, id: NodeID) -> bool { + let nodes = &editor.func().nodes; + nodes[id.idx()] + .try_constant() + .map(|id| editor.get_constant(id).is_smallest()) + .unwrap_or(false) + || nodes[id.idx()] + .try_dynamic_constant() + .map(|id| editor.get_dynamic_constant(id).is_smallest()) + .unwrap_or(false) + || nodes[id.idx()].is_undef() +} diff --git a/juno_samples/edge_detection/src/cpu.sch b/juno_samples/edge_detection/src/cpu.sch index 3c3d09b34f9bd8c4b412d4b19e3898769cf2670a..d08e86e62d4002086bc29db2a4682eb5706c429e 100644 --- a/juno_samples/edge_detection/src/cpu.sch +++ b/juno_samples/edge_detection/src/cpu.sch @@ -58,6 +58,8 @@ fixpoint { fork-coalesce(max_gradient); } simpl!(max_gradient); +clean-monoid-reduces(max_gradient); +xdot[true](max_gradient); no-memset(reject_zero_crossings@res); fixpoint {