[llvm] [SLP]Recognize interchangeable cmp predicates with boundary constants (PR #218237)

Alexey Bataev via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 23 06:05:20 PDT 2026


https://github.com/alexey-bataev created https://github.com/llvm/llvm-project/pull/218237

Treat boundary comparisons canonicalized to eq/ne (e.g. x <u 1 became
x == 0) as interchangeable with the rest of the bundle by adjusting
the compared constant, emitting a single vector compare.

Fixes #190505


>From 9742b7e2f71a66b0a55d3bd947d4f7dc6018b2b5 Mon Sep 17 00:00:00 2001
From: Alexey Bataev <a.bataev at outlook.com>
Date: Sun, 23 Aug 2026 06:05:04 -0700
Subject: [PATCH] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20initia?=
 =?UTF-8?q?l=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.7
---
 .../Transforms/Vectorize/SLPVectorizer.cpp    |  57 ++++-
 .../SLPCompatibilityAnalysis.cpp              | 222 ++++++++++++++++++
 .../SLPVectorizer/SLPCompatibilityAnalysis.h  |  52 ++++
 .../X86/interchangeable-cmp-predicates.ll     |  78 ++----
 4 files changed, 351 insertions(+), 58 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 8d49f8b9fda9d..192c3cf7e5195 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -10379,7 +10379,8 @@ BoUpSLP::TreeEntry::EntryState BoUpSLP::getScalarsVectorizationState(
       if (isa<PoisonValue>(V))
         continue;
       auto *Cmp = cast<CmpInst>(V);
-      if ((Cmp->getPredicate() != P0 && Cmp->getPredicate() != SwapP0) ||
+      if ((Cmp->getPredicate() != P0 && Cmp->getPredicate() != SwapP0 &&
+           !CmpSamePredicateHelper::canConvertTo(Cmp, P0)) ||
           Cmp->getOperand(0)->getType() != ComparedTy) {
         LLVM_DEBUG(dbgs() << "SLP: Gathering cmp with different predicate.\n");
         return TreeEntry::NeedToGather;
@@ -12705,6 +12706,30 @@ void BoUpSLP::buildTreeRec(ArrayRef<Value *> VLRef, unsigned Depth,
   if (S.isAltShuffle() && TrySplitNode(S))
     return;
 
+  // Cmp nodes with interchangeable lanes (e.g. x == 0 mixed with x <u C)
+  // try the split by the original predicates, like the alternate nodes.
+  if (S.getOpcode() == Instruction::ICmp && !S.isAltShuffle()) {
+    auto SameOrSwapped = [](const ICmpInst *CI, CmpInst::Predicate P) {
+      return CI->getPredicate() == P ||
+             CI->getPredicate() == CmpInst::getSwappedPredicate(P);
+    };
+    ICmpInst *MainI = cast<ICmpInst>(*find_if(VL, IsaPred<ICmpInst>));
+    auto *AltIt = find_if(VL, [&](Value *V) {
+      auto *CI = dyn_cast<ICmpInst>(V);
+      return CI && !SameOrSwapped(CI, MainI->getPredicate());
+    });
+    ICmpInst *AltI = AltIt == VL.end() ? nullptr : cast<ICmpInst>(*AltIt);
+    if (AltI &&
+        all_of(VL,
+               [&](Value *V) {
+                 auto *CI = dyn_cast<ICmpInst>(V);
+                 return !CI || SameOrSwapped(CI, MainI->getPredicate()) ||
+                        SameOrSwapped(CI, AltI->getPredicate());
+               }) &&
+        TrySplitNode(InstructionsState(MainI, AltI)))
+      return;
+  }
+
   // Check that every instruction appears once in this bundle.
   if (!tryToFindDuplicates(VL, ReuseShuffleIndices, *TTI, *TLI, S, UserTreeIdx,
                            *this, /*BuildGatherOnly=*/false)) {
@@ -13219,11 +13244,14 @@ void BoUpSLP::buildTreeRec(ArrayRef<Value *> VLRef, unsigned Depth,
         Operands.back() = Ops.getVL(1);
       } else {
         // Collect operands - commute if it uses the swapped predicate.
+        // Lanes interchangeable with P0 (e.g. x == 0 in an x <u C bundle)
+        // already have their operands adjusted, no need to commute them.
         for (auto [Idx, V] : enumerate(VL)) {
           if (isa<PoisonValue>(V))
             continue;
           auto *Cmp = cast<CmpInst>(V);
-          if (Cmp->getPredicate() != P0)
+          if (Cmp->getPredicate() != P0 &&
+              !CmpSamePredicateHelper::canConvertTo(Cmp, P0))
             std::swap(Operands.front()[Idx], Operands.back()[Idx]);
         }
       }
@@ -23504,8 +23532,29 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E) {
           return CI && CI->getValue() == CI->getBitWidth() - 1;
         }))
       I->setHasNoSignedWrap(/*b=*/false);
-    if (auto *ICmp = dyn_cast<ICmpInst>(I); ICmp && It == MinBWs.end())
-      ICmp->setSameSign(/*B=*/false);
+    // Keep the intersected samesign unless the compared operands were
+    // narrowed (the sign relation may change in the narrower type) or a
+    // converted lane's adjusted constant flips the sign.
+    if (auto *ICmp = dyn_cast<ICmpInst>(I); ICmp && It == MinBWs.end()) {
+      bool Narrowed = MinBWs.contains(getOperandEntry(E, 0)) ||
+                      MinBWs.contains(getOperandEntry(E, 1));
+      bool SignFlip = !Narrowed && [&] {
+        CmpInst::Predicate P0 = cast<CmpInst>(E->getMainOp())->getPredicate();
+        return any_of(E->Scalars, [&](Value *Scalar) {
+          auto *LaneCI = dyn_cast<ICmpInst>(Scalar);
+          if (!LaneCI || LaneCI->getPredicate() == P0)
+            return false;
+          auto *OrigC = dyn_cast<ConstantInt>(LaneCI->getOperand(1));
+          if (!OrigC)
+            return false;
+          ConstantInt *AdjC =
+              CmpSamePredicateHelper::getAdjustedConstant(LaneCI, P0);
+          return AdjC && AdjC->isNegative() != OrigC->isNegative();
+        });
+      }();
+      if (Narrowed || SignFlip)
+        ICmp->setSameSign(/*B=*/false);
+    }
     return I;
   };
   switch (ShuffleOrOp) {
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPCompatibilityAnalysis.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPCompatibilityAnalysis.cpp
index 63c0a921a7917..ba840bd10acb6 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPCompatibilityAnalysis.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPCompatibilityAnalysis.cpp
@@ -15,6 +15,7 @@
 #include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/SmallVectorExtras.h"
+#include "llvm/ADT/bit.h"
 #include "llvm/Analysis/VectorUtils.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/InstrTypes.h"
@@ -30,6 +31,7 @@
 #include <algorithm>
 #include <array>
 #include <cassert>
+#include <optional>
 #include <utility>
 
 using namespace llvm;
@@ -324,6 +326,192 @@ bool BinOpSameOpcodeHelper::add(const Instruction *I) {
           AltOp.trySet(OpcodeInMaskForm, InterchangeableMask));
 }
 
+/// If the comparison (Pred, X, C) is a single-element or single-complement
+/// range check, returns its boundary family: false + K for the singleton
+/// {K} (eq forms), true + K for the complement of {K} (ne forms).
+static std::optional<std::pair<bool, APInt>>
+getCmpBoundaryFamily(CmpInst::Predicate Pred, const APInt &C) {
+  const unsigned BW = C.getBitWidth();
+  const APInt MaxU = APInt::getMaxValue(BW);
+  const APInt MinS = APInt::getSignedMinValue(BW);
+  const APInt MaxS = APInt::getSignedMaxValue(BW);
+  switch (Pred) {
+  case CmpInst::ICMP_EQ:
+    return std::make_pair(false, C);
+  case CmpInst::ICMP_NE:
+    return std::make_pair(true, C);
+  case CmpInst::ICMP_ULT:
+    if (C.isOne())
+      return std::make_pair(false, APInt(BW, 0));
+    if (C == MaxU)
+      return std::make_pair(true, C);
+    break;
+  case CmpInst::ICMP_ULE:
+    if (C.isZero())
+      return std::make_pair(false, C);
+    if (C == MaxU - 1)
+      return std::make_pair(true, MaxU);
+    break;
+  case CmpInst::ICMP_UGT:
+    if (C.isZero())
+      return std::make_pair(true, C);
+    if (C == MaxU - 1)
+      return std::make_pair(false, MaxU);
+    break;
+  case CmpInst::ICMP_UGE:
+    if (C.isOne())
+      return std::make_pair(true, APInt(BW, 0));
+    if (C == MaxU)
+      return std::make_pair(false, C);
+    break;
+  case CmpInst::ICMP_SLT:
+    if (C == MinS + 1)
+      return std::make_pair(false, MinS);
+    if (C == MaxS)
+      return std::make_pair(true, C);
+    break;
+  case CmpInst::ICMP_SLE:
+    if (C == MinS)
+      return std::make_pair(false, C);
+    if (C == MaxS - 1)
+      return std::make_pair(true, MaxS);
+    break;
+  case CmpInst::ICMP_SGT:
+    if (C == MinS)
+      return std::make_pair(true, C);
+    if (C == MaxS - 1)
+      return std::make_pair(false, MaxS);
+    break;
+  case CmpInst::ICMP_SGE:
+    if (C == MinS + 1)
+      return std::make_pair(true, MinS);
+    if (C == MaxS)
+      return std::make_pair(false, C);
+    break;
+  default:
+    break;
+  }
+  return std::nullopt;
+}
+
+CmpSamePredicateHelper::MaskType
+CmpSamePredicateHelper::getFormsMask(CmpInst::Predicate Pred, const APInt &C) {
+  MaskType M = getBit(Pred);
+  std::optional<std::pair<bool, APInt>> Family = getCmpBoundaryFamily(Pred, C);
+  if (!Family)
+    return M;
+  const auto &[IsComplement, K] = *Family;
+  if (!IsComplement) {
+    M |= getBit(CmpInst::ICMP_EQ);
+    if (K.isZero())
+      M |= getBit(CmpInst::ICMP_ULT) | getBit(CmpInst::ICMP_ULE);
+    if (K.isMaxValue())
+      M |= getBit(CmpInst::ICMP_UGT) | getBit(CmpInst::ICMP_UGE);
+    if (K.isMinSignedValue())
+      M |= getBit(CmpInst::ICMP_SLT) | getBit(CmpInst::ICMP_SLE);
+    if (K.isMaxSignedValue())
+      M |= getBit(CmpInst::ICMP_SGT) | getBit(CmpInst::ICMP_SGE);
+    return M;
+  }
+  M |= getBit(CmpInst::ICMP_NE);
+  if (K.isZero())
+    M |= getBit(CmpInst::ICMP_UGT) | getBit(CmpInst::ICMP_UGE);
+  if (K.isMaxValue())
+    M |= getBit(CmpInst::ICMP_ULT) | getBit(CmpInst::ICMP_ULE);
+  if (K.isMinSignedValue())
+    M |= getBit(CmpInst::ICMP_SGT) | getBit(CmpInst::ICMP_SGE);
+  if (K.isMaxSignedValue())
+    M |= getBit(CmpInst::ICMP_SLT) | getBit(CmpInst::ICMP_SLE);
+  return M;
+}
+
+APInt CmpSamePredicateHelper::getFamilyConstant(bool IsComplement,
+                                                const APInt &K,
+                                                CmpInst::Predicate Pred) {
+  switch (Pred) {
+  case CmpInst::ICMP_EQ:
+  case CmpInst::ICMP_NE:
+    return K;
+  case CmpInst::ICMP_ULT:
+  case CmpInst::ICMP_SLT:
+    return IsComplement ? K : K + 1;
+  case CmpInst::ICMP_ULE:
+  case CmpInst::ICMP_SLE:
+    return IsComplement ? K - 1 : K;
+  case CmpInst::ICMP_UGT:
+  case CmpInst::ICMP_SGT:
+    return IsComplement ? K : K - 1;
+  case CmpInst::ICMP_UGE:
+  case CmpInst::ICMP_SGE:
+    return IsComplement ? K + 1 : K;
+  default:
+    llvm_unreachable("Unexpected predicate.");
+  }
+}
+
+bool CmpSamePredicateHelper::add(const ICmpInst *CI) {
+  MaskType LaneMask = getBit(CI->getPredicate());
+  if (auto *C = dyn_cast<ConstantInt>(CI->getOperand(1)))
+    LaneMask = getFormsMask(CI->getPredicate(), C->getValue());
+  SeenBefore |= getBit(CI->getPredicate());
+  Mask &= LaneMask;
+  return Mask != 0;
+}
+
+CmpInst::Predicate
+CmpSamePredicateHelper::getPredicate(const ICmpInst *Preferred) const {
+  MaskType Candidate = Mask & SeenBefore;
+  if (!Candidate)
+    return CmpInst::BAD_ICMP_PREDICATE;
+  if (Candidate & getBit(Preferred->getPredicate()))
+    return Preferred->getPredicate();
+  return static_cast<CmpInst::Predicate>(CmpInst::ICMP_EQ +
+                                         countr_zero(Candidate));
+}
+
+CmpInst::Predicate
+CmpSamePredicateHelper::getSharedPredicate(ArrayRef<Value *> VL,
+                                           const ICmpInst *Preferred) {
+  CmpSamePredicateHelper Helper;
+  if (!all_of(VL, [&](Value *V) {
+        auto *CI = dyn_cast<ICmpInst>(V);
+        return isa<PoisonValue>(V) || (CI && Helper.add(CI));
+      }))
+    return CmpInst::BAD_ICMP_PREDICATE;
+  return Helper.getPredicate(Preferred);
+}
+
+bool CmpSamePredicateHelper::canConvertTo(const CmpInst *CI,
+                                          CmpInst::Predicate Pred) {
+  if (!CmpInst::isIntPredicate(Pred))
+    return false;
+  auto *ICI = dyn_cast<ICmpInst>(CI);
+  if (!ICI)
+    return false;
+  if (ICI->getPredicate() == Pred)
+    return true;
+  auto *C = dyn_cast<ConstantInt>(ICI->getOperand(1));
+  if (!C)
+    return false;
+  return getFormsMask(ICI->getPredicate(), C->getValue()) & getBit(Pred);
+}
+
+ConstantInt *
+CmpSamePredicateHelper::getAdjustedConstant(const CmpInst *CI,
+                                            CmpInst::Predicate Pred) {
+  if (!canConvertTo(CI, Pred))
+    return nullptr;
+  auto *ICI = cast<ICmpInst>(CI);
+  if (ICI->getPredicate() == Pred)
+    return nullptr;
+  auto *C = cast<ConstantInt>(ICI->getOperand(1));
+  std::optional<std::pair<bool, APInt>> Family =
+      getCmpBoundaryFamily(ICI->getPredicate(), C->getValue());
+  assert(Family && "Expected a boundary family for a convertible compare.");
+  return ConstantInt::get(
+      CI->getContext(), getFamilyConstant(Family->first, Family->second, Pred));
+}
+
 bool InstructionsState::isSameOperation(const Instruction *I,
                                         const Instruction *Op) {
   if (I->getOpcode() != Op->getOpcode())
@@ -610,6 +798,12 @@ InstructionsState getSameOpcode(ArrayRef<Value *> VL,
     // not alternate.
     return UniqueNonSwappedPreds.size() > 2 && UniquePreds.size() == 2;
   }();
+  // Find the predicate the whole bundle can share, if any, treating
+  // boundary comparisons canonicalized to eq/ne as interchangeable.
+  CmpInst::Predicate InterchangeablePred = CmpInst::BAD_ICMP_PREDICATE;
+  if (IsCmpOp && isa<ICmpInst>(MainOp))
+    InterchangeablePred =
+        CmpSamePredicateHelper::getSharedPredicate(VL, cast<ICmpInst>(MainOp));
   // Check for one alternate opcode from another BinaryOperator.
   // TODO - generalize to support all operators (types, calls etc.).
   Intrinsic::ID BaseID = 0;
@@ -675,6 +869,8 @@ InstructionsState getSameOpcode(ArrayRef<Value *> VL,
 
         if (isCmpSameOrSwapped(BaseInst, Inst, TLI))
           continue;
+        if (CmpSamePredicateHelper::canConvertTo(Inst, InterchangeablePred))
+          continue;
         auto *AltInst = cast<CmpInst>(AltOp);
         if (MainOp != AltOp) {
           if (isCmpSameOrSwapped(AltInst, Inst, TLI))
@@ -761,6 +957,20 @@ InstructionsState getSameOpcode(ArrayRef<Value *> VL,
     if (It != VL.end())
       MainOp = AltOp = cast<Instruction>(*It);
   }
+  if (IsCmpOp && InterchangeablePred != CmpInst::BAD_ICMP_PREDICATE &&
+      InterchangeablePred != BasePred) {
+    // Every lane is convertible to the shared predicate, so the alternate
+    // operation is never set for such bundles.
+    if (MainOp != AltOp)
+      return InstructionsState::invalid();
+    auto *It = find_if(VL, [&](Value *V) {
+      auto *CI = dyn_cast<ICmpInst>(V);
+      return CI && CI->getPredicate() == InterchangeablePred;
+    });
+    assert(It != VL.end() &&
+           "Expected an instruction with the shared predicate.");
+    MainOp = AltOp = cast<Instruction>(*It);
+  }
   assert((MainOp == AltOp || !allSameOpcode(VL)) &&
          "Incorrect implementation of allSameOpcode.");
   InstructionsState S(MainOp, AltOp);
@@ -784,6 +994,18 @@ convertTo(Instruction *I, const InstructionsState &S) {
   // Use args() to skip the trailing callee operand in CallInst::operands().
   if (auto *CI = dyn_cast<CallInst>(I))
     return std::make_pair(SelectedOp, SmallVector<Value *>(CI->args()));
+  // A comparison lane interchangeable with the main operation (e.g. x == 0
+  // in an x <u C bundle) is emitted with the main predicate and the
+  // adjusted constant.
+  if (auto *MainCI = dyn_cast<ICmpInst>(SelectedOp);
+      MainCI && !S.isAltShuffle()) {
+    auto *CI = cast<ICmpInst>(I);
+    if (CI->getPredicate() != MainCI->getPredicate())
+      if (ConstantInt *C = CmpSamePredicateHelper::getAdjustedConstant(
+              CI, MainCI->getPredicate()))
+        return std::make_pair(SelectedOp,
+                              SmallVector<Value *>{CI->getOperand(0), C});
+  }
   return std::make_pair(SelectedOp, SmallVector<Value *>(I->operands()));
 }
 
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPCompatibilityAnalysis.h b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPCompatibilityAnalysis.h
index 62c8fe985c4a7..f938a030e1c5d 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPCompatibilityAnalysis.h
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPCompatibilityAnalysis.h
@@ -23,12 +23,15 @@
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Analysis/IVDescriptors.h"
 #include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
 
 #include <cstdint>
 #include <utility>
 
 namespace llvm {
+class APInt;
 class Constant;
+class ConstantInt;
 class TargetLibraryInfo;
 class Value;
 } // namespace llvm
@@ -130,6 +133,55 @@ class BinOpSameOpcodeHelper {
   }
 };
 
+/// Helper class that determines whether a list of integer comparisons can
+/// share a single predicate. InstCombine canonicalizes single-element and
+/// single-complement range comparisons to eq/ne at the type boundaries
+/// (e.g. x <u 1 becomes x == 0); such lanes are interchangeable with the
+/// rest of the list by adjusting the compared constant.
+class CmpSamePredicateHelper {
+  using MaskType = std::uint16_t;
+  /// Bit i represents predicate ICMP_EQ + i.
+  static constexpr unsigned NumPreds = CmpInst::ICMP_SLE - CmpInst::ICMP_EQ + 1;
+  static constexpr MaskType AllPreds = (1 << NumPreds) - 1;
+  /// Intersection of the per-lane convertible predicate sets.
+  MaskType Mask = AllPreds;
+  /// Predicates present in the list natively. The shared predicate must be
+  /// one of them: the main op must be an actual instruction with this
+  /// predicate.
+  MaskType SeenBefore = 0;
+
+  static constexpr MaskType getBit(CmpInst::Predicate P) {
+    return static_cast<MaskType>(1) << (P - CmpInst::ICMP_EQ);
+  }
+  /// Returns the mask of the predicates that can express the comparison
+  /// (Pred, X, C) with an adjusted constant C, including Pred itself.
+  static MaskType getFormsMask(CmpInst::Predicate Pred, const APInt &C);
+  /// Returns the constant of the (Pred, X, C') form equivalent to the
+  /// boundary family (IsComplement, K). Pred must be in the family mask.
+  static APInt getFamilyConstant(bool IsComplement, const APInt &K,
+                                 CmpInst::Predicate Pred);
+
+public:
+  /// Intersects the convertible predicate set of \p CI with the running
+  /// set. Returns false when the intersection becomes empty.
+  bool add(const ICmpInst *CI);
+  /// Returns the shared predicate, preferring the predicate of
+  /// \p Preferred when the whole list can use it, or BAD_ICMP_PREDICATE
+  /// when the list cannot share a natively present predicate.
+  CmpInst::Predicate getPredicate(const ICmpInst *Preferred) const;
+  /// Returns the predicate the whole list can share, or BAD_ICMP_PREDICATE
+  /// when it cannot share a natively present predicate.
+  static CmpInst::Predicate getSharedPredicate(ArrayRef<Value *> VL,
+                                               const ICmpInst *Preferred);
+  /// Checks if the comparison \p CI can be expressed with the predicate
+  /// \p Pred by adjusting its constant operand.
+  static bool canConvertTo(const CmpInst *CI, CmpInst::Predicate Pred);
+  /// Returns the adjusted constant operand expressing \p CI with the
+  /// predicate \p Pred, or nullptr if not convertible.
+  static ConstantInt *getAdjustedConstant(const CmpInst *CI,
+                                          CmpInst::Predicate Pred);
+};
+
 /// Main data required for vectorization of instructions.
 class InstructionsState {
   /// MainOp and AltOp are primarily determined by getSameOpcode. Currently,
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/interchangeable-cmp-predicates.ll b/llvm/test/Transforms/SLPVectorizer/X86/interchangeable-cmp-predicates.ll
index 51156bc66d2c3..53fb104458c81 100644
--- a/llvm/test/Transforms/SLPVectorizer/X86/interchangeable-cmp-predicates.ll
+++ b/llvm/test/Transforms/SLPVectorizer/X86/interchangeable-cmp-predicates.ll
@@ -8,12 +8,9 @@
 define <8 x i1> @eq_ult(i16 %x) {
 ; CHECK-LABEL: define <8 x i1> @eq_ult(
 ; CHECK-SAME: i16 [[X:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <8 x i16> <i16 0, i16 poison, i16 poison, i16 poison, i16 poison, i16 poison, i16 poison, i16 poison>, i16 [[X]], i64 1
-; CHECK-NEXT:    [[TMP2:%.*]] = shufflevector <8 x i16> [[TMP1]], <8 x i16> poison, <8 x i32> <i32 0, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
-; CHECK-NEXT:    [[TMP6:%.*]] = insertelement <8 x i16> <i16 poison, i16 2, i16 3, i16 4, i16 5, i16 6, i16 7, i16 8>, i16 [[X]], i64 0
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq <8 x i16> [[TMP2]], [[TMP6]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp ult <8 x i16> [[TMP2]], [[TMP6]]
-; CHECK-NEXT:    [[TMP3:%.*]] = shufflevector <8 x i1> [[TMP4]], <8 x i1> [[TMP5]], <8 x i32> <i32 0, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <8 x i16> poison, i16 [[X]], i64 0
+; CHECK-NEXT:    [[TMP2:%.*]] = shufflevector <8 x i16> [[TMP1]], <8 x i16> poison, <8 x i32> zeroinitializer
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp ult <8 x i16> [[TMP2]], <i16 1, i16 2, i16 3, i16 4, i16 5, i16 6, i16 7, i16 8>
 ; CHECK-NEXT:    ret <8 x i1> [[TMP3]]
 ;
   %c1 = icmp eq i16 %x, 0
@@ -38,12 +35,9 @@ define <8 x i1> @eq_ult(i16 %x) {
 define <8 x i1> @ne_ugt(i16 %x) {
 ; CHECK-LABEL: define <8 x i1> @ne_ugt(
 ; CHECK-SAME: i16 [[X:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <8 x i16> <i16 0, i16 poison, i16 poison, i16 poison, i16 poison, i16 poison, i16 poison, i16 poison>, i16 [[X]], i64 1
-; CHECK-NEXT:    [[TMP2:%.*]] = shufflevector <8 x i16> [[TMP1]], <8 x i16> poison, <8 x i32> <i32 0, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
-; CHECK-NEXT:    [[TMP6:%.*]] = insertelement <8 x i16> <i16 poison, i16 1, i16 2, i16 3, i16 4, i16 5, i16 6, i16 7>, i16 [[X]], i64 0
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp ne <8 x i16> [[TMP2]], [[TMP6]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp ugt <8 x i16> [[TMP2]], [[TMP6]]
-; CHECK-NEXT:    [[TMP3:%.*]] = shufflevector <8 x i1> [[TMP4]], <8 x i1> [[TMP5]], <8 x i32> <i32 0, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <8 x i16> poison, i16 [[X]], i64 0
+; CHECK-NEXT:    [[TMP2:%.*]] = shufflevector <8 x i16> [[TMP1]], <8 x i16> poison, <8 x i32> zeroinitializer
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp ugt <8 x i16> [[TMP2]], <i16 0, i16 1, i16 2, i16 3, i16 4, i16 5, i16 6, i16 7>
 ; CHECK-NEXT:    ret <8 x i1> [[TMP3]]
 ;
   %c1 = icmp ne i16 %x, 0
@@ -68,12 +62,9 @@ define <8 x i1> @ne_ugt(i16 %x) {
 define <8 x i1> @eq_slt_signed_mins(i16 %x) {
 ; CHECK-LABEL: define <8 x i1> @eq_slt_signed_mins(
 ; CHECK-SAME: i16 [[X:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <8 x i16> <i16 -32768, i16 poison, i16 poison, i16 poison, i16 poison, i16 poison, i16 poison, i16 poison>, i16 [[X]], i64 1
-; CHECK-NEXT:    [[TMP2:%.*]] = shufflevector <8 x i16> [[TMP1]], <8 x i16> poison, <8 x i32> <i32 0, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
-; CHECK-NEXT:    [[TMP6:%.*]] = insertelement <8 x i16> <i16 poison, i16 -32766, i16 -32765, i16 -32764, i16 -32763, i16 -32762, i16 -32761, i16 -32760>, i16 [[X]], i64 0
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq <8 x i16> [[TMP2]], [[TMP6]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp slt <8 x i16> [[TMP2]], [[TMP6]]
-; CHECK-NEXT:    [[TMP3:%.*]] = shufflevector <8 x i1> [[TMP4]], <8 x i1> [[TMP5]], <8 x i32> <i32 0, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <8 x i16> poison, i16 [[X]], i64 0
+; CHECK-NEXT:    [[TMP2:%.*]] = shufflevector <8 x i16> [[TMP1]], <8 x i16> poison, <8 x i32> zeroinitializer
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp slt <8 x i16> [[TMP2]], <i16 -32767, i16 -32766, i16 -32765, i16 -32764, i16 -32763, i16 -32762, i16 -32761, i16 -32760>
 ; CHECK-NEXT:    ret <8 x i1> [[TMP3]]
 ;
   %c1 = icmp eq i16 %x, -32768
@@ -98,12 +89,9 @@ define <8 x i1> @eq_slt_signed_mins(i16 %x) {
 define <8 x i1> @ne_sle_signed_maxs(i16 %x) {
 ; CHECK-LABEL: define <8 x i1> @ne_sle_signed_maxs(
 ; CHECK-SAME: i16 [[X:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <8 x i16> <i16 32767, i16 poison, i16 poison, i16 poison, i16 poison, i16 poison, i16 poison, i16 poison>, i16 [[X]], i64 1
-; CHECK-NEXT:    [[TMP2:%.*]] = shufflevector <8 x i16> [[TMP1]], <8 x i16> poison, <8 x i32> <i32 0, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
-; CHECK-NEXT:    [[TMP6:%.*]] = insertelement <8 x i16> <i16 poison, i16 32765, i16 32764, i16 32763, i16 32762, i16 32761, i16 32760, i16 32759>, i16 [[X]], i64 0
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp ne <8 x i16> [[TMP2]], [[TMP6]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp sle <8 x i16> [[TMP2]], [[TMP6]]
-; CHECK-NEXT:    [[TMP3:%.*]] = shufflevector <8 x i1> [[TMP4]], <8 x i1> [[TMP5]], <8 x i32> <i32 0, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <8 x i16> poison, i16 [[X]], i64 0
+; CHECK-NEXT:    [[TMP2:%.*]] = shufflevector <8 x i16> [[TMP1]], <8 x i16> poison, <8 x i32> zeroinitializer
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp sle <8 x i16> [[TMP2]], <i16 32766, i16 32765, i16 32764, i16 32763, i16 32762, i16 32761, i16 32760, i16 32759>
 ; CHECK-NEXT:    ret <8 x i1> [[TMP3]]
 ;
   %c1 = icmp ne i16 %x, 32767
@@ -130,9 +118,7 @@ define <8 x i1> @ule_ult(i16 %x) {
 ; CHECK-SAME: i16 [[X:%.*]]) {
 ; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <8 x i16> poison, i16 [[X]], i64 0
 ; CHECK-NEXT:    [[TMP2:%.*]] = shufflevector <8 x i16> [[TMP1]], <8 x i16> poison, <8 x i32> zeroinitializer
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp ule <8 x i16> [[TMP2]], <i16 0, i16 2, i16 3, i16 4, i16 5, i16 6, i16 7, i16 8>
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp ult <8 x i16> [[TMP2]], <i16 0, i16 2, i16 3, i16 4, i16 5, i16 6, i16 7, i16 8>
-; CHECK-NEXT:    [[TMP3:%.*]] = shufflevector <8 x i1> [[TMP5]], <8 x i1> [[TMP4]], <8 x i32> <i32 0, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp ult <8 x i16> [[TMP2]], <i16 1, i16 2, i16 3, i16 4, i16 5, i16 6, i16 7, i16 8>
 ; CHECK-NEXT:    ret <8 x i1> [[TMP3]]
 ;
   %c1 = icmp ule i16 %x, 0
@@ -221,19 +207,9 @@ define <8 x i1> @neg_eq_ne(i16 %x) {
 define <8 x i1> @samesign_lanes(i8 %x) {
 ; CHECK-LABEL: define <8 x i1> @samesign_lanes(
 ; CHECK-SAME: i8 [[X:%.*]]) {
-; CHECK-NEXT:    [[C1:%.*]] = icmp samesign eq i8 [[X]], 0
-; CHECK-NEXT:    [[C2:%.*]] = icmp samesign ult i8 [[X]], 2
-; CHECK-NEXT:    [[C3:%.*]] = icmp samesign ult i8 [[X]], 3
-; CHECK-NEXT:    [[C4:%.*]] = icmp samesign ult i8 [[X]], 4
-; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <4 x i8> poison, i8 [[X]], i64 0
-; CHECK-NEXT:    [[TMP2:%.*]] = shufflevector <4 x i8> [[TMP1]], <4 x i8> poison, <4 x i32> zeroinitializer
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp ult <4 x i8> [[TMP2]], <i8 5, i8 6, i8 7, i8 8>
-; CHECK-NEXT:    [[I1:%.*]] = insertelement <8 x i1> poison, i1 [[C1]], i32 0
-; CHECK-NEXT:    [[I2:%.*]] = insertelement <8 x i1> [[I1]], i1 [[C2]], i32 1
-; CHECK-NEXT:    [[I3:%.*]] = insertelement <8 x i1> [[I2]], i1 [[C3]], i32 2
-; CHECK-NEXT:    [[I4:%.*]] = insertelement <8 x i1> [[I3]], i1 [[C4]], i32 3
-; CHECK-NEXT:    [[TMP4:%.*]] = shufflevector <4 x i1> [[TMP5]], <4 x i1> poison, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 poison, i32 poison, i32 poison, i32 poison>
-; CHECK-NEXT:    [[TMP3:%.*]] = shufflevector <8 x i1> [[I4]], <8 x i1> [[TMP4]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 8, i32 9, i32 10, i32 11>
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <8 x i8> poison, i8 [[X]], i64 0
+; CHECK-NEXT:    [[TMP2:%.*]] = shufflevector <8 x i8> [[TMP1]], <8 x i8> poison, <8 x i32> zeroinitializer
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp samesign ult <8 x i8> [[TMP2]], <i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8>
 ; CHECK-NEXT:    ret <8 x i1> [[TMP3]]
 ;
   %c1 = icmp samesign eq i8 %x, 0
@@ -259,14 +235,11 @@ define <8 x i1> @samesign_lanes(i8 %x) {
 define <4 x i1> @samesign_i1_signflip(i1 %x, i1 %y, i1 %z, i1 %w) {
 ; CHECK-LABEL: define <4 x i1> @samesign_i1_signflip(
 ; CHECK-SAME: i1 [[X:%.*]], i1 [[Y:%.*]], i1 [[Z:%.*]], i1 [[W:%.*]]) {
-; CHECK-NEXT:    [[C1:%.*]] = icmp samesign eq i1 [[X]], false
-; CHECK-NEXT:    [[C2:%.*]] = icmp samesign ult i1 [[Y]], true
-; CHECK-NEXT:    [[C3:%.*]] = icmp samesign ult i1 [[Z]], true
-; CHECK-NEXT:    [[C4:%.*]] = icmp samesign ult i1 [[W]], true
-; CHECK-NEXT:    [[I1:%.*]] = insertelement <4 x i1> poison, i1 [[C1]], i32 0
-; CHECK-NEXT:    [[I2:%.*]] = insertelement <4 x i1> [[I1]], i1 [[C2]], i32 1
-; CHECK-NEXT:    [[I3:%.*]] = insertelement <4 x i1> [[I2]], i1 [[C3]], i32 2
-; CHECK-NEXT:    [[TMP5:%.*]] = insertelement <4 x i1> [[I3]], i1 [[C4]], i32 3
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <4 x i1> poison, i1 [[X]], i64 0
+; CHECK-NEXT:    [[TMP2:%.*]] = insertelement <4 x i1> [[TMP1]], i1 [[Y]], i64 1
+; CHECK-NEXT:    [[TMP3:%.*]] = insertelement <4 x i1> [[TMP2]], i1 [[Z]], i64 2
+; CHECK-NEXT:    [[TMP4:%.*]] = insertelement <4 x i1> [[TMP3]], i1 [[W]], i64 3
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp eq <4 x i1> [[TMP4]], zeroinitializer
 ; CHECK-NEXT:    ret <4 x i1> [[TMP5]]
 ;
   %c1 = icmp samesign eq i1 %x, 0
@@ -313,12 +286,9 @@ define void @selects(ptr noalias %out, ptr addrspace(11) %a, ptr addrspace(11) %
 ; CHECK-LABEL: define void @selects(
 ; CHECK-SAME: ptr noalias [[OUT:%.*]], ptr addrspace(11) [[A:%.*]], ptr addrspace(11) [[B:%.*]], i64 [[N:%.*]]) {
 ; CHECK-NEXT:    [[X:%.*]] = trunc i64 [[N]] to i16
-; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <4 x i16> <i16 0, i16 poison, i16 poison, i16 poison>, i16 [[X]], i64 1
-; CHECK-NEXT:    [[TMP2:%.*]] = shufflevector <4 x i16> [[TMP1]], <4 x i16> poison, <4 x i32> <i32 0, i32 1, i32 1, i32 1>
-; CHECK-NEXT:    [[TMP7:%.*]] = insertelement <4 x i16> <i16 poison, i16 2, i16 3, i16 4>, i16 [[X]], i64 0
-; CHECK-NEXT:    [[TMP8:%.*]] = icmp eq <4 x i16> [[TMP2]], [[TMP7]]
-; CHECK-NEXT:    [[TMP9:%.*]] = icmp ult <4 x i16> [[TMP2]], [[TMP7]]
-; CHECK-NEXT:    [[TMP3:%.*]] = shufflevector <4 x i1> [[TMP8]], <4 x i1> [[TMP9]], <4 x i32> <i32 0, i32 5, i32 6, i32 7>
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <4 x i16> poison, i16 [[X]], i64 0
+; CHECK-NEXT:    [[TMP2:%.*]] = shufflevector <4 x i16> [[TMP1]], <4 x i16> poison, <4 x i32> zeroinitializer
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp ult <4 x i16> [[TMP2]], <i16 1, i16 2, i16 3, i16 4>
 ; CHECK-NEXT:    [[TMP4:%.*]] = load <4 x i16>, ptr addrspace(11) [[A]], align 2
 ; CHECK-NEXT:    [[TMP5:%.*]] = load <4 x i16>, ptr addrspace(11) [[B]], align 2
 ; CHECK-NEXT:    [[TMP6:%.*]] = select <4 x i1> [[TMP3]], <4 x i16> [[TMP5]], <4 x i16> [[TMP4]]



More information about the llvm-commits mailing list