@@ -256,6 +256,9 @@ pub(crate) enum Instruction {
256256 /// Constrains two values to be equal to one another.
257257 Constrain ( ValueId , ValueId , Option < ConstrainError > ) ,
258258
259+ /// Constrains two values to not be equal to one another.
260+ ConstrainNotEqual ( ValueId , ValueId , Option < ConstrainError > ) ,
261+
259262 /// Range constrain `value` to `max_bit_size`
260263 RangeCheck { value : ValueId , max_bit_size : u32 , assert_message : Option < String > } ,
261264
@@ -364,6 +367,7 @@ impl Instruction {
364367 InstructionResultType :: Operand ( * value)
365368 }
366369 Instruction :: Constrain ( ..)
370+ | Instruction :: ConstrainNotEqual ( ..)
367371 | Instruction :: Store { .. }
368372 | Instruction :: IncrementRc { .. }
369373 | Instruction :: DecrementRc { .. }
@@ -405,7 +409,7 @@ impl Instruction {
405409 } ,
406410
407411 // These can fail.
408- Constrain ( ..) | RangeCheck { .. } => true ,
412+ Constrain ( ..) | ConstrainNotEqual ( .. ) | RangeCheck { .. } => true ,
409413
410414 // This should never be side-effectful
411415 MakeArray { .. } | Noop => false ,
@@ -472,7 +476,7 @@ impl Instruction {
472476 } ,
473477
474478 // We can deduplicate these instructions if we know the predicate is also the same.
475- Constrain ( ..) | RangeCheck { .. } => deduplicate_with_predicate,
479+ Constrain ( ..) | ConstrainNotEqual ( .. ) | RangeCheck { .. } => deduplicate_with_predicate,
476480
477481 // Noop instructions can always be deduplicated, although they're more likely to be
478482 // removed entirely.
@@ -540,6 +544,7 @@ impl Instruction {
540544 }
541545
542546 Constrain ( ..)
547+ | ConstrainNotEqual ( ..)
543548 | EnableSideEffectsIf { .. }
544549 | IncrementRc { .. }
545550 | DecrementRc { .. }
@@ -610,6 +615,7 @@ impl Instruction {
610615 Instruction :: Cast ( _, _)
611616 | Instruction :: Not ( _)
612617 | Instruction :: Truncate { .. }
618+ | Instruction :: ConstrainNotEqual ( ..)
613619 | Instruction :: Constrain ( _, _, _)
614620 | Instruction :: RangeCheck { .. }
615621 | Instruction :: Allocate
@@ -656,6 +662,22 @@ impl Instruction {
656662 } ) ;
657663 Instruction :: Constrain ( lhs, rhs, assert_message)
658664 }
665+ Instruction :: ConstrainNotEqual ( lhs, rhs, assert_message) => {
666+ // Must map the `lhs` and `rhs` first as the value `f` is moved with the closure
667+ let lhs = f ( * lhs) ;
668+ let rhs = f ( * rhs) ;
669+ let assert_message = assert_message. as_ref ( ) . map ( |error| match error {
670+ ConstrainError :: Dynamic ( selector, is_string, payload_values) => {
671+ ConstrainError :: Dynamic (
672+ * selector,
673+ * is_string,
674+ payload_values. iter ( ) . map ( |& value| f ( value) ) . collect ( ) ,
675+ )
676+ }
677+ _ => error. clone ( ) ,
678+ } ) ;
679+ Instruction :: ConstrainNotEqual ( lhs, rhs, assert_message)
680+ }
659681 Instruction :: Call { func, arguments } => Instruction :: Call {
660682 func : f ( * func) ,
661683 arguments : vecmap ( arguments. iter ( ) . copied ( ) , f) ,
@@ -714,7 +736,8 @@ impl Instruction {
714736 Instruction :: Truncate { value, bit_size : _, max_bit_size : _ } => {
715737 * value = f ( * value) ;
716738 }
717- Instruction :: Constrain ( lhs, rhs, assert_message) => {
739+ Instruction :: Constrain ( lhs, rhs, assert_message)
740+ | Instruction :: ConstrainNotEqual ( lhs, rhs, assert_message) => {
718741 * lhs = f ( * lhs) ;
719742 * rhs = f ( * rhs) ;
720743 if let Some ( ConstrainError :: Dynamic ( _, _, payload_values) ) = assert_message {
@@ -786,7 +809,8 @@ impl Instruction {
786809 | Instruction :: Load { address : value } => {
787810 f ( * value) ;
788811 }
789- Instruction :: Constrain ( lhs, rhs, assert_error) => {
812+ Instruction :: Constrain ( lhs, rhs, assert_error)
813+ | Instruction :: ConstrainNotEqual ( lhs, rhs, assert_error) => {
790814 f ( * lhs) ;
791815 f ( * rhs) ;
792816 if let Some ( ConstrainError :: Dynamic ( _, _, values) ) = assert_error. as_ref ( ) {
@@ -878,6 +902,7 @@ impl Instruction {
878902 SimplifiedToInstructionMultiple ( constraints)
879903 }
880904 }
905+ Instruction :: ConstrainNotEqual ( ..) => None ,
881906 Instruction :: ArrayGet { array, index } => {
882907 if let Some ( index) = dfg. get_numeric_constant ( * index) {
883908 try_optimize_array_get_from_previous_set ( dfg, * array, index)
0 commit comments