[GlobalISel] Combine (X op Y) == X --> Y == 0
authorJessica Paquette <jpaquette@apple.com>
Thu, 6 Oct 2022 18:03:43 +0000 (11:03 -0700)
committerJessica Paquette <jpaquette@apple.com>
Tue, 11 Oct 2022 16:52:48 +0000 (09:52 -0700)
This matches patterns of the form

```
(X op Y) == X
```

And transforms them to

```
Y == 0
```

where appropriate.

Example: https://godbolt.org/z/hfW811c7W

Differential Revision: https://reviews.llvm.org/D135380

llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
llvm/include/llvm/Target/GlobalISel/Combine.td
llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
llvm/test/CodeGen/AArch64/GlobalISel/combine-icmp-of-binop-to-icmp-of-0.mir [new file with mode: 0644]

index 12b6124..515382a 100644 (file)
@@ -768,6 +768,15 @@ public:
   /// to a min/max instruction of some sort.
   bool matchSimplifySelectToMinMax(MachineInstr &MI, BuildFnTy &MatchInfo);
 
+  /// Transform:
+  ///   (X + Y) == X -> Y == 0
+  ///   (X - Y) == X -> Y == 0
+  ///   (X ^ Y) == X -> Y == 0
+  ///   (X + Y) != X -> Y != 0
+  ///   (X - Y) != X -> Y != 0
+  ///   (X ^ Y) != X -> Y != 0
+  bool matchRedundantBinOpInEquality(MachineInstr &MI, BuildFnTy &MatchInfo);
+
 private:
   /// Given a non-indexed load or store instruction \p MI, find an offset that
   /// can be usefully and legally folded into it as a post-indexing operation.
index 2d61315..d2fad89 100644 (file)
@@ -736,6 +736,12 @@ def icmp_to_lhs_known_bits : GICombineRule<
          [{ return Helper.matchICmpToLHSKnownBits(*${root}, ${info}); }]),
   (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>;
 
+def redundant_binop_in_equality : GICombineRule<
+  (defs root:$root, build_fn_matchinfo:$info),
+  (match (wip_match_opcode G_ICMP):$root,
+         [{ return Helper.matchRedundantBinOpInEquality(*${root}, ${info}); }]),
+  (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>;
+
 def and_or_disjoint_mask : GICombineRule<
   (defs root:$root, build_fn_matchinfo:$info),
   (match (wip_match_opcode G_AND):$root,
@@ -1045,7 +1051,7 @@ def all_combines : GICombineGroup<[trivial_combines, insert_vec_elt_combines,
     form_bitfield_extract, constant_fold, fabs_fneg_fold,
     intdiv_combines, mulh_combines, redundant_neg_operands,
     and_or_disjoint_mask, fma_combines, fold_binop_into_select,
-    sub_add_reg, select_to_minmax]>;
+    sub_add_reg, select_to_minmax, redundant_binop_in_equality]>;
 
 // A combine group used to for prelegalizer combiners at -O0. The combines in
 // this group have been selected based on experiments to balance code size and
index 32d4b53..f3a58cc 100644 (file)
@@ -27,6 +27,7 @@
 #include "llvm/CodeGen/TargetLowering.h"
 #include "llvm/CodeGen/TargetOpcodes.h"
 #include "llvm/IR/DataLayout.h"
+#include "llvm/IR/InstrTypes.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/DivisionByConstantInfo.h"
 #include "llvm/Support/MathExtras.h"
@@ -6060,6 +6061,38 @@ bool CombinerHelper::matchSimplifySelectToMinMax(MachineInstr &MI,
   return matchFPSelectToMinMax(Dst, Cond, TrueVal, FalseVal, MatchInfo);
 }
 
+bool CombinerHelper::matchRedundantBinOpInEquality(MachineInstr &MI,
+                                                   BuildFnTy &MatchInfo) {
+  assert(MI.getOpcode() == TargetOpcode::G_ICMP);
+  // (X + Y) == X --> Y == 0
+  // (X + Y) != X --> Y != 0
+  // (X - Y) == X --> Y == 0
+  // (X - Y) != X --> Y != 0
+  // (X ^ Y) == X --> Y == 0
+  // (X ^ Y) != X --> Y != 0
+  Register Dst = MI.getOperand(0).getReg();
+  CmpInst::Predicate Pred;
+  Register X, Y, OpLHS, OpRHS;
+  bool MatchedSub = mi_match(
+      Dst, MRI,
+      m_c_GICmp(m_Pred(Pred), m_Reg(X), m_GSub(m_Reg(OpLHS), m_Reg(Y))));
+  if (MatchedSub && X != OpLHS)
+    return false;
+  if (!MatchedSub) {
+    if (!mi_match(Dst, MRI,
+                  m_c_GICmp(m_Pred(Pred), m_Reg(X),
+                            m_any_of(m_GAdd(m_Reg(OpLHS), m_Reg(OpRHS)),
+                                     m_GXor(m_Reg(OpLHS), m_Reg(OpRHS))))))
+      return false;
+    Y = X == OpLHS ? OpRHS : X == OpRHS ? OpLHS : Register();
+  }
+  MatchInfo = [=](MachineIRBuilder &B) {
+    auto Zero = B.buildConstant(MRI.getType(Y), 0);
+    B.buildICmp(Pred, Dst, Y, Zero);
+  };
+  return CmpInst::isEquality(Pred) && Y.isValid();
+}
+
 bool CombinerHelper::tryCombine(MachineInstr &MI) {
   if (tryCombineCopy(MI))
     return true;
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-icmp-of-binop-to-icmp-of-0.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-icmp-of-binop-to-icmp-of-0.mir
new file mode 100644 (file)
index 0000000..966b781
--- /dev/null
@@ -0,0 +1,863 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple aarch64 -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs %s -o - | FileCheck %s
+
+# Test:
+#  (X + Y) == X --> Y == 0
+#  (X - Y) == X --> Y == 0
+#  (X ^ Y) == X --> Y == 0
+#  (X + Y) != X --> Y != 0
+#  (X - Y) != X --> Y != 0
+#  (X ^ Y) != X --> Y != 0
+#
+# And all commuted cases.
+
+...
+---
+name:            add_scalar_eq
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1
+    ; CHECK-LABEL: name: add_scalar_eq
+    ; CHECK: liveins: $w0, $w1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(s32) = COPY $w1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: %cmp:_(s1) = G_ICMP intpred(eq), %y(s32), [[C]]
+    ; CHECK-NEXT: %ext:_(s32) = G_ZEXT %cmp(s1)
+    ; CHECK-NEXT: $w0 = COPY %ext(s32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %x:_(s32) = COPY $w0
+    %y:_(s32) = COPY $w1
+    %op:_(s32) = G_ADD %x, %y
+    %cmp:_(s1) = G_ICMP intpred(eq), %op(s32), %x
+    %ext:_(s32) = G_ZEXT %cmp(s1)
+    $w0 = COPY %ext(s32)
+    RET_ReallyLR implicit $w0
+...
+---
+name:            add_vector_eq
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $q0, $q1
+    ; CHECK-LABEL: name: add_vector_eq
+    ; CHECK: liveins: $q0, $q1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(<4 x s32>) = COPY $q1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+    ; CHECK-NEXT: %cmp:_(<4 x s1>) = G_ICMP intpred(eq), %y(<4 x s32>), [[BUILD_VECTOR]]
+    ; CHECK-NEXT: %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    ; CHECK-NEXT: $d0 = COPY %ext(<4 x s16>)
+    ; CHECK-NEXT: RET_ReallyLR implicit $d0
+    %x:_(<4 x s32>) = COPY $q0
+    %y:_(<4 x s32>) = COPY $q1
+    %op:_(<4 x s32>) = G_ADD %x, %y
+    %cmp:_(<4 x s1>) = G_ICMP intpred(eq), %op(<4 x s32>), %x
+    %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    $d0 = COPY %ext(<4 x s16>)
+    RET_ReallyLR implicit $d0
+...
+---
+name:            add_scalar_eq_commuted_in_op
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1
+    ; CHECK-LABEL: name: add_scalar_eq_commuted_in_op
+    ; CHECK: liveins: $w0, $w1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(s32) = COPY $w1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: %cmp:_(s1) = G_ICMP intpred(eq), %y(s32), [[C]]
+    ; CHECK-NEXT: %ext:_(s32) = G_ZEXT %cmp(s1)
+    ; CHECK-NEXT: $w0 = COPY %ext(s32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %x:_(s32) = COPY $w0
+    %y:_(s32) = COPY $w1
+    %op:_(s32) = G_ADD %y, %x
+    %cmp:_(s1) = G_ICMP intpred(eq), %op(s32), %x
+    %ext:_(s32) = G_ZEXT %cmp(s1)
+    $w0 = COPY %ext(s32)
+    RET_ReallyLR implicit $w0
+...
+---
+name:            add_vector_eq_commuted_in_op
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $q0, $q1
+    ; CHECK-LABEL: name: add_vector_eq_commuted_in_op
+    ; CHECK: liveins: $q0, $q1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(<4 x s32>) = COPY $q1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+    ; CHECK-NEXT: %cmp:_(<4 x s1>) = G_ICMP intpred(eq), %y(<4 x s32>), [[BUILD_VECTOR]]
+    ; CHECK-NEXT: %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    ; CHECK-NEXT: $d0 = COPY %ext(<4 x s16>)
+    ; CHECK-NEXT: RET_ReallyLR implicit $d0
+    %x:_(<4 x s32>) = COPY $q0
+    %y:_(<4 x s32>) = COPY $q1
+    %op:_(<4 x s32>) = G_ADD %y, %x
+    %cmp:_(<4 x s1>) = G_ICMP intpred(eq), %op(<4 x s32>), %x
+    %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    $d0 = COPY %ext(<4 x s16>)
+    RET_ReallyLR implicit $d0
+...
+---
+name:            add_scalar_eq_commuted_in_cmp
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1
+    ; CHECK-LABEL: name: add_scalar_eq_commuted_in_cmp
+    ; CHECK: liveins: $w0, $w1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(s32) = COPY $w1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: %cmp:_(s1) = G_ICMP intpred(eq), %y(s32), [[C]]
+    ; CHECK-NEXT: %ext:_(s32) = G_ZEXT %cmp(s1)
+    ; CHECK-NEXT: $w0 = COPY %ext(s32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %x:_(s32) = COPY $w0
+    %y:_(s32) = COPY $w1
+    %op:_(s32) = G_ADD %x, %y
+    %cmp:_(s1) = G_ICMP intpred(eq), %x(s32), %op
+    %ext:_(s32) = G_ZEXT %cmp(s1)
+    $w0 = COPY %ext(s32)
+    RET_ReallyLR implicit $w0
+...
+---
+name:            add_vector_eq_commuted_in_cmp
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $q0, $q1
+    ; CHECK-LABEL: name: add_vector_eq_commuted_in_cmp
+    ; CHECK: liveins: $q0, $q1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(<4 x s32>) = COPY $q1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+    ; CHECK-NEXT: %cmp:_(<4 x s1>) = G_ICMP intpred(eq), %y(<4 x s32>), [[BUILD_VECTOR]]
+    ; CHECK-NEXT: %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    ; CHECK-NEXT: $d0 = COPY %ext(<4 x s16>)
+    ; CHECK-NEXT: RET_ReallyLR implicit $d0
+    %x:_(<4 x s32>) = COPY $q0
+    %y:_(<4 x s32>) = COPY $q1
+    %op:_(<4 x s32>) = G_ADD %x, %y
+    %cmp:_(<4 x s1>) = G_ICMP intpred(eq), %x(<4 x s32>), %op
+    %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    $d0 = COPY %ext(<4 x s16>)
+    RET_ReallyLR implicit $d0
+...
+---
+name:            xor_scalar_eq
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1
+    ; CHECK-LABEL: name: xor_scalar_eq
+    ; CHECK: liveins: $w0, $w1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(s32) = COPY $w1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: %cmp:_(s1) = G_ICMP intpred(eq), %y(s32), [[C]]
+    ; CHECK-NEXT: %ext:_(s32) = G_ZEXT %cmp(s1)
+    ; CHECK-NEXT: $w0 = COPY %ext(s32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %x:_(s32) = COPY $w0
+    %y:_(s32) = COPY $w1
+    %op:_(s32) = G_XOR %x, %y
+    %cmp:_(s1) = G_ICMP intpred(eq), %op(s32), %x
+    %ext:_(s32) = G_ZEXT %cmp(s1)
+    $w0 = COPY %ext(s32)
+    RET_ReallyLR implicit $w0
+...
+---
+name:            xor_vector_eq
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $q0, $q1
+    ; CHECK-LABEL: name: xor_vector_eq
+    ; CHECK: liveins: $q0, $q1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(<4 x s32>) = COPY $q1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+    ; CHECK-NEXT: %cmp:_(<4 x s1>) = G_ICMP intpred(eq), %y(<4 x s32>), [[BUILD_VECTOR]]
+    ; CHECK-NEXT: %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    ; CHECK-NEXT: $d0 = COPY %ext(<4 x s16>)
+    ; CHECK-NEXT: RET_ReallyLR implicit $d0
+    %x:_(<4 x s32>) = COPY $q0
+    %y:_(<4 x s32>) = COPY $q1
+    %op:_(<4 x s32>) = G_XOR %x, %y
+    %cmp:_(<4 x s1>) = G_ICMP intpred(eq), %op(<4 x s32>), %x
+    %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    $d0 = COPY %ext(<4 x s16>)
+    RET_ReallyLR implicit $d0
+...
+---
+name:            xor_scalar_eq_commuted_in_op
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1
+    ; CHECK-LABEL: name: xor_scalar_eq_commuted_in_op
+    ; CHECK: liveins: $w0, $w1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(s32) = COPY $w1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: %cmp:_(s1) = G_ICMP intpred(eq), %y(s32), [[C]]
+    ; CHECK-NEXT: %ext:_(s32) = G_ZEXT %cmp(s1)
+    ; CHECK-NEXT: $w0 = COPY %ext(s32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %x:_(s32) = COPY $w0
+    %y:_(s32) = COPY $w1
+    %op:_(s32) = G_XOR %y, %x
+    %cmp:_(s1) = G_ICMP intpred(eq), %op(s32), %x
+    %ext:_(s32) = G_ZEXT %cmp(s1)
+    $w0 = COPY %ext(s32)
+    RET_ReallyLR implicit $w0
+...
+---
+name:            xor_vector_eq_commuted_in_op
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $q0, $q1
+    ; CHECK-LABEL: name: xor_vector_eq_commuted_in_op
+    ; CHECK: liveins: $q0, $q1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(<4 x s32>) = COPY $q1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+    ; CHECK-NEXT: %cmp:_(<4 x s1>) = G_ICMP intpred(eq), %y(<4 x s32>), [[BUILD_VECTOR]]
+    ; CHECK-NEXT: %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    ; CHECK-NEXT: $d0 = COPY %ext(<4 x s16>)
+    ; CHECK-NEXT: RET_ReallyLR implicit $d0
+    %x:_(<4 x s32>) = COPY $q0
+    %y:_(<4 x s32>) = COPY $q1
+    %op:_(<4 x s32>) = G_XOR %y, %x
+    %cmp:_(<4 x s1>) = G_ICMP intpred(eq), %op(<4 x s32>), %x
+    %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    $d0 = COPY %ext(<4 x s16>)
+    RET_ReallyLR implicit $d0
+...
+---
+name:            xor_scalar_eq_commuted_in_cmp
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1
+    ; CHECK-LABEL: name: xor_scalar_eq_commuted_in_cmp
+    ; CHECK: liveins: $w0, $w1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(s32) = COPY $w1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: %cmp:_(s1) = G_ICMP intpred(eq), %y(s32), [[C]]
+    ; CHECK-NEXT: %ext:_(s32) = G_ZEXT %cmp(s1)
+    ; CHECK-NEXT: $w0 = COPY %ext(s32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %x:_(s32) = COPY $w0
+    %y:_(s32) = COPY $w1
+    %op:_(s32) = G_XOR %x, %y
+    %cmp:_(s1) = G_ICMP intpred(eq), %x(s32), %op
+    %ext:_(s32) = G_ZEXT %cmp(s1)
+    $w0 = COPY %ext(s32)
+    RET_ReallyLR implicit $w0
+...
+---
+name:            xor_vector_eq_commuted_in_cmp
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $q0, $q1
+    ; CHECK-LABEL: name: xor_vector_eq_commuted_in_cmp
+    ; CHECK: liveins: $q0, $q1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(<4 x s32>) = COPY $q1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+    ; CHECK-NEXT: %cmp:_(<4 x s1>) = G_ICMP intpred(eq), %y(<4 x s32>), [[BUILD_VECTOR]]
+    ; CHECK-NEXT: %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    ; CHECK-NEXT: $d0 = COPY %ext(<4 x s16>)
+    ; CHECK-NEXT: RET_ReallyLR implicit $d0
+    %x:_(<4 x s32>) = COPY $q0
+    %y:_(<4 x s32>) = COPY $q1
+    %op:_(<4 x s32>) = G_XOR %x, %y
+    %cmp:_(<4 x s1>) = G_ICMP intpred(eq), %x(<4 x s32>), %op
+    %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    $d0 = COPY %ext(<4 x s16>)
+    RET_ReallyLR implicit $d0
+...
+---
+name:            sub_scalar_eq
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1
+    ; CHECK-LABEL: name: sub_scalar_eq
+    ; CHECK: liveins: $w0, $w1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(s32) = COPY $w1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: %cmp:_(s1) = G_ICMP intpred(eq), %y(s32), [[C]]
+    ; CHECK-NEXT: %ext:_(s32) = G_ZEXT %cmp(s1)
+    ; CHECK-NEXT: $w0 = COPY %ext(s32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %x:_(s32) = COPY $w0
+    %y:_(s32) = COPY $w1
+    %op:_(s32) = G_SUB %x, %y
+    %cmp:_(s1) = G_ICMP intpred(eq), %op(s32), %x
+    %ext:_(s32) = G_ZEXT %cmp(s1)
+    $w0 = COPY %ext(s32)
+    RET_ReallyLR implicit $w0
+...
+---
+name:            sub_vector_eq
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $q0, $q1
+    ; CHECK-LABEL: name: sub_vector_eq
+    ; CHECK: liveins: $q0, $q1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(<4 x s32>) = COPY $q1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+    ; CHECK-NEXT: %cmp:_(<4 x s1>) = G_ICMP intpred(eq), %y(<4 x s32>), [[BUILD_VECTOR]]
+    ; CHECK-NEXT: %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    ; CHECK-NEXT: $d0 = COPY %ext(<4 x s16>)
+    ; CHECK-NEXT: RET_ReallyLR implicit $d0
+    %x:_(<4 x s32>) = COPY $q0
+    %y:_(<4 x s32>) = COPY $q1
+    %op:_(<4 x s32>) = G_SUB %x, %y
+    %cmp:_(<4 x s1>) = G_ICMP intpred(eq), %op(<4 x s32>), %x
+    %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    $d0 = COPY %ext(<4 x s16>)
+    RET_ReallyLR implicit $d0
+...
+---
+name:            sub_scalar_eq_commuted_in_cmp
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1
+    ; CHECK-LABEL: name: sub_scalar_eq_commuted_in_cmp
+    ; CHECK: liveins: $w0, $w1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(s32) = COPY $w1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: %cmp:_(s1) = G_ICMP intpred(eq), %y(s32), [[C]]
+    ; CHECK-NEXT: %ext:_(s32) = G_ZEXT %cmp(s1)
+    ; CHECK-NEXT: $w0 = COPY %ext(s32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %x:_(s32) = COPY $w0
+    %y:_(s32) = COPY $w1
+    %op:_(s32) = G_SUB %x, %y
+    %cmp:_(s1) = G_ICMP intpred(eq), %x(s32), %op
+    %ext:_(s32) = G_ZEXT %cmp(s1)
+    $w0 = COPY %ext(s32)
+    RET_ReallyLR implicit $w0
+...
+---
+name:            sub_vector_eq_commuted_in_cmp
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $q0, $q1
+    ; CHECK-LABEL: name: sub_vector_eq_commuted_in_cmp
+    ; CHECK: liveins: $q0, $q1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(<4 x s32>) = COPY $q1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+    ; CHECK-NEXT: %cmp:_(<4 x s1>) = G_ICMP intpred(eq), %y(<4 x s32>), [[BUILD_VECTOR]]
+    ; CHECK-NEXT: %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    ; CHECK-NEXT: $d0 = COPY %ext(<4 x s16>)
+    ; CHECK-NEXT: RET_ReallyLR implicit $d0
+    %x:_(<4 x s32>) = COPY $q0
+    %y:_(<4 x s32>) = COPY $q1
+    %op:_(<4 x s32>) = G_SUB %x, %y
+    %cmp:_(<4 x s1>) = G_ICMP intpred(eq), %x(<4 x s32>), %op
+    %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    $d0 = COPY %ext(<4 x s16>)
+    RET_ReallyLR implicit $d0
+...
+---
+name:            add_scalar_ne
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1
+    ; CHECK-LABEL: name: add_scalar_ne
+    ; CHECK: liveins: $w0, $w1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(s32) = COPY $w1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: %cmp:_(s1) = G_ICMP intpred(ne), %y(s32), [[C]]
+    ; CHECK-NEXT: %ext:_(s32) = G_ZEXT %cmp(s1)
+    ; CHECK-NEXT: $w0 = COPY %ext(s32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %x:_(s32) = COPY $w0
+    %y:_(s32) = COPY $w1
+    %op:_(s32) = G_ADD %x, %y
+    %cmp:_(s1) = G_ICMP intpred(ne), %op(s32), %x
+    %ext:_(s32) = G_ZEXT %cmp(s1)
+    $w0 = COPY %ext(s32)
+    RET_ReallyLR implicit $w0
+...
+---
+name:            add_vector_ne
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $q0, $q1
+    ; CHECK-LABEL: name: add_vector_ne
+    ; CHECK: liveins: $q0, $q1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(<4 x s32>) = COPY $q1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+    ; CHECK-NEXT: %cmp:_(<4 x s1>) = G_ICMP intpred(ne), %y(<4 x s32>), [[BUILD_VECTOR]]
+    ; CHECK-NEXT: %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    ; CHECK-NEXT: $d0 = COPY %ext(<4 x s16>)
+    ; CHECK-NEXT: RET_ReallyLR implicit $d0
+    %x:_(<4 x s32>) = COPY $q0
+    %y:_(<4 x s32>) = COPY $q1
+    %op:_(<4 x s32>) = G_ADD %x, %y
+    %cmp:_(<4 x s1>) = G_ICMP intpred(ne), %op(<4 x s32>), %x
+    %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    $d0 = COPY %ext(<4 x s16>)
+    RET_ReallyLR implicit $d0
+...
+---
+name:            add_scalar_ne_commuted_in_op
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1
+    ; CHECK-LABEL: name: add_scalar_ne_commuted_in_op
+    ; CHECK: liveins: $w0, $w1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(s32) = COPY $w1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: %cmp:_(s1) = G_ICMP intpred(ne), %y(s32), [[C]]
+    ; CHECK-NEXT: %ext:_(s32) = G_ZEXT %cmp(s1)
+    ; CHECK-NEXT: $w0 = COPY %ext(s32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %x:_(s32) = COPY $w0
+    %y:_(s32) = COPY $w1
+    %op:_(s32) = G_ADD %y, %x
+    %cmp:_(s1) = G_ICMP intpred(ne), %op(s32), %x
+    %ext:_(s32) = G_ZEXT %cmp(s1)
+    $w0 = COPY %ext(s32)
+    RET_ReallyLR implicit $w0
+...
+---
+name:            add_vector_ne_commuted_in_op
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $q0, $q1
+    ; CHECK-LABEL: name: add_vector_ne_commuted_in_op
+    ; CHECK: liveins: $q0, $q1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(<4 x s32>) = COPY $q1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+    ; CHECK-NEXT: %cmp:_(<4 x s1>) = G_ICMP intpred(ne), %y(<4 x s32>), [[BUILD_VECTOR]]
+    ; CHECK-NEXT: %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    ; CHECK-NEXT: $d0 = COPY %ext(<4 x s16>)
+    ; CHECK-NEXT: RET_ReallyLR implicit $d0
+    %x:_(<4 x s32>) = COPY $q0
+    %y:_(<4 x s32>) = COPY $q1
+    %op:_(<4 x s32>) = G_ADD %y, %x
+    %cmp:_(<4 x s1>) = G_ICMP intpred(ne), %op(<4 x s32>), %x
+    %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    $d0 = COPY %ext(<4 x s16>)
+    RET_ReallyLR implicit $d0
+...
+---
+name:            add_scalar_ne_commuted_in_cmp
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1
+    ; CHECK-LABEL: name: add_scalar_ne_commuted_in_cmp
+    ; CHECK: liveins: $w0, $w1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(s32) = COPY $w1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: %cmp:_(s1) = G_ICMP intpred(ne), %y(s32), [[C]]
+    ; CHECK-NEXT: %ext:_(s32) = G_ZEXT %cmp(s1)
+    ; CHECK-NEXT: $w0 = COPY %ext(s32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %x:_(s32) = COPY $w0
+    %y:_(s32) = COPY $w1
+    %op:_(s32) = G_ADD %x, %y
+    %cmp:_(s1) = G_ICMP intpred(ne), %x(s32), %op
+    %ext:_(s32) = G_ZEXT %cmp(s1)
+    $w0 = COPY %ext(s32)
+    RET_ReallyLR implicit $w0
+...
+---
+name:            add_vector_ne_commuted_in_cmp
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $q0, $q1
+    ; CHECK-LABEL: name: add_vector_ne_commuted_in_cmp
+    ; CHECK: liveins: $q0, $q1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(<4 x s32>) = COPY $q1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+    ; CHECK-NEXT: %cmp:_(<4 x s1>) = G_ICMP intpred(ne), %y(<4 x s32>), [[BUILD_VECTOR]]
+    ; CHECK-NEXT: %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    ; CHECK-NEXT: $d0 = COPY %ext(<4 x s16>)
+    ; CHECK-NEXT: RET_ReallyLR implicit $d0
+    %x:_(<4 x s32>) = COPY $q0
+    %y:_(<4 x s32>) = COPY $q1
+    %op:_(<4 x s32>) = G_ADD %x, %y
+    %cmp:_(<4 x s1>) = G_ICMP intpred(ne), %x(<4 x s32>), %op
+    %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    $d0 = COPY %ext(<4 x s16>)
+    RET_ReallyLR implicit $d0
+...
+---
+name:            xor_scalar_ne
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1
+    ; CHECK-LABEL: name: xor_scalar_ne
+    ; CHECK: liveins: $w0, $w1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(s32) = COPY $w1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: %cmp:_(s1) = G_ICMP intpred(ne), %y(s32), [[C]]
+    ; CHECK-NEXT: %ext:_(s32) = G_ZEXT %cmp(s1)
+    ; CHECK-NEXT: $w0 = COPY %ext(s32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %x:_(s32) = COPY $w0
+    %y:_(s32) = COPY $w1
+    %op:_(s32) = G_XOR %x, %y
+    %cmp:_(s1) = G_ICMP intpred(ne), %op(s32), %x
+    %ext:_(s32) = G_ZEXT %cmp(s1)
+    $w0 = COPY %ext(s32)
+    RET_ReallyLR implicit $w0
+...
+---
+name:            xor_vector_ne
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $q0, $q1
+    ; CHECK-LABEL: name: xor_vector_ne
+    ; CHECK: liveins: $q0, $q1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(<4 x s32>) = COPY $q1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+    ; CHECK-NEXT: %cmp:_(<4 x s1>) = G_ICMP intpred(ne), %y(<4 x s32>), [[BUILD_VECTOR]]
+    ; CHECK-NEXT: %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    ; CHECK-NEXT: $d0 = COPY %ext(<4 x s16>)
+    ; CHECK-NEXT: RET_ReallyLR implicit $d0
+    %x:_(<4 x s32>) = COPY $q0
+    %y:_(<4 x s32>) = COPY $q1
+    %op:_(<4 x s32>) = G_XOR %x, %y
+    %cmp:_(<4 x s1>) = G_ICMP intpred(ne), %op(<4 x s32>), %x
+    %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    $d0 = COPY %ext(<4 x s16>)
+    RET_ReallyLR implicit $d0
+...
+---
+name:            xor_scalar_ne_commuted_in_op
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1
+    ; CHECK-LABEL: name: xor_scalar_ne_commuted_in_op
+    ; CHECK: liveins: $w0, $w1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(s32) = COPY $w1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: %cmp:_(s1) = G_ICMP intpred(ne), %y(s32), [[C]]
+    ; CHECK-NEXT: %ext:_(s32) = G_ZEXT %cmp(s1)
+    ; CHECK-NEXT: $w0 = COPY %ext(s32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %x:_(s32) = COPY $w0
+    %y:_(s32) = COPY $w1
+    %op:_(s32) = G_XOR %y, %x
+    %cmp:_(s1) = G_ICMP intpred(ne), %op(s32), %x
+    %ext:_(s32) = G_ZEXT %cmp(s1)
+    $w0 = COPY %ext(s32)
+    RET_ReallyLR implicit $w0
+...
+---
+name:            xor_vector_ne_commuted_in_op
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $q0, $q1
+    ; CHECK-LABEL: name: xor_vector_ne_commuted_in_op
+    ; CHECK: liveins: $q0, $q1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(<4 x s32>) = COPY $q1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+    ; CHECK-NEXT: %cmp:_(<4 x s1>) = G_ICMP intpred(ne), %y(<4 x s32>), [[BUILD_VECTOR]]
+    ; CHECK-NEXT: %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    ; CHECK-NEXT: $d0 = COPY %ext(<4 x s16>)
+    ; CHECK-NEXT: RET_ReallyLR implicit $d0
+    %x:_(<4 x s32>) = COPY $q0
+    %y:_(<4 x s32>) = COPY $q1
+    %op:_(<4 x s32>) = G_XOR %y, %x
+    %cmp:_(<4 x s1>) = G_ICMP intpred(ne), %op(<4 x s32>), %x
+    %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    $d0 = COPY %ext(<4 x s16>)
+    RET_ReallyLR implicit $d0
+...
+---
+name:            xor_scalar_ne_commuted_in_cmp
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1
+    ; CHECK-LABEL: name: xor_scalar_ne_commuted_in_cmp
+    ; CHECK: liveins: $w0, $w1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(s32) = COPY $w1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: %cmp:_(s1) = G_ICMP intpred(ne), %y(s32), [[C]]
+    ; CHECK-NEXT: %ext:_(s32) = G_ZEXT %cmp(s1)
+    ; CHECK-NEXT: $w0 = COPY %ext(s32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %x:_(s32) = COPY $w0
+    %y:_(s32) = COPY $w1
+    %op:_(s32) = G_XOR %x, %y
+    %cmp:_(s1) = G_ICMP intpred(ne), %x(s32), %op
+    %ext:_(s32) = G_ZEXT %cmp(s1)
+    $w0 = COPY %ext(s32)
+    RET_ReallyLR implicit $w0
+...
+---
+name:            xor_vector_ne_commuted_in_cmp
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $q0, $q1
+    ; CHECK-LABEL: name: xor_vector_ne_commuted_in_cmp
+    ; CHECK: liveins: $q0, $q1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(<4 x s32>) = COPY $q1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+    ; CHECK-NEXT: %cmp:_(<4 x s1>) = G_ICMP intpred(ne), %y(<4 x s32>), [[BUILD_VECTOR]]
+    ; CHECK-NEXT: %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    ; CHECK-NEXT: $d0 = COPY %ext(<4 x s16>)
+    ; CHECK-NEXT: RET_ReallyLR implicit $d0
+    %x:_(<4 x s32>) = COPY $q0
+    %y:_(<4 x s32>) = COPY $q1
+    %op:_(<4 x s32>) = G_XOR %x, %y
+    %cmp:_(<4 x s1>) = G_ICMP intpred(ne), %x(<4 x s32>), %op
+    %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    $d0 = COPY %ext(<4 x s16>)
+    RET_ReallyLR implicit $d0
+...
+---
+name:            sub_scalar_ne
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1
+    ; CHECK-LABEL: name: sub_scalar_ne
+    ; CHECK: liveins: $w0, $w1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(s32) = COPY $w1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: %cmp:_(s1) = G_ICMP intpred(ne), %y(s32), [[C]]
+    ; CHECK-NEXT: %ext:_(s32) = G_ZEXT %cmp(s1)
+    ; CHECK-NEXT: $w0 = COPY %ext(s32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %x:_(s32) = COPY $w0
+    %y:_(s32) = COPY $w1
+    %op:_(s32) = G_SUB %x, %y
+    %cmp:_(s1) = G_ICMP intpred(ne), %op(s32), %x
+    %ext:_(s32) = G_ZEXT %cmp(s1)
+    $w0 = COPY %ext(s32)
+    RET_ReallyLR implicit $w0
+...
+---
+name:            sub_vector_ne
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $q0, $q1
+    ; CHECK-LABEL: name: sub_vector_ne
+    ; CHECK: liveins: $q0, $q1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(<4 x s32>) = COPY $q1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+    ; CHECK-NEXT: %cmp:_(<4 x s1>) = G_ICMP intpred(ne), %y(<4 x s32>), [[BUILD_VECTOR]]
+    ; CHECK-NEXT: %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    ; CHECK-NEXT: $d0 = COPY %ext(<4 x s16>)
+    ; CHECK-NEXT: RET_ReallyLR implicit $d0
+    %x:_(<4 x s32>) = COPY $q0
+    %y:_(<4 x s32>) = COPY $q1
+    %op:_(<4 x s32>) = G_SUB %x, %y
+    %cmp:_(<4 x s1>) = G_ICMP intpred(ne), %op(<4 x s32>), %x
+    %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    $d0 = COPY %ext(<4 x s16>)
+    RET_ReallyLR implicit $d0
+...
+---
+name:            sub_scalar_ne_commuted_in_cmp
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1
+    ; CHECK-LABEL: name: sub_scalar_ne_commuted_in_cmp
+    ; CHECK: liveins: $w0, $w1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(s32) = COPY $w1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: %cmp:_(s1) = G_ICMP intpred(ne), %y(s32), [[C]]
+    ; CHECK-NEXT: %ext:_(s32) = G_ZEXT %cmp(s1)
+    ; CHECK-NEXT: $w0 = COPY %ext(s32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %x:_(s32) = COPY $w0
+    %y:_(s32) = COPY $w1
+    %op:_(s32) = G_SUB %x, %y
+    %cmp:_(s1) = G_ICMP intpred(ne), %x(s32), %op
+    %ext:_(s32) = G_ZEXT %cmp(s1)
+    $w0 = COPY %ext(s32)
+    RET_ReallyLR implicit $w0
+...
+---
+name:            sub_vector_ne_commuted_in_cmp
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $q0, $q1
+    ; CHECK-LABEL: name: sub_vector_ne_commuted_in_cmp
+    ; CHECK: liveins: $q0, $q1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %y:_(<4 x s32>) = COPY $q1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+    ; CHECK-NEXT: %cmp:_(<4 x s1>) = G_ICMP intpred(ne), %y(<4 x s32>), [[BUILD_VECTOR]]
+    ; CHECK-NEXT: %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    ; CHECK-NEXT: $d0 = COPY %ext(<4 x s16>)
+    ; CHECK-NEXT: RET_ReallyLR implicit $d0
+    %x:_(<4 x s32>) = COPY $q0
+    %y:_(<4 x s32>) = COPY $q1
+    %op:_(<4 x s32>) = G_SUB %x, %y
+    %cmp:_(<4 x s1>) = G_ICMP intpred(ne), %x(<4 x s32>), %op
+    %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    $d0 = COPY %ext(<4 x s16>)
+    RET_ReallyLR implicit $d0
+...
+---
+name:            dont_combine_sub_scalar_eq_commuted_in_op
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1
+    ; CHECK-LABEL: name: dont_combine_sub_scalar_eq_commuted_in_op
+    ; CHECK: liveins: $w0, $w1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %x:_(s32) = COPY $w0
+    ; CHECK-NEXT: %y:_(s32) = COPY $w1
+    ; CHECK-NEXT: %op:_(s32) = G_SUB %y, %x
+    ; CHECK-NEXT: %cmp:_(s1) = G_ICMP intpred(eq), %op(s32), %x
+    ; CHECK-NEXT: %ext:_(s32) = G_ZEXT %cmp(s1)
+    ; CHECK-NEXT: $w0 = COPY %ext(s32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %x:_(s32) = COPY $w0
+    %y:_(s32) = COPY $w1
+    %op:_(s32) = G_SUB %y, %x
+    %cmp:_(s1) = G_ICMP intpred(eq), %op(s32), %x
+    %ext:_(s32) = G_ZEXT %cmp(s1)
+    $w0 = COPY %ext(s32)
+    RET_ReallyLR implicit $w0
+...
+---
+name:            dont_combine_sub_vector_eq_commuted_in_op
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $q0, $q1
+    ; CHECK-LABEL: name: dont_combine_sub_vector_eq_commuted_in_op
+    ; CHECK: liveins: $q0, $q1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %x:_(<4 x s32>) = COPY $q0
+    ; CHECK-NEXT: %y:_(<4 x s32>) = COPY $q1
+    ; CHECK-NEXT: %op:_(<4 x s32>) = G_SUB %y, %x
+    ; CHECK-NEXT: %cmp:_(<4 x s1>) = G_ICMP intpred(eq), %op(<4 x s32>), %x
+    ; CHECK-NEXT: %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    ; CHECK-NEXT: $d0 = COPY %ext(<4 x s16>)
+    ; CHECK-NEXT: RET_ReallyLR implicit $d0
+    %x:_(<4 x s32>) = COPY $q0
+    %y:_(<4 x s32>) = COPY $q1
+    %op:_(<4 x s32>) = G_SUB %y, %x
+    %cmp:_(<4 x s1>) = G_ICMP intpred(eq), %op(<4 x s32>), %x
+    %ext:_(<4 x s16>) = G_ANYEXT %cmp(<4 x s1>)
+    $d0 = COPY %ext(<4 x s16>)
+    RET_ReallyLR implicit $d0
+...
+---
+name:            dont_combine_not_equality
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1
+    ; CHECK-LABEL: name: dont_combine_not_equality
+    ; CHECK: liveins: $w0, $w1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %x:_(s32) = COPY $w0
+    ; CHECK-NEXT: %y:_(s32) = COPY $w1
+    ; CHECK-NEXT: %op:_(s32) = G_ADD %x, %y
+    ; CHECK-NEXT: %cmp:_(s1) = G_ICMP intpred(slt), %op(s32), %x
+    ; CHECK-NEXT: %ext:_(s32) = G_ZEXT %cmp(s1)
+    ; CHECK-NEXT: $w0 = COPY %ext(s32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %x:_(s32) = COPY $w0
+    %y:_(s32) = COPY $w1
+    %op:_(s32) = G_ADD %x, %y
+    %cmp:_(s1) = G_ICMP intpred(slt), %op(s32), %x
+    %ext:_(s32) = G_ZEXT %cmp(s1)
+    $w0 = COPY %ext(s32)
+    RET_ReallyLR implicit $w0
+...
+---
+name:            dont_combine_unique_operands
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1, $w2
+    ; CHECK-LABEL: name: dont_combine_unique_operands
+    ; CHECK: liveins: $w0, $w1, $w2
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %x:_(s32) = COPY $w0
+    ; CHECK-NEXT: %y:_(s32) = COPY $w1
+    ; CHECK-NEXT: %z:_(s32) = COPY $w2
+    ; CHECK-NEXT: %op:_(s32) = G_ADD %x, %y
+    ; CHECK-NEXT: %cmp:_(s1) = G_ICMP intpred(eq), %op(s32), %z
+    ; CHECK-NEXT: %ext:_(s32) = G_ZEXT %cmp(s1)
+    ; CHECK-NEXT: $w0 = COPY %ext(s32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %x:_(s32) = COPY $w0
+    %y:_(s32) = COPY $w1
+    %z:_(s32) = COPY $w2
+    %op:_(s32) = G_ADD %x, %y
+    %cmp:_(s1) = G_ICMP intpred(eq), %op(s32), %z
+    %ext:_(s32) = G_ZEXT %cmp(s1)
+    $w0 = COPY %ext(s32)
+    RET_ReallyLR implicit $w0