[llvm] [VPlan] Dispatch to multiple exit blocks via middle blocks. (PR #112138)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 10 06:06:40 PST 2024


https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/112138

>From 245b56a80bca6369a9be3102308617f2a4a4d51b Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 1 Oct 2024 20:57:24 +0100
Subject: [PATCH 01/18] [VPlan] Support VPIRBBs and VPIRInst phis with multiple
 predecessors.

---
 llvm/lib/Transforms/Vectorize/VPlan.cpp        | 5 ++++-
 llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp | 9 +++++----
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp
index c1b97791331bcf..8609514c39e7d0 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp
@@ -1056,7 +1056,10 @@ void VPlan::execute(VPTransformState *State) {
   State->CFG.DTU.applyUpdates({{DominatorTree::Delete, MiddleBB, ScalarPh}});
 
   // Generate code in the loop pre-header and body.
-  for (VPBlockBase *Block : vp_depth_first_shallow(Entry))
+  ReversePostOrderTraversal<VPBlockShallowTraversalWrapper<VPBlockBase *>> RPOT(
+      Entry);
+
+  for (VPBlockBase *Block : RPOT)
     Block->execute(State);
 
   VPBasicBlock *LatchVPBB = getVectorLoopRegion()->getExitingBasicBlock();
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index 41f13cc2d9a978..be3e958320e771 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -857,12 +857,13 @@ void VPInstruction::print(raw_ostream &O, const Twine &Indent,
 void VPIRInstruction::execute(VPTransformState &State) {
   assert((isa<PHINode>(&I) || getNumOperands() == 0) &&
          "Only PHINodes can have extra operands");
-  if (getNumOperands() == 1) {
-    VPValue *ExitValue = getOperand(0);
+  for (const auto &[Idx, Op] : enumerate(operands())) {
+    VPValue *ExitValue = Op;
     auto Lane = vputils::isUniformAfterVectorization(ExitValue)
                     ? VPLane::getFirstLane()
                     : VPLane::getLastLaneForVF(State.VF);
-    auto *PredVPBB = cast<VPBasicBlock>(getParent()->getSinglePredecessor());
+    VPBlockBase *Pred = getParent()->getPredecessors()[Idx];
+    auto *PredVPBB = Pred->getExitingBasicBlock();
     BasicBlock *PredBB = State.CFG.VPBB2IRBB[PredVPBB];
     // Set insertion point in PredBB in case an extract needs to be generated.
     // TODO: Model extracts explicitly.
@@ -890,7 +891,7 @@ void VPIRInstruction::print(raw_ostream &O, const Twine &Indent,
   O << Indent << "IR " << I;
 
   if (getNumOperands() != 0) {
-    assert(getNumOperands() == 1 && "can have at most 1 operand");
+    // assert(getNumOperands() == 1 && "can have at most 1 operand");
     O << " (extra operand: ";
     printOperands(O, SlotTracker);
     O << ")";

>From 47258deea863675e43fd7fd48376dce131441dc5 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Wed, 18 Sep 2024 21:35:57 +0100
Subject: [PATCH 02/18] [VPlan] Dispatch to multiple exit blocks via middle
 blocks.

A more lightweight variant of https://github.com/llvm/llvm-project/pull/109193,
which dispatches to multiple exit blocks via the middle blocks.
---
 .../Vectorize/LoopVectorizationLegality.h     |   3 +
 .../Vectorize/LoopVectorizationLegality.cpp   |  29 +++
 .../Transforms/Vectorize/LoopVectorize.cpp    |  82 +++---
 llvm/lib/Transforms/Vectorize/VPlan.cpp       |  39 ++-
 llvm/lib/Transforms/Vectorize/VPlan.h         |   1 +
 .../lib/Transforms/Vectorize/VPlanRecipes.cpp |  16 +-
 .../Transforms/Vectorize/VPlanTransforms.cpp  |  82 ++++++
 .../Transforms/Vectorize/VPlanTransforms.h    |   4 +
 .../Transforms/Vectorize/VPlanVerifier.cpp    |   8 -
 .../LoopVectorize/X86/multi-exit-codegen.ll   | 240 ++++++++++++++++++
 .../LoopVectorize/X86/multi-exit-cost.ll      |  18 +-
 .../LoopVectorize/X86/multi-exit-vplan.ll     | 148 +++++++++++
 12 files changed, 614 insertions(+), 56 deletions(-)
 create mode 100644 llvm/test/Transforms/LoopVectorize/X86/multi-exit-codegen.ll
 create mode 100644 llvm/test/Transforms/LoopVectorize/X86/multi-exit-vplan.ll

diff --git a/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h b/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h
index dc7e484a40a452..af6fae44cf0f09 100644
--- a/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h
+++ b/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h
@@ -287,6 +287,9 @@ class LoopVectorizationLegality {
   /// we can use in-order reductions.
   bool canVectorizeFPMath(bool EnableStrictReductions);
 
+  /// Returns true if the loop has an early exit that we can vectorize.
+  bool canVectorizeEarlyExit() const;
+
   /// Return true if we can vectorize this loop while folding its tail by
   /// masking.
   bool canFoldTailByMasking() const;
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
index 43be72f0f34d45..ee53d28a4c8282 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
@@ -43,6 +43,10 @@ AllowStridedPointerIVs("lv-strided-pointer-ivs", cl::init(false), cl::Hidden,
                        cl::desc("Enable recognition of non-constant strided "
                                 "pointer induction variables."));
 
+static cl::opt<bool>
+    EnableEarlyExitVectorization("enable-early-exit-vectorization",
+                                 cl::init(false), cl::Hidden, cl::desc(""));
+
 namespace llvm {
 cl::opt<bool>
     HintsAllowReordering("hints-allow-reordering", cl::init(true), cl::Hidden,
@@ -1378,6 +1382,10 @@ bool LoopVectorizationLegality::isFixedOrderRecurrence(
 }
 
 bool LoopVectorizationLegality::blockNeedsPredication(BasicBlock *BB) const {
+  // When vectorizing early exits, create predicates for all blocks, except the
+  // header.
+  if (canVectorizeEarlyExit() && BB != TheLoop->getHeader())
+    return true;
   return LoopAccessInfo::blockNeedsPredication(BB, TheLoop, DT);
 }
 
@@ -1514,6 +1522,27 @@ bool LoopVectorizationLegality::canVectorizeWithIfConvert() {
   return true;
 }
 
+bool LoopVectorizationLegality::canVectorizeEarlyExit() const {
+  // Currently only allow vectorizing loops with early exits, if early-exit
+  // vectorization is explicitly enabled and the loop has metadata to force
+  // vectorization.
+  if (!EnableEarlyExitVectorization)
+    return false;
+
+  SmallVector<BasicBlock *> Exiting;
+  TheLoop->getExitingBlocks(Exiting);
+  if (Exiting.size() == 1)
+    return false;
+
+  LoopVectorizeHints Hints(TheLoop, true, *ORE);
+  if (Hints.getForce() == LoopVectorizeHints::FK_Undefined)
+    return false;
+
+  Function *Fn = TheLoop->getHeader()->getParent();
+  return Hints.allowVectorization(Fn, TheLoop,
+                                  true /*VectorizeOnlyWhenForced*/);
+}
+
 // Helper function to canVectorizeLoopNestCFG.
 bool LoopVectorizationLegality::canVectorizeLoopCFG(Loop *Lp,
                                                     bool UseVPlanNativePath) {
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index e8653498d32a12..befe8f7c0076a3 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -1363,9 +1363,11 @@ class LoopVectorizationCostModel {
     // If we might exit from anywhere but the latch, must run the exiting
     // iteration in scalar form.
     if (TheLoop->getExitingBlock() != TheLoop->getLoopLatch()) {
-      LLVM_DEBUG(
-          dbgs() << "LV: Loop requires scalar epilogue: multiple exits\n");
-      return true;
+      if (!Legal->canVectorizeEarlyExit()) {
+        LLVM_DEBUG(
+            dbgs() << "LV: Loop requires scalar epilogue: multiple exits\n");
+        return true;
+      }
     }
     if (IsVectorizing && InterleaveInfo.requiresScalarEpilogue()) {
       LLVM_DEBUG(dbgs() << "LV: Loop requires scalar epilogue: "
@@ -2575,7 +2577,8 @@ void InnerLoopVectorizer::createVectorLoopSkeleton(StringRef Prefix) {
   LoopVectorPreHeader = OrigLoop->getLoopPreheader();
   assert(LoopVectorPreHeader && "Invalid loop structure");
   LoopExitBlock = OrigLoop->getUniqueExitBlock(); // may be nullptr
-  assert((LoopExitBlock || Cost->requiresScalarEpilogue(VF.isVector())) &&
+  assert((LoopExitBlock || Cost->requiresScalarEpilogue(VF.isVector()) ||
+          Legal->canVectorizeEarlyExit()) &&
          "multiple exit loop without required epilogue?");
 
   LoopMiddleBlock =
@@ -2758,8 +2761,6 @@ void InnerLoopVectorizer::fixupIVUsers(PHINode *OrigPhi,
   // value (the value that feeds into the phi from the loop latch).
   // We allow both, but they, obviously, have different values.
 
-  assert(OrigLoop->getUniqueExitBlock() && "Expected a single exit block");
-
   DenseMap<Value *, Value *> MissingVals;
 
   // An external user of the last iteration's value should see the value that
@@ -2819,6 +2820,9 @@ void InnerLoopVectorizer::fixupIVUsers(PHINode *OrigPhi,
     if (PHI->getBasicBlockIndex(MiddleBlock) == -1)
       PHI->addIncoming(I.second, MiddleBlock);
   }
+
+  assert((MissingVals.empty() || OrigLoop->getUniqueExitBlock()) &&
+         "Expected a single exit block");
 }
 
 namespace {
@@ -3599,7 +3603,8 @@ void LoopVectorizationCostModel::collectLoopUniforms(ElementCount VF) {
   TheLoop->getExitingBlocks(Exiting);
   for (BasicBlock *E : Exiting) {
     auto *Cmp = dyn_cast<Instruction>(E->getTerminator()->getOperand(0));
-    if (Cmp && TheLoop->contains(Cmp) && Cmp->hasOneUse())
+    if (Cmp && TheLoop->contains(Cmp) && Cmp->hasOneUse() &&
+        (TheLoop->getLoopLatch() == E || !Legal->canVectorizeEarlyExit()))
       AddToWorklistIfAllowed(Cmp);
   }
 
@@ -7692,12 +7697,15 @@ DenseMap<const SCEV *, Value *> LoopVectorizationPlanner::executePlan(
   BestVPlan.execute(&State);
 
   // 2.5 Collect reduction resume values.
-  auto *ExitVPBB =
-      cast<VPBasicBlock>(BestVPlan.getVectorLoopRegion()->getSingleSuccessor());
-  for (VPRecipeBase &R : *ExitVPBB) {
-    createAndCollectMergePhiForReduction(
-        dyn_cast<VPInstruction>(&R), State, OrigLoop,
-        State.CFG.VPBB2IRBB[ExitVPBB], ExpandedSCEVs);
+  VPBasicBlock *ExitVPBB = nullptr;
+  if (BestVPlan.getVectorLoopRegion()->getSingleSuccessor()) {
+    ExitVPBB = cast<VPBasicBlock>(
+        BestVPlan.getVectorLoopRegion()->getSingleSuccessor());
+    for (VPRecipeBase &R : *ExitVPBB) {
+      createAndCollectMergePhiForReduction(
+          dyn_cast<VPInstruction>(&R), State, OrigLoop,
+          State.CFG.VPBB2IRBB[ExitVPBB], ExpandedSCEVs);
+    }
   }
 
   // 2.6. Maintain Loop Hints
@@ -7723,6 +7731,7 @@ DenseMap<const SCEV *, Value *> LoopVectorizationPlanner::executePlan(
     LoopVectorizeHints Hints(L, true, *ORE);
     Hints.setAlreadyVectorized();
   }
+
   TargetTransformInfo::UnrollingPreferences UP;
   TTI.getUnrollingPreferences(L, *PSE.getSE(), UP, ORE);
   if (!UP.UnrollVectorizedLoop || CanonicalIVStartValue)
@@ -7735,15 +7744,17 @@ DenseMap<const SCEV *, Value *> LoopVectorizationPlanner::executePlan(
   ILV.printDebugTracesAtEnd();
 
   // 4. Adjust branch weight of the branch in the middle block.
-  auto *MiddleTerm =
-      cast<BranchInst>(State.CFG.VPBB2IRBB[ExitVPBB]->getTerminator());
-  if (MiddleTerm->isConditional() &&
-      hasBranchWeightMD(*OrigLoop->getLoopLatch()->getTerminator())) {
-    // Assume that `Count % VectorTripCount` is equally distributed.
-    unsigned TripCount = BestVPlan.getUF() * State.VF.getKnownMinValue();
-    assert(TripCount > 0 && "trip count should not be zero");
-    const uint32_t Weights[] = {1, TripCount - 1};
-    setBranchWeights(*MiddleTerm, Weights, /*IsExpected=*/false);
+  if (ExitVPBB) {
+    auto *MiddleTerm =
+        cast<BranchInst>(State.CFG.VPBB2IRBB[ExitVPBB]->getTerminator());
+    if (MiddleTerm->isConditional() &&
+        hasBranchWeightMD(*OrigLoop->getLoopLatch()->getTerminator())) {
+      // Assume that `Count % VectorTripCount` is equally distributed.
+      unsigned TripCount = BestVPlan.getUF() * State.VF.getKnownMinValue();
+      assert(TripCount > 0 && "trip count should not be zero");
+      const uint32_t Weights[] = {1, TripCount - 1};
+      setBranchWeights(*MiddleTerm, Weights, /*IsExpected=*/false);
+    }
   }
 
   return State.ExpandedSCEVs;
@@ -8128,7 +8139,7 @@ VPValue *VPRecipeBuilder::createEdgeMask(BasicBlock *Src, BasicBlock *Dst) {
   // If source is an exiting block, we know the exit edge is dynamically dead
   // in the vector loop, and thus we don't need to restrict the mask.  Avoid
   // adding uses of an otherwise potentially dead instruction.
-  if (OrigLoop->isLoopExiting(Src))
+  if (!Legal->canVectorizeEarlyExit() && OrigLoop->isLoopExiting(Src))
     return EdgeMaskCache[Edge] = SrcMask;
 
   VPValue *EdgeMask = getVPValueOrAddLiveIn(BI->getCondition());
@@ -8778,6 +8789,8 @@ static void addCanonicalIVRecipes(VPlan &Plan, Type *IdxTy, bool HasNUW,
 static SetVector<VPIRInstruction *> collectUsersInExitBlock(
     Loop *OrigLoop, VPRecipeBuilder &Builder, VPlan &Plan,
     const MapVector<PHINode *, InductionDescriptor> &Inductions) {
+  if (!Plan.getVectorLoopRegion()->getSingleSuccessor())
+    return {};
   auto *MiddleVPBB =
       cast<VPBasicBlock>(Plan.getVectorLoopRegion()->getSingleSuccessor());
   // No edge from the middle block to the unique exit block has been inserted
@@ -8863,6 +8876,8 @@ static void addLiveOutsForFirstOrderRecurrences(
   // TODO: Should be replaced by
   // Plan->getScalarLoopRegion()->getSinglePredecessor() in the future once the
   // scalar region is modeled as well.
+  if (!VectorRegion->getSingleSuccessor())
+    return;
   auto *MiddleVPBB = cast<VPBasicBlock>(VectorRegion->getSingleSuccessor());
   VPBasicBlock *ScalarPHVPBB = nullptr;
   if (MiddleVPBB->getNumSuccessors() == 2) {
@@ -9146,10 +9161,15 @@ LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(VFRange &Range) {
          "VPBasicBlock");
   RecipeBuilder.fixHeaderPhis();
 
-  SetVector<VPIRInstruction *> ExitUsersToFix = collectUsersInExitBlock(
-      OrigLoop, RecipeBuilder, *Plan, Legal->getInductionVars());
-  addLiveOutsForFirstOrderRecurrences(*Plan, ExitUsersToFix);
-  addUsersInExitBlock(*Plan, ExitUsersToFix);
+  if (Legal->canVectorizeEarlyExit()) {
+    VPlanTransforms::convertToMultiCond(*Plan, *PSE.getSE(), OrigLoop,
+                                        RecipeBuilder);
+  } else {
+    SetVector<VPIRInstruction *> ExitUsersToFix = collectUsersInExitBlock(
+        OrigLoop, RecipeBuilder, *Plan, Legal->getInductionVars());
+    addLiveOutsForFirstOrderRecurrences(*Plan, ExitUsersToFix);
+    addUsersInExitBlock(*Plan, ExitUsersToFix);
+  }
 
   // ---------------------------------------------------------------------------
   // Transform initial VPlan: Apply previously taken decisions, in order, to
@@ -9277,8 +9297,6 @@ void LoopVectorizationPlanner::adjustRecipesForReductions(
   using namespace VPlanPatternMatch;
   VPRegionBlock *VectorLoopRegion = Plan->getVectorLoopRegion();
   VPBasicBlock *Header = VectorLoopRegion->getEntryBasicBlock();
-  VPBasicBlock *MiddleVPBB =
-      cast<VPBasicBlock>(VectorLoopRegion->getSingleSuccessor());
   for (VPRecipeBase &R : Header->phis()) {
     auto *PhiR = dyn_cast<VPReductionPHIRecipe>(&R);
     if (!PhiR || !PhiR->isInLoop() || (MinVF.isScalar() && !PhiR->isOrdered()))
@@ -9297,8 +9315,6 @@ void LoopVectorizationPlanner::adjustRecipesForReductions(
       for (VPUser *U : Cur->users()) {
         auto *UserRecipe = cast<VPSingleDefRecipe>(U);
         if (!UserRecipe->getParent()->getEnclosingLoopRegion()) {
-          assert(UserRecipe->getParent() == MiddleVPBB &&
-                 "U must be either in the loop region or the middle block.");
           continue;
         }
         Worklist.insert(UserRecipe);
@@ -9403,6 +9419,10 @@ void LoopVectorizationPlanner::adjustRecipesForReductions(
   }
   VPBasicBlock *LatchVPBB = VectorLoopRegion->getExitingBasicBlock();
   Builder.setInsertPoint(&*LatchVPBB->begin());
+  if (!VectorLoopRegion->getSingleSuccessor())
+    return;
+  VPBasicBlock *MiddleVPBB =
+      cast<VPBasicBlock>(VectorLoopRegion->getSingleSuccessor());
   VPBasicBlock::iterator IP = MiddleVPBB->getFirstNonPhi();
   for (VPRecipeBase &R :
        Plan->getVectorLoopRegion()->getEntryBasicBlock()->phis()) {
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp
index 8609514c39e7d0..eb7c808551340d 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp
@@ -474,6 +474,14 @@ void VPIRBasicBlock::execute(VPTransformState *State) {
     // backedges. A backward successor is set when the branch is created.
     const auto &PredVPSuccessors = PredVPBB->getHierarchicalSuccessors();
     unsigned idx = PredVPSuccessors.front() == this ? 0 : 1;
+    if (TermBr->getSuccessor(idx) &&
+        PredVPBlock == getPlan()->getVectorLoopRegion() &&
+        PredVPBlock->getNumSuccessors()) {
+      // Update PRedBB and TermBr for BranchOnMultiCond in predecessor.
+      PredBB = TermBr->getSuccessor(1);
+      TermBr = cast<BranchInst>(PredBB->getTerminator());
+      idx = 0;
+    }
     assert(!TermBr->getSuccessor(idx) &&
            "Trying to reset an existing successor block.");
     TermBr->setSuccessor(idx, IRBB);
@@ -908,8 +916,8 @@ VPlanPtr VPlan::createInitialVPlan(Type *InductionTy,
   VPBasicBlock *MiddleVPBB = new VPBasicBlock("middle.block");
   VPBlockUtils::insertBlockAfter(MiddleVPBB, TopRegion);
 
-  VPBasicBlock *ScalarPH = new VPBasicBlock("scalar.ph");
   if (!RequiresScalarEpilogueCheck) {
+    VPBasicBlock *ScalarPH = new VPBasicBlock("scalar.ph");
     VPBlockUtils::connectBlocks(MiddleVPBB, ScalarPH);
     return Plan;
   }
@@ -923,10 +931,14 @@ VPlanPtr VPlan::createInitialVPlan(Type *InductionTy,
   //    we unconditionally branch to the scalar preheader.  Do nothing.
   // 3) Otherwise, construct a runtime check.
   BasicBlock *IRExitBlock = TheLoop->getUniqueExitBlock();
-  auto *VPExitBlock = VPIRBasicBlock::fromBasicBlock(IRExitBlock);
-  // The connection order corresponds to the operands of the conditional branch.
-  VPBlockUtils::insertBlockAfter(VPExitBlock, MiddleVPBB);
-  VPBlockUtils::connectBlocks(MiddleVPBB, ScalarPH);
+  if (IRExitBlock) {
+    auto *VPExitBlock = VPIRBasicBlock::fromBasicBlock(IRExitBlock);
+    // The connection order corresponds to the operands of the conditional
+    // branch.
+    VPBlockUtils::insertBlockAfter(VPExitBlock, MiddleVPBB);
+    VPBasicBlock *ScalarPH = new VPBasicBlock("scalar.ph");
+    VPBlockUtils::connectBlocks(MiddleVPBB, ScalarPH);
+  }
 
   auto *ScalarLatchTerm = TheLoop->getLoopLatch()->getTerminator();
   // Here we use the same DebugLoc as the scalar loop latch terminator instead
@@ -1031,7 +1043,9 @@ void VPlan::execute(VPTransformState *State) {
   // VPlan execution rather than earlier during VPlan construction.
   BasicBlock *MiddleBB = State->CFG.ExitBB;
   VPBasicBlock *MiddleVPBB =
-      cast<VPBasicBlock>(getVectorLoopRegion()->getSingleSuccessor());
+      getVectorLoopRegion()->getNumSuccessors() == 1
+          ? cast<VPBasicBlock>(getVectorLoopRegion()->getSuccessors()[0])
+          : cast<VPBasicBlock>(getVectorLoopRegion()->getSuccessors()[1]);
   // Find the VPBB for the scalar preheader, relying on the current structure
   // when creating the middle block and its successrs: if there's a single
   // predecessor, it must be the scalar preheader. Otherwise, the second
@@ -1044,6 +1058,10 @@ void VPlan::execute(VPTransformState *State) {
       MiddleSuccs.size() == 1 ? MiddleSuccs[0] : MiddleSuccs[1]);
   assert(!isa<VPIRBasicBlock>(ScalarPhVPBB) &&
          "scalar preheader cannot be wrapped already");
+  if (ScalarPhVPBB->getNumSuccessors() != 0) {
+    ScalarPhVPBB = cast<VPBasicBlock>(ScalarPhVPBB->getSuccessors()[1]);
+    MiddleVPBB = cast<VPBasicBlock>(MiddleVPBB->getSuccessors()[1]);
+  }
   replaceVPBBWithIRVPBB(ScalarPhVPBB, ScalarPh);
   replaceVPBBWithIRVPBB(MiddleVPBB, MiddleBB);
 
@@ -1065,6 +1083,10 @@ void VPlan::execute(VPTransformState *State) {
   VPBasicBlock *LatchVPBB = getVectorLoopRegion()->getExitingBasicBlock();
   BasicBlock *VectorLatchBB = State->CFG.VPBB2IRBB[LatchVPBB];
 
+  if (!getVectorLoopRegion()->getSingleSuccessor())
+    VectorLatchBB =
+        cast<BranchInst>(VectorLatchBB->getTerminator())->getSuccessor(1);
+
   // Fix the latch value of canonical, reduction and first-order recurrences
   // phis in the vector loop.
   VPBasicBlock *Header = getVectorLoopRegion()->getEntryBasicBlock();
@@ -1091,7 +1113,10 @@ void VPlan::execute(VPTransformState *State) {
       // Move the last step to the end of the latch block. This ensures
       // consistent placement of all induction updates.
       Instruction *Inc = cast<Instruction>(Phi->getIncomingValue(1));
-      Inc->moveBefore(VectorLatchBB->getTerminator()->getPrevNode());
+      if (VectorLatchBB->getTerminator() == &*VectorLatchBB->getFirstNonPHI())
+        Inc->moveBefore(VectorLatchBB->getTerminator());
+      else
+        Inc->moveBefore(VectorLatchBB->getTerminator()->getPrevNode());
 
       // Use the steps for the last part as backedge value for the induction.
       if (auto *IV = dyn_cast<VPWidenIntOrFpInductionRecipe>(&R))
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 59a084401cc9bf..21f44eac188936 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -1274,6 +1274,7 @@ class VPInstruction : public VPRecipeWithIRFlags,
     // operand). Only generates scalar values (either for the first lane only or
     // for all lanes, depending on its uses).
     PtrAdd,
+    AnyOf,
   };
 
 private:
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index be3e958320e771..9d5c609ad26043 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -67,6 +67,8 @@ bool VPRecipeBase::mayWriteToMemory() const {
     default:
       return true;
     }
+  case VPExpandSCEVSC:
+    return getParent()->getPlan()->getTripCount() == getVPSingleValue();
   case VPInterleaveSC:
     return cast<VPInterleaveRecipe>(this)->getNumStoreOperands() > 0;
   case VPWidenStoreEVLSC:
@@ -160,6 +162,8 @@ bool VPRecipeBase::mayHaveSideEffects() const {
   case VPPredInstPHISC:
   case VPScalarCastSC:
     return false;
+  case VPExpandSCEVSC:
+    return getParent()->getPlan()->getTripCount() == getVPSingleValue();
   case VPInstructionSC:
     return mayWriteToMemory();
   case VPWidenCallSC: {
@@ -399,6 +403,7 @@ bool VPInstruction::canGenerateScalarForFirstLane() const {
   case VPInstruction::CanonicalIVIncrementForPart:
   case VPInstruction::PtrAdd:
   case VPInstruction::ExplicitVectorLength:
+  case VPInstruction::AnyOf:
     return true;
   default:
     return false;
@@ -674,6 +679,10 @@ Value *VPInstruction::generate(VPTransformState &State) {
     }
     return NewPhi;
   }
+  case VPInstruction::AnyOf: {
+    Value *A = State.get(getOperand(0));
+    return Builder.CreateOrReduce(A);
+  }
 
   default:
     llvm_unreachable("Unsupported opcode for instruction");
@@ -682,7 +691,8 @@ Value *VPInstruction::generate(VPTransformState &State) {
 
 bool VPInstruction::isVectorToScalar() const {
   return getOpcode() == VPInstruction::ExtractFromEnd ||
-         getOpcode() == VPInstruction::ComputeReductionResult;
+         getOpcode() == VPInstruction::ComputeReductionResult ||
+         getOpcode() == VPInstruction::AnyOf;
 }
 
 bool VPInstruction::isSingleScalar() const {
@@ -745,6 +755,7 @@ bool VPInstruction::onlyFirstLaneUsed(const VPValue *Op) const {
     return false;
   case Instruction::ICmp:
   case Instruction::Select:
+  case Instruction::Or:
   case VPInstruction::PtrAdd:
     // TODO: Cover additional opcodes.
     return vputils::onlyFirstLaneUsed(this);
@@ -840,6 +851,9 @@ void VPInstruction::print(raw_ostream &O, const Twine &Indent,
   case VPInstruction::PtrAdd:
     O << "ptradd";
     break;
+  case VPInstruction::AnyOf:
+    O << "any-of";
+    break;
   default:
     O << Instruction::getOpcodeName(getOpcode());
   }
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index d50f3c0c3f3e04..a86498eb9aa30c 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -515,6 +515,12 @@ void VPlanTransforms::removeDeadRecipes(VPlan &Plan) {
   ReversePostOrderTraversal<VPBlockDeepTraversalWrapper<VPBlockBase *>> RPOT(
       Plan.getEntry());
 
+  for (VPRecipeBase &R : make_early_inc_range(
+           reverse(*cast<VPBasicBlock>(Plan.getPreheader())))) {
+    if (isDeadRecipe(R))
+      R.eraseFromParent();
+  }
+
   for (VPBasicBlock *VPBB : reverse(VPBlockUtils::blocksOnly<VPBasicBlock>(RPOT))) {
     // The recipes in the block are processed in reverse order, to catch chains
     // of dead recipes.
@@ -1696,3 +1702,79 @@ void VPlanTransforms::createInterleaveGroups(
       }
   }
 }
+
+void VPlanTransforms::convertToMultiCond(VPlan &Plan, ScalarEvolution &SE,
+                                         Loop *OrigLoop,
+                                         VPRecipeBuilder &RecipeBuilder) {
+  auto *LatchVPBB =
+      cast<VPBasicBlock>(Plan.getVectorLoopRegion()->getExiting());
+  VPBuilder Builder(LatchVPBB->getTerminator());
+  auto *MiddleVPBB =
+      cast<VPBasicBlock>(Plan.getVectorLoopRegion()->getSingleSuccessor());
+
+  VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
+
+  const SCEV *BackedgeTakenCount =
+      SE.getExitCount(OrigLoop, OrigLoop->getLoopLatch());
+  const SCEV *TripCount = SE.getTripCountFromExitCount(
+      BackedgeTakenCount, Plan.getCanonicalIV()->getScalarType(), OrigLoop);
+  VPValue *NewTC = vputils::getOrCreateVPValueForSCEVExpr(Plan, TripCount, SE);
+  Plan.getTripCount()->replaceAllUsesWith(NewTC);
+  Plan.resetTripCount(NewTC);
+
+  VPValue *EarlyExitTaken = nullptr;
+  SmallVector<BasicBlock *> ExitingBBs;
+  OrigLoop->getExitingBlocks(ExitingBBs);
+  for (BasicBlock *Exiting : ExitingBBs) {
+    auto *ExitingTerm = cast<BranchInst>(Exiting->getTerminator());
+    BasicBlock *TrueSucc = ExitingTerm->getSuccessor(0);
+    BasicBlock *FalseSucc = ExitingTerm->getSuccessor(1);
+    VPIRBasicBlock *VPExitBlock;
+    if (OrigLoop->getUniqueExitBlock())
+      VPExitBlock = cast<VPIRBasicBlock>(MiddleVPBB->getSuccessors()[0]);
+    else
+      VPExitBlock = VPIRBasicBlock::fromBasicBlock(
+          !OrigLoop->contains(TrueSucc) ? TrueSucc : FalseSucc);
+
+    for (VPRecipeBase &R : *VPExitBlock) {
+      auto *ExitIRI = cast<VPIRInstruction>(&R);
+      auto *ExitPhi = dyn_cast<PHINode>(&ExitIRI->getInstruction());
+      if (!ExitPhi)
+        break;
+      Value *IncomingValue = ExitPhi->getIncomingValueForBlock(Exiting);
+      VPValue *V = RecipeBuilder.getVPValueOrAddLiveIn(IncomingValue);
+      ExitIRI->addOperand(V);
+    }
+
+    if (Exiting == OrigLoop->getLoopLatch()) {
+      if (MiddleVPBB->getNumSuccessors() == 0) {
+        VPBasicBlock *ScalarPH = new VPBasicBlock("scalar.ph");
+        VPBlockUtils::connectBlocks(MiddleVPBB, VPExitBlock);
+        VPBlockUtils::connectBlocks(MiddleVPBB, ScalarPH);
+      }
+      continue;
+    }
+
+    VPValue *M = RecipeBuilder.getBlockInMask(
+        OrigLoop->contains(TrueSucc) ? TrueSucc : FalseSucc);
+    auto *N = Builder.createNot(M);
+    EarlyExitTaken = Builder.createNaryOp(VPInstruction::AnyOf, {N});
+
+    VPBasicBlock *NewMiddle = new VPBasicBlock("middle.split");
+    VPBlockUtils::disconnectBlocks(LoopRegion, MiddleVPBB);
+    VPBlockUtils::insertBlockAfter(NewMiddle, LoopRegion);
+    VPBlockUtils::connectBlocks(NewMiddle, VPExitBlock);
+    VPBlockUtils::connectBlocks(NewMiddle, MiddleVPBB);
+
+    VPBuilder MiddleBuilder(NewMiddle);
+    MiddleBuilder.createNaryOp(VPInstruction::BranchOnCond, {EarlyExitTaken});
+    // MiddleVPBB = NewMiddle;
+  }
+  auto *Term = dyn_cast<VPInstruction>(LatchVPBB->getTerminator());
+  auto *IsLatchExiting = Builder.createICmp(
+      CmpInst::ICMP_EQ, Term->getOperand(0), Term->getOperand(1));
+  auto *AnyExiting =
+      Builder.createNaryOp(Instruction::Or, {EarlyExitTaken, IsLatchExiting});
+  Builder.createNaryOp(VPInstruction::BranchOnCond, AnyExiting);
+  Term->eraseFromParent();
+}
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.h b/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
index 60a44bfb0dca6b..9745211db275f0 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
@@ -123,6 +123,10 @@ struct VPlanTransforms {
 
   /// Remove dead recipes from \p Plan.
   static void removeDeadRecipes(VPlan &Plan);
+
+  static void convertToMultiCond(VPlan &Plan, ScalarEvolution &SE,
+                                 Loop *OrigLoop,
+                                 VPRecipeBuilder &RecipeBuilder);
 };
 
 } // namespace llvm
diff --git a/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp b/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp
index 7ea5ee341cc547..1ac79f8887ab46 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp
@@ -248,14 +248,6 @@ bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) {
     return false;
   }
 
-  VPBlockBase *MiddleBB =
-      IRBB->getPlan()->getVectorLoopRegion()->getSingleSuccessor();
-  if (IRBB != IRBB->getPlan()->getPreheader() &&
-      IRBB->getSinglePredecessor() != MiddleBB) {
-    errs() << "VPIRBasicBlock can only be used as pre-header or a successor of "
-              "middle-block at the moment!\n";
-    return false;
-  }
   return true;
 }
 
diff --git a/llvm/test/Transforms/LoopVectorize/X86/multi-exit-codegen.ll b/llvm/test/Transforms/LoopVectorize/X86/multi-exit-codegen.ll
new file mode 100644
index 00000000000000..0c33715c6bd271
--- /dev/null
+++ b/llvm/test/Transforms/LoopVectorize/X86/multi-exit-codegen.ll
@@ -0,0 +1,240 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -p loop-vectorize -mcpu=skylake-avx512 -mtriple=x86_64-apple-macosx -force-vector-interleave=1 -S -enable-early-exit-vectorization %s | FileCheck --check-prefix=MULTI %s
+; RUN: opt -p loop-vectorize -mcpu=skylake-avx512 -mtriple=x86_64-apple-macosx -force-vector-interleave=1 -S -enable-early-exit-vectorization=false %s | FileCheck --check-prefix=DEFAULT %s
+
+define i64 @multi_exit_with_store(ptr %p, i64 %N) {
+; MULTI-LABEL: define i64 @multi_exit_with_store(
+; MULTI-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) #[[ATTR0:[0-9]+]] {
+; MULTI-NEXT:  [[ENTRY:.*]]:
+; MULTI-NEXT:    br i1 false, label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
+; MULTI:       [[VECTOR_PH]]:
+; MULTI-NEXT:    [[BROADCAST_SPLATINSERT:%.*]] = insertelement <4 x i64> poison, i64 [[N]], i64 0
+; MULTI-NEXT:    [[BROADCAST_SPLAT:%.*]] = shufflevector <4 x i64> [[BROADCAST_SPLATINSERT]], <4 x i64> poison, <4 x i32> zeroinitializer
+; MULTI-NEXT:    br label %[[VECTOR_BODY:.*]]
+; MULTI:       [[VECTOR_BODY]]:
+; MULTI-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]
+; MULTI-NEXT:    [[VEC_IND:%.*]] = phi <4 x i64> [ <i64 0, i64 1, i64 2, i64 3>, %[[VECTOR_PH]] ], [ [[VEC_IND_NEXT:%.*]], %[[VECTOR_BODY]] ]
+; MULTI-NEXT:    [[TMP0:%.*]] = add i64 [[INDEX]], 0
+; MULTI-NEXT:    [[TMP1:%.*]] = icmp uge <4 x i64> [[VEC_IND]], [[BROADCAST_SPLAT]]
+; MULTI-NEXT:    [[TMP2:%.*]] = xor <4 x i1> [[TMP1]], <i1 true, i1 true, i1 true, i1 true>
+; MULTI-NEXT:    [[TMP3:%.*]] = getelementptr i32, ptr [[P]], i64 [[TMP0]]
+; MULTI-NEXT:    [[TMP4:%.*]] = getelementptr i32, ptr [[TMP3]], i32 0
+; MULTI-NEXT:    call void @llvm.masked.store.v4i32.p0(<4 x i32> zeroinitializer, ptr [[TMP4]], i32 4, <4 x i1> [[TMP2]])
+; MULTI-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
+; MULTI-NEXT:    [[TMP5:%.*]] = xor <4 x i1> [[TMP2]], <i1 true, i1 true, i1 true, i1 true>
+; MULTI-NEXT:    [[TMP6:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP5]])
+; MULTI-NEXT:    [[TMP7:%.*]] = icmp eq i64 [[INDEX_NEXT]], 128
+; MULTI-NEXT:    [[VEC_IND_NEXT]] = add <4 x i64> [[VEC_IND]], <i64 4, i64 4, i64 4, i64 4>
+; MULTI-NEXT:    [[TMP8:%.*]] = or i1 [[TMP6]], [[TMP7]]
+; MULTI-NEXT:    br i1 [[TMP8]], label %[[MIDDLE_SPLIT:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP0:![0-9]+]]
+; MULTI:       [[MIDDLE_SPLIT]]:
+; MULTI-NEXT:    br i1 [[TMP6]], label %[[E1:.*]], label %[[MIDDLE_BLOCK:.*]]
+; MULTI:       [[MIDDLE_BLOCK]]:
+; MULTI-NEXT:    br i1 true, label %[[E2:.*]], label %[[SCALAR_PH]]
+; MULTI:       [[SCALAR_PH]]:
+; MULTI-NEXT:    [[BC_RESUME_VAL:%.*]] = phi i64 [ 128, %[[MIDDLE_BLOCK]] ], [ 0, %[[ENTRY]] ]
+; MULTI-NEXT:    br label %[[LOOP_HEADER:.*]]
+; MULTI:       [[LOOP_HEADER]]:
+; MULTI-NEXT:    [[I_07:%.*]] = phi i64 [ [[INC:%.*]], %[[LOOP_LATCH:.*]] ], [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ]
+; MULTI-NEXT:    [[CMP1:%.*]] = icmp uge i64 [[I_07]], [[N]]
+; MULTI-NEXT:    br i1 [[CMP1]], label %[[E1]], label %[[LOOP_LATCH]]
+; MULTI:       [[LOOP_LATCH]]:
+; MULTI-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i32, ptr [[P]], i64 [[I_07]]
+; MULTI-NEXT:    store i32 0, ptr [[ARRAYIDX]], align 4
+; MULTI-NEXT:    [[INC]] = add nuw i64 [[I_07]], 1
+; MULTI-NEXT:    [[CMP_NOT:%.*]] = icmp eq i64 [[INC]], 128
+; MULTI-NEXT:    br i1 [[CMP_NOT]], label %[[E2]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP3:![0-9]+]]
+; MULTI:       [[E1]]:
+; MULTI-NEXT:    ret i64 0
+; MULTI:       [[E2]]:
+; MULTI-NEXT:    ret i64 1
+;
+; DEFAULT-LABEL: define i64 @multi_exit_with_store(
+; DEFAULT-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) #[[ATTR0:[0-9]+]] {
+; DEFAULT-NEXT:  [[ENTRY:.*]]:
+; DEFAULT-NEXT:    [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[N]], i64 127)
+; DEFAULT-NEXT:    [[TMP4:%.*]] = add nuw nsw i64 [[UMIN]], 1
+; DEFAULT-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ule i64 [[TMP4]], 4
+; DEFAULT-NEXT:    br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
+; DEFAULT:       [[VECTOR_PH]]:
+; DEFAULT-NEXT:    [[N_MOD_VF:%.*]] = urem i64 [[TMP4]], 4
+; DEFAULT-NEXT:    [[TMP5:%.*]] = icmp eq i64 [[N_MOD_VF]], 0
+; DEFAULT-NEXT:    [[TMP2:%.*]] = select i1 [[TMP5]], i64 4, i64 [[N_MOD_VF]]
+; DEFAULT-NEXT:    [[N_VEC:%.*]] = sub i64 [[TMP4]], [[TMP2]]
+; DEFAULT-NEXT:    br label %[[VECTOR_BODY:.*]]
+; DEFAULT:       [[VECTOR_BODY]]:
+; DEFAULT-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]
+; DEFAULT-NEXT:    [[TMP0:%.*]] = add i64 [[INDEX]], 0
+; DEFAULT-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[P]], i64 [[TMP0]]
+; DEFAULT-NEXT:    [[TMP3:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i32 0
+; DEFAULT-NEXT:    store <4 x i32> zeroinitializer, ptr [[TMP3]], align 4
+; DEFAULT-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
+; DEFAULT-NEXT:    [[TMP6:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
+; DEFAULT-NEXT:    br i1 [[TMP6]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP0:![0-9]+]]
+; DEFAULT:       [[MIDDLE_BLOCK]]:
+; DEFAULT-NEXT:    br label %[[SCALAR_PH]]
+; DEFAULT:       [[SCALAR_PH]]:
+; DEFAULT-NEXT:    [[BC_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], %[[MIDDLE_BLOCK]] ], [ 0, %[[ENTRY]] ]
+; DEFAULT-NEXT:    br label %[[LOOP_HEADER:.*]]
+; DEFAULT:       [[LOOP_HEADER]]:
+; DEFAULT-NEXT:    [[I_07:%.*]] = phi i64 [ [[INC:%.*]], %[[LOOP_LATCH:.*]] ], [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ]
+; DEFAULT-NEXT:    [[CMP1:%.*]] = icmp uge i64 [[I_07]], [[N]]
+; DEFAULT-NEXT:    br i1 [[CMP1]], label %[[E1:.*]], label %[[LOOP_LATCH]]
+; DEFAULT:       [[LOOP_LATCH]]:
+; DEFAULT-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i32, ptr [[P]], i64 [[I_07]]
+; DEFAULT-NEXT:    store i32 0, ptr [[ARRAYIDX]], align 4
+; DEFAULT-NEXT:    [[INC]] = add nuw i64 [[I_07]], 1
+; DEFAULT-NEXT:    [[CMP_NOT:%.*]] = icmp eq i64 [[INC]], 128
+; DEFAULT-NEXT:    br i1 [[CMP_NOT]], label %[[E2:.*]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP3:![0-9]+]]
+; DEFAULT:       [[E1]]:
+; DEFAULT-NEXT:    ret i64 0
+; DEFAULT:       [[E2]]:
+; DEFAULT-NEXT:    ret i64 1
+;
+entry:
+  br label %loop.header
+
+loop.header:
+  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
+  %c.1 = icmp uge i64 %iv, %N
+  br i1 %c.1, label %e1, label %loop.latch
+
+loop.latch:
+  %arrayidx = getelementptr inbounds nuw i32, ptr %p, i64 %iv
+  store i32 0, ptr %arrayidx
+  %inc = add nuw i64 %iv, 1
+  %c.2 = icmp eq i64 %inc, 128
+  br i1 %c.2, label %e2, label %loop.header, !llvm.loop !1
+
+e1:
+  ret i64 0
+
+e2:
+  ret i64 1
+}
+
+define i64 @multi_exiting_to_same_exit_with_store(ptr %p, i64 %N) {
+; MULTI-LABEL: define i64 @multi_exiting_to_same_exit_with_store(
+; MULTI-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) #[[ATTR0]] {
+; MULTI-NEXT:  [[ENTRY:.*]]:
+; MULTI-NEXT:    br i1 false, label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
+; MULTI:       [[VECTOR_PH]]:
+; MULTI-NEXT:    [[BROADCAST_SPLATINSERT:%.*]] = insertelement <4 x i64> poison, i64 [[N]], i64 0
+; MULTI-NEXT:    [[BROADCAST_SPLAT:%.*]] = shufflevector <4 x i64> [[BROADCAST_SPLATINSERT]], <4 x i64> poison, <4 x i32> zeroinitializer
+; MULTI-NEXT:    br label %[[VECTOR_BODY:.*]]
+; MULTI:       [[VECTOR_BODY]]:
+; MULTI-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]
+; MULTI-NEXT:    [[VEC_IND:%.*]] = phi <4 x i64> [ <i64 0, i64 1, i64 2, i64 3>, %[[VECTOR_PH]] ], [ [[VEC_IND_NEXT:%.*]], %[[VECTOR_BODY]] ]
+; MULTI-NEXT:    [[TMP0:%.*]] = add i64 [[INDEX]], 0
+; MULTI-NEXT:    [[TMP1:%.*]] = icmp uge <4 x i64> [[VEC_IND]], [[BROADCAST_SPLAT]]
+; MULTI-NEXT:    [[TMP2:%.*]] = xor <4 x i1> [[TMP1]], <i1 true, i1 true, i1 true, i1 true>
+; MULTI-NEXT:    [[TMP3:%.*]] = getelementptr i32, ptr [[P]], i64 [[TMP0]]
+; MULTI-NEXT:    [[TMP4:%.*]] = getelementptr i32, ptr [[TMP3]], i32 0
+; MULTI-NEXT:    call void @llvm.masked.store.v4i32.p0(<4 x i32> zeroinitializer, ptr [[TMP4]], i32 4, <4 x i1> [[TMP2]])
+; MULTI-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
+; MULTI-NEXT:    [[TMP5:%.*]] = xor <4 x i1> [[TMP2]], <i1 true, i1 true, i1 true, i1 true>
+; MULTI-NEXT:    [[TMP6:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP5]])
+; MULTI-NEXT:    [[TMP7:%.*]] = icmp eq i64 [[INDEX_NEXT]], 128
+; MULTI-NEXT:    [[VEC_IND_NEXT]] = add <4 x i64> [[VEC_IND]], <i64 4, i64 4, i64 4, i64 4>
+; MULTI-NEXT:    [[TMP8:%.*]] = or i1 [[TMP6]], [[TMP7]]
+; MULTI-NEXT:    br i1 [[TMP8]], label %[[MIDDLE_SPLIT:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP4:![0-9]+]]
+; MULTI:       [[MIDDLE_SPLIT]]:
+; MULTI-NEXT:    br i1 [[TMP6]], label %[[E:.*]], label %[[MIDDLE_BLOCK:.*]]
+; MULTI:       [[MIDDLE_BLOCK]]:
+; MULTI-NEXT:    br i1 true, label %[[E]], label %[[SCALAR_PH]]
+; MULTI:       [[SCALAR_PH]]:
+; MULTI-NEXT:    [[BC_RESUME_VAL:%.*]] = phi i64 [ 128, %[[MIDDLE_BLOCK]] ], [ 0, %[[ENTRY]] ]
+; MULTI-NEXT:    br label %[[LOOP_HEADER:.*]]
+; MULTI:       [[LOOP_HEADER]]:
+; MULTI-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], %[[LOOP_LATCH:.*]] ], [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ]
+; MULTI-NEXT:    [[C_1:%.*]] = icmp uge i64 [[IV]], [[N]]
+; MULTI-NEXT:    br i1 [[C_1]], label %[[E]], label %[[LOOP_LATCH]]
+; MULTI:       [[LOOP_LATCH]]:
+; MULTI-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i32, ptr [[P]], i64 [[IV]]
+; MULTI-NEXT:    store i32 0, ptr [[ARRAYIDX]], align 4
+; MULTI-NEXT:    [[INC]] = add nuw i64 [[IV]], 1
+; MULTI-NEXT:    [[C_2:%.*]] = icmp eq i64 [[INC]], 128
+; MULTI-NEXT:    br i1 [[C_2]], label %[[E]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP5:![0-9]+]]
+; MULTI:       [[E]]:
+; MULTI-NEXT:    [[P1:%.*]] = phi i64 [ 0, %[[LOOP_HEADER]] ], [ 1, %[[LOOP_LATCH]] ], [ 0, %[[MIDDLE_BLOCK]] ], [ 1, %[[MIDDLE_SPLIT]] ]
+; MULTI-NEXT:    ret i64 [[P1]]
+;
+; DEFAULT-LABEL: define i64 @multi_exiting_to_same_exit_with_store(
+; DEFAULT-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) #[[ATTR0]] {
+; DEFAULT-NEXT:  [[ENTRY:.*]]:
+; DEFAULT-NEXT:    [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[N]], i64 127)
+; DEFAULT-NEXT:    [[TMP0:%.*]] = add nuw nsw i64 [[UMIN]], 1
+; DEFAULT-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ule i64 [[TMP0]], 4
+; DEFAULT-NEXT:    br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
+; DEFAULT:       [[VECTOR_PH]]:
+; DEFAULT-NEXT:    [[N_MOD_VF:%.*]] = urem i64 [[TMP0]], 4
+; DEFAULT-NEXT:    [[TMP1:%.*]] = icmp eq i64 [[N_MOD_VF]], 0
+; DEFAULT-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i64 4, i64 [[N_MOD_VF]]
+; DEFAULT-NEXT:    [[N_VEC:%.*]] = sub i64 [[TMP0]], [[TMP2]]
+; DEFAULT-NEXT:    br label %[[VECTOR_BODY:.*]]
+; DEFAULT:       [[VECTOR_BODY]]:
+; DEFAULT-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]
+; DEFAULT-NEXT:    [[TMP3:%.*]] = add i64 [[INDEX]], 0
+; DEFAULT-NEXT:    [[TMP4:%.*]] = getelementptr inbounds i32, ptr [[P]], i64 [[TMP3]]
+; DEFAULT-NEXT:    [[TMP5:%.*]] = getelementptr inbounds i32, ptr [[TMP4]], i32 0
+; DEFAULT-NEXT:    store <4 x i32> zeroinitializer, ptr [[TMP5]], align 4
+; DEFAULT-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
+; DEFAULT-NEXT:    [[TMP6:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
+; DEFAULT-NEXT:    br i1 [[TMP6]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP4:![0-9]+]]
+; DEFAULT:       [[MIDDLE_BLOCK]]:
+; DEFAULT-NEXT:    br label %[[SCALAR_PH]]
+; DEFAULT:       [[SCALAR_PH]]:
+; DEFAULT-NEXT:    [[BC_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], %[[MIDDLE_BLOCK]] ], [ 0, %[[ENTRY]] ]
+; DEFAULT-NEXT:    br label %[[LOOP_HEADER:.*]]
+; DEFAULT:       [[LOOP_HEADER]]:
+; DEFAULT-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], %[[LOOP_LATCH:.*]] ], [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ]
+; DEFAULT-NEXT:    [[C_1:%.*]] = icmp uge i64 [[IV]], [[N]]
+; DEFAULT-NEXT:    br i1 [[C_1]], label %[[E:.*]], label %[[LOOP_LATCH]]
+; DEFAULT:       [[LOOP_LATCH]]:
+; DEFAULT-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i32, ptr [[P]], i64 [[IV]]
+; DEFAULT-NEXT:    store i32 0, ptr [[ARRAYIDX]], align 4
+; DEFAULT-NEXT:    [[INC]] = add nuw i64 [[IV]], 1
+; DEFAULT-NEXT:    [[C_2:%.*]] = icmp eq i64 [[INC]], 128
+; DEFAULT-NEXT:    br i1 [[C_2]], label %[[E]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP5:![0-9]+]]
+; DEFAULT:       [[E]]:
+; DEFAULT-NEXT:    [[P1:%.*]] = phi i64 [ 0, %[[LOOP_HEADER]] ], [ 1, %[[LOOP_LATCH]] ]
+; DEFAULT-NEXT:    ret i64 [[P1]]
+;
+entry:
+  br label %loop.header
+
+loop.header:
+  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
+  %c.1 = icmp uge i64 %iv, %N
+  br i1 %c.1, label %e, label %loop.latch
+
+loop.latch:
+  %arrayidx = getelementptr inbounds nuw i32, ptr %p, i64 %iv
+  store i32 0, ptr %arrayidx
+  %inc = add nuw i64 %iv, 1
+  %c.2 = icmp eq i64 %inc, 128
+  br i1 %c.2, label %e, label %loop.header, !llvm.loop !1
+
+e:
+  %p1 = phi i64 [ 0, %loop.header ], [ 1, %loop.latch ]
+  ret i64 %p1
+}
+
+!1 = distinct !{!1, !2, !3}
+!2 = !{!"llvm.loop.vectorize.width", i32 4}
+!3 = !{!"llvm.loop.vectorize.enable", i1 true}
+;.
+; MULTI: [[LOOP0]] = distinct !{[[LOOP0]], [[META1:![0-9]+]], [[META2:![0-9]+]]}
+; MULTI: [[META1]] = !{!"llvm.loop.isvectorized", i32 1}
+; MULTI: [[META2]] = !{!"llvm.loop.unroll.runtime.disable"}
+; MULTI: [[LOOP3]] = distinct !{[[LOOP3]], [[META2]], [[META1]]}
+; MULTI: [[LOOP4]] = distinct !{[[LOOP4]], [[META1]], [[META2]]}
+; MULTI: [[LOOP5]] = distinct !{[[LOOP5]], [[META2]], [[META1]]}
+;.
+; DEFAULT: [[LOOP0]] = distinct !{[[LOOP0]], [[META1:![0-9]+]], [[META2:![0-9]+]]}
+; DEFAULT: [[META1]] = !{!"llvm.loop.isvectorized", i32 1}
+; DEFAULT: [[META2]] = !{!"llvm.loop.unroll.runtime.disable"}
+; DEFAULT: [[LOOP3]] = distinct !{[[LOOP3]], [[META2]], [[META1]]}
+; DEFAULT: [[LOOP4]] = distinct !{[[LOOP4]], [[META1]], [[META2]]}
+; DEFAULT: [[LOOP5]] = distinct !{[[LOOP5]], [[META2]], [[META1]]}
+;.
diff --git a/llvm/test/Transforms/LoopVectorize/X86/multi-exit-cost.ll b/llvm/test/Transforms/LoopVectorize/X86/multi-exit-cost.ll
index cd128979fc1431..1c02f10753745c 100644
--- a/llvm/test/Transforms/LoopVectorize/X86/multi-exit-cost.ll
+++ b/llvm/test/Transforms/LoopVectorize/X86/multi-exit-cost.ll
@@ -5,18 +5,18 @@ define i64 @test_value_in_exit_compare_chain_used_outside(ptr %src, i64 %x, i64
 ; CHECK-LABEL: define i64 @test_value_in_exit_compare_chain_used_outside(
 ; CHECK-SAME: ptr [[SRC:%.*]], i64 [[X:%.*]], i64 range(i64 1, 32) [[N:%.*]]) #[[ATTR0:[0-9]+]] {
 ; CHECK-NEXT:  [[ENTRY:.*]]:
-; CHECK-NEXT:    [[TMP0:%.*]] = add nsw i64 [[N]], -1
-; CHECK-NEXT:    [[TMP1:%.*]] = freeze i64 [[TMP0]]
-; CHECK-NEXT:    [[UMIN2:%.*]] = call i64 @llvm.umin.i64(i64 [[TMP1]], i64 [[X]])
-; CHECK-NEXT:    [[TMP2:%.*]] = add nuw nsw i64 [[UMIN2]], 1
-; CHECK-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ule i64 [[TMP2]], 8
-; CHECK-NEXT:    br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_SCEVCHECK:.*]]
-; CHECK:       [[VECTOR_SCEVCHECK]]:
 ; CHECK-NEXT:    [[TMP3:%.*]] = add nsw i64 [[N]], -1
 ; CHECK-NEXT:    [[TMP4:%.*]] = freeze i64 [[TMP3]]
 ; CHECK-NEXT:    [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[TMP4]], i64 [[X]])
-; CHECK-NEXT:    [[TMP5:%.*]] = trunc i64 [[UMIN]] to i1
-; CHECK-NEXT:    [[TMP6:%.*]] = icmp ugt i64 [[UMIN]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = add nuw nsw i64 [[UMIN]], 1
+; CHECK-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ule i64 [[TMP2]], 8
+; CHECK-NEXT:    br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_SCEVCHECK:.*]]
+; CHECK:       [[VECTOR_SCEVCHECK]]:
+; CHECK-NEXT:    [[TMP32:%.*]] = add nsw i64 [[N]], -1
+; CHECK-NEXT:    [[TMP33:%.*]] = freeze i64 [[TMP32]]
+; CHECK-NEXT:    [[UMIN1:%.*]] = call i64 @llvm.umin.i64(i64 [[TMP33]], i64 [[X]])
+; CHECK-NEXT:    [[TMP5:%.*]] = trunc i64 [[UMIN1]] to i1
+; CHECK-NEXT:    [[TMP6:%.*]] = icmp ugt i64 [[UMIN1]], 1
 ; CHECK-NEXT:    [[TMP7:%.*]] = or i1 [[TMP5]], [[TMP6]]
 ; CHECK-NEXT:    br i1 [[TMP7]], label %[[SCALAR_PH]], label %[[VECTOR_PH:.*]]
 ; CHECK:       [[VECTOR_PH]]:
diff --git a/llvm/test/Transforms/LoopVectorize/X86/multi-exit-vplan.ll b/llvm/test/Transforms/LoopVectorize/X86/multi-exit-vplan.ll
new file mode 100644
index 00000000000000..5c5d532b93bc89
--- /dev/null
+++ b/llvm/test/Transforms/LoopVectorize/X86/multi-exit-vplan.ll
@@ -0,0 +1,148 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -p loop-vectorize -mcpu=skylake-avx512 -mtriple=x86_64-apple-macosx -force-vector-interleave=1 -S -enable-early-exit-vectorization -debug %s 2>&1 | FileCheck %s
+
+define i64 @multi_exiting_to_different_exits_with_store(ptr %p, i64 %N) {
+; CHECK-LABEL: VPlan 'Final VPlan for VF={4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VF:%.+]]> = VF
+; CHECK-NEXT: Live-in vp<[[VFxUF:%.+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VTC:%.+]]> = vector-trip-count
+; CHECK-NEXT: Live-in ir<128> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT:   vector.body:
+; CHECK-NEXT:     EMIT vp<[[CAN_IV:%.+]]> = CANONICAL-INDUCTION ir<0>, vp<%index.next>
+; CHECK-NEXT:     WIDEN-INDUCTION %iv = phi %inc, 0, ir<1>, vp<[[VF]]>
+; CHECK-NEXT:     vp<[[STEPS:%.+]]> = SCALAR-STEPS vp<[[CAN_IV]]>, ir<1>
+; CHECK-NEXT:     WIDEN ir<%c.1> = icmp uge ir<%iv>, ir<%N>
+; CHECK-NEXT:     EMIT vp<[[NOT1:%.+]]> = not ir<%c.1>
+; CHECK-NEXT:     CLONE ir<%arrayidx> = getelementptr ir<%p>, vp<[[STEPS]]>
+; CHECK-NEXT:     vp<[[VEC_PTR:%.+]]> = vector-pointer ir<%arrayidx>
+; CHECK-NEXT:     WIDEN store vp<[[VEC_PTR]]>, ir<0>, vp<[[NOT1]]>
+; CHECK-NEXT:     EMIT vp<%index.next> = add nuw vp<[[CAN_IV]]>, vp<[[VFxUF]]>
+; CHECK-NEXT:     EMIT vp<[[NOT2:%.+]]> = not vp<[[NOT1]]>
+; CHECK-NEXT:     EMIT vp<[[EA_TAKEN:%.+]]> = any-of vp<[[NOT2]]>
+; CHECK-NEXT:     EMIT vp<[[LATCH_CMP:%.+]]> = icmp eq vp<%index.next>, vp<[[VTC]]>
+; CHECK-NEXT:     EMIT vp<[[EC:%.+]]> = or vp<[[EA_TAKEN]]>, vp<[[LATCH_CMP]]>
+; CHECK-NEXT:     EMIT branch-on-cond vp<[[EC]]>
+; CHECK-NEXT:   No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.split
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.split:
+; CHECK-NEXT:   EMIT branch-on-cond vp<[[EA_TAKEN]]>
+; CHECK-NEXT: Successor(s): ir-bb<e1>, middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<e1>:
+; CHECK-NEXT:   IR %p1 = phi i64 [ 0, %loop.header ] (extra operand: ir<0>)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT:   EMIT vp<[[MIDDLE_CMP:%.+]]> = icmp eq ir<128>, vp<[[VTC]]>
+; CHECK-NEXT:   EMIT branch-on-cond vp<[[MIDDLE_CMP]]>
+; CHECK-NEXT: Successor(s): ir-bb<e2>, scalar.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<e2>:
+; CHECK-NEXT:  IR %p2 = phi i64 [ 1, %loop.latch ] (extra operand: ir<1>)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+;
+entry:
+  br label %loop.header
+
+loop.header:
+  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
+  %c.1 = icmp uge i64 %iv, %N
+  br i1 %c.1, label %e1, label %loop.latch
+
+loop.latch:
+  %arrayidx = getelementptr inbounds nuw i32, ptr %p, i64 %iv
+  store i32 0, ptr %arrayidx
+  %inc = add nuw i64 %iv, 1
+  %c.2 = icmp eq i64 %inc, 128
+  br i1 %c.2, label %e2, label %loop.header, !llvm.loop !1
+
+e1:
+  %p1 = phi i64 [ 0, %loop.header ]
+  ret i64 %p1
+
+e2:
+  %p2 = phi i64 [ 1, %loop.latch ]
+  ret i64 %p2
+}
+
+define i64 @multi_exiting_to_same_exit_with_store(ptr %p, i64 %N) {
+; CHECK-LABEL: VPlan 'Final VPlan for VF={4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VF:%.+]]> = VF
+; CHECK-NEXT: Live-in vp<[[VFxUF:%.+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VTC:%.+]]> = vector-trip-count
+; CHECK-NEXT: Live-in ir<128> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT:   vector.body:
+; CHECK-NEXT:     EMIT vp<[[CAN_IV:%.+]]> = CANONICAL-INDUCTION ir<0>, vp<%index.next>
+; CHECK-NEXT:     WIDEN-INDUCTION %iv = phi %inc, 0, ir<1>, vp<[[VF]]>
+; CHECK-NEXT:     vp<[[STEPS:%.+]]> = SCALAR-STEPS vp<[[CAN_IV]]>, ir<1>
+; CHECK-NEXT:     WIDEN ir<%c.1> = icmp uge ir<%iv>, ir<%N>
+; CHECK-NEXT:     EMIT vp<[[NOT1:%.+]]> = not ir<%c.1>
+; CHECK-NEXT:     CLONE ir<%arrayidx> = getelementptr ir<%p>, vp<[[STEPS]]>
+; CHECK-NEXT:     vp<[[VEC_PTR:%.+]]> = vector-pointer ir<%arrayidx>
+; CHECK-NEXT:     WIDEN store vp<[[VEC_PTR]]>, ir<0>, vp<[[NOT1]]>
+; CHECK-NEXT:     EMIT vp<%index.next> = add nuw vp<[[CAN_IV]]>, vp<[[VFxUF]]>
+; CHECK-NEXT:     EMIT vp<[[NOT2:%.+]]> = not vp<[[NOT1]]>
+; CHECK-NEXT:     EMIT vp<[[EA_TAKEN:%.+]]> = any-of vp<[[NOT2]]>
+; CHECK-NEXT:     EMIT vp<[[LATCH_CMP:%.+]]> = icmp eq vp<%index.next>, vp<[[VTC]]>
+; CHECK-NEXT:     EMIT vp<[[EC:%.+]]> = or vp<[[EA_TAKEN]]>, vp<[[LATCH_CMP]]>
+; CHECK-NEXT:     EMIT branch-on-cond vp<[[EC]]>
+; CHECK-NEXT:   No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.split
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.split:
+; CHECK-NEXT:   EMIT branch-on-cond vp<[[EA_TAKEN]]>
+; CHECK-NEXT: Successor(s): ir-bb<e>, middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<e>:
+; CHECK-NEXT:    IR   %p1 = phi i64 [ 0, %loop.header ], [ 1, %loop.latch ] (extra operand: ir<0>, ir<1>)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT:   EMIT vp<[[MIDDLE_CMP:%.+]]> = icmp eq ir<128>, vp<[[VTC]]>
+; CHECK-NEXT:   EMIT branch-on-cond vp<[[MIDDLE_CMP]]>
+; CHECK-NEXT: Successor(s): ir-bb<e>, scalar.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+;
+entry:
+  br label %loop.header
+
+loop.header:
+  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
+  %c.1 = icmp uge i64 %iv, %N
+  br i1 %c.1, label %e, label %loop.latch
+
+loop.latch:
+  %arrayidx = getelementptr inbounds nuw i32, ptr %p, i64 %iv
+  store i32 0, ptr %arrayidx
+  %inc = add nuw i64 %iv, 1
+  %c.2 = icmp eq i64 %inc, 128
+  br i1 %c.2, label %e, label %loop.header, !llvm.loop !1
+
+e:
+  %p1 = phi i64 [ 0, %loop.header ], [ 1, %loop.latch ]
+  ret i64 %p1
+}
+
+!1 = distinct !{!1, !2, !3}
+!2 = !{!"llvm.loop.vectorize.width", i32 4}
+!3 = !{!"llvm.loop.vectorize.enable", i1 true}

>From 3831acb97053230cb09f8316ce1ada17be50564c Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Thu, 31 Oct 2024 19:48:40 +0000
Subject: [PATCH 03/18] !fixup address first set of comments, thanks!

---
 llvm/lib/Transforms/Vectorize/LoopVectorize.cpp | 13 ++-----------
 llvm/lib/Transforms/Vectorize/VPlan.cpp         | 16 +---------------
 2 files changed, 3 insertions(+), 26 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 3a69750460f4d8..80a0fda81aeaf1 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -7711,16 +7711,13 @@ DenseMap<const SCEV *, Value *> LoopVectorizationPlanner::executePlan(
   BestVPlan.execute(&State);
 
   // 2.5 Collect reduction resume values.
-  VPBasicBlock *ExitVPBB = nullptr;
-  if (BestVPlan.getVectorLoopRegion()->getSingleSuccessor()) {
-    ExitVPBB = cast<VPBasicBlock>(
-        BestVPlan.getVectorLoopRegion()->getSingleSuccessor());
+  VPBasicBlock *ExitVPBB =
+      cast<VPBasicBlock>(BestVPlan.getVectorLoopRegion()->getSingleSuccessor());
   if (VectorizingEpilogue)
     for (VPRecipeBase &R : *ExitVPBB) {
       fixReductionScalarResumeWhenVectorizingEpilog(
           &R, State, State.CFG.VPBB2IRBB[ExitVPBB]);
     }
-  }
 
   // 2.6. Maintain Loop Hints
   // Keep all loop hints from the original loop on the vector loop (we'll
@@ -8809,8 +8806,6 @@ static void addCanonicalIVRecipes(VPlan &Plan, Type *IdxTy, bool HasNUW,
 static SetVector<VPIRInstruction *> collectUsersInExitBlock(
     Loop *OrigLoop, VPRecipeBuilder &Builder, VPlan &Plan,
     const MapVector<PHINode *, InductionDescriptor> &Inductions) {
-  if (!Plan.getVectorLoopRegion()->getSingleSuccessor())
-    return {};
   auto *MiddleVPBB =
       cast<VPBasicBlock>(Plan.getVectorLoopRegion()->getSingleSuccessor());
   // No edge from the middle block to the unique exit block has been inserted
@@ -8896,8 +8891,6 @@ static void addLiveOutsForFirstOrderRecurrences(
   // TODO: Should be replaced by
   // Plan->getScalarLoopRegion()->getSinglePredecessor() in the future once the
   // scalar region is modeled as well.
-  if (!VectorRegion->getSingleSuccessor())
-    return;
   auto *MiddleVPBB = cast<VPBasicBlock>(VectorRegion->getSingleSuccessor());
   VPBasicBlock *ScalarPHVPBB = nullptr;
   if (MiddleVPBB->getNumSuccessors() == 2) {
@@ -9447,8 +9440,6 @@ void LoopVectorizationPlanner::adjustRecipesForReductions(
   }
   VPBasicBlock *LatchVPBB = VectorLoopRegion->getExitingBasicBlock();
   Builder.setInsertPoint(&*LatchVPBB->begin());
-  if (!VectorLoopRegion->getSingleSuccessor())
-    return;
   VPBasicBlock *MiddleVPBB =
       cast<VPBasicBlock>(VectorLoopRegion->getSingleSuccessor());
   VPBasicBlock::iterator IP = MiddleVPBB->getFirstNonPhi();
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp
index be3579b4cd5dde..4032468b4f76da 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp
@@ -474,14 +474,6 @@ void VPIRBasicBlock::execute(VPTransformState *State) {
     // backedges. A backward successor is set when the branch is created.
     const auto &PredVPSuccessors = PredVPBB->getHierarchicalSuccessors();
     unsigned idx = PredVPSuccessors.front() == this ? 0 : 1;
-    if (TermBr->getSuccessor(idx) &&
-        PredVPBlock == getPlan()->getVectorLoopRegion() &&
-        PredVPBlock->getNumSuccessors()) {
-      // Update PRedBB and TermBr for BranchOnMultiCond in predecessor.
-      PredBB = TermBr->getSuccessor(1);
-      TermBr = cast<BranchInst>(PredBB->getTerminator());
-      idx = 0;
-    }
     assert(!TermBr->getSuccessor(idx) &&
            "Trying to reset an existing successor block.");
     TermBr->setSuccessor(idx, IRBB);
@@ -1043,9 +1035,7 @@ void VPlan::execute(VPTransformState *State) {
   // VPlan execution rather than earlier during VPlan construction.
   BasicBlock *MiddleBB = State->CFG.ExitBB;
   VPBasicBlock *MiddleVPBB =
-      getVectorLoopRegion()->getNumSuccessors() == 1
-          ? cast<VPBasicBlock>(getVectorLoopRegion()->getSuccessors()[0])
-          : cast<VPBasicBlock>(getVectorLoopRegion()->getSuccessors()[1]);
+      cast<VPBasicBlock>(getVectorLoopRegion()->getSingleSuccessor());
   // Find the VPBB for the scalar preheader, relying on the current structure
   // when creating the middle block and its successrs: if there's a single
   // predecessor, it must be the scalar preheader. Otherwise, the second
@@ -1083,10 +1073,6 @@ void VPlan::execute(VPTransformState *State) {
   VPBasicBlock *LatchVPBB = getVectorLoopRegion()->getExitingBasicBlock();
   BasicBlock *VectorLatchBB = State->CFG.VPBB2IRBB[LatchVPBB];
 
-  if (!getVectorLoopRegion()->getSingleSuccessor())
-    VectorLatchBB =
-        cast<BranchInst>(VectorLatchBB->getTerminator())->getSuccessor(1);
-
   // Fix the latch value of canonical, reduction and first-order recurrences
   // phis in the vector loop.
   VPBasicBlock *Header = getVectorLoopRegion()->getEntryBasicBlock();

>From 64db0eea4073e1cdc3d394155754ed0653ca0c3d Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Mon, 4 Nov 2024 21:10:24 +0000
Subject: [PATCH 04/18] !fixup clean up merge failures

---
 llvm/lib/Transforms/Vectorize/VPlan.cpp        | 18 ++++++++++--------
 llvm/lib/Transforms/Vectorize/VPlan.h          |  4 ++--
 .../Transforms/Vectorize/VPlanTransforms.cpp   | 11 ++---------
 .../LoopVectorize/X86/multi-exit-vplan.ll      | 11 ++++++++++-
 4 files changed, 24 insertions(+), 20 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp
index 924b63bbd9639f..e2c063928e9906 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp
@@ -911,7 +911,6 @@ VPlanPtr VPlan::createInitialVPlan(Type *InductionTy,
   VPBasicBlock *ScalarPH = new VPBasicBlock("scalar.ph");
   VPBlockUtils::connectBlocks(ScalarPH, ScalarHeader);
   if (!RequiresScalarEpilogueCheck) {
-    VPBasicBlock *ScalarPH = new VPBasicBlock("scalar.ph");
     VPBlockUtils::connectBlocks(MiddleVPBB, ScalarPH);
     return Plan;
   }
@@ -925,14 +924,17 @@ VPlanPtr VPlan::createInitialVPlan(Type *InductionTy,
   //    we unconditionally branch to the scalar preheader.  Do nothing.
   // 3) Otherwise, construct a runtime check.
   BasicBlock *IRExitBlock = TheLoop->getUniqueExitBlock();
-  if (IRExitBlock) {
-    auto *VPExitBlock = VPIRBasicBlock::fromBasicBlock(IRExitBlock);
-    // The connection order corresponds to the operands of the conditional
-    // branch.
-    VPBlockUtils::insertBlockAfter(VPExitBlock, MiddleVPBB);
-    VPBasicBlock *ScalarPH = new VPBasicBlock("scalar.ph");
-    VPBlockUtils::connectBlocks(MiddleVPBB, ScalarPH);
+  if (!IRExitBlock) {
+    auto *Term = cast<BranchInst>(TheLoop->getLoopLatch()->getTerminator());
+    IRExitBlock = TheLoop->contains(Term->getSuccessor(0))
+                      ? Term->getSuccessor(1)
+                      : Term->getSuccessor(0);
   }
+  auto *VPExitBlock = VPIRBasicBlock::fromBasicBlock(IRExitBlock);
+  // The connection order corresponds to the operands of the conditional
+  // branch.
+  VPBlockUtils::insertBlockAfter(VPExitBlock, MiddleVPBB);
+  VPBlockUtils::connectBlocks(MiddleVPBB, ScalarPH);
 
   auto *ScalarLatchTerm = TheLoop->getLoopLatch()->getTerminator();
   // Here we use the same DebugLoc as the scalar loop latch terminator instead
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 861fea7ff469ff..8efa648a7e1ea7 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -3822,10 +3822,10 @@ class VPlan {
   /// whether to execute the scalar tail loop or the exit block from the loop
   /// latch.
   const VPBasicBlock *getMiddleBlock() const {
-    return cast<VPBasicBlock>(getVectorLoopRegion()->getSingleSuccessor());
+    return cast<VPBasicBlock>(getScalarPreheader()->getSinglePredecessor());
   }
   VPBasicBlock *getMiddleBlock() {
-    return cast<VPBasicBlock>(getVectorLoopRegion()->getSingleSuccessor());
+    return cast<VPBasicBlock>(getScalarPreheader()->getSinglePredecessor());
   }
 
   /// The trip count of the original loop.
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index eed3efd666e712..1369693b01971c 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -1797,8 +1797,7 @@ void VPlanTransforms::convertToMultiCond(VPlan &Plan, ScalarEvolution &SE,
   auto *LatchVPBB =
       cast<VPBasicBlock>(Plan.getVectorLoopRegion()->getExiting());
   VPBuilder Builder(LatchVPBB->getTerminator());
-  auto *MiddleVPBB =
-      cast<VPBasicBlock>(Plan.getVectorLoopRegion()->getSingleSuccessor());
+  auto *MiddleVPBB = Plan.getMiddleBlock();
 
   VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
 
@@ -1818,7 +1817,7 @@ void VPlanTransforms::convertToMultiCond(VPlan &Plan, ScalarEvolution &SE,
     BasicBlock *TrueSucc = ExitingTerm->getSuccessor(0);
     BasicBlock *FalseSucc = ExitingTerm->getSuccessor(1);
     VPIRBasicBlock *VPExitBlock;
-    if (OrigLoop->getUniqueExitBlock())
+    if (OrigLoop->getUniqueExitBlock() || Exiting == OrigLoop->getLoopLatch())
       VPExitBlock = cast<VPIRBasicBlock>(MiddleVPBB->getSuccessors()[0]);
     else
       VPExitBlock = VPIRBasicBlock::fromBasicBlock(
@@ -1835,11 +1834,6 @@ void VPlanTransforms::convertToMultiCond(VPlan &Plan, ScalarEvolution &SE,
     }
 
     if (Exiting == OrigLoop->getLoopLatch()) {
-      if (MiddleVPBB->getNumSuccessors() == 0) {
-        VPBasicBlock *ScalarPH = new VPBasicBlock("scalar.ph");
-        VPBlockUtils::connectBlocks(MiddleVPBB, VPExitBlock);
-        VPBlockUtils::connectBlocks(MiddleVPBB, ScalarPH);
-      }
       continue;
     }
 
@@ -1856,7 +1850,6 @@ void VPlanTransforms::convertToMultiCond(VPlan &Plan, ScalarEvolution &SE,
 
     VPBuilder MiddleBuilder(NewMiddle);
     MiddleBuilder.createNaryOp(VPInstruction::BranchOnCond, {EarlyExitTaken});
-    // MiddleVPBB = NewMiddle;
   }
   auto *Term = dyn_cast<VPInstruction>(LatchVPBB->getTerminator());
   auto *IsLatchExiting = Builder.createICmp(
diff --git a/llvm/test/Transforms/LoopVectorize/X86/multi-exit-vplan.ll b/llvm/test/Transforms/LoopVectorize/X86/multi-exit-vplan.ll
index 5c5d532b93bc89..47304c571bfcb1 100644
--- a/llvm/test/Transforms/LoopVectorize/X86/multi-exit-vplan.ll
+++ b/llvm/test/Transforms/LoopVectorize/X86/multi-exit-vplan.ll
@@ -49,9 +49,13 @@ define i64 @multi_exiting_to_different_exits_with_store(ptr %p, i64 %N) {
 ; CHECK-NEXT: No successors
 ; CHECK-EMPTY:
 ; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: ir-bb<loop.header>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop.header>:
+; CHECK-NEXT:   IR   %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
+; CHECK-NEXT:   IR   %c.1 = icmp uge i64 %iv, %N
 ; CHECK-NEXT: No successors
 ; CHECK-NEXT: }
-;
 entry:
   br label %loop.header
 
@@ -120,6 +124,11 @@ define i64 @multi_exiting_to_same_exit_with_store(ptr %p, i64 %N) {
 ; CHECK-NEXT: Successor(s): ir-bb<e>, scalar.ph
 ; CHECK-EMPTY:
 ; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: ir-bb<loop.header>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop.header>:
+; CHECK-NEXT:   IR   %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
+; CHECK-NEXT:   IR   %c.1 = icmp uge i64 %iv, %N
 ; CHECK-NEXT: No successors
 ; CHECK-NEXT: }
 ;

>From 0f8aedfaf89bc6dbe18bd00e6bad0aad52db10f3 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 5 Nov 2024 13:50:43 +0000
Subject: [PATCH 05/18] !fixup address latest comments, thanks!

---
 .../Vectorize/LoopVectorizationLegality.cpp   |   8 +-
 .../Transforms/Vectorize/LoopVectorize.cpp    | 121 ++++++++++--------
 llvm/lib/Transforms/Vectorize/VPlan.cpp       |  13 +-
 .../Transforms/Vectorize/VPlanTransforms.cpp  |  48 +++----
 .../Transforms/Vectorize/VPlanTransforms.h    |   6 +-
 .../LoopVectorize/X86/multi-exit-vplan.ll     |  82 +-----------
 6 files changed, 98 insertions(+), 180 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
index 0d8bda5a2112c7..ed3808d2f30bf1 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
@@ -43,10 +43,6 @@ AllowStridedPointerIVs("lv-strided-pointer-ivs", cl::init(false), cl::Hidden,
                        cl::desc("Enable recognition of non-constant strided "
                                 "pointer induction variables."));
 
-static cl::opt<bool>
-    EnableEarlyExitVectorization("enable-early-exit-vectorization",
-                                 cl::init(false), cl::Hidden, cl::desc(""));
-
 namespace llvm {
 cl::opt<bool>
     HintsAllowReordering("hints-allow-reordering", cl::init(true), cl::Hidden,
@@ -1381,7 +1377,7 @@ bool LoopVectorizationLegality::isFixedOrderRecurrence(
 bool LoopVectorizationLegality::blockNeedsPredication(BasicBlock *BB) const {
   // When vectorizing early exits, create predicates for all blocks, except the
   // header.
-  if (canVectorizeEarlyExit() && BB != TheLoop->getHeader())
+  if (hasUncountableEarlyExit() && BB != TheLoop->getHeader())
     return true;
   return LoopAccessInfo::blockNeedsPredication(BB, TheLoop, DT);
 }
@@ -1523,8 +1519,6 @@ bool LoopVectorizationLegality::canVectorizeEarlyExit() const {
   // Currently only allow vectorizing loops with early exits, if early-exit
   // vectorization is explicitly enabled and the loop has metadata to force
   // vectorization.
-  if (!EnableEarlyExitVectorization)
-    return false;
 
   SmallVector<BasicBlock *> Exiting;
   TheLoop->getExitingBlocks(Exiting);
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 60607b7cf6b46c..47e78a916f8cea 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -384,6 +384,11 @@ static cl::opt<bool> UseWiderVFIfCallVariantsPresent(
     cl::Hidden,
     cl::desc("Try wider VFs if they enable the use of vector variants"));
 
+static cl::opt<bool> EnableEarlyExitVectorization(
+    "enable-early-exit-vectorization", cl::init(false), cl::Hidden,
+    cl::desc(
+        "Enable vectorization of early exit loops with uncountable exits."));
+
 // Likelyhood of bypassing the vectorized loop because assumptions about SCEV
 // variables not overflowing do not hold. See `emitSCEVChecks`.
 static constexpr uint32_t SCEVCheckBypassWeights[] = {1, 127};
@@ -1358,14 +1363,13 @@ class LoopVectorizationCostModel {
       LLVM_DEBUG(dbgs() << "LV: Loop does not require scalar epilogue\n");
       return false;
     }
-    // If we might exit from anywhere but the latch, must run the exiting
-    // iteration in scalar form.
-    if (TheLoop->getExitingBlock() != TheLoop->getLoopLatch()) {
-      if (!Legal->canVectorizeEarlyExit()) {
-        LLVM_DEBUG(
-            dbgs() << "LV: Loop requires scalar epilogue: multiple exits\n");
-        return true;
-      }
+    // If we might exit from anywhere but the latch and early exit vectorization
+    // is disabled, we must run the exiting iteration in scalar form.
+    if (TheLoop->getExitingBlock() != TheLoop->getLoopLatch() &&
+        !(EnableEarlyExitVectorization && Legal->hasUncountableEarlyExit())) {
+      LLVM_DEBUG(
+          dbgs() << "LV: Loop requires scalar epilogue: multiple exits\n");
+      return true;
     }
     if (IsVectorizing && InterleaveInfo.requiresScalarEpilogue()) {
       LLVM_DEBUG(dbgs() << "LV: Loop requires scalar epilogue: "
@@ -2576,7 +2580,7 @@ void InnerLoopVectorizer::createVectorLoopSkeleton(StringRef Prefix) {
   assert(LoopVectorPreHeader && "Invalid loop structure");
   LoopExitBlock = OrigLoop->getUniqueExitBlock(); // may be nullptr
   assert((LoopExitBlock || Cost->requiresScalarEpilogue(VF.isVector()) ||
-          Legal->canVectorizeEarlyExit()) &&
+          Legal->hasUncountableEarlyExit()) &&
          "multiple exit loop without required epilogue?");
 
   LoopMiddleBlock =
@@ -2809,6 +2813,8 @@ void InnerLoopVectorizer::fixupIVUsers(PHINode *OrigPhi,
     }
   }
 
+  assert((MissingVals.empty() || OrigLoop->getUniqueExitBlock()) &&
+         "Expected a single exit block for escaping values");
   for (auto &I : MissingVals) {
     PHINode *PHI = cast<PHINode>(I.first);
     // One corner case we have to handle is two IVs "chasing" each-other,
@@ -2819,9 +2825,6 @@ void InnerLoopVectorizer::fixupIVUsers(PHINode *OrigPhi,
     if (PHI->getBasicBlockIndex(MiddleBlock) == -1)
       PHI->addIncoming(I.second, MiddleBlock);
   }
-
-  assert((MissingVals.empty() || OrigLoop->getUniqueExitBlock()) &&
-         "Expected a single exit block");
 }
 
 namespace {
@@ -3597,7 +3600,7 @@ void LoopVectorizationCostModel::collectLoopUniforms(ElementCount VF) {
   for (BasicBlock *E : Exiting) {
     auto *Cmp = dyn_cast<Instruction>(E->getTerminator()->getOperand(0));
     if (Cmp && TheLoop->contains(Cmp) && Cmp->hasOneUse() &&
-        (TheLoop->getLoopLatch() == E || !Legal->canVectorizeEarlyExit()))
+        (TheLoop->getLoopLatch() == E || !Legal->hasUncountableEarlyExit()))
       AddToWorklistIfAllowed(Cmp);
   }
 
@@ -8144,7 +8147,7 @@ VPValue *VPRecipeBuilder::createEdgeMask(BasicBlock *Src, BasicBlock *Dst) {
   // If source is an exiting block, we know the exit edge is dynamically dead
   // in the vector loop, and thus we don't need to restrict the mask.  Avoid
   // adding uses of an otherwise potentially dead instruction.
-  if (!Legal->canVectorizeEarlyExit() && OrigLoop->isLoopExiting(Src))
+  if (!Legal->hasUncountableEarlyExit() && OrigLoop->isLoopExiting(Src))
     return EdgeMaskCache[Edge] = SrcMask;
 
   VPValue *EdgeMask = getVPValueOrAddLiveIn(BI->getCondition());
@@ -8835,39 +8838,43 @@ static void addScalarResumePhis(VPRecipeBuilder &Builder, VPlan &Plan) {
 static SetVector<VPIRInstruction *> collectUsersInExitBlock(
     Loop *OrigLoop, VPRecipeBuilder &Builder, VPlan &Plan,
     const MapVector<PHINode *, InductionDescriptor> &Inductions) {
-  auto *MiddleVPBB = Plan.getMiddleBlock();
-  // No edge from the middle block to the unique exit block has been inserted
-  // and there is nothing to fix from vector loop; phis should have incoming
-  // from scalar loop only.
-  if (MiddleVPBB->getNumSuccessors() != 2)
-    return {};
   SetVector<VPIRInstruction *> ExitUsersToFix;
-  VPBasicBlock *ExitVPBB = cast<VPIRBasicBlock>(MiddleVPBB->getSuccessors()[0]);
-  BasicBlock *ExitingBB = OrigLoop->getExitingBlock();
-  for (VPRecipeBase &R : *ExitVPBB) {
-    auto *ExitIRI = dyn_cast<VPIRInstruction>(&R);
-    if (!ExitIRI)
-      continue;
-    auto *ExitPhi = dyn_cast<PHINode>(&ExitIRI->getInstruction());
-    if (!ExitPhi)
-      break;
-    Value *IncomingValue = ExitPhi->getIncomingValueForBlock(ExitingBB);
-    VPValue *V = Builder.getVPValueOrAddLiveIn(IncomingValue);
-    // Exit values for inductions are computed and updated outside of VPlan and
-    // independent of induction recipes.
-    // TODO: Compute induction exit values in VPlan.
-    if ((isa<VPWidenIntOrFpInductionRecipe>(V) &&
-         !cast<VPWidenIntOrFpInductionRecipe>(V)->getTruncInst()) ||
-        isa<VPWidenPointerInductionRecipe>(V) ||
-        (isa<Instruction>(IncomingValue) &&
-         OrigLoop->contains(cast<Instruction>(IncomingValue)) &&
-         any_of(IncomingValue->users(), [&Inductions](User *U) {
-           auto *P = dyn_cast<PHINode>(U);
-           return P && Inductions.contains(P);
-         })))
+  for (VPBlockBase *VPB : vp_depth_first_shallow(
+           Plan.getVectorLoopRegion()->getSingleSuccessor())) {
+    if (VPB->getNumSuccessors() != 0 || VPB == Plan.getScalarHeader())
       continue;
-    ExitUsersToFix.insert(ExitIRI);
-    ExitIRI->addOperand(V);
+    auto *ExitVPBB = cast<VPIRBasicBlock>(VPB);
+    BasicBlock *ExitBB = ExitVPBB->getIRBasicBlock();
+    BasicBlock *ExitingBB = find_singleton<BasicBlock>(
+        to_vector(predecessors(ExitBB)),
+        [OrigLoop](BasicBlock *Pred, bool AllowRepeats) {
+          return OrigLoop->contains(Pred) ? Pred : nullptr;
+        });
+    for (VPRecipeBase &R : *ExitVPBB) {
+      auto *ExitIRI = dyn_cast<VPIRInstruction>(&R);
+      if (!ExitIRI)
+        continue;
+      auto *ExitPhi = dyn_cast<PHINode>(&ExitIRI->getInstruction());
+      if (!ExitPhi)
+        break;
+      Value *IncomingValue = ExitPhi->getIncomingValueForBlock(ExitingBB);
+      VPValue *V = Builder.getVPValueOrAddLiveIn(IncomingValue);
+      // Exit values for inductions are computed and updated outside of VPlan
+      // and independent of induction recipes.
+      // TODO: Compute induction exit values in VPlan.
+      if ((isa<VPWidenIntOrFpInductionRecipe>(V) &&
+           !cast<VPWidenIntOrFpInductionRecipe>(V)->getTruncInst()) ||
+          isa<VPWidenPointerInductionRecipe>(V) ||
+          (isa<Instruction>(IncomingValue) &&
+           OrigLoop->contains(cast<Instruction>(IncomingValue)) &&
+           any_of(IncomingValue->users(), [&Inductions](User *U) {
+             auto *P = dyn_cast<PHINode>(U);
+             return P && Inductions.contains(P);
+           })))
+        continue;
+      ExitUsersToFix.insert(ExitIRI);
+      ExitIRI->addOperand(V);
+    }
   }
   return ExitUsersToFix;
 }
@@ -9168,16 +9175,15 @@ LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(VFRange &Range) {
          "VPBasicBlock");
   RecipeBuilder.fixHeaderPhis();
 
-  if (Legal->canVectorizeEarlyExit()) {
-    VPlanTransforms::convertToMultiCond(*Plan, *PSE.getSE(), OrigLoop,
-                                        RecipeBuilder);
-  } else {
+  if (Legal->hasUncountableEarlyExit()) {
+    VPlanTransforms::handleUncountableEarlyExit(*Plan, *PSE.getSE(), OrigLoop,
+                                                RecipeBuilder);
+  }
     addScalarResumePhis(RecipeBuilder, *Plan);
     SetVector<VPIRInstruction *> ExitUsersToFix = collectUsersInExitBlock(
         OrigLoop, RecipeBuilder, *Plan, Legal->getInductionVars());
     addExitUsersForFirstOrderRecurrences(*Plan, ExitUsersToFix);
     addUsersInExitBlock(*Plan, ExitUsersToFix);
-  }
 
   // ---------------------------------------------------------------------------
   // Transform initial VPlan: Apply previously taken decisions, in order, to
@@ -9940,12 +9946,15 @@ bool LoopVectorizePass::processLoop(Loop *L) {
   }
 
   if (LVL.hasUncountableEarlyExit()) {
-    reportVectorizationFailure("Auto-vectorization of loops with uncountable "
-                               "early exit is not yet supported",
-                               "Auto-vectorization of loops with uncountable "
-                               "early exit is not yet supported",
-                               "UncountableEarlyExitLoopsUnsupported", ORE, L);
-    return false;
+    if (!EnableEarlyExitVectorization) {
+      reportVectorizationFailure("Auto-vectorization of loops with uncountable "
+                                 "early exit is not yet supported",
+                                 "Auto-vectorization of loops with uncountable "
+                                 "early exit is not yet supported",
+                                 "UncountableEarlyExitLoopsUnsupported", ORE,
+                                 L);
+      return false;
+    }
   }
 
   // Entrance to the VPlan-native vectorization path. Outer loops are processed
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp
index ed2d6aa5f3df4b..1c609d89c47b9b 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp
@@ -878,15 +878,9 @@ VPlanPtr VPlan::createInitialVPlan(Type *InductionTy,
   auto Plan = std::make_unique<VPlan>(Entry, VecPreheader, ScalarHeader);
 
   // Create SCEV and VPValue for the trip count.
-
-  // Currently only loops with countable exits are vectorized, but calling
-  // getSymbolicMaxBackedgeTakenCount allows enablement work for loops with
-  // uncountable exits whilst also ensuring the symbolic maximum and known
-  // back-edge taken count remain identical for loops with countable exits.
+  // We use the symbolic max backedge-taken-count, which is used when
+  // vectorizing loops with uncountable early exits
   const SCEV *BackedgeTakenCountSCEV = PSE.getSymbolicMaxBackedgeTakenCount();
-  assert((!isa<SCEVCouldNotCompute>(BackedgeTakenCountSCEV) &&
-          BackedgeTakenCountSCEV == PSE.getBackedgeTakenCount()) &&
-         "Invalid loop count");
   ScalarEvolution &SE = *PSE.getSE();
   const SCEV *TripCount = SE.getTripCountFromExitCount(BackedgeTakenCountSCEV,
                                                        InductionTy, TheLoop);
@@ -922,6 +916,9 @@ VPlanPtr VPlan::createInitialVPlan(Type *InductionTy,
   // 3) Otherwise, construct a runtime check.
   BasicBlock *IRExitBlock = TheLoop->getUniqueExitBlock();
   if (!IRExitBlock) {
+    // If there's no unique exit block (i.e. vectorizing with an uncountable
+    // early exit), use the block exiting from the latch. The other uncountable
+    // exit blocks will be added later.
     auto *Term = cast<BranchInst>(TheLoop->getLoopLatch()->getTerminator());
     IRExitBlock = TheLoop->contains(Term->getSuccessor(0))
                       ? Term->getSuccessor(1)
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index 1369693b01971c..d336827b23ddf3 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -1791,51 +1791,33 @@ void VPlanTransforms::createInterleaveGroups(
   }
 }
 
-void VPlanTransforms::convertToMultiCond(VPlan &Plan, ScalarEvolution &SE,
-                                         Loop *OrigLoop,
-                                         VPRecipeBuilder &RecipeBuilder) {
+void VPlanTransforms::handleUncountableEarlyExit(
+    VPlan &Plan, ScalarEvolution &SE, Loop *OrigLoop,
+    VPRecipeBuilder &RecipeBuilder) {
   auto *LatchVPBB =
       cast<VPBasicBlock>(Plan.getVectorLoopRegion()->getExiting());
   VPBuilder Builder(LatchVPBB->getTerminator());
   auto *MiddleVPBB = Plan.getMiddleBlock();
-
   VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
 
-  const SCEV *BackedgeTakenCount =
-      SE.getExitCount(OrigLoop, OrigLoop->getLoopLatch());
-  const SCEV *TripCount = SE.getTripCountFromExitCount(
-      BackedgeTakenCount, Plan.getCanonicalIV()->getScalarType(), OrigLoop);
-  VPValue *NewTC = vputils::getOrCreateVPValueForSCEVExpr(Plan, TripCount, SE);
-  Plan.getTripCount()->replaceAllUsesWith(NewTC);
-  Plan.resetTripCount(NewTC);
-
   VPValue *EarlyExitTaken = nullptr;
   SmallVector<BasicBlock *> ExitingBBs;
   OrigLoop->getExitingBlocks(ExitingBBs);
+
+  // Process all uncountable exiting blocks. For each exiting block, update the
+  // EarlyExitTaken, which tracks if any uncountable early exit has been taken.
+  // Also split the middle block and branch to the exit block for the early exit
+  // if it has been taken.
   for (BasicBlock *Exiting : ExitingBBs) {
+    if (Exiting == OrigLoop->getLoopLatch())
+      continue;
+
     auto *ExitingTerm = cast<BranchInst>(Exiting->getTerminator());
     BasicBlock *TrueSucc = ExitingTerm->getSuccessor(0);
     BasicBlock *FalseSucc = ExitingTerm->getSuccessor(1);
     VPIRBasicBlock *VPExitBlock;
-    if (OrigLoop->getUniqueExitBlock() || Exiting == OrigLoop->getLoopLatch())
-      VPExitBlock = cast<VPIRBasicBlock>(MiddleVPBB->getSuccessors()[0]);
-    else
-      VPExitBlock = VPIRBasicBlock::fromBasicBlock(
-          !OrigLoop->contains(TrueSucc) ? TrueSucc : FalseSucc);
-
-    for (VPRecipeBase &R : *VPExitBlock) {
-      auto *ExitIRI = cast<VPIRInstruction>(&R);
-      auto *ExitPhi = dyn_cast<PHINode>(&ExitIRI->getInstruction());
-      if (!ExitPhi)
-        break;
-      Value *IncomingValue = ExitPhi->getIncomingValueForBlock(Exiting);
-      VPValue *V = RecipeBuilder.getVPValueOrAddLiveIn(IncomingValue);
-      ExitIRI->addOperand(V);
-    }
-
-    if (Exiting == OrigLoop->getLoopLatch()) {
-      continue;
-    }
+    VPExitBlock = VPIRBasicBlock::fromBasicBlock(
+        !OrigLoop->contains(TrueSucc) ? TrueSucc : FalseSucc);
 
     VPValue *M = RecipeBuilder.getBlockInMask(
         OrigLoop->contains(TrueSucc) ? TrueSucc : FalseSucc);
@@ -1851,6 +1833,10 @@ void VPlanTransforms::convertToMultiCond(VPlan &Plan, ScalarEvolution &SE,
     VPBuilder MiddleBuilder(NewMiddle);
     MiddleBuilder.createNaryOp(VPInstruction::BranchOnCond, {EarlyExitTaken});
   }
+
+  // Replace the condition controlling the exit from the vector loop with one
+  // exiting if either the original condition of the vector latch is true or any
+  // early exit has been taken.
   auto *Term = dyn_cast<VPInstruction>(LatchVPBB->getTerminator());
   auto *IsLatchExiting = Builder.createICmp(
       CmpInst::ICMP_EQ, Term->getOperand(0), Term->getOperand(1));
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.h b/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
index b5b7144568ff54..f7bbae25279fce 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
@@ -124,9 +124,9 @@ struct VPlanTransforms {
   /// Remove dead recipes from \p Plan.
   static void removeDeadRecipes(VPlan &Plan);
 
-  static void convertToMultiCond(VPlan &Plan, ScalarEvolution &SE,
-                                 Loop *OrigLoop,
-                                 VPRecipeBuilder &RecipeBuilder);
+  static void handleUncountableEarlyExit(VPlan &Plan, ScalarEvolution &SE,
+                                         Loop *OrigLoop,
+                                         VPRecipeBuilder &RecipeBuilder);
 };
 
 } // namespace llvm
diff --git a/llvm/test/Transforms/LoopVectorize/X86/multi-exit-vplan.ll b/llvm/test/Transforms/LoopVectorize/X86/multi-exit-vplan.ll
index 47304c571bfcb1..5da97ef8f9b3bc 100644
--- a/llvm/test/Transforms/LoopVectorize/X86/multi-exit-vplan.ll
+++ b/llvm/test/Transforms/LoopVectorize/X86/multi-exit-vplan.ll
@@ -1,6 +1,8 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
 ; RUN: opt -p loop-vectorize -mcpu=skylake-avx512 -mtriple=x86_64-apple-macosx -force-vector-interleave=1 -S -enable-early-exit-vectorization -debug %s 2>&1 | FileCheck %s
 
+declare void @init(ptr)
+
 define i64 @multi_exiting_to_different_exits_with_store(ptr %p, i64 %N) {
 ; CHECK-LABEL: VPlan 'Final VPlan for VF={4},UF={1}' {
 ; CHECK-NEXT: Live-in vp<[[VF:%.+]]> = VF
@@ -57,16 +59,18 @@ define i64 @multi_exiting_to_different_exits_with_store(ptr %p, i64 %N) {
 ; CHECK-NEXT: No successors
 ; CHECK-NEXT: }
 entry:
+  %src = alloca [128 x i32]
+  call void @init(ptr %src)
   br label %loop.header
 
 loop.header:
   %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
-  %c.1 = icmp uge i64 %iv, %N
+  %gep.src = getelementptr inbounds i32, ptr %src, i64 %iv
+  %l = load i32, ptr %gep.src
+  %c.1 = icmp eq i32 %l, 10
   br i1 %c.1, label %e1, label %loop.latch
 
 loop.latch:
-  %arrayidx = getelementptr inbounds nuw i32, ptr %p, i64 %iv
-  store i32 0, ptr %arrayidx
   %inc = add nuw i64 %iv, 1
   %c.2 = icmp eq i64 %inc, 128
   br i1 %c.2, label %e2, label %loop.header, !llvm.loop !1
@@ -80,78 +84,6 @@ e2:
   ret i64 %p2
 }
 
-define i64 @multi_exiting_to_same_exit_with_store(ptr %p, i64 %N) {
-; CHECK-LABEL: VPlan 'Final VPlan for VF={4},UF={1}' {
-; CHECK-NEXT: Live-in vp<[[VF:%.+]]> = VF
-; CHECK-NEXT: Live-in vp<[[VFxUF:%.+]]> = VF * UF
-; CHECK-NEXT: Live-in vp<[[VTC:%.+]]> = vector-trip-count
-; CHECK-NEXT: Live-in ir<128> = original trip-count
-; CHECK-EMPTY:
-; CHECK-NEXT: vector.ph:
-; CHECK-NEXT: Successor(s): vector loop
-; CHECK-EMPTY:
-; CHECK-NEXT: <x1> vector loop: {
-; CHECK-NEXT:   vector.body:
-; CHECK-NEXT:     EMIT vp<[[CAN_IV:%.+]]> = CANONICAL-INDUCTION ir<0>, vp<%index.next>
-; CHECK-NEXT:     WIDEN-INDUCTION %iv = phi %inc, 0, ir<1>, vp<[[VF]]>
-; CHECK-NEXT:     vp<[[STEPS:%.+]]> = SCALAR-STEPS vp<[[CAN_IV]]>, ir<1>
-; CHECK-NEXT:     WIDEN ir<%c.1> = icmp uge ir<%iv>, ir<%N>
-; CHECK-NEXT:     EMIT vp<[[NOT1:%.+]]> = not ir<%c.1>
-; CHECK-NEXT:     CLONE ir<%arrayidx> = getelementptr ir<%p>, vp<[[STEPS]]>
-; CHECK-NEXT:     vp<[[VEC_PTR:%.+]]> = vector-pointer ir<%arrayidx>
-; CHECK-NEXT:     WIDEN store vp<[[VEC_PTR]]>, ir<0>, vp<[[NOT1]]>
-; CHECK-NEXT:     EMIT vp<%index.next> = add nuw vp<[[CAN_IV]]>, vp<[[VFxUF]]>
-; CHECK-NEXT:     EMIT vp<[[NOT2:%.+]]> = not vp<[[NOT1]]>
-; CHECK-NEXT:     EMIT vp<[[EA_TAKEN:%.+]]> = any-of vp<[[NOT2]]>
-; CHECK-NEXT:     EMIT vp<[[LATCH_CMP:%.+]]> = icmp eq vp<%index.next>, vp<[[VTC]]>
-; CHECK-NEXT:     EMIT vp<[[EC:%.+]]> = or vp<[[EA_TAKEN]]>, vp<[[LATCH_CMP]]>
-; CHECK-NEXT:     EMIT branch-on-cond vp<[[EC]]>
-; CHECK-NEXT:   No successors
-; CHECK-NEXT: }
-; CHECK-NEXT: Successor(s): middle.split
-; CHECK-EMPTY:
-; CHECK-NEXT: middle.split:
-; CHECK-NEXT:   EMIT branch-on-cond vp<[[EA_TAKEN]]>
-; CHECK-NEXT: Successor(s): ir-bb<e>, middle.block
-; CHECK-EMPTY:
-; CHECK-NEXT: ir-bb<e>:
-; CHECK-NEXT:    IR   %p1 = phi i64 [ 0, %loop.header ], [ 1, %loop.latch ] (extra operand: ir<0>, ir<1>)
-; CHECK-NEXT: No successors
-; CHECK-EMPTY:
-; CHECK-NEXT: middle.block:
-; CHECK-NEXT:   EMIT vp<[[MIDDLE_CMP:%.+]]> = icmp eq ir<128>, vp<[[VTC]]>
-; CHECK-NEXT:   EMIT branch-on-cond vp<[[MIDDLE_CMP]]>
-; CHECK-NEXT: Successor(s): ir-bb<e>, scalar.ph
-; CHECK-EMPTY:
-; CHECK-NEXT: scalar.ph:
-; CHECK-NEXT: ir-bb<loop.header>
-; CHECK-EMPTY:
-; CHECK-NEXT: ir-bb<loop.header>:
-; CHECK-NEXT:   IR   %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
-; CHECK-NEXT:   IR   %c.1 = icmp uge i64 %iv, %N
-; CHECK-NEXT: No successors
-; CHECK-NEXT: }
-;
-entry:
-  br label %loop.header
-
-loop.header:
-  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
-  %c.1 = icmp uge i64 %iv, %N
-  br i1 %c.1, label %e, label %loop.latch
-
-loop.latch:
-  %arrayidx = getelementptr inbounds nuw i32, ptr %p, i64 %iv
-  store i32 0, ptr %arrayidx
-  %inc = add nuw i64 %iv, 1
-  %c.2 = icmp eq i64 %inc, 128
-  br i1 %c.2, label %e, label %loop.header, !llvm.loop !1
-
-e:
-  %p1 = phi i64 [ 0, %loop.header ], [ 1, %loop.latch ]
-  ret i64 %p1
-}
-
 !1 = distinct !{!1, !2, !3}
 !2 = !{!"llvm.loop.vectorize.width", i32 4}
 !3 = !{!"llvm.loop.vectorize.enable", i1 true}

>From 9212f9647692387fb4a6ff8cc6a90b1fa2b73628 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 5 Nov 2024 15:07:50 +0000
Subject: [PATCH 06/18] [VPlan] Generalize collectUsersInExitBlocks for
 multiple exit bbs.

Generalize collectUsersInExitBlock to collecting exit users in multiple
exit blocks. Exit blocks are leaf nodes in the VPlan (without
successors) except the scalar header.

Split off from https://github.com/llvm/llvm-project/pull/112138
---
 .../Transforms/Vectorize/LoopVectorize.cpp    | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 47e78a916f8cea..4ccbc8e95d1edf 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -8830,12 +8830,12 @@ static void addScalarResumePhis(VPRecipeBuilder &Builder, VPlan &Plan) {
   }
 }
 
-// Collect VPIRInstructions for phis in the original exit block that are modeled
+// Collect VPIRInstructions for phis in the exit blocks that are modeled
 // in VPlan and add the exiting VPValue as operand. Some exiting values are not
 // modeled explicitly yet and won't be included. Those are un-truncated
 // VPWidenIntOrFpInductionRecipe, VPWidenPointerInductionRecipe and induction
 // increments.
-static SetVector<VPIRInstruction *> collectUsersInExitBlock(
+static SetVector<VPIRInstruction *> collectUsersInExitBlocks(
     Loop *OrigLoop, VPRecipeBuilder &Builder, VPlan &Plan,
     const MapVector<PHINode *, InductionDescriptor> &Inductions) {
   SetVector<VPIRInstruction *> ExitUsersToFix;
@@ -8882,8 +8882,8 @@ static SetVector<VPIRInstruction *> collectUsersInExitBlock(
 // Add exit values to \p Plan. Extracts are added for each entry in \p
 // ExitUsersToFix if needed and their operands are updated.
 static void
-addUsersInExitBlock(VPlan &Plan,
-                    const SetVector<VPIRInstruction *> &ExitUsersToFix) {
+addUsersInExitBlocks(VPlan &Plan,
+                     const SetVector<VPIRInstruction *> &ExitUsersToFix) {
   if (ExitUsersToFix.empty())
     return;
 
@@ -9179,12 +9179,11 @@ LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(VFRange &Range) {
     VPlanTransforms::handleUncountableEarlyExit(*Plan, *PSE.getSE(), OrigLoop,
                                                 RecipeBuilder);
   }
-    addScalarResumePhis(RecipeBuilder, *Plan);
-    SetVector<VPIRInstruction *> ExitUsersToFix = collectUsersInExitBlock(
-        OrigLoop, RecipeBuilder, *Plan, Legal->getInductionVars());
-    addExitUsersForFirstOrderRecurrences(*Plan, ExitUsersToFix);
-    addUsersInExitBlock(*Plan, ExitUsersToFix);
-
+  addScalarResumePhis(RecipeBuilder, *Plan);
+  SetVector<VPIRInstruction *> ExitUsersToFix = collectUsersInExitBlocks(
+      OrigLoop, RecipeBuilder, *Plan, Legal->getInductionVars());
+  addExitUsersForFirstOrderRecurrences(*Plan, ExitUsersToFix);
+  addUsersInExitBlocks(*Plan, ExitUsersToFix);
   // ---------------------------------------------------------------------------
   // Transform initial VPlan: Apply previously taken decisions, in order, to
   // bring the VPlan to its final state.

>From 5cb0851d69513eee7c14f21b598a014925ec6ae1 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 5 Nov 2024 15:36:04 +0000
Subject: [PATCH 07/18] !fixup address comments

---
 .../Transforms/Vectorize/LoopVectorize.cpp    |  62 ++---
 .../Transforms/Vectorize/VPlanTransforms.cpp  |  10 +-
 .../LoopVectorize/X86/multi-exit-vplan.ll     |  89 -------
 .../X86/uncountable-early-exit-vplan.ll       | 244 ++++++++++++++++++
 4 files changed, 283 insertions(+), 122 deletions(-)
 delete mode 100644 llvm/test/Transforms/LoopVectorize/X86/multi-exit-vplan.ll
 create mode 100644 llvm/test/Transforms/LoopVectorize/X86/uncountable-early-exit-vplan.ll

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 4ccbc8e95d1edf..5188aeed2f32b5 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -8845,11 +8845,6 @@ static SetVector<VPIRInstruction *> collectUsersInExitBlocks(
       continue;
     auto *ExitVPBB = cast<VPIRBasicBlock>(VPB);
     BasicBlock *ExitBB = ExitVPBB->getIRBasicBlock();
-    BasicBlock *ExitingBB = find_singleton<BasicBlock>(
-        to_vector(predecessors(ExitBB)),
-        [OrigLoop](BasicBlock *Pred, bool AllowRepeats) {
-          return OrigLoop->contains(Pred) ? Pred : nullptr;
-        });
     for (VPRecipeBase &R : *ExitVPBB) {
       auto *ExitIRI = dyn_cast<VPIRInstruction>(&R);
       if (!ExitIRI)
@@ -8857,23 +8852,27 @@ static SetVector<VPIRInstruction *> collectUsersInExitBlocks(
       auto *ExitPhi = dyn_cast<PHINode>(&ExitIRI->getInstruction());
       if (!ExitPhi)
         break;
-      Value *IncomingValue = ExitPhi->getIncomingValueForBlock(ExitingBB);
-      VPValue *V = Builder.getVPValueOrAddLiveIn(IncomingValue);
-      // Exit values for inductions are computed and updated outside of VPlan
-      // and independent of induction recipes.
-      // TODO: Compute induction exit values in VPlan.
-      if ((isa<VPWidenIntOrFpInductionRecipe>(V) &&
-           !cast<VPWidenIntOrFpInductionRecipe>(V)->getTruncInst()) ||
-          isa<VPWidenPointerInductionRecipe>(V) ||
-          (isa<Instruction>(IncomingValue) &&
-           OrigLoop->contains(cast<Instruction>(IncomingValue)) &&
-           any_of(IncomingValue->users(), [&Inductions](User *U) {
-             auto *P = dyn_cast<PHINode>(U);
-             return P && Inductions.contains(P);
-           })))
-        continue;
-      ExitUsersToFix.insert(ExitIRI);
-      ExitIRI->addOperand(V);
+      for (BasicBlock *ExitingBB : predecessors(ExitBB)) {
+        if (!OrigLoop->contains(ExitingBB))
+          continue;
+        Value *IncomingValue = ExitPhi->getIncomingValueForBlock(ExitingBB);
+        VPValue *V = Builder.getVPValueOrAddLiveIn(IncomingValue);
+        // Exit values for inductions are computed and updated outside of VPlan
+        // and independent of induction recipes.
+        // TODO: Compute induction exit values in VPlan.
+        if ((isa<VPWidenIntOrFpInductionRecipe>(V) &&
+             !cast<VPWidenIntOrFpInductionRecipe>(V)->getTruncInst()) ||
+            isa<VPWidenPointerInductionRecipe>(V) ||
+            (isa<Instruction>(IncomingValue) &&
+             OrigLoop->contains(cast<Instruction>(IncomingValue)) &&
+             any_of(IncomingValue->users(), [&Inductions](User *U) {
+               auto *P = dyn_cast<PHINode>(U);
+               return P && Inductions.contains(P);
+             })))
+          continue;
+        ExitUsersToFix.insert(ExitIRI);
+        ExitIRI->addOperand(V);
+      }
     }
   }
   return ExitUsersToFix;
@@ -8887,23 +8886,26 @@ addUsersInExitBlocks(VPlan &Plan,
   if (ExitUsersToFix.empty())
     return;
 
-  auto *MiddleVPBB = Plan.getMiddleBlock();
-  VPBuilder B(MiddleVPBB, MiddleVPBB->getFirstNonPhi());
-
   // Introduce extract for exiting values and update the VPIRInstructions
   // modeling the corresponding LCSSA phis.
   for (VPIRInstruction *ExitIRI : ExitUsersToFix) {
+
     VPValue *V = ExitIRI->getOperand(0);
     // Pass live-in values used by exit phis directly through to their users in
     // the exit block.
     if (V->isLiveIn())
       continue;
 
-    LLVMContext &Ctx = ExitIRI->getInstruction().getContext();
-    VPValue *Ext = B.createNaryOp(VPInstruction::ExtractFromEnd,
-                                  {V, Plan.getOrAddLiveIn(ConstantInt::get(
-                                          IntegerType::get(Ctx, 32), 1))});
-    ExitIRI->setOperand(0, Ext);
+    for (VPBlockBase *PredVPB : ExitIRI->getParent()->getPredecessors()) {
+      auto *PredVPBB = cast<VPBasicBlock>(PredVPB);
+      VPBuilder B(PredVPBB, PredVPBB->getFirstNonPhi());
+
+      LLVMContext &Ctx = ExitIRI->getInstruction().getContext();
+      VPValue *Ext = B.createNaryOp(VPInstruction::ExtractFromEnd,
+                                    {V, Plan.getOrAddLiveIn(ConstantInt::get(
+                                            IntegerType::get(Ctx, 32), 1))});
+      ExitIRI->setOperand(0, Ext);
+    }
   }
 }
 
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index d336827b23ddf3..661b100d7881c2 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -1815,9 +1815,13 @@ void VPlanTransforms::handleUncountableEarlyExit(
     auto *ExitingTerm = cast<BranchInst>(Exiting->getTerminator());
     BasicBlock *TrueSucc = ExitingTerm->getSuccessor(0);
     BasicBlock *FalseSucc = ExitingTerm->getSuccessor(1);
-    VPIRBasicBlock *VPExitBlock;
-    VPExitBlock = VPIRBasicBlock::fromBasicBlock(
-        !OrigLoop->contains(TrueSucc) ? TrueSucc : FalseSucc);
+    VPBasicBlock *VPExitBlock;
+    if (OrigLoop->getUniqueExitBlock()) {
+      VPExitBlock = cast<VPBasicBlock>(MiddleVPBB->getSuccessors()[0]);
+    } else {
+      VPExitBlock = VPIRBasicBlock::fromBasicBlock(
+          !OrigLoop->contains(TrueSucc) ? TrueSucc : FalseSucc);
+    }
 
     VPValue *M = RecipeBuilder.getBlockInMask(
         OrigLoop->contains(TrueSucc) ? TrueSucc : FalseSucc);
diff --git a/llvm/test/Transforms/LoopVectorize/X86/multi-exit-vplan.ll b/llvm/test/Transforms/LoopVectorize/X86/multi-exit-vplan.ll
deleted file mode 100644
index 5da97ef8f9b3bc..00000000000000
--- a/llvm/test/Transforms/LoopVectorize/X86/multi-exit-vplan.ll
+++ /dev/null
@@ -1,89 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
-; RUN: opt -p loop-vectorize -mcpu=skylake-avx512 -mtriple=x86_64-apple-macosx -force-vector-interleave=1 -S -enable-early-exit-vectorization -debug %s 2>&1 | FileCheck %s
-
-declare void @init(ptr)
-
-define i64 @multi_exiting_to_different_exits_with_store(ptr %p, i64 %N) {
-; CHECK-LABEL: VPlan 'Final VPlan for VF={4},UF={1}' {
-; CHECK-NEXT: Live-in vp<[[VF:%.+]]> = VF
-; CHECK-NEXT: Live-in vp<[[VFxUF:%.+]]> = VF * UF
-; CHECK-NEXT: Live-in vp<[[VTC:%.+]]> = vector-trip-count
-; CHECK-NEXT: Live-in ir<128> = original trip-count
-; CHECK-EMPTY:
-; CHECK-NEXT: vector.ph:
-; CHECK-NEXT: Successor(s): vector loop
-; CHECK-EMPTY:
-; CHECK-NEXT: <x1> vector loop: {
-; CHECK-NEXT:   vector.body:
-; CHECK-NEXT:     EMIT vp<[[CAN_IV:%.+]]> = CANONICAL-INDUCTION ir<0>, vp<%index.next>
-; CHECK-NEXT:     WIDEN-INDUCTION %iv = phi %inc, 0, ir<1>, vp<[[VF]]>
-; CHECK-NEXT:     vp<[[STEPS:%.+]]> = SCALAR-STEPS vp<[[CAN_IV]]>, ir<1>
-; CHECK-NEXT:     WIDEN ir<%c.1> = icmp uge ir<%iv>, ir<%N>
-; CHECK-NEXT:     EMIT vp<[[NOT1:%.+]]> = not ir<%c.1>
-; CHECK-NEXT:     CLONE ir<%arrayidx> = getelementptr ir<%p>, vp<[[STEPS]]>
-; CHECK-NEXT:     vp<[[VEC_PTR:%.+]]> = vector-pointer ir<%arrayidx>
-; CHECK-NEXT:     WIDEN store vp<[[VEC_PTR]]>, ir<0>, vp<[[NOT1]]>
-; CHECK-NEXT:     EMIT vp<%index.next> = add nuw vp<[[CAN_IV]]>, vp<[[VFxUF]]>
-; CHECK-NEXT:     EMIT vp<[[NOT2:%.+]]> = not vp<[[NOT1]]>
-; CHECK-NEXT:     EMIT vp<[[EA_TAKEN:%.+]]> = any-of vp<[[NOT2]]>
-; CHECK-NEXT:     EMIT vp<[[LATCH_CMP:%.+]]> = icmp eq vp<%index.next>, vp<[[VTC]]>
-; CHECK-NEXT:     EMIT vp<[[EC:%.+]]> = or vp<[[EA_TAKEN]]>, vp<[[LATCH_CMP]]>
-; CHECK-NEXT:     EMIT branch-on-cond vp<[[EC]]>
-; CHECK-NEXT:   No successors
-; CHECK-NEXT: }
-; CHECK-NEXT: Successor(s): middle.split
-; CHECK-EMPTY:
-; CHECK-NEXT: middle.split:
-; CHECK-NEXT:   EMIT branch-on-cond vp<[[EA_TAKEN]]>
-; CHECK-NEXT: Successor(s): ir-bb<e1>, middle.block
-; CHECK-EMPTY:
-; CHECK-NEXT: ir-bb<e1>:
-; CHECK-NEXT:   IR %p1 = phi i64 [ 0, %loop.header ] (extra operand: ir<0>)
-; CHECK-NEXT: No successors
-; CHECK-EMPTY:
-; CHECK-NEXT: middle.block:
-; CHECK-NEXT:   EMIT vp<[[MIDDLE_CMP:%.+]]> = icmp eq ir<128>, vp<[[VTC]]>
-; CHECK-NEXT:   EMIT branch-on-cond vp<[[MIDDLE_CMP]]>
-; CHECK-NEXT: Successor(s): ir-bb<e2>, scalar.ph
-; CHECK-EMPTY:
-; CHECK-NEXT: ir-bb<e2>:
-; CHECK-NEXT:  IR %p2 = phi i64 [ 1, %loop.latch ] (extra operand: ir<1>)
-; CHECK-NEXT: No successors
-; CHECK-EMPTY:
-; CHECK-NEXT: scalar.ph:
-; CHECK-NEXT: ir-bb<loop.header>
-; CHECK-EMPTY:
-; CHECK-NEXT: ir-bb<loop.header>:
-; CHECK-NEXT:   IR   %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
-; CHECK-NEXT:   IR   %c.1 = icmp uge i64 %iv, %N
-; CHECK-NEXT: No successors
-; CHECK-NEXT: }
-entry:
-  %src = alloca [128 x i32]
-  call void @init(ptr %src)
-  br label %loop.header
-
-loop.header:
-  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
-  %gep.src = getelementptr inbounds i32, ptr %src, i64 %iv
-  %l = load i32, ptr %gep.src
-  %c.1 = icmp eq i32 %l, 10
-  br i1 %c.1, label %e1, label %loop.latch
-
-loop.latch:
-  %inc = add nuw i64 %iv, 1
-  %c.2 = icmp eq i64 %inc, 128
-  br i1 %c.2, label %e2, label %loop.header, !llvm.loop !1
-
-e1:
-  %p1 = phi i64 [ 0, %loop.header ]
-  ret i64 %p1
-
-e2:
-  %p2 = phi i64 [ 1, %loop.latch ]
-  ret i64 %p2
-}
-
-!1 = distinct !{!1, !2, !3}
-!2 = !{!"llvm.loop.vectorize.width", i32 4}
-!3 = !{!"llvm.loop.vectorize.enable", i1 true}
diff --git a/llvm/test/Transforms/LoopVectorize/X86/uncountable-early-exit-vplan.ll b/llvm/test/Transforms/LoopVectorize/X86/uncountable-early-exit-vplan.ll
new file mode 100644
index 00000000000000..13f5671f893651
--- /dev/null
+++ b/llvm/test/Transforms/LoopVectorize/X86/uncountable-early-exit-vplan.ll
@@ -0,0 +1,244 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -p loop-vectorize -mcpu=skylake-avx512 -mtriple=x86_64-apple-macosx -force-vector-interleave=1 -S -enable-early-exit-vectorization -debug %s 2>&1 | FileCheck %s
+
+declare void @init(ptr)
+
+define i64 @multi_exiting_to_different_exits_live_in_exit_values() {
+; CHECK-LABEL: VPlan 'Final VPlan for VF={4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VF:%.+]]> = VF
+; CHECK-NEXT: Live-in vp<[[VFxUF:%.+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VTC:%.+]]> = vector-trip-count
+; CHECK-NEXT: Live-in ir<128> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT:   vector.body:
+; CHECK-NEXT:     EMIT vp<[[CAN_IV:%.+]]> = CANONICAL-INDUCTION ir<0>, vp<%index.next>
+; CHECK-NEXT:     WIDEN-INDUCTION %iv = phi %inc, 0, ir<1>, vp<[[VF]]>
+; CHECK-NEXT:     vp<[[STEPS:%.+]]> = SCALAR-STEPS vp<[[CAN_IV]]>, ir<1>
+; CHECK-NEXT:     WIDEN ir<%c.1> = icmp uge ir<%iv>, ir<%N>
+; CHECK-NEXT:     EMIT vp<[[NOT1:%.+]]> = not ir<%c.1>
+; CHECK-NEXT:     CLONE ir<%arrayidx> = getelementptr ir<%p>, vp<[[STEPS]]>
+; CHECK-NEXT:     vp<[[VEC_PTR:%.+]]> = vector-pointer ir<%arrayidx>
+; CHECK-NEXT:     WIDEN store vp<[[VEC_PTR]]>, ir<0>, vp<[[NOT1]]>
+; CHECK-NEXT:     EMIT vp<%index.next> = add nuw vp<[[CAN_IV]]>, vp<[[VFxUF]]>
+; CHECK-NEXT:     EMIT vp<[[NOT2:%.+]]> = not vp<[[NOT1]]>
+; CHECK-NEXT:     EMIT vp<[[EA_TAKEN:%.+]]> = any-of vp<[[NOT2]]>
+; CHECK-NEXT:     EMIT vp<[[LATCH_CMP:%.+]]> = icmp eq vp<%index.next>, vp<[[VTC]]>
+; CHECK-NEXT:     EMIT vp<[[EC:%.+]]> = or vp<[[EA_TAKEN]]>, vp<[[LATCH_CMP]]>
+; CHECK-NEXT:     EMIT branch-on-cond vp<[[EC]]>
+; CHECK-NEXT:   No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.split
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.split:
+; CHECK-NEXT:   EMIT branch-on-cond vp<[[EA_TAKEN]]>
+; CHECK-NEXT: Successor(s): ir-bb<e1>, middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<e1>:
+; CHECK-NEXT:   IR %p1 = phi i64 [ 0, %loop.header ] (extra operand: ir<0>)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT:   EMIT vp<[[MIDDLE_CMP:%.+]]> = icmp eq ir<128>, vp<[[VTC]]>
+; CHECK-NEXT:   EMIT branch-on-cond vp<[[MIDDLE_CMP]]>
+; CHECK-NEXT: Successor(s): ir-bb<e2>, scalar.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<e2>:
+; CHECK-NEXT:  IR %p2 = phi i64 [ 1, %loop.latch ] (extra operand: ir<1>)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: ir-bb<loop.header>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop.header>:
+; CHECK-NEXT:   IR   %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
+; CHECK-NEXT:   IR   %c.1 = icmp uge i64 %iv, %N
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+entry:
+  %src = alloca [128 x i32]
+  call void @init(ptr %src)
+  br label %loop.header
+
+loop.header:
+  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
+  %gep.src = getelementptr inbounds i32, ptr %src, i64 %iv
+  %l = load i32, ptr %gep.src
+  %c.1 = icmp eq i32 %l, 10
+  br i1 %c.1, label %e1, label %loop.latch
+
+loop.latch:
+  %inc = add nuw i64 %iv, 1
+  %c.2 = icmp eq i64 %inc, 128
+  br i1 %c.2, label %e2, label %loop.header
+
+e1:
+  %p1 = phi i64 [ 0, %loop.header ]
+  ret i64 %p1
+
+e2:
+  %p2 = phi i64 [ 1, %loop.latch ]
+  ret i64 %p2
+}
+
+define i64 @multi_exiting_to_different_exits_load_exit_value() {
+; CHECK-LABEL: VPlan 'Final VPlan for VF={4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VF:%.+]]> = VF
+; CHECK-NEXT: Live-in vp<[[VFxUF:%.+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VTC:%.+]]> = vector-trip-count
+; CHECK-NEXT: Live-in ir<128> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT:   vector.body:
+; CHECK-NEXT:     EMIT vp<[[CAN_IV:%.+]]> = CANONICAL-INDUCTION ir<0>, vp<%index.next>
+; CHECK-NEXT:     WIDEN-INDUCTION %iv = phi %inc, 0, ir<1>, vp<[[VF]]>
+; CHECK-NEXT:     vp<[[STEPS:%.+]]> = SCALAR-STEPS vp<[[CAN_IV]]>, ir<1>
+; CHECK-NEXT:     WIDEN ir<%c.1> = icmp uge ir<%iv>, ir<%N>
+; CHECK-NEXT:     EMIT vp<[[NOT1:%.+]]> = not ir<%c.1>
+; CHECK-NEXT:     CLONE ir<%arrayidx> = getelementptr ir<%p>, vp<[[STEPS]]>
+; CHECK-NEXT:     vp<[[VEC_PTR:%.+]]> = vector-pointer ir<%arrayidx>
+; CHECK-NEXT:     WIDEN store vp<[[VEC_PTR]]>, ir<0>, vp<[[NOT1]]>
+; CHECK-NEXT:     EMIT vp<%index.next> = add nuw vp<[[CAN_IV]]>, vp<[[VFxUF]]>
+; CHECK-NEXT:     EMIT vp<[[NOT2:%.+]]> = not vp<[[NOT1]]>
+; CHECK-NEXT:     EMIT vp<[[EA_TAKEN:%.+]]> = any-of vp<[[NOT2]]>
+; CHECK-NEXT:     EMIT vp<[[LATCH_CMP:%.+]]> = icmp eq vp<%index.next>, vp<[[VTC]]>
+; CHECK-NEXT:     EMIT vp<[[EC:%.+]]> = or vp<[[EA_TAKEN]]>, vp<[[LATCH_CMP]]>
+; CHECK-NEXT:     EMIT branch-on-cond vp<[[EC]]>
+; CHECK-NEXT:   No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.split
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.split:
+; CHECK-NEXT:   EMIT branch-on-cond vp<[[EA_TAKEN]]>
+; CHECK-NEXT: Successor(s): ir-bb<e1>, middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<e1>:
+; CHECK-NEXT:   IR %p1 = phi i64 [ 0, %loop.header ] (extra operand: ir<0>)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT:   EMIT vp<[[MIDDLE_CMP:%.+]]> = icmp eq ir<128>, vp<[[VTC]]>
+; CHECK-NEXT:   EMIT branch-on-cond vp<[[MIDDLE_CMP]]>
+; CHECK-NEXT: Successor(s): ir-bb<e2>, scalar.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<e2>:
+; CHECK-NEXT:  IR %p2 = phi i64 [ 1, %loop.latch ] (extra operand: ir<1>)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: ir-bb<loop.header>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop.header>:
+; CHECK-NEXT:   IR   %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
+; CHECK-NEXT:   IR   %c.1 = icmp uge i64 %iv, %N
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+entry:
+  %src = alloca [128 x i64]
+  call void @init(ptr %src)
+  br label %loop.header
+
+loop.header:
+  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
+  %gep.src = getelementptr inbounds i64, ptr %src, i64 %iv
+  %l = load i64, ptr %gep.src
+  %c.1 = icmp eq i64 %l, 10
+  br i1 %c.1, label %e1, label %loop.latch
+
+loop.latch:
+  %inc = add nuw i64 %iv, 1
+  %c.2 = icmp eq i64 %inc, 128
+  br i1 %c.2, label %e2, label %loop.header
+
+e1:
+  %p1 = phi i64 [ %l, %loop.header ]
+  ret i64 %p1
+
+e2:
+  %p2 = phi i64 [ 1, %loop.latch ]
+  ret i64 %p2
+}
+
+define i64 @multi_exiting_to_same_exit_load_exit_value() {
+; CHECK-LABEL: VPlan 'Final VPlan for VF={4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VF:%.+]]> = VF
+; CHECK-NEXT: Live-in vp<[[VFxUF:%.+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VTC:%.+]]> = vector-trip-count
+; CHECK-NEXT: Live-in ir<128> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT:   vector.body:
+; CHECK-NEXT:     EMIT vp<[[CAN_IV:%.+]]> = CANONICAL-INDUCTION ir<0>, vp<%index.next>
+; CHECK-NEXT:     WIDEN-INDUCTION %iv = phi %inc, 0, ir<1>, vp<[[VF]]>
+; CHECK-NEXT:     vp<[[STEPS:%.+]]> = SCALAR-STEPS vp<[[CAN_IV]]>, ir<1>
+; CHECK-NEXT:     WIDEN ir<%c.1> = icmp uge ir<%iv>, ir<%N>
+; CHECK-NEXT:     EMIT vp<[[NOT1:%.+]]> = not ir<%c.1>
+; CHECK-NEXT:     CLONE ir<%arrayidx> = getelementptr ir<%p>, vp<[[STEPS]]>
+; CHECK-NEXT:     vp<[[VEC_PTR:%.+]]> = vector-pointer ir<%arrayidx>
+; CHECK-NEXT:     WIDEN store vp<[[VEC_PTR]]>, ir<0>, vp<[[NOT1]]>
+; CHECK-NEXT:     EMIT vp<%index.next> = add nuw vp<[[CAN_IV]]>, vp<[[VFxUF]]>
+; CHECK-NEXT:     EMIT vp<[[NOT2:%.+]]> = not vp<[[NOT1]]>
+; CHECK-NEXT:     EMIT vp<[[EA_TAKEN:%.+]]> = any-of vp<[[NOT2]]>
+; CHECK-NEXT:     EMIT vp<[[LATCH_CMP:%.+]]> = icmp eq vp<%index.next>, vp<[[VTC]]>
+; CHECK-NEXT:     EMIT vp<[[EC:%.+]]> = or vp<[[EA_TAKEN]]>, vp<[[LATCH_CMP]]>
+; CHECK-NEXT:     EMIT branch-on-cond vp<[[EC]]>
+; CHECK-NEXT:   No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.split
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.split:
+; CHECK-NEXT:   EMIT branch-on-cond vp<[[EA_TAKEN]]>
+; CHECK-NEXT: Successor(s): ir-bb<e1>, middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<e1>:
+; CHECK-NEXT:   IR %p1 = phi i64 [ 0, %loop.header ] (extra operand: ir<0>)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT:   EMIT vp<[[MIDDLE_CMP:%.+]]> = icmp eq ir<128>, vp<[[VTC]]>
+; CHECK-NEXT:   EMIT branch-on-cond vp<[[MIDDLE_CMP]]>
+; CHECK-NEXT: Successor(s): ir-bb<e2>, scalar.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<e2>:
+; CHECK-NEXT:  IR %p2 = phi i64 [ 1, %loop.latch ] (extra operand: ir<1>)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: ir-bb<loop.header>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop.header>:
+; CHECK-NEXT:   IR   %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
+; CHECK-NEXT:   IR   %c.1 = icmp uge i64 %iv, %N
+; CHECK-NEXT: No successors
+; CHECK-NEXT: }
+entry:
+  %src = alloca [128 x i64]
+  call void @init(ptr %src)
+  br label %loop.header
+
+loop.header:
+  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
+  %gep.src = getelementptr inbounds i64, ptr %src, i64 %iv
+  %l = load i64, ptr %gep.src
+  %l.2 = load i64, ptr %gep.src
+  %c.1 = icmp eq i64 %l, 10
+  br i1 %c.1, label %e1, label %loop.latch
+
+loop.latch:
+  %inc = add nuw i64 %iv, 1
+  %c.2 = icmp eq i64 %inc, 128
+  br i1 %c.2, label %e1, label %loop.header
+
+e1:
+  %p1 = phi i64 [ %l, %loop.header ], [ %l.2, %loop.latch ]
+  ret i64 %p1
+}

>From e849195a4994293aab10fb9786dc006064374ac0 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 5 Nov 2024 20:48:45 +0000
Subject: [PATCH 08/18] !fixup address more comments.

---
 .../Transforms/Vectorize/LoopVectorize.cpp    |  27 +-
 llvm/lib/Transforms/Vectorize/VPlan.h         |   4 +
 llvm/lib/Transforms/Vectorize/VPlanCFG.h      |   9 +
 .../lib/Transforms/Vectorize/VPlanRecipes.cpp |   1 -
 .../Transforms/Vectorize/VPlanTransforms.cpp  |  13 +-
 .../Transforms/Vectorize/VPlanTransforms.h    |  13 +-
 .../LoopVectorize/X86/multi-exit-codegen.ll   | 240 -----------------
 .../X86/uncountable-early-exit-vplan.ll       | 244 ------------------
 .../uncountable-early-exit-vplan.ll           | 171 ++++++++++++
 9 files changed, 218 insertions(+), 504 deletions(-)
 delete mode 100644 llvm/test/Transforms/LoopVectorize/X86/multi-exit-codegen.ll
 delete mode 100644 llvm/test/Transforms/LoopVectorize/X86/uncountable-early-exit-vplan.ll
 create mode 100644 llvm/test/Transforms/LoopVectorize/uncountable-early-exit-vplan.ll

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 5188aeed2f32b5..1c02db88c3f3c8 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -8839,11 +8839,7 @@ static SetVector<VPIRInstruction *> collectUsersInExitBlocks(
     Loop *OrigLoop, VPRecipeBuilder &Builder, VPlan &Plan,
     const MapVector<PHINode *, InductionDescriptor> &Inductions) {
   SetVector<VPIRInstruction *> ExitUsersToFix;
-  for (VPBlockBase *VPB : vp_depth_first_shallow(
-           Plan.getVectorLoopRegion()->getSingleSuccessor())) {
-    if (VPB->getNumSuccessors() != 0 || VPB == Plan.getScalarHeader())
-      continue;
-    auto *ExitVPBB = cast<VPIRBasicBlock>(VPB);
+  for (VPIRBasicBlock *ExitVPBB : Plan.getExitBlocks()) {
     BasicBlock *ExitBB = ExitVPBB->getIRBasicBlock();
     for (VPRecipeBase &R : *ExitVPBB) {
       auto *ExitIRI = dyn_cast<VPIRInstruction>(&R);
@@ -9178,14 +9174,31 @@ LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(VFRange &Range) {
   RecipeBuilder.fixHeaderPhis();
 
   if (Legal->hasUncountableEarlyExit()) {
-    VPlanTransforms::handleUncountableEarlyExit(*Plan, *PSE.getSE(), OrigLoop,
-                                                RecipeBuilder);
+    VPlanTransforms::handleUncountableEarlyExit(
+        *Plan, *PSE.getSE(), OrigLoop, Legal->getUncountableExitingBlocks(),
+        RecipeBuilder);
   }
   addScalarResumePhis(RecipeBuilder, *Plan);
   SetVector<VPIRInstruction *> ExitUsersToFix = collectUsersInExitBlocks(
       OrigLoop, RecipeBuilder, *Plan, Legal->getInductionVars());
   addExitUsersForFirstOrderRecurrences(*Plan, ExitUsersToFix);
   addUsersInExitBlocks(*Plan, ExitUsersToFix);
+
+  // Currently only live-ins can be used by exit values. We also bail out if any
+  // exit value isn't handled in VPlan yet, i.e. a VPIRInstruction in the exit
+  // without any operands.
+  if (Legal->hasUncountableEarlyExit()) {
+    if (any_of(Plan->getExitBlocks(), [](VPIRBasicBlock *ExitBB) {
+          return any_of(*ExitBB, [](VPRecipeBase &R) {
+            auto VPIRI = cast<VPIRInstruction>(&R);
+            return VPIRI->getNumOperands() == 0 ||
+                   any_of(VPIRI->operands(),
+                          [](VPValue *Op) { return !Op->isLiveIn(); });
+          });
+        }))
+      return nullptr;
+  }
+
   // ---------------------------------------------------------------------------
   // Transform initial VPlan: Apply previously taken decisions, in order, to
   // bring the VPlan to its final state.
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 44fd49fed6ad90..34a3a180bfa52a 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -3832,6 +3832,10 @@ class VPlan {
     return cast<VPBasicBlock>(getScalarPreheader()->getSinglePredecessor());
   }
 
+  /// Return the exit blocks of the VPlan, that is leaf nodes except the scalar
+  /// header.
+  auto getExitBlocks();
+
   /// The trip count of the original loop.
   VPValue *getTripCount() const {
     assert(TripCount && "trip count needs to be set before accessing it");
diff --git a/llvm/lib/Transforms/Vectorize/VPlanCFG.h b/llvm/lib/Transforms/Vectorize/VPlanCFG.h
index 89e2e7514dac2b..6ca388a953a6ff 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanCFG.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanCFG.h
@@ -306,6 +306,15 @@ template <> struct GraphTraits<VPlan *> {
   }
 };
 
+inline auto VPlan::getExitBlocks() {
+  VPBlockBase *ScalarHeader = getScalarHeader();
+  return make_filter_range(
+      VPBlockUtils::blocksOnly<VPIRBasicBlock>(
+          vp_depth_first_shallow(getVectorLoopRegion()->getSingleSuccessor())),
+      [ScalarHeader](VPIRBasicBlock *VPIRBB) {
+        return VPIRBB != ScalarHeader && VPIRBB->getNumSuccessors() == 0;
+      });
+}
 } // namespace llvm
 
 #endif // LLVM_TRANSFORMS_VECTORIZE_VPLANCFG_H
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index 7f582ce8c99433..a1a0c2ffcf0597 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -872,7 +872,6 @@ void VPIRInstruction::print(raw_ostream &O, const Twine &Indent,
   O << Indent << "IR " << I;
 
   if (getNumOperands() != 0) {
-    // assert(getNumOperands() == 1 && "can have at most 1 operand");
     O << " (extra operand: ";
     printOperands(O, SlotTracker);
     O << ")";
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index 661b100d7881c2..ed37e492b34fb1 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -1793,31 +1793,26 @@ void VPlanTransforms::createInterleaveGroups(
 
 void VPlanTransforms::handleUncountableEarlyExit(
     VPlan &Plan, ScalarEvolution &SE, Loop *OrigLoop,
+    ArrayRef<BasicBlock *> UncountableExitingBlocks,
     VPRecipeBuilder &RecipeBuilder) {
   auto *LatchVPBB =
       cast<VPBasicBlock>(Plan.getVectorLoopRegion()->getExiting());
   VPBuilder Builder(LatchVPBB->getTerminator());
   auto *MiddleVPBB = Plan.getMiddleBlock();
   VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
-
   VPValue *EarlyExitTaken = nullptr;
-  SmallVector<BasicBlock *> ExitingBBs;
-  OrigLoop->getExitingBlocks(ExitingBBs);
 
   // Process all uncountable exiting blocks. For each exiting block, update the
   // EarlyExitTaken, which tracks if any uncountable early exit has been taken.
   // Also split the middle block and branch to the exit block for the early exit
   // if it has been taken.
-  for (BasicBlock *Exiting : ExitingBBs) {
-    if (Exiting == OrigLoop->getLoopLatch())
-      continue;
-
+  for (BasicBlock *Exiting : UncountableExitingBlocks) {
     auto *ExitingTerm = cast<BranchInst>(Exiting->getTerminator());
     BasicBlock *TrueSucc = ExitingTerm->getSuccessor(0);
     BasicBlock *FalseSucc = ExitingTerm->getSuccessor(1);
-    VPBasicBlock *VPExitBlock;
+    VPIRBasicBlock *VPExitBlock;
     if (OrigLoop->getUniqueExitBlock()) {
-      VPExitBlock = cast<VPBasicBlock>(MiddleVPBB->getSuccessors()[0]);
+      VPExitBlock = cast<VPIRBasicBlock>(MiddleVPBB->getSuccessors()[0]);
     } else {
       VPExitBlock = VPIRBasicBlock::fromBasicBlock(
           !OrigLoop->contains(TrueSucc) ? TrueSucc : FalseSucc);
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.h b/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
index f7bbae25279fce..dc5dec2f1b84a6 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
@@ -124,9 +124,16 @@ struct VPlanTransforms {
   /// Remove dead recipes from \p Plan.
   static void removeDeadRecipes(VPlan &Plan);
 
-  static void handleUncountableEarlyExit(VPlan &Plan, ScalarEvolution &SE,
-                                         Loop *OrigLoop,
-                                         VPRecipeBuilder &RecipeBuilder);
+  /// Update \p Plan to account for uncountable exit blocks in \p
+  /// UncountableExitingBlocks by
+  ///  * updating the condition to exit the vector loop to include the early
+  ///  exit conditions
+  ///  * splitting the original middle block to branch to the early exit blocks
+  ///  if taken. Returns false if the transformation wasn't successful.
+  static void
+  handleUncountableEarlyExit(VPlan &Plan, ScalarEvolution &SE, Loop *OrigLoop,
+                             ArrayRef<BasicBlock *> UncountableExitingBlocks,
+                             VPRecipeBuilder &RecipeBuilder);
 };
 
 } // namespace llvm
diff --git a/llvm/test/Transforms/LoopVectorize/X86/multi-exit-codegen.ll b/llvm/test/Transforms/LoopVectorize/X86/multi-exit-codegen.ll
deleted file mode 100644
index 0c33715c6bd271..00000000000000
--- a/llvm/test/Transforms/LoopVectorize/X86/multi-exit-codegen.ll
+++ /dev/null
@@ -1,240 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
-; RUN: opt -p loop-vectorize -mcpu=skylake-avx512 -mtriple=x86_64-apple-macosx -force-vector-interleave=1 -S -enable-early-exit-vectorization %s | FileCheck --check-prefix=MULTI %s
-; RUN: opt -p loop-vectorize -mcpu=skylake-avx512 -mtriple=x86_64-apple-macosx -force-vector-interleave=1 -S -enable-early-exit-vectorization=false %s | FileCheck --check-prefix=DEFAULT %s
-
-define i64 @multi_exit_with_store(ptr %p, i64 %N) {
-; MULTI-LABEL: define i64 @multi_exit_with_store(
-; MULTI-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) #[[ATTR0:[0-9]+]] {
-; MULTI-NEXT:  [[ENTRY:.*]]:
-; MULTI-NEXT:    br i1 false, label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
-; MULTI:       [[VECTOR_PH]]:
-; MULTI-NEXT:    [[BROADCAST_SPLATINSERT:%.*]] = insertelement <4 x i64> poison, i64 [[N]], i64 0
-; MULTI-NEXT:    [[BROADCAST_SPLAT:%.*]] = shufflevector <4 x i64> [[BROADCAST_SPLATINSERT]], <4 x i64> poison, <4 x i32> zeroinitializer
-; MULTI-NEXT:    br label %[[VECTOR_BODY:.*]]
-; MULTI:       [[VECTOR_BODY]]:
-; MULTI-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]
-; MULTI-NEXT:    [[VEC_IND:%.*]] = phi <4 x i64> [ <i64 0, i64 1, i64 2, i64 3>, %[[VECTOR_PH]] ], [ [[VEC_IND_NEXT:%.*]], %[[VECTOR_BODY]] ]
-; MULTI-NEXT:    [[TMP0:%.*]] = add i64 [[INDEX]], 0
-; MULTI-NEXT:    [[TMP1:%.*]] = icmp uge <4 x i64> [[VEC_IND]], [[BROADCAST_SPLAT]]
-; MULTI-NEXT:    [[TMP2:%.*]] = xor <4 x i1> [[TMP1]], <i1 true, i1 true, i1 true, i1 true>
-; MULTI-NEXT:    [[TMP3:%.*]] = getelementptr i32, ptr [[P]], i64 [[TMP0]]
-; MULTI-NEXT:    [[TMP4:%.*]] = getelementptr i32, ptr [[TMP3]], i32 0
-; MULTI-NEXT:    call void @llvm.masked.store.v4i32.p0(<4 x i32> zeroinitializer, ptr [[TMP4]], i32 4, <4 x i1> [[TMP2]])
-; MULTI-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
-; MULTI-NEXT:    [[TMP5:%.*]] = xor <4 x i1> [[TMP2]], <i1 true, i1 true, i1 true, i1 true>
-; MULTI-NEXT:    [[TMP6:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP5]])
-; MULTI-NEXT:    [[TMP7:%.*]] = icmp eq i64 [[INDEX_NEXT]], 128
-; MULTI-NEXT:    [[VEC_IND_NEXT]] = add <4 x i64> [[VEC_IND]], <i64 4, i64 4, i64 4, i64 4>
-; MULTI-NEXT:    [[TMP8:%.*]] = or i1 [[TMP6]], [[TMP7]]
-; MULTI-NEXT:    br i1 [[TMP8]], label %[[MIDDLE_SPLIT:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP0:![0-9]+]]
-; MULTI:       [[MIDDLE_SPLIT]]:
-; MULTI-NEXT:    br i1 [[TMP6]], label %[[E1:.*]], label %[[MIDDLE_BLOCK:.*]]
-; MULTI:       [[MIDDLE_BLOCK]]:
-; MULTI-NEXT:    br i1 true, label %[[E2:.*]], label %[[SCALAR_PH]]
-; MULTI:       [[SCALAR_PH]]:
-; MULTI-NEXT:    [[BC_RESUME_VAL:%.*]] = phi i64 [ 128, %[[MIDDLE_BLOCK]] ], [ 0, %[[ENTRY]] ]
-; MULTI-NEXT:    br label %[[LOOP_HEADER:.*]]
-; MULTI:       [[LOOP_HEADER]]:
-; MULTI-NEXT:    [[I_07:%.*]] = phi i64 [ [[INC:%.*]], %[[LOOP_LATCH:.*]] ], [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ]
-; MULTI-NEXT:    [[CMP1:%.*]] = icmp uge i64 [[I_07]], [[N]]
-; MULTI-NEXT:    br i1 [[CMP1]], label %[[E1]], label %[[LOOP_LATCH]]
-; MULTI:       [[LOOP_LATCH]]:
-; MULTI-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i32, ptr [[P]], i64 [[I_07]]
-; MULTI-NEXT:    store i32 0, ptr [[ARRAYIDX]], align 4
-; MULTI-NEXT:    [[INC]] = add nuw i64 [[I_07]], 1
-; MULTI-NEXT:    [[CMP_NOT:%.*]] = icmp eq i64 [[INC]], 128
-; MULTI-NEXT:    br i1 [[CMP_NOT]], label %[[E2]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP3:![0-9]+]]
-; MULTI:       [[E1]]:
-; MULTI-NEXT:    ret i64 0
-; MULTI:       [[E2]]:
-; MULTI-NEXT:    ret i64 1
-;
-; DEFAULT-LABEL: define i64 @multi_exit_with_store(
-; DEFAULT-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) #[[ATTR0:[0-9]+]] {
-; DEFAULT-NEXT:  [[ENTRY:.*]]:
-; DEFAULT-NEXT:    [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[N]], i64 127)
-; DEFAULT-NEXT:    [[TMP4:%.*]] = add nuw nsw i64 [[UMIN]], 1
-; DEFAULT-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ule i64 [[TMP4]], 4
-; DEFAULT-NEXT:    br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
-; DEFAULT:       [[VECTOR_PH]]:
-; DEFAULT-NEXT:    [[N_MOD_VF:%.*]] = urem i64 [[TMP4]], 4
-; DEFAULT-NEXT:    [[TMP5:%.*]] = icmp eq i64 [[N_MOD_VF]], 0
-; DEFAULT-NEXT:    [[TMP2:%.*]] = select i1 [[TMP5]], i64 4, i64 [[N_MOD_VF]]
-; DEFAULT-NEXT:    [[N_VEC:%.*]] = sub i64 [[TMP4]], [[TMP2]]
-; DEFAULT-NEXT:    br label %[[VECTOR_BODY:.*]]
-; DEFAULT:       [[VECTOR_BODY]]:
-; DEFAULT-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]
-; DEFAULT-NEXT:    [[TMP0:%.*]] = add i64 [[INDEX]], 0
-; DEFAULT-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[P]], i64 [[TMP0]]
-; DEFAULT-NEXT:    [[TMP3:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i32 0
-; DEFAULT-NEXT:    store <4 x i32> zeroinitializer, ptr [[TMP3]], align 4
-; DEFAULT-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
-; DEFAULT-NEXT:    [[TMP6:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
-; DEFAULT-NEXT:    br i1 [[TMP6]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP0:![0-9]+]]
-; DEFAULT:       [[MIDDLE_BLOCK]]:
-; DEFAULT-NEXT:    br label %[[SCALAR_PH]]
-; DEFAULT:       [[SCALAR_PH]]:
-; DEFAULT-NEXT:    [[BC_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], %[[MIDDLE_BLOCK]] ], [ 0, %[[ENTRY]] ]
-; DEFAULT-NEXT:    br label %[[LOOP_HEADER:.*]]
-; DEFAULT:       [[LOOP_HEADER]]:
-; DEFAULT-NEXT:    [[I_07:%.*]] = phi i64 [ [[INC:%.*]], %[[LOOP_LATCH:.*]] ], [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ]
-; DEFAULT-NEXT:    [[CMP1:%.*]] = icmp uge i64 [[I_07]], [[N]]
-; DEFAULT-NEXT:    br i1 [[CMP1]], label %[[E1:.*]], label %[[LOOP_LATCH]]
-; DEFAULT:       [[LOOP_LATCH]]:
-; DEFAULT-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i32, ptr [[P]], i64 [[I_07]]
-; DEFAULT-NEXT:    store i32 0, ptr [[ARRAYIDX]], align 4
-; DEFAULT-NEXT:    [[INC]] = add nuw i64 [[I_07]], 1
-; DEFAULT-NEXT:    [[CMP_NOT:%.*]] = icmp eq i64 [[INC]], 128
-; DEFAULT-NEXT:    br i1 [[CMP_NOT]], label %[[E2:.*]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP3:![0-9]+]]
-; DEFAULT:       [[E1]]:
-; DEFAULT-NEXT:    ret i64 0
-; DEFAULT:       [[E2]]:
-; DEFAULT-NEXT:    ret i64 1
-;
-entry:
-  br label %loop.header
-
-loop.header:
-  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
-  %c.1 = icmp uge i64 %iv, %N
-  br i1 %c.1, label %e1, label %loop.latch
-
-loop.latch:
-  %arrayidx = getelementptr inbounds nuw i32, ptr %p, i64 %iv
-  store i32 0, ptr %arrayidx
-  %inc = add nuw i64 %iv, 1
-  %c.2 = icmp eq i64 %inc, 128
-  br i1 %c.2, label %e2, label %loop.header, !llvm.loop !1
-
-e1:
-  ret i64 0
-
-e2:
-  ret i64 1
-}
-
-define i64 @multi_exiting_to_same_exit_with_store(ptr %p, i64 %N) {
-; MULTI-LABEL: define i64 @multi_exiting_to_same_exit_with_store(
-; MULTI-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) #[[ATTR0]] {
-; MULTI-NEXT:  [[ENTRY:.*]]:
-; MULTI-NEXT:    br i1 false, label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
-; MULTI:       [[VECTOR_PH]]:
-; MULTI-NEXT:    [[BROADCAST_SPLATINSERT:%.*]] = insertelement <4 x i64> poison, i64 [[N]], i64 0
-; MULTI-NEXT:    [[BROADCAST_SPLAT:%.*]] = shufflevector <4 x i64> [[BROADCAST_SPLATINSERT]], <4 x i64> poison, <4 x i32> zeroinitializer
-; MULTI-NEXT:    br label %[[VECTOR_BODY:.*]]
-; MULTI:       [[VECTOR_BODY]]:
-; MULTI-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]
-; MULTI-NEXT:    [[VEC_IND:%.*]] = phi <4 x i64> [ <i64 0, i64 1, i64 2, i64 3>, %[[VECTOR_PH]] ], [ [[VEC_IND_NEXT:%.*]], %[[VECTOR_BODY]] ]
-; MULTI-NEXT:    [[TMP0:%.*]] = add i64 [[INDEX]], 0
-; MULTI-NEXT:    [[TMP1:%.*]] = icmp uge <4 x i64> [[VEC_IND]], [[BROADCAST_SPLAT]]
-; MULTI-NEXT:    [[TMP2:%.*]] = xor <4 x i1> [[TMP1]], <i1 true, i1 true, i1 true, i1 true>
-; MULTI-NEXT:    [[TMP3:%.*]] = getelementptr i32, ptr [[P]], i64 [[TMP0]]
-; MULTI-NEXT:    [[TMP4:%.*]] = getelementptr i32, ptr [[TMP3]], i32 0
-; MULTI-NEXT:    call void @llvm.masked.store.v4i32.p0(<4 x i32> zeroinitializer, ptr [[TMP4]], i32 4, <4 x i1> [[TMP2]])
-; MULTI-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
-; MULTI-NEXT:    [[TMP5:%.*]] = xor <4 x i1> [[TMP2]], <i1 true, i1 true, i1 true, i1 true>
-; MULTI-NEXT:    [[TMP6:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP5]])
-; MULTI-NEXT:    [[TMP7:%.*]] = icmp eq i64 [[INDEX_NEXT]], 128
-; MULTI-NEXT:    [[VEC_IND_NEXT]] = add <4 x i64> [[VEC_IND]], <i64 4, i64 4, i64 4, i64 4>
-; MULTI-NEXT:    [[TMP8:%.*]] = or i1 [[TMP6]], [[TMP7]]
-; MULTI-NEXT:    br i1 [[TMP8]], label %[[MIDDLE_SPLIT:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP4:![0-9]+]]
-; MULTI:       [[MIDDLE_SPLIT]]:
-; MULTI-NEXT:    br i1 [[TMP6]], label %[[E:.*]], label %[[MIDDLE_BLOCK:.*]]
-; MULTI:       [[MIDDLE_BLOCK]]:
-; MULTI-NEXT:    br i1 true, label %[[E]], label %[[SCALAR_PH]]
-; MULTI:       [[SCALAR_PH]]:
-; MULTI-NEXT:    [[BC_RESUME_VAL:%.*]] = phi i64 [ 128, %[[MIDDLE_BLOCK]] ], [ 0, %[[ENTRY]] ]
-; MULTI-NEXT:    br label %[[LOOP_HEADER:.*]]
-; MULTI:       [[LOOP_HEADER]]:
-; MULTI-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], %[[LOOP_LATCH:.*]] ], [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ]
-; MULTI-NEXT:    [[C_1:%.*]] = icmp uge i64 [[IV]], [[N]]
-; MULTI-NEXT:    br i1 [[C_1]], label %[[E]], label %[[LOOP_LATCH]]
-; MULTI:       [[LOOP_LATCH]]:
-; MULTI-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i32, ptr [[P]], i64 [[IV]]
-; MULTI-NEXT:    store i32 0, ptr [[ARRAYIDX]], align 4
-; MULTI-NEXT:    [[INC]] = add nuw i64 [[IV]], 1
-; MULTI-NEXT:    [[C_2:%.*]] = icmp eq i64 [[INC]], 128
-; MULTI-NEXT:    br i1 [[C_2]], label %[[E]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP5:![0-9]+]]
-; MULTI:       [[E]]:
-; MULTI-NEXT:    [[P1:%.*]] = phi i64 [ 0, %[[LOOP_HEADER]] ], [ 1, %[[LOOP_LATCH]] ], [ 0, %[[MIDDLE_BLOCK]] ], [ 1, %[[MIDDLE_SPLIT]] ]
-; MULTI-NEXT:    ret i64 [[P1]]
-;
-; DEFAULT-LABEL: define i64 @multi_exiting_to_same_exit_with_store(
-; DEFAULT-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) #[[ATTR0]] {
-; DEFAULT-NEXT:  [[ENTRY:.*]]:
-; DEFAULT-NEXT:    [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[N]], i64 127)
-; DEFAULT-NEXT:    [[TMP0:%.*]] = add nuw nsw i64 [[UMIN]], 1
-; DEFAULT-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ule i64 [[TMP0]], 4
-; DEFAULT-NEXT:    br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
-; DEFAULT:       [[VECTOR_PH]]:
-; DEFAULT-NEXT:    [[N_MOD_VF:%.*]] = urem i64 [[TMP0]], 4
-; DEFAULT-NEXT:    [[TMP1:%.*]] = icmp eq i64 [[N_MOD_VF]], 0
-; DEFAULT-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i64 4, i64 [[N_MOD_VF]]
-; DEFAULT-NEXT:    [[N_VEC:%.*]] = sub i64 [[TMP0]], [[TMP2]]
-; DEFAULT-NEXT:    br label %[[VECTOR_BODY:.*]]
-; DEFAULT:       [[VECTOR_BODY]]:
-; DEFAULT-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]
-; DEFAULT-NEXT:    [[TMP3:%.*]] = add i64 [[INDEX]], 0
-; DEFAULT-NEXT:    [[TMP4:%.*]] = getelementptr inbounds i32, ptr [[P]], i64 [[TMP3]]
-; DEFAULT-NEXT:    [[TMP5:%.*]] = getelementptr inbounds i32, ptr [[TMP4]], i32 0
-; DEFAULT-NEXT:    store <4 x i32> zeroinitializer, ptr [[TMP5]], align 4
-; DEFAULT-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
-; DEFAULT-NEXT:    [[TMP6:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
-; DEFAULT-NEXT:    br i1 [[TMP6]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP4:![0-9]+]]
-; DEFAULT:       [[MIDDLE_BLOCK]]:
-; DEFAULT-NEXT:    br label %[[SCALAR_PH]]
-; DEFAULT:       [[SCALAR_PH]]:
-; DEFAULT-NEXT:    [[BC_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], %[[MIDDLE_BLOCK]] ], [ 0, %[[ENTRY]] ]
-; DEFAULT-NEXT:    br label %[[LOOP_HEADER:.*]]
-; DEFAULT:       [[LOOP_HEADER]]:
-; DEFAULT-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], %[[LOOP_LATCH:.*]] ], [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ]
-; DEFAULT-NEXT:    [[C_1:%.*]] = icmp uge i64 [[IV]], [[N]]
-; DEFAULT-NEXT:    br i1 [[C_1]], label %[[E:.*]], label %[[LOOP_LATCH]]
-; DEFAULT:       [[LOOP_LATCH]]:
-; DEFAULT-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i32, ptr [[P]], i64 [[IV]]
-; DEFAULT-NEXT:    store i32 0, ptr [[ARRAYIDX]], align 4
-; DEFAULT-NEXT:    [[INC]] = add nuw i64 [[IV]], 1
-; DEFAULT-NEXT:    [[C_2:%.*]] = icmp eq i64 [[INC]], 128
-; DEFAULT-NEXT:    br i1 [[C_2]], label %[[E]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP5:![0-9]+]]
-; DEFAULT:       [[E]]:
-; DEFAULT-NEXT:    [[P1:%.*]] = phi i64 [ 0, %[[LOOP_HEADER]] ], [ 1, %[[LOOP_LATCH]] ]
-; DEFAULT-NEXT:    ret i64 [[P1]]
-;
-entry:
-  br label %loop.header
-
-loop.header:
-  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
-  %c.1 = icmp uge i64 %iv, %N
-  br i1 %c.1, label %e, label %loop.latch
-
-loop.latch:
-  %arrayidx = getelementptr inbounds nuw i32, ptr %p, i64 %iv
-  store i32 0, ptr %arrayidx
-  %inc = add nuw i64 %iv, 1
-  %c.2 = icmp eq i64 %inc, 128
-  br i1 %c.2, label %e, label %loop.header, !llvm.loop !1
-
-e:
-  %p1 = phi i64 [ 0, %loop.header ], [ 1, %loop.latch ]
-  ret i64 %p1
-}
-
-!1 = distinct !{!1, !2, !3}
-!2 = !{!"llvm.loop.vectorize.width", i32 4}
-!3 = !{!"llvm.loop.vectorize.enable", i1 true}
-;.
-; MULTI: [[LOOP0]] = distinct !{[[LOOP0]], [[META1:![0-9]+]], [[META2:![0-9]+]]}
-; MULTI: [[META1]] = !{!"llvm.loop.isvectorized", i32 1}
-; MULTI: [[META2]] = !{!"llvm.loop.unroll.runtime.disable"}
-; MULTI: [[LOOP3]] = distinct !{[[LOOP3]], [[META2]], [[META1]]}
-; MULTI: [[LOOP4]] = distinct !{[[LOOP4]], [[META1]], [[META2]]}
-; MULTI: [[LOOP5]] = distinct !{[[LOOP5]], [[META2]], [[META1]]}
-;.
-; DEFAULT: [[LOOP0]] = distinct !{[[LOOP0]], [[META1:![0-9]+]], [[META2:![0-9]+]]}
-; DEFAULT: [[META1]] = !{!"llvm.loop.isvectorized", i32 1}
-; DEFAULT: [[META2]] = !{!"llvm.loop.unroll.runtime.disable"}
-; DEFAULT: [[LOOP3]] = distinct !{[[LOOP3]], [[META2]], [[META1]]}
-; DEFAULT: [[LOOP4]] = distinct !{[[LOOP4]], [[META1]], [[META2]]}
-; DEFAULT: [[LOOP5]] = distinct !{[[LOOP5]], [[META2]], [[META1]]}
-;.
diff --git a/llvm/test/Transforms/LoopVectorize/X86/uncountable-early-exit-vplan.ll b/llvm/test/Transforms/LoopVectorize/X86/uncountable-early-exit-vplan.ll
deleted file mode 100644
index 13f5671f893651..00000000000000
--- a/llvm/test/Transforms/LoopVectorize/X86/uncountable-early-exit-vplan.ll
+++ /dev/null
@@ -1,244 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
-; RUN: opt -p loop-vectorize -mcpu=skylake-avx512 -mtriple=x86_64-apple-macosx -force-vector-interleave=1 -S -enable-early-exit-vectorization -debug %s 2>&1 | FileCheck %s
-
-declare void @init(ptr)
-
-define i64 @multi_exiting_to_different_exits_live_in_exit_values() {
-; CHECK-LABEL: VPlan 'Final VPlan for VF={4},UF={1}' {
-; CHECK-NEXT: Live-in vp<[[VF:%.+]]> = VF
-; CHECK-NEXT: Live-in vp<[[VFxUF:%.+]]> = VF * UF
-; CHECK-NEXT: Live-in vp<[[VTC:%.+]]> = vector-trip-count
-; CHECK-NEXT: Live-in ir<128> = original trip-count
-; CHECK-EMPTY:
-; CHECK-NEXT: vector.ph:
-; CHECK-NEXT: Successor(s): vector loop
-; CHECK-EMPTY:
-; CHECK-NEXT: <x1> vector loop: {
-; CHECK-NEXT:   vector.body:
-; CHECK-NEXT:     EMIT vp<[[CAN_IV:%.+]]> = CANONICAL-INDUCTION ir<0>, vp<%index.next>
-; CHECK-NEXT:     WIDEN-INDUCTION %iv = phi %inc, 0, ir<1>, vp<[[VF]]>
-; CHECK-NEXT:     vp<[[STEPS:%.+]]> = SCALAR-STEPS vp<[[CAN_IV]]>, ir<1>
-; CHECK-NEXT:     WIDEN ir<%c.1> = icmp uge ir<%iv>, ir<%N>
-; CHECK-NEXT:     EMIT vp<[[NOT1:%.+]]> = not ir<%c.1>
-; CHECK-NEXT:     CLONE ir<%arrayidx> = getelementptr ir<%p>, vp<[[STEPS]]>
-; CHECK-NEXT:     vp<[[VEC_PTR:%.+]]> = vector-pointer ir<%arrayidx>
-; CHECK-NEXT:     WIDEN store vp<[[VEC_PTR]]>, ir<0>, vp<[[NOT1]]>
-; CHECK-NEXT:     EMIT vp<%index.next> = add nuw vp<[[CAN_IV]]>, vp<[[VFxUF]]>
-; CHECK-NEXT:     EMIT vp<[[NOT2:%.+]]> = not vp<[[NOT1]]>
-; CHECK-NEXT:     EMIT vp<[[EA_TAKEN:%.+]]> = any-of vp<[[NOT2]]>
-; CHECK-NEXT:     EMIT vp<[[LATCH_CMP:%.+]]> = icmp eq vp<%index.next>, vp<[[VTC]]>
-; CHECK-NEXT:     EMIT vp<[[EC:%.+]]> = or vp<[[EA_TAKEN]]>, vp<[[LATCH_CMP]]>
-; CHECK-NEXT:     EMIT branch-on-cond vp<[[EC]]>
-; CHECK-NEXT:   No successors
-; CHECK-NEXT: }
-; CHECK-NEXT: Successor(s): middle.split
-; CHECK-EMPTY:
-; CHECK-NEXT: middle.split:
-; CHECK-NEXT:   EMIT branch-on-cond vp<[[EA_TAKEN]]>
-; CHECK-NEXT: Successor(s): ir-bb<e1>, middle.block
-; CHECK-EMPTY:
-; CHECK-NEXT: ir-bb<e1>:
-; CHECK-NEXT:   IR %p1 = phi i64 [ 0, %loop.header ] (extra operand: ir<0>)
-; CHECK-NEXT: No successors
-; CHECK-EMPTY:
-; CHECK-NEXT: middle.block:
-; CHECK-NEXT:   EMIT vp<[[MIDDLE_CMP:%.+]]> = icmp eq ir<128>, vp<[[VTC]]>
-; CHECK-NEXT:   EMIT branch-on-cond vp<[[MIDDLE_CMP]]>
-; CHECK-NEXT: Successor(s): ir-bb<e2>, scalar.ph
-; CHECK-EMPTY:
-; CHECK-NEXT: ir-bb<e2>:
-; CHECK-NEXT:  IR %p2 = phi i64 [ 1, %loop.latch ] (extra operand: ir<1>)
-; CHECK-NEXT: No successors
-; CHECK-EMPTY:
-; CHECK-NEXT: scalar.ph:
-; CHECK-NEXT: ir-bb<loop.header>
-; CHECK-EMPTY:
-; CHECK-NEXT: ir-bb<loop.header>:
-; CHECK-NEXT:   IR   %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
-; CHECK-NEXT:   IR   %c.1 = icmp uge i64 %iv, %N
-; CHECK-NEXT: No successors
-; CHECK-NEXT: }
-entry:
-  %src = alloca [128 x i32]
-  call void @init(ptr %src)
-  br label %loop.header
-
-loop.header:
-  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
-  %gep.src = getelementptr inbounds i32, ptr %src, i64 %iv
-  %l = load i32, ptr %gep.src
-  %c.1 = icmp eq i32 %l, 10
-  br i1 %c.1, label %e1, label %loop.latch
-
-loop.latch:
-  %inc = add nuw i64 %iv, 1
-  %c.2 = icmp eq i64 %inc, 128
-  br i1 %c.2, label %e2, label %loop.header
-
-e1:
-  %p1 = phi i64 [ 0, %loop.header ]
-  ret i64 %p1
-
-e2:
-  %p2 = phi i64 [ 1, %loop.latch ]
-  ret i64 %p2
-}
-
-define i64 @multi_exiting_to_different_exits_load_exit_value() {
-; CHECK-LABEL: VPlan 'Final VPlan for VF={4},UF={1}' {
-; CHECK-NEXT: Live-in vp<[[VF:%.+]]> = VF
-; CHECK-NEXT: Live-in vp<[[VFxUF:%.+]]> = VF * UF
-; CHECK-NEXT: Live-in vp<[[VTC:%.+]]> = vector-trip-count
-; CHECK-NEXT: Live-in ir<128> = original trip-count
-; CHECK-EMPTY:
-; CHECK-NEXT: vector.ph:
-; CHECK-NEXT: Successor(s): vector loop
-; CHECK-EMPTY:
-; CHECK-NEXT: <x1> vector loop: {
-; CHECK-NEXT:   vector.body:
-; CHECK-NEXT:     EMIT vp<[[CAN_IV:%.+]]> = CANONICAL-INDUCTION ir<0>, vp<%index.next>
-; CHECK-NEXT:     WIDEN-INDUCTION %iv = phi %inc, 0, ir<1>, vp<[[VF]]>
-; CHECK-NEXT:     vp<[[STEPS:%.+]]> = SCALAR-STEPS vp<[[CAN_IV]]>, ir<1>
-; CHECK-NEXT:     WIDEN ir<%c.1> = icmp uge ir<%iv>, ir<%N>
-; CHECK-NEXT:     EMIT vp<[[NOT1:%.+]]> = not ir<%c.1>
-; CHECK-NEXT:     CLONE ir<%arrayidx> = getelementptr ir<%p>, vp<[[STEPS]]>
-; CHECK-NEXT:     vp<[[VEC_PTR:%.+]]> = vector-pointer ir<%arrayidx>
-; CHECK-NEXT:     WIDEN store vp<[[VEC_PTR]]>, ir<0>, vp<[[NOT1]]>
-; CHECK-NEXT:     EMIT vp<%index.next> = add nuw vp<[[CAN_IV]]>, vp<[[VFxUF]]>
-; CHECK-NEXT:     EMIT vp<[[NOT2:%.+]]> = not vp<[[NOT1]]>
-; CHECK-NEXT:     EMIT vp<[[EA_TAKEN:%.+]]> = any-of vp<[[NOT2]]>
-; CHECK-NEXT:     EMIT vp<[[LATCH_CMP:%.+]]> = icmp eq vp<%index.next>, vp<[[VTC]]>
-; CHECK-NEXT:     EMIT vp<[[EC:%.+]]> = or vp<[[EA_TAKEN]]>, vp<[[LATCH_CMP]]>
-; CHECK-NEXT:     EMIT branch-on-cond vp<[[EC]]>
-; CHECK-NEXT:   No successors
-; CHECK-NEXT: }
-; CHECK-NEXT: Successor(s): middle.split
-; CHECK-EMPTY:
-; CHECK-NEXT: middle.split:
-; CHECK-NEXT:   EMIT branch-on-cond vp<[[EA_TAKEN]]>
-; CHECK-NEXT: Successor(s): ir-bb<e1>, middle.block
-; CHECK-EMPTY:
-; CHECK-NEXT: ir-bb<e1>:
-; CHECK-NEXT:   IR %p1 = phi i64 [ 0, %loop.header ] (extra operand: ir<0>)
-; CHECK-NEXT: No successors
-; CHECK-EMPTY:
-; CHECK-NEXT: middle.block:
-; CHECK-NEXT:   EMIT vp<[[MIDDLE_CMP:%.+]]> = icmp eq ir<128>, vp<[[VTC]]>
-; CHECK-NEXT:   EMIT branch-on-cond vp<[[MIDDLE_CMP]]>
-; CHECK-NEXT: Successor(s): ir-bb<e2>, scalar.ph
-; CHECK-EMPTY:
-; CHECK-NEXT: ir-bb<e2>:
-; CHECK-NEXT:  IR %p2 = phi i64 [ 1, %loop.latch ] (extra operand: ir<1>)
-; CHECK-NEXT: No successors
-; CHECK-EMPTY:
-; CHECK-NEXT: scalar.ph:
-; CHECK-NEXT: ir-bb<loop.header>
-; CHECK-EMPTY:
-; CHECK-NEXT: ir-bb<loop.header>:
-; CHECK-NEXT:   IR   %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
-; CHECK-NEXT:   IR   %c.1 = icmp uge i64 %iv, %N
-; CHECK-NEXT: No successors
-; CHECK-NEXT: }
-entry:
-  %src = alloca [128 x i64]
-  call void @init(ptr %src)
-  br label %loop.header
-
-loop.header:
-  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
-  %gep.src = getelementptr inbounds i64, ptr %src, i64 %iv
-  %l = load i64, ptr %gep.src
-  %c.1 = icmp eq i64 %l, 10
-  br i1 %c.1, label %e1, label %loop.latch
-
-loop.latch:
-  %inc = add nuw i64 %iv, 1
-  %c.2 = icmp eq i64 %inc, 128
-  br i1 %c.2, label %e2, label %loop.header
-
-e1:
-  %p1 = phi i64 [ %l, %loop.header ]
-  ret i64 %p1
-
-e2:
-  %p2 = phi i64 [ 1, %loop.latch ]
-  ret i64 %p2
-}
-
-define i64 @multi_exiting_to_same_exit_load_exit_value() {
-; CHECK-LABEL: VPlan 'Final VPlan for VF={4},UF={1}' {
-; CHECK-NEXT: Live-in vp<[[VF:%.+]]> = VF
-; CHECK-NEXT: Live-in vp<[[VFxUF:%.+]]> = VF * UF
-; CHECK-NEXT: Live-in vp<[[VTC:%.+]]> = vector-trip-count
-; CHECK-NEXT: Live-in ir<128> = original trip-count
-; CHECK-EMPTY:
-; CHECK-NEXT: vector.ph:
-; CHECK-NEXT: Successor(s): vector loop
-; CHECK-EMPTY:
-; CHECK-NEXT: <x1> vector loop: {
-; CHECK-NEXT:   vector.body:
-; CHECK-NEXT:     EMIT vp<[[CAN_IV:%.+]]> = CANONICAL-INDUCTION ir<0>, vp<%index.next>
-; CHECK-NEXT:     WIDEN-INDUCTION %iv = phi %inc, 0, ir<1>, vp<[[VF]]>
-; CHECK-NEXT:     vp<[[STEPS:%.+]]> = SCALAR-STEPS vp<[[CAN_IV]]>, ir<1>
-; CHECK-NEXT:     WIDEN ir<%c.1> = icmp uge ir<%iv>, ir<%N>
-; CHECK-NEXT:     EMIT vp<[[NOT1:%.+]]> = not ir<%c.1>
-; CHECK-NEXT:     CLONE ir<%arrayidx> = getelementptr ir<%p>, vp<[[STEPS]]>
-; CHECK-NEXT:     vp<[[VEC_PTR:%.+]]> = vector-pointer ir<%arrayidx>
-; CHECK-NEXT:     WIDEN store vp<[[VEC_PTR]]>, ir<0>, vp<[[NOT1]]>
-; CHECK-NEXT:     EMIT vp<%index.next> = add nuw vp<[[CAN_IV]]>, vp<[[VFxUF]]>
-; CHECK-NEXT:     EMIT vp<[[NOT2:%.+]]> = not vp<[[NOT1]]>
-; CHECK-NEXT:     EMIT vp<[[EA_TAKEN:%.+]]> = any-of vp<[[NOT2]]>
-; CHECK-NEXT:     EMIT vp<[[LATCH_CMP:%.+]]> = icmp eq vp<%index.next>, vp<[[VTC]]>
-; CHECK-NEXT:     EMIT vp<[[EC:%.+]]> = or vp<[[EA_TAKEN]]>, vp<[[LATCH_CMP]]>
-; CHECK-NEXT:     EMIT branch-on-cond vp<[[EC]]>
-; CHECK-NEXT:   No successors
-; CHECK-NEXT: }
-; CHECK-NEXT: Successor(s): middle.split
-; CHECK-EMPTY:
-; CHECK-NEXT: middle.split:
-; CHECK-NEXT:   EMIT branch-on-cond vp<[[EA_TAKEN]]>
-; CHECK-NEXT: Successor(s): ir-bb<e1>, middle.block
-; CHECK-EMPTY:
-; CHECK-NEXT: ir-bb<e1>:
-; CHECK-NEXT:   IR %p1 = phi i64 [ 0, %loop.header ] (extra operand: ir<0>)
-; CHECK-NEXT: No successors
-; CHECK-EMPTY:
-; CHECK-NEXT: middle.block:
-; CHECK-NEXT:   EMIT vp<[[MIDDLE_CMP:%.+]]> = icmp eq ir<128>, vp<[[VTC]]>
-; CHECK-NEXT:   EMIT branch-on-cond vp<[[MIDDLE_CMP]]>
-; CHECK-NEXT: Successor(s): ir-bb<e2>, scalar.ph
-; CHECK-EMPTY:
-; CHECK-NEXT: ir-bb<e2>:
-; CHECK-NEXT:  IR %p2 = phi i64 [ 1, %loop.latch ] (extra operand: ir<1>)
-; CHECK-NEXT: No successors
-; CHECK-EMPTY:
-; CHECK-NEXT: scalar.ph:
-; CHECK-NEXT: ir-bb<loop.header>
-; CHECK-EMPTY:
-; CHECK-NEXT: ir-bb<loop.header>:
-; CHECK-NEXT:   IR   %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
-; CHECK-NEXT:   IR   %c.1 = icmp uge i64 %iv, %N
-; CHECK-NEXT: No successors
-; CHECK-NEXT: }
-entry:
-  %src = alloca [128 x i64]
-  call void @init(ptr %src)
-  br label %loop.header
-
-loop.header:
-  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
-  %gep.src = getelementptr inbounds i64, ptr %src, i64 %iv
-  %l = load i64, ptr %gep.src
-  %l.2 = load i64, ptr %gep.src
-  %c.1 = icmp eq i64 %l, 10
-  br i1 %c.1, label %e1, label %loop.latch
-
-loop.latch:
-  %inc = add nuw i64 %iv, 1
-  %c.2 = icmp eq i64 %inc, 128
-  br i1 %c.2, label %e1, label %loop.header
-
-e1:
-  %p1 = phi i64 [ %l, %loop.header ], [ %l.2, %loop.latch ]
-  ret i64 %p1
-}
diff --git a/llvm/test/Transforms/LoopVectorize/uncountable-early-exit-vplan.ll b/llvm/test/Transforms/LoopVectorize/uncountable-early-exit-vplan.ll
new file mode 100644
index 00000000000000..d840646a259529
--- /dev/null
+++ b/llvm/test/Transforms/LoopVectorize/uncountable-early-exit-vplan.ll
@@ -0,0 +1,171 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -p loop-vectorize -force-vector-width=4 -force-vector-interleave=1 -S -enable-early-exit-vectorization -debug %s 2>&1 | FileCheck %s
+
+declare void @init(ptr)
+
+define i64 @multi_exiting_to_different_exits_live_in_exit_values() {
+; CHECK-LABEL: VPlan 'Final VPlan for VF={4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VFxUF:%.+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VTC:%.+]]> = vector-trip-count
+; CHECK-NEXT: Live-in ir<128> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<entry>:
+; CHECK-NEXT:   IR %src = alloca [128 x i32], align 4
+; CHECK-NEXT:   IR call void @init(ptr %src)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT:   vector.body:
+; CHECK-NEXT:     EMIT vp<[[CAN_IV:%.+]]> = CANONICAL-INDUCTION ir<0>, vp<%index.next>
+; CHECK-NEXT:     vp<[[STEPS:%.+]]> = SCALAR-STEPS vp<[[CAN_IV]]>, ir<1>
+; CHECK-NEXT:     CLONE ir<%gep.src> = getelementptr inbounds ir<%src>, vp<%3>
+; CHECK-NEXT:     vp<[[VEC_PTR:%.+]]> = vector-pointer ir<%gep.src>
+; CHECK-NEXT:     WIDEN ir<%l> = load vp<[[VEC_PTR]]>
+; CHECK-NEXT:     WIDEN ir<%c.1> = icmp eq ir<%l>, ir<10>
+; CHECK-NEXT:     EMIT vp<[[NOT1:%.+]]> = not ir<%c.1>
+; CHECK-NEXT:     EMIT vp<%index.next> = add nuw vp<[[CAN_IV]]>, vp<[[VFxUF]]>
+; CHECK-NEXT:     EMIT vp<[[NOT2:%.+]]> = not vp<[[NOT1]]>
+; CHECK-NEXT:     EMIT vp<[[EA_TAKEN:%.+]]> = any-of vp<[[NOT2]]>
+; CHECK-NEXT:     EMIT vp<[[LATCH_CMP:%.+]]> = icmp eq vp<%index.next>, vp<[[VTC]]>
+; CHECK-NEXT:     EMIT vp<[[EC:%.+]]> = or vp<[[EA_TAKEN]]>, vp<[[LATCH_CMP]]>
+; CHECK-NEXT:     EMIT branch-on-cond vp<[[EC]]>
+; CHECK-NEXT:   No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.split
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.split:
+; CHECK-NEXT:   EMIT branch-on-cond vp<[[EA_TAKEN]]>
+; CHECK-NEXT: Successor(s): ir-bb<e1>, middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<e1>:
+; CHECK-NEXT:   IR %p1 = phi i64 [ 0, %loop.header ] (extra operand: ir<0>)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT:   EMIT vp<[[MIDDLE_CMP:%.+]]> = icmp eq ir<128>, vp<[[VTC]]>
+; CHECK-NEXT:   EMIT branch-on-cond vp<[[MIDDLE_CMP]]>
+; CHECK-NEXT: Successor(s): ir-bb<e2>, scalar.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<e2>:
+; CHECK-NEXT:  IR %p2 = phi i64 [ 1, %loop.latch ] (extra operand: ir<1>)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: ir-bb<loop.header>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop.header>:
+; CHECK-NEXT:   IR   %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
+; CHECK:      No successors
+; CHECK-NEXT: }
+entry:
+  %src = alloca [128 x i32]
+  call void @init(ptr %src)
+  br label %loop.header
+
+loop.header:
+  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
+  %gep.src = getelementptr inbounds i32, ptr %src, i64 %iv
+  %l = load i32, ptr %gep.src
+  %c.1 = icmp eq i32 %l, 10
+  br i1 %c.1, label %e1, label %loop.latch
+
+loop.latch:
+  %inc = add nuw i64 %iv, 1
+  %c.2 = icmp eq i64 %inc, 128
+  br i1 %c.2, label %e2, label %loop.header
+
+e1:
+  %p1 = phi i64 [ 0, %loop.header ]
+  ret i64 %p1
+
+e2:
+  %p2 = phi i64 [ 1, %loop.latch ]
+  ret i64 %p2
+}
+
+define i64 @multi_exiting_to_different_exits_load_exit_value() {
+; CHECK-NOT: VPlan 'Final VPlan for VF={4},UF={1}' {
+entry:
+  %src = alloca [128 x i64]
+  call void @init(ptr %src)
+  br label %loop.header
+
+loop.header:
+  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
+  %gep.src = getelementptr inbounds i64, ptr %src, i64 %iv
+  %l = load i64, ptr %gep.src
+  %c.1 = icmp eq i64 %l, 10
+  br i1 %c.1, label %e1, label %loop.latch
+
+loop.latch:
+  %inc = add nuw i64 %iv, 1
+  %c.2 = icmp eq i64 %inc, 128
+  br i1 %c.2, label %e2, label %loop.header
+
+e1:
+  %p1 = phi i64 [ %l, %loop.header ]
+  ret i64 %p1
+
+e2:
+  %p2 = phi i64 [ 1, %loop.latch ]
+  ret i64 %p2
+}
+
+define i64 @multi_exiting_to_same_exit_load_exit_value() {
+; CHECK-NOT: VPlan 'Final VPlan for VF={4},UF={1}' {
+
+entry:
+  %src = alloca [128 x i64]
+  call void @init(ptr %src)
+  br label %loop.header
+
+loop.header:
+  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
+  %gep.src = getelementptr inbounds i64, ptr %src, i64 %iv
+  %l = load i64, ptr %gep.src
+  %l.2 = load i64, ptr %gep.src
+  %c.1 = icmp eq i64 %l, 10
+  br i1 %c.1, label %e1, label %loop.latch
+
+loop.latch:
+  %inc = add nuw i64 %iv, 1
+  %c.2 = icmp eq i64 %inc, 128
+  br i1 %c.2, label %e1, label %loop.header
+
+e1:
+  %p1 = phi i64 [ %l, %loop.header ], [ %l.2, %loop.latch ]
+  ret i64 %p1
+}
+
+define i64 @multi_exiting_to_different_exits_induction_exit_value() {
+; CHECK-NOT: VPlan 'Final VPlan for VF={4},UF={1}' {
+entry:
+  %src = alloca [128 x i64]
+  call void @init(ptr %src)
+  br label %loop.header
+
+loop.header:
+  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
+  %gep.src = getelementptr inbounds i64, ptr %src, i64 %iv
+  %l = load i64, ptr %gep.src
+  %c.1 = icmp eq i64 %l, 10
+  br i1 %c.1, label %e1, label %loop.latch
+
+loop.latch:
+  %inc = add nuw i64 %iv, 1
+  %c.2 = icmp eq i64 %inc, 128
+  br i1 %c.2, label %e2, label %loop.header
+
+e1:
+  %p1 = phi i64 [ %iv, %loop.header ]
+  ret i64 %p1
+
+e2:
+  %p2 = phi i64 [ 1, %loop.latch ]
+  ret i64 %p2
+}
+
+

>From c53eca6a59f55edc3dcb2bb692956de2fd97bfce Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Wed, 6 Nov 2024 20:40:41 +0000
Subject: [PATCH 09/18] !fixup remove left over canVectorizeEarlyExit

---
 .../Vectorize/LoopVectorizationLegality.h     |  3 ---
 .../Vectorize/LoopVectorizationLegality.cpp   | 19 -------------------
 2 files changed, 22 deletions(-)

diff --git a/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h b/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h
index af6fae44cf0f09..dc7e484a40a452 100644
--- a/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h
+++ b/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h
@@ -287,9 +287,6 @@ class LoopVectorizationLegality {
   /// we can use in-order reductions.
   bool canVectorizeFPMath(bool EnableStrictReductions);
 
-  /// Returns true if the loop has an early exit that we can vectorize.
-  bool canVectorizeEarlyExit() const;
-
   /// Return true if we can vectorize this loop while folding its tail by
   /// masking.
   bool canFoldTailByMasking() const;
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
index ed3808d2f30bf1..0267fb1adb16d6 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
@@ -1515,25 +1515,6 @@ bool LoopVectorizationLegality::canVectorizeWithIfConvert() {
   return true;
 }
 
-bool LoopVectorizationLegality::canVectorizeEarlyExit() const {
-  // Currently only allow vectorizing loops with early exits, if early-exit
-  // vectorization is explicitly enabled and the loop has metadata to force
-  // vectorization.
-
-  SmallVector<BasicBlock *> Exiting;
-  TheLoop->getExitingBlocks(Exiting);
-  if (Exiting.size() == 1)
-    return false;
-
-  LoopVectorizeHints Hints(TheLoop, true, *ORE);
-  if (Hints.getForce() == LoopVectorizeHints::FK_Undefined)
-    return false;
-
-  Function *Fn = TheLoop->getHeader()->getParent();
-  return Hints.allowVectorization(Fn, TheLoop,
-                                  true /*VectorizeOnlyWhenForced*/);
-}
-
 // Helper function to canVectorizeLoopNestCFG.
 bool LoopVectorizationLegality::canVectorizeLoopCFG(Loop *Lp,
                                                     bool UseVPlanNativePath) {

>From e26af8e878c6484d1b7f95cb6f4c3c9966836fe2 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sat, 23 Nov 2024 12:56:49 +0000
Subject: [PATCH 10/18] !fixup address latest comments, thanks!

---
 .../Transforms/Vectorize/LoopVectorize.cpp    |  94 +++++------
 llvm/lib/Transforms/Vectorize/VPlan.cpp       |  15 +-
 llvm/lib/Transforms/Vectorize/VPlan.h         |   2 +
 .../lib/Transforms/Vectorize/VPlanRecipes.cpp |   4 -
 .../Transforms/Vectorize/VPlanTransforms.cpp  |  61 +++----
 .../Transforms/Vectorize/VPlanTransforms.h    |  12 +-
 .../LoopVectorize/early_exit_legality.ll      |   2 +-
 .../LoopVectorize/single_early_exit.ll        | 157 ++++++++++++++++--
 .../uncountable-early-exit-vplan.ll           | 156 +++++++++++++++++
 .../LoopVectorize/unsupported_early_exit.ll   |   2 +-
 10 files changed, 384 insertions(+), 121 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index b59922fd3fd7c2..5134c4ec7d225c 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -7783,7 +7783,6 @@ DenseMap<const SCEV *, Value *> LoopVectorizationPlanner::executePlan(
     LoopVectorizeHints Hints(L, true, *ORE);
     Hints.setAlreadyVectorized();
   }
-
   TargetTransformInfo::UnrollingPreferences UP;
   TTI.getUnrollingPreferences(L, *PSE.getSE(), UP, ORE);
   if (!UP.UnrollVectorizedLoop || CanonicalIVStartValue)
@@ -8882,9 +8881,9 @@ static void addScalarResumePhis(VPRecipeBuilder &Builder, VPlan &Plan) {
 static SetVector<VPIRInstruction *> collectUsersInExitBlocks(
     Loop *OrigLoop, VPRecipeBuilder &Builder, VPlan &Plan,
     const MapVector<PHINode *, InductionDescriptor> &Inductions) {
+  auto *MiddleVPBB = Plan.getMiddleBlock();
   SetVector<VPIRInstruction *> ExitUsersToFix;
   for (VPIRBasicBlock *ExitVPBB : Plan.getExitBlocks()) {
-    BasicBlock *ExitBB = ExitVPBB->getIRBasicBlock();
     for (VPRecipeBase &R : *ExitVPBB) {
       auto *ExitIRI = dyn_cast<VPIRInstruction>(&R);
       if (!ExitIRI)
@@ -8892,26 +8891,34 @@ static SetVector<VPIRInstruction *> collectUsersInExitBlocks(
       auto *ExitPhi = dyn_cast<PHINode>(&ExitIRI->getInstruction());
       if (!ExitPhi)
         break;
-      for (BasicBlock *ExitingBB : predecessors(ExitBB)) {
-        if (!OrigLoop->contains(ExitingBB))
-          continue;
-      Value *IncomingValue = ExitPhi->getIncomingValueForBlock(ExitingBB);
-      VPValue *V = Builder.getVPValueOrAddLiveIn(IncomingValue);
-      // Exit values for inductions are computed and updated outside of VPlan
-      // and independent of induction recipes.
-      // TODO: Compute induction exit values in VPlan.
-      if ((isa<VPWidenIntOrFpInductionRecipe>(V) &&
-           !cast<VPWidenIntOrFpInductionRecipe>(V)->getTruncInst()) ||
-          isa<VPWidenPointerInductionRecipe>(V) ||
-          (isa<Instruction>(IncomingValue) &&
-           OrigLoop->contains(cast<Instruction>(IncomingValue)) &&
-           any_of(IncomingValue->users(), [&Inductions](User *U) {
-             auto *P = dyn_cast<PHINode>(U);
-             return P && Inductions.contains(P);
-           })))
-        continue;
-      ExitUsersToFix.insert(ExitIRI);
-      ExitIRI->addOperand(V);
+      for (VPBlockBase *PredVPBB : ExitVPBB->getPredecessors()) {
+        BasicBlock *ExitingBB = OrigLoop->getLoopLatch();
+        if (PredVPBB != MiddleVPBB) {
+          SmallVector<BasicBlock *> ExitingBlocks;
+          OrigLoop->getExitingBlocks(ExitingBlocks);
+          assert(ExitingBlocks.size() == 2 && "only support 2 exiting blocks");
+          ExitingBB = ExitingBB == ExitingBlocks[0] ? ExitingBlocks[1]
+                                                    : ExitingBlocks[0];
+        }
+        Value *IncomingValue = ExitPhi->getIncomingValueForBlock(ExitingBB);
+        VPValue *V = Builder.getVPValueOrAddLiveIn(IncomingValue);
+        // Exit values for inductions are computed and updated outside of VPlan
+        // and independent of induction recipes.
+        // TODO: Compute induction exit values in VPlan.
+        if ((isa<VPWidenIntOrFpInductionRecipe>(V) &&
+             !cast<VPWidenIntOrFpInductionRecipe>(V)->getTruncInst()) ||
+            isa<VPWidenPointerInductionRecipe>(V) ||
+            (isa<Instruction>(IncomingValue) &&
+             OrigLoop->contains(cast<Instruction>(IncomingValue)) &&
+             any_of(IncomingValue->users(), [&Inductions](User *U) {
+               auto *P = dyn_cast<PHINode>(U);
+               return P && Inductions.contains(P);
+             }))) {
+          if (ExitVPBB->getSinglePredecessor() == MiddleVPBB)
+            continue;
+        }
+        ExitUsersToFix.insert(ExitIRI);
+        ExitIRI->addOperand(V);
       }
     }
   }
@@ -8919,24 +8926,28 @@ static SetVector<VPIRInstruction *> collectUsersInExitBlocks(
 }
 
 // Add exit values to \p Plan. Extracts are added for each entry in \p
-// ExitUsersToFix if needed and their operands are updated.
-static void
+// ExitUsersToFix if needed and their operands are updated. Returns true if all
+// exit users can be handled, otherwise return false.
+static bool
 addUsersInExitBlocks(VPlan &Plan,
                      const SetVector<VPIRInstruction *> &ExitUsersToFix) {
   if (ExitUsersToFix.empty())
-    return;
+    return true;
+
+  auto *MiddleVPBB = Plan.getMiddleBlock();
+  VPBuilder B(MiddleVPBB, MiddleVPBB->getFirstNonPhi());
 
   // Introduce extract for exiting values and update the VPIRInstructions
   // modeling the corresponding LCSSA phis.
   for (VPIRInstruction *ExitIRI : ExitUsersToFix) {
-
     VPValue *V = ExitIRI->getOperand(0);
     // Pass live-in values used by exit phis directly through to their users in
     // the exit block.
     if (V->isLiveIn())
       continue;
 
-    // Currently only live-ins can be used by exit values from blocks not exiting via the vector latch through to the middle block.
+    // Currently only live-ins can be used by exit values from blocks not
+    // exiting via the vector latch through to the middle block.
     if (ExitIRI->getParent()->getSinglePredecessor() != MiddleVPBB)
       return false;
 
@@ -9218,31 +9229,19 @@ LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(VFRange &Range) {
   RecipeBuilder.fixHeaderPhis();
 
   if (Legal->hasUncountableEarlyExit()) {
+    assert(Legal->getUncountableExitingBlocks().size() == 1 &&
+           "Only single uncountable exiting bock supported");
     VPlanTransforms::handleUncountableEarlyExit(
-        *Plan, *PSE.getSE(), OrigLoop, Legal->getUncountableExitingBlocks(),
+        *Plan, *PSE.getSE(), OrigLoop, Legal->getUncountableExitingBlocks()[0],
         RecipeBuilder);
   }
   addScalarResumePhis(RecipeBuilder, *Plan);
   SetVector<VPIRInstruction *> ExitUsersToFix = collectUsersInExitBlocks(
       OrigLoop, RecipeBuilder, *Plan, Legal->getInductionVars());
   addExitUsersForFirstOrderRecurrences(*Plan, ExitUsersToFix);
-  if (!addUsersInExitBlocks(*Plan, ExitUsersToFix)) 
-<<<<<<< HEAD
-
-  if (Legal->hasUncountableEarlyExit()) {
-    if (any_of(Plan->getExitBlocks(), [](VPIRBasicBlock *ExitBB) {
-          return any_of(*ExitBB, [](VPRecipeBase &R) {
-            auto VPIRI = cast<VPIRInstruction>(&R);
-            return VPIRI->getNumOperands() == 0 ||
-                   any_of(VPIRI->operands(),
-                          [](VPValue *Op) { return !Op->isLiveIn(); });
-          });
-        }))
-      return nullptr;
-  }
+  if (!addUsersInExitBlocks(*Plan, ExitUsersToFix))
+    return nullptr;
 
-=======
->>>>>>> origin/main
   // ---------------------------------------------------------------------------
   // Transform initial VPlan: Apply previously taken decisions, in order, to
   // bring the VPlan to its final state.
@@ -9998,11 +9997,10 @@ bool LoopVectorizePass::processLoop(Loop *L) {
   if (LVL.hasUncountableEarlyExit()) {
     if (!EnableEarlyExitVectorization) {
       reportVectorizationFailure("Auto-vectorization of loops with uncountable "
-                                 "early exit is not yet supported",
+                                 "early exit is not enabled",
                                  "Auto-vectorization of loops with uncountable "
-                                 "early exit is not yet supported",
-                                 "UncountableEarlyExitLoopsUnsupported", ORE,
-                                 L);
+                                 "early exit is no enabled",
+                                 "UncountableEarlyExitLoopsDisabled", ORE, L);
       return false;
     }
   }
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp
index b99196961917eb..db8f0bfd60b4bc 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp
@@ -872,8 +872,10 @@ VPlanPtr VPlan::createInitialVPlan(Type *InductionTy,
 
   // Create SCEV and VPValue for the trip count.
   // We use the symbolic max backedge-taken-count, which is used when
-  // vectorizing loops with uncountable early exits
+  // vectorizing loops with uncountable early exits.
   const SCEV *BackedgeTakenCountSCEV = PSE.getSymbolicMaxBackedgeTakenCount();
+  assert(!isa<SCEVCouldNotCompute>(BackedgeTakenCountSCEV) &&
+         "Invalid loop count");
   ScalarEvolution &SE = *PSE.getSE();
   const SCEV *TripCount = SE.getTripCountFromExitCount(BackedgeTakenCountSCEV,
                                                        InductionTy, TheLoop);
@@ -907,16 +909,7 @@ VPlanPtr VPlan::createInitialVPlan(Type *InductionTy,
   // 2) If we require a scalar epilogue, there is no conditional branch as
   //    we unconditionally branch to the scalar preheader.  Do nothing.
   // 3) Otherwise, construct a runtime check.
-  BasicBlock *IRExitBlock = TheLoop->getUniqueExitBlock();
-  if (!IRExitBlock) {
-    // If there's no unique exit block (i.e. vectorizing with an uncountable
-    // early exit), use the block exiting from the latch. The other uncountable
-    // exit blocks will be added later.
-    auto *Term = cast<BranchInst>(TheLoop->getLoopLatch()->getTerminator());
-    IRExitBlock = TheLoop->contains(Term->getSuccessor(0))
-                      ? Term->getSuccessor(1)
-                      : Term->getSuccessor(0);
-  }
+  BasicBlock *IRExitBlock = TheLoop->getUniqueLatchExitBlock();
   auto *VPExitBlock = VPIRBasicBlock::fromBasicBlock(IRExitBlock);
   // The connection order corresponds to the operands of the conditional
   // branch.
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 9d159b9adfba0a..00c69dd53a3635 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -1232,6 +1232,8 @@ class VPInstruction : public VPRecipeWithIRFlags,
     // operand). Only generates scalar values (either for the first lane only or
     // for all lanes, depending on its uses).
     PtrAdd,
+    // Returns a scalar boolean value, which is true if any lane of its single
+    // operand is true.
     AnyOf,
   };
 
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index cc816b0cba22fb..5527ed3c1fad08 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -68,8 +68,6 @@ bool VPRecipeBase::mayWriteToMemory() const {
     default:
       return true;
     }
-  case VPExpandSCEVSC:
-    return getParent()->getPlan()->getTripCount() == getVPSingleValue();
   case VPInterleaveSC:
     return cast<VPInterleaveRecipe>(this)->getNumStoreOperands() > 0;
   case VPWidenStoreEVLSC:
@@ -165,8 +163,6 @@ bool VPRecipeBase::mayHaveSideEffects() const {
   case VPScalarCastSC:
   case VPReverseVectorPointerSC:
     return false;
-  case VPExpandSCEVSC:
-    return getParent()->getPlan()->getTripCount() == getVPSingleValue();
   case VPInstructionSC:
     return mayWriteToMemory();
   case VPWidenCallSC: {
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index fce63c340230e3..80089fa4dfa334 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -509,12 +509,6 @@ void VPlanTransforms::removeDeadRecipes(VPlan &Plan) {
   ReversePostOrderTraversal<VPBlockDeepTraversalWrapper<VPBlockBase *>> RPOT(
       Plan.getEntry());
 
-  for (VPRecipeBase &R : make_early_inc_range(
-           reverse(*cast<VPBasicBlock>(Plan.getPreheader())))) {
-    if (isDeadRecipe(R))
-      R.eraseFromParent();
-  }
-
   for (VPBasicBlock *VPBB : reverse(VPBlockUtils::blocksOnly<VPBasicBlock>(RPOT))) {
     // The recipes in the block are processed in reverse order, to catch chains
     // of dead recipes.
@@ -1809,8 +1803,7 @@ void VPlanTransforms::createInterleaveGroups(
 
 void VPlanTransforms::handleUncountableEarlyExit(
     VPlan &Plan, ScalarEvolution &SE, Loop *OrigLoop,
-    ArrayRef<BasicBlock *> UncountableExitingBlocks,
-    VPRecipeBuilder &RecipeBuilder) {
+    BasicBlock *UncountableExitingBlock, VPRecipeBuilder &RecipeBuilder) {
   auto *LatchVPBB =
       cast<VPBasicBlock>(Plan.getVectorLoopRegion()->getExiting());
   VPBuilder Builder(LatchVPBB->getTerminator());
@@ -1818,36 +1811,34 @@ void VPlanTransforms::handleUncountableEarlyExit(
   VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
   VPValue *EarlyExitTaken = nullptr;
 
-  // Process all uncountable exiting blocks. For each exiting block, update the
-  // EarlyExitTaken, which tracks if any uncountable early exit has been taken.
-  // Also split the middle block and branch to the exit block for the early exit
-  // if it has been taken.
-  for (BasicBlock *Exiting : UncountableExitingBlocks) {
-    auto *ExitingTerm = cast<BranchInst>(Exiting->getTerminator());
-    BasicBlock *TrueSucc = ExitingTerm->getSuccessor(0);
-    BasicBlock *FalseSucc = ExitingTerm->getSuccessor(1);
-    VPIRBasicBlock *VPExitBlock;
-    if (OrigLoop->getUniqueExitBlock()) {
-      VPExitBlock = cast<VPIRBasicBlock>(MiddleVPBB->getSuccessors()[0]);
-    } else {
-      VPExitBlock = VPIRBasicBlock::fromBasicBlock(
-          !OrigLoop->contains(TrueSucc) ? TrueSucc : FalseSucc);
-    }
+  // Process the uncountable exiting block. Update EarlyExitTaken, which tracks
+  // if any uncountable early exit has been taken. Also split the middle block
+  // and branch to the exit block for the early exit if it has been taken.
+  auto *ExitingTerm =
+      cast<BranchInst>(UncountableExitingBlock->getTerminator());
+  BasicBlock *TrueSucc = ExitingTerm->getSuccessor(0);
+  BasicBlock *FalseSucc = ExitingTerm->getSuccessor(1);
+  VPIRBasicBlock *VPExitBlock;
+  if (OrigLoop->getUniqueExitBlock()) {
+    VPExitBlock = cast<VPIRBasicBlock>(MiddleVPBB->getSuccessors()[0]);
+  } else {
+    VPExitBlock = VPIRBasicBlock::fromBasicBlock(
+        !OrigLoop->contains(TrueSucc) ? TrueSucc : FalseSucc);
+  }
 
-    VPValue *M = RecipeBuilder.getBlockInMask(
-        OrigLoop->contains(TrueSucc) ? TrueSucc : FalseSucc);
-    auto *N = Builder.createNot(M);
-    EarlyExitTaken = Builder.createNaryOp(VPInstruction::AnyOf, {N});
+  VPValue *M = RecipeBuilder.getBlockInMask(
+      OrigLoop->contains(TrueSucc) ? TrueSucc : FalseSucc);
+  auto *N = Builder.createNot(M);
+  EarlyExitTaken = Builder.createNaryOp(VPInstruction::AnyOf, {N});
 
-    VPBasicBlock *NewMiddle = new VPBasicBlock("middle.split");
-    VPBlockUtils::disconnectBlocks(LoopRegion, MiddleVPBB);
-    VPBlockUtils::insertBlockAfter(NewMiddle, LoopRegion);
-    VPBlockUtils::connectBlocks(NewMiddle, VPExitBlock);
-    VPBlockUtils::connectBlocks(NewMiddle, MiddleVPBB);
+  VPBasicBlock *NewMiddle = new VPBasicBlock("middle.split");
+  VPBlockUtils::disconnectBlocks(LoopRegion, MiddleVPBB);
+  VPBlockUtils::insertBlockAfter(NewMiddle, LoopRegion);
+  VPBlockUtils::connectBlocks(NewMiddle, VPExitBlock);
+  VPBlockUtils::connectBlocks(NewMiddle, MiddleVPBB);
 
-    VPBuilder MiddleBuilder(NewMiddle);
-    MiddleBuilder.createNaryOp(VPInstruction::BranchOnCond, {EarlyExitTaken});
-  }
+  VPBuilder MiddleBuilder(NewMiddle);
+  MiddleBuilder.createNaryOp(VPInstruction::BranchOnCond, {EarlyExitTaken});
 
   // Replace the condition controlling the exit from the vector loop with one
   // exiting if either the original condition of the vector latch is true or any
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.h b/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
index dc5dec2f1b84a6..98f30c13c7e9b4 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
@@ -127,13 +127,13 @@ struct VPlanTransforms {
   /// Update \p Plan to account for uncountable exit blocks in \p
   /// UncountableExitingBlocks by
   ///  * updating the condition to exit the vector loop to include the early
-  ///  exit conditions
+  ///    exit conditions
   ///  * splitting the original middle block to branch to the early exit blocks
-  ///  if taken. Returns false if the transformation wasn't successful.
-  static void
-  handleUncountableEarlyExit(VPlan &Plan, ScalarEvolution &SE, Loop *OrigLoop,
-                             ArrayRef<BasicBlock *> UncountableExitingBlocks,
-                             VPRecipeBuilder &RecipeBuilder);
+  ///    if taken. Returns false if the transformation wasn't successful.
+  static void handleUncountableEarlyExit(VPlan &Plan, ScalarEvolution &SE,
+                                         Loop *OrigLoop,
+                                         BasicBlock *UncountableExitingBlock,
+                                         VPRecipeBuilder &RecipeBuilder);
 };
 
 } // namespace llvm
diff --git a/llvm/test/Transforms/LoopVectorize/early_exit_legality.ll b/llvm/test/Transforms/LoopVectorize/early_exit_legality.ll
index 21433477c1d7a3..f7fd55a0f039a3 100644
--- a/llvm/test/Transforms/LoopVectorize/early_exit_legality.ll
+++ b/llvm/test/Transforms/LoopVectorize/early_exit_legality.ll
@@ -1,6 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
 ; REQUIRES: asserts
-; RUN: opt -S < %s -p loop-vectorize -debug-only=loop-vectorize -disable-output 2>&1 | FileCheck %s
+; RUN: opt -S < %s -p loop-vectorize -debug-only=loop-vectorize -enable-early-exit-vectorization -force-vector-width=4 -disable-output 2>&1 | FileCheck %s
 
 declare void @init_mem(ptr, i64);
 
diff --git a/llvm/test/Transforms/LoopVectorize/single_early_exit.ll b/llvm/test/Transforms/LoopVectorize/single_early_exit.ll
index 52f82d007de4df..08a333fa865154 100644
--- a/llvm/test/Transforms/LoopVectorize/single_early_exit.ll
+++ b/llvm/test/Transforms/LoopVectorize/single_early_exit.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
-; RUN: opt -S < %s -p loop-vectorize | FileCheck %s
+; RUN: opt -S < %s -p loop-vectorize -enable-early-exit-vectorization -force-vector-width=4 | FileCheck %s
 
 declare void @init_mem(ptr, i64);
 
@@ -11,21 +11,47 @@ define i64 @same_exit_block_phi_of_consts() {
 ; CHECK-NEXT:    [[P2:%.*]] = alloca [1024 x i8], align 1
 ; CHECK-NEXT:    call void @init_mem(ptr [[P1]], i64 1024)
 ; CHECK-NEXT:    call void @init_mem(ptr [[P2]], i64 1024)
+; CHECK-NEXT:    br i1 false, label [[SCALAR_PH:%.*]], label [[VECTOR_PH:%.*]]
+; CHECK:       vector.ph:
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       vector.body:
+; CHECK-NEXT:    [[INDEX1:%.*]] = phi i64 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT3:%.*]], [[LOOP]] ]
+; CHECK-NEXT:    [[OFFSET_IDX:%.*]] = add i64 3, [[INDEX1]]
+; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[OFFSET_IDX]], 0
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 [[TMP0]]
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i32 0
+; CHECK-NEXT:    [[WIDE_LOAD:%.*]] = load <4 x i8>, ptr [[TMP2]], align 1
+; CHECK-NEXT:    [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[P2]], i64 [[TMP0]]
+; CHECK-NEXT:    [[TMP4:%.*]] = getelementptr inbounds i8, ptr [[TMP3]], i32 0
+; CHECK-NEXT:    [[WIDE_LOAD2:%.*]] = load <4 x i8>, ptr [[TMP4]], align 1
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp eq <4 x i8> [[WIDE_LOAD]], [[WIDE_LOAD2]]
+; CHECK-NEXT:    [[INDEX_NEXT3]] = add nuw i64 [[INDEX1]], 4
+; CHECK-NEXT:    [[TMP6:%.*]] = xor <4 x i1> [[TMP5]], splat (i1 true)
+; CHECK-NEXT:    [[TMP7:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP6]])
+; CHECK-NEXT:    [[TMP8:%.*]] = icmp eq i64 [[INDEX_NEXT3]], 64
+; CHECK-NEXT:    [[TMP9:%.*]] = or i1 [[TMP7]], [[TMP8]]
+; CHECK-NEXT:    br i1 [[TMP9]], label [[MIDDLE_SPLIT:%.*]], label [[LOOP]], !llvm.loop [[LOOP0:![0-9]+]]
+; CHECK:       middle.split:
+; CHECK-NEXT:    br i1 [[TMP7]], label [[LOOP_END:%.*]], label [[MIDDLE_BLOCK:%.*]]
+; CHECK:       middle.block:
+; CHECK-NEXT:    br i1 true, label [[LOOP_END]], label [[SCALAR_PH]]
+; CHECK:       scalar.ph:
+; CHECK-NEXT:    [[BC_RESUME_VAL:%.*]] = phi i64 [ 67, [[MIDDLE_BLOCK]] ], [ 3, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    br label [[LOOP1:%.*]]
 ; CHECK:       loop:
-; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ [[INDEX_NEXT:%.*]], [[LOOP_INC:%.*]] ], [ 3, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ [[INDEX_NEXT:%.*]], [[LOOP_INC:%.*]] ], [ [[BC_RESUME_VAL]], [[SCALAR_PH]] ]
 ; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 [[INDEX]]
 ; CHECK-NEXT:    [[LD1:%.*]] = load i8, ptr [[ARRAYIDX]], align 1
 ; CHECK-NEXT:    [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, ptr [[P2]], i64 [[INDEX]]
 ; CHECK-NEXT:    [[LD2:%.*]] = load i8, ptr [[ARRAYIDX1]], align 1
 ; CHECK-NEXT:    [[CMP3:%.*]] = icmp eq i8 [[LD1]], [[LD2]]
-; CHECK-NEXT:    br i1 [[CMP3]], label [[LOOP_INC]], label [[LOOP_END:%.*]]
+; CHECK-NEXT:    br i1 [[CMP3]], label [[LOOP_INC]], label [[LOOP_END]]
 ; CHECK:       loop.inc:
 ; CHECK-NEXT:    [[INDEX_NEXT]] = add i64 [[INDEX]], 1
 ; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i64 [[INDEX_NEXT]], 67
-; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LOOP]], label [[LOOP_END]]
+; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LOOP1]], label [[LOOP_END]], !llvm.loop [[LOOP3:![0-9]+]]
 ; CHECK:       loop.end:
-; CHECK-NEXT:    [[RETVAL:%.*]] = phi i64 [ 0, [[LOOP]] ], [ 1, [[LOOP_INC]] ]
+; CHECK-NEXT:    [[RETVAL:%.*]] = phi i64 [ 0, [[LOOP1]] ], [ 1, [[LOOP_INC]] ], [ 1, [[MIDDLE_BLOCK]] ], [ 0, [[MIDDLE_SPLIT]] ]
 ; CHECK-NEXT:    ret i64 [[RETVAL]]
 ;
 entry:
@@ -62,19 +88,45 @@ define i64 @diff_exit_block_phi_of_consts() {
 ; CHECK-NEXT:    [[P2:%.*]] = alloca [1024 x i8], align 1
 ; CHECK-NEXT:    call void @init_mem(ptr [[P1]], i64 1024)
 ; CHECK-NEXT:    call void @init_mem(ptr [[P2]], i64 1024)
+; CHECK-NEXT:    br i1 false, label [[SCALAR_PH:%.*]], label [[VECTOR_PH:%.*]]
+; CHECK:       vector.ph:
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       vector.body:
+; CHECK-NEXT:    [[INDEX1:%.*]] = phi i64 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT3:%.*]], [[LOOP]] ]
+; CHECK-NEXT:    [[OFFSET_IDX:%.*]] = add i64 3, [[INDEX1]]
+; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[OFFSET_IDX]], 0
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 [[TMP0]]
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i32 0
+; CHECK-NEXT:    [[WIDE_LOAD:%.*]] = load <4 x i8>, ptr [[TMP2]], align 1
+; CHECK-NEXT:    [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[P2]], i64 [[TMP0]]
+; CHECK-NEXT:    [[TMP4:%.*]] = getelementptr inbounds i8, ptr [[TMP3]], i32 0
+; CHECK-NEXT:    [[WIDE_LOAD2:%.*]] = load <4 x i8>, ptr [[TMP4]], align 1
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp eq <4 x i8> [[WIDE_LOAD]], [[WIDE_LOAD2]]
+; CHECK-NEXT:    [[INDEX_NEXT3]] = add nuw i64 [[INDEX1]], 4
+; CHECK-NEXT:    [[TMP6:%.*]] = xor <4 x i1> [[TMP5]], splat (i1 true)
+; CHECK-NEXT:    [[TMP7:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP6]])
+; CHECK-NEXT:    [[TMP8:%.*]] = icmp eq i64 [[INDEX_NEXT3]], 64
+; CHECK-NEXT:    [[TMP9:%.*]] = or i1 [[TMP7]], [[TMP8]]
+; CHECK-NEXT:    br i1 [[TMP9]], label [[MIDDLE_SPLIT:%.*]], label [[LOOP]], !llvm.loop [[LOOP4:![0-9]+]]
+; CHECK:       middle.split:
+; CHECK-NEXT:    br i1 [[TMP7]], label [[LOOP_EARLY_EXIT:%.*]], label [[MIDDLE_BLOCK:%.*]]
+; CHECK:       middle.block:
+; CHECK-NEXT:    br i1 true, label [[LOOP_END:%.*]], label [[SCALAR_PH]]
+; CHECK:       scalar.ph:
+; CHECK-NEXT:    [[BC_RESUME_VAL:%.*]] = phi i64 [ 67, [[MIDDLE_BLOCK]] ], [ 3, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    br label [[LOOP1:%.*]]
 ; CHECK:       loop:
-; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ [[INDEX_NEXT:%.*]], [[LOOP_INC:%.*]] ], [ 3, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ [[INDEX_NEXT:%.*]], [[LOOP_INC:%.*]] ], [ [[BC_RESUME_VAL]], [[SCALAR_PH]] ]
 ; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 [[INDEX]]
 ; CHECK-NEXT:    [[LD1:%.*]] = load i8, ptr [[ARRAYIDX]], align 1
 ; CHECK-NEXT:    [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, ptr [[P2]], i64 [[INDEX]]
 ; CHECK-NEXT:    [[LD2:%.*]] = load i8, ptr [[ARRAYIDX1]], align 1
 ; CHECK-NEXT:    [[CMP3:%.*]] = icmp eq i8 [[LD1]], [[LD2]]
-; CHECK-NEXT:    br i1 [[CMP3]], label [[LOOP_INC]], label [[LOOP_EARLY_EXIT:%.*]]
+; CHECK-NEXT:    br i1 [[CMP3]], label [[LOOP_INC]], label [[LOOP_EARLY_EXIT]]
 ; CHECK:       loop.inc:
 ; CHECK-NEXT:    [[INDEX_NEXT]] = add i64 [[INDEX]], 1
 ; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i64 [[INDEX_NEXT]], 67
-; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LOOP]], label [[LOOP_END:%.*]]
+; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LOOP1]], label [[LOOP_END]], !llvm.loop [[LOOP5:![0-9]+]]
 ; CHECK:       loop.early.exit:
 ; CHECK-NEXT:    ret i64 0
 ; CHECK:       loop.end:
@@ -119,22 +171,66 @@ define i32 @diff_exit_block_needs_scev_check(i32 %end) {
 ; CHECK-NEXT:    call void @init_mem(ptr [[P1]], i64 1024)
 ; CHECK-NEXT:    call void @init_mem(ptr [[P2]], i64 1024)
 ; CHECK-NEXT:    [[END_CLAMPED:%.*]] = and i32 [[END]], 1023
+; CHECK-NEXT:    [[TMP19:%.*]] = trunc i32 [[END]] to i10
+; CHECK-NEXT:    [[TMP20:%.*]] = zext i10 [[TMP19]] to i64
+; CHECK-NEXT:    [[UMAX1:%.*]] = call i64 @llvm.umax.i64(i64 [[TMP20]], i64 1)
+; CHECK-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[UMAX1]], 4
+; CHECK-NEXT:    br i1 [[MIN_ITERS_CHECK]], label [[SCALAR_PH:%.*]], label [[VECTOR_SCEVCHECK:%.*]]
+; CHECK:       vector.scevcheck:
+; CHECK-NEXT:    [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[END_CLAMPED]], i32 1)
+; CHECK-NEXT:    [[TMP2:%.*]] = add nsw i32 [[UMAX]], -1
+; CHECK-NEXT:    [[TMP3:%.*]] = trunc i32 [[TMP2]] to i8
+; CHECK-NEXT:    [[TMP4:%.*]] = add i8 1, [[TMP3]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp ult i8 [[TMP4]], 1
+; CHECK-NEXT:    [[TMP6:%.*]] = icmp ugt i32 [[TMP2]], 255
+; CHECK-NEXT:    [[TMP7:%.*]] = or i1 [[TMP5]], [[TMP6]]
+; CHECK-NEXT:    br i1 [[TMP7]], label [[SCALAR_PH]], label [[VECTOR_PH:%.*]]
+; CHECK:       vector.ph:
+; CHECK-NEXT:    [[N_MOD_VF:%.*]] = urem i64 [[UMAX1]], 4
+; CHECK-NEXT:    [[N_VEC:%.*]] = sub i64 [[UMAX1]], [[N_MOD_VF]]
+; CHECK-NEXT:    [[IND_END:%.*]] = trunc i64 [[N_VEC]] to i8
 ; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
+; CHECK:       vector.body:
+; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[FOR_BODY]] ]
+; CHECK-NEXT:    [[TMP8:%.*]] = add i64 [[INDEX]], 0
+; CHECK-NEXT:    [[TMP9:%.*]] = getelementptr inbounds i32, ptr [[P1]], i64 [[TMP8]]
+; CHECK-NEXT:    [[TMP10:%.*]] = getelementptr inbounds i32, ptr [[TMP9]], i32 0
+; CHECK-NEXT:    [[WIDE_LOAD:%.*]] = load <4 x i32>, ptr [[TMP10]], align 4
+; CHECK-NEXT:    [[TMP11:%.*]] = getelementptr inbounds i32, ptr [[P2]], i64 [[TMP8]]
+; CHECK-NEXT:    [[TMP12:%.*]] = getelementptr inbounds i32, ptr [[TMP11]], i32 0
+; CHECK-NEXT:    [[WIDE_LOAD3:%.*]] = load <4 x i32>, ptr [[TMP12]], align 4
+; CHECK-NEXT:    [[TMP13:%.*]] = icmp eq <4 x i32> [[WIDE_LOAD]], [[WIDE_LOAD3]]
+; CHECK-NEXT:    [[TMP14:%.*]] = xor <4 x i1> [[TMP13]], splat (i1 true)
+; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
+; CHECK-NEXT:    [[TMP15:%.*]] = xor <4 x i1> [[TMP14]], splat (i1 true)
+; CHECK-NEXT:    [[TMP16:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP15]])
+; CHECK-NEXT:    [[TMP17:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
+; CHECK-NEXT:    [[TMP18:%.*]] = or i1 [[TMP16]], [[TMP17]]
+; CHECK-NEXT:    br i1 [[TMP18]], label [[MIDDLE_SPLIT:%.*]], label [[FOR_BODY]], !llvm.loop [[LOOP6:![0-9]+]]
+; CHECK:       middle.split:
+; CHECK-NEXT:    br i1 [[TMP16]], label [[FOUND:%.*]], label [[MIDDLE_BLOCK:%.*]]
+; CHECK:       middle.block:
+; CHECK-NEXT:    [[CMP_N:%.*]] = icmp eq i64 [[UMAX1]], [[N_VEC]]
+; CHECK-NEXT:    br i1 [[CMP_N]], label [[EXIT:%.*]], label [[SCALAR_PH]]
+; CHECK:       scalar.ph:
+; CHECK-NEXT:    [[BC_RESUME_VAL:%.*]] = phi i8 [ [[IND_END]], [[MIDDLE_BLOCK]] ], [ 0, [[ENTRY:%.*]] ], [ 0, [[VECTOR_SCEVCHECK]] ]
+; CHECK-NEXT:    [[BC_RESUME_VAL2:%.*]] = phi i64 [ [[N_VEC]], [[MIDDLE_BLOCK]] ], [ 0, [[ENTRY]] ], [ 0, [[VECTOR_SCEVCHECK]] ]
+; CHECK-NEXT:    br label [[FOR_BODY1:%.*]]
 ; CHECK:       for.body:
-; CHECK-NEXT:    [[IND:%.*]] = phi i8 [ [[IND_NEXT:%.*]], [[FOR_INC:%.*]] ], [ 0, [[ENTRY:%.*]] ]
-; CHECK-NEXT:    [[GEP_IND:%.*]] = phi i64 [ [[GEP_IND_NEXT:%.*]], [[FOR_INC]] ], [ 0, [[ENTRY]] ]
+; CHECK-NEXT:    [[IND:%.*]] = phi i8 [ [[IND_NEXT:%.*]], [[FOR_INC:%.*]] ], [ [[BC_RESUME_VAL]], [[SCALAR_PH]] ]
+; CHECK-NEXT:    [[GEP_IND:%.*]] = phi i64 [ [[GEP_IND_NEXT:%.*]], [[FOR_INC]] ], [ [[BC_RESUME_VAL2]], [[SCALAR_PH]] ]
 ; CHECK-NEXT:    [[ARRAYIDX1:%.*]] = getelementptr inbounds i32, ptr [[P1]], i64 [[GEP_IND]]
 ; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX1]], align 4
 ; CHECK-NEXT:    [[ARRAYIDX2:%.*]] = getelementptr inbounds i32, ptr [[P2]], i64 [[GEP_IND]]
 ; CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[ARRAYIDX2]], align 4
 ; CHECK-NEXT:    [[CMP_EARLY:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]]
-; CHECK-NEXT:    br i1 [[CMP_EARLY]], label [[FOUND:%.*]], label [[FOR_INC]]
+; CHECK-NEXT:    br i1 [[CMP_EARLY]], label [[FOUND]], label [[FOR_INC]]
 ; CHECK:       for.inc:
 ; CHECK-NEXT:    [[IND_NEXT]] = add i8 [[IND]], 1
 ; CHECK-NEXT:    [[CONV:%.*]] = zext i8 [[IND_NEXT]] to i32
 ; CHECK-NEXT:    [[GEP_IND_NEXT]] = add i64 [[GEP_IND]], 1
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[CONV]], [[END_CLAMPED]]
-; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[EXIT:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY1]], label [[EXIT]], !llvm.loop [[LOOP7:![0-9]+]]
 ; CHECK:       found:
 ; CHECK-NEXT:    ret i32 1
 ; CHECK:       exit:
@@ -183,14 +279,33 @@ define i32 @diff_blocks_invariant_early_exit_cond(ptr %s) {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[SVAL:%.*]] = load i32, ptr [[S]], align 4
 ; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[SVAL]], 0
+; CHECK-NEXT:    br i1 false, label [[SCALAR_PH:%.*]], label [[VECTOR_PH:%.*]]
+; CHECK:       vector.ph:
+; CHECK-NEXT:    [[BROADCAST_SPLATINSERT:%.*]] = insertelement <4 x i1> poison, i1 [[COND]], i64 0
+; CHECK-NEXT:    [[BROADCAST_SPLAT:%.*]] = shufflevector <4 x i1> [[BROADCAST_SPLATINSERT]], <4 x i1> poison, <4 x i32> zeroinitializer
 ; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
+; CHECK:       vector.body:
+; CHECK-NEXT:    [[INDEX:%.*]] = phi i32 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[FOR_BODY]] ]
+; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i32 [[INDEX]], 4
+; CHECK-NEXT:    [[TMP0:%.*]] = xor <4 x i1> [[BROADCAST_SPLAT]], splat (i1 true)
+; CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP0]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[INDEX_NEXT]], 276
+; CHECK-NEXT:    [[TMP3:%.*]] = or i1 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    br i1 [[TMP3]], label [[MIDDLE_SPLIT:%.*]], label [[FOR_BODY]], !llvm.loop [[LOOP8:![0-9]+]]
+; CHECK:       middle.split:
+; CHECK-NEXT:    br i1 [[TMP1]], label [[EARLY_EXIT:%.*]], label [[MIDDLE_BLOCK:%.*]]
+; CHECK:       middle.block:
+; CHECK-NEXT:    br i1 true, label [[FOR_END:%.*]], label [[SCALAR_PH]]
+; CHECK:       scalar.ph:
+; CHECK-NEXT:    [[BC_RESUME_VAL:%.*]] = phi i32 [ 266, [[MIDDLE_BLOCK]] ], [ -10, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    br label [[FOR_BODY1:%.*]]
 ; CHECK:       for.body:
-; CHECK-NEXT:    [[IND:%.*]] = phi i32 [ -10, [[ENTRY:%.*]] ], [ [[IND_NEXT:%.*]], [[FOR_INC:%.*]] ]
-; CHECK-NEXT:    br i1 [[COND]], label [[FOR_INC]], label [[EARLY_EXIT:%.*]]
+; CHECK-NEXT:    [[IND:%.*]] = phi i32 [ [[BC_RESUME_VAL]], [[SCALAR_PH]] ], [ [[IND_NEXT:%.*]], [[FOR_INC:%.*]] ]
+; CHECK-NEXT:    br i1 [[COND]], label [[FOR_INC]], label [[EARLY_EXIT]]
 ; CHECK:       for.inc:
 ; CHECK-NEXT:    [[IND_NEXT]] = add nsw i32 [[IND]], 1
 ; CHECK-NEXT:    [[EXITCOND_NOT:%.*]] = icmp eq i32 [[IND_NEXT]], 266
-; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label [[FOR_END:%.*]], label [[FOR_BODY]]
+; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label [[FOR_END]], label [[FOR_BODY1]], !llvm.loop [[LOOP9:![0-9]+]]
 ; CHECK:       early.exit:
 ; CHECK-NEXT:    tail call void @abort()
 ; CHECK-NEXT:    unreachable
@@ -218,3 +333,15 @@ early.exit:
 for.end:
   ret i32 0
 }
+;.
+; CHECK: [[LOOP0]] = distinct !{[[LOOP0]], [[META1:![0-9]+]], [[META2:![0-9]+]]}
+; CHECK: [[META1]] = !{!"llvm.loop.isvectorized", i32 1}
+; CHECK: [[META2]] = !{!"llvm.loop.unroll.runtime.disable"}
+; CHECK: [[LOOP3]] = distinct !{[[LOOP3]], [[META2]], [[META1]]}
+; CHECK: [[LOOP4]] = distinct !{[[LOOP4]], [[META1]], [[META2]]}
+; CHECK: [[LOOP5]] = distinct !{[[LOOP5]], [[META2]], [[META1]]}
+; CHECK: [[LOOP6]] = distinct !{[[LOOP6]], [[META1]], [[META2]]}
+; CHECK: [[LOOP7]] = distinct !{[[LOOP7]], [[META1]]}
+; CHECK: [[LOOP8]] = distinct !{[[LOOP8]], [[META1]], [[META2]]}
+; CHECK: [[LOOP9]] = distinct !{[[LOOP9]], [[META2]], [[META1]]}
+;.
diff --git a/llvm/test/Transforms/LoopVectorize/uncountable-early-exit-vplan.ll b/llvm/test/Transforms/LoopVectorize/uncountable-early-exit-vplan.ll
index d840646a259529..9df40d77ecc5fd 100644
--- a/llvm/test/Transforms/LoopVectorize/uncountable-early-exit-vplan.ll
+++ b/llvm/test/Transforms/LoopVectorize/uncountable-early-exit-vplan.ll
@@ -114,6 +114,162 @@ e2:
   ret i64 %p2
 }
 
+define i64 @multi_exiting_to_same_exit_live_in_exit_values() {
+; CHECK-LABEL: VPlan 'Final VPlan for VF={4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VFxUF:%.+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VTC:%.+]]> = vector-trip-count
+; CHECK-NEXT: Live-in ir<128> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<entry>:
+; CHECK-NEXT:   IR %src = alloca [128 x i32], align 4
+; CHECK-NEXT:   IR call void @init(ptr %src)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT:   vector.body:
+; CHECK-NEXT:     EMIT vp<[[CAN_IV:%.+]]> = CANONICAL-INDUCTION ir<0>, vp<%index.next>
+; CHECK-NEXT:     vp<[[STEPS:%.+]]> = SCALAR-STEPS vp<[[CAN_IV]]>, ir<1>
+; CHECK-NEXT:     CLONE ir<%gep.src> = getelementptr inbounds ir<%src>, vp<%3>
+; CHECK-NEXT:     vp<[[VEC_PTR:%.+]]> = vector-pointer ir<%gep.src>
+; CHECK-NEXT:     WIDEN ir<%l> = load vp<[[VEC_PTR]]>
+; CHECK-NEXT:     WIDEN ir<%c.1> = icmp eq ir<%l>, ir<10>
+; CHECK-NEXT:     EMIT vp<[[NOT1:%.+]]> = not ir<%c.1>
+; CHECK-NEXT:     EMIT vp<%index.next> = add nuw vp<[[CAN_IV]]>, vp<[[VFxUF]]>
+; CHECK-NEXT:     EMIT vp<[[NOT2:%.+]]> = not vp<[[NOT1]]>
+; CHECK-NEXT:     EMIT vp<[[EA_TAKEN:%.+]]> = any-of vp<[[NOT2]]>
+; CHECK-NEXT:     EMIT vp<[[LATCH_CMP:%.+]]> = icmp eq vp<%index.next>, vp<[[VTC]]>
+; CHECK-NEXT:     EMIT vp<[[EC:%.+]]> = or vp<[[EA_TAKEN]]>, vp<[[LATCH_CMP]]>
+; CHECK-NEXT:     EMIT branch-on-cond vp<[[EC]]>
+; CHECK-NEXT:   No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.split
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.split:
+; CHECK-NEXT:   EMIT branch-on-cond vp<[[EA_TAKEN]]>
+; CHECK-NEXT: Successor(s): ir-bb<exit>, middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<exit>:
+; CHECK-NEXT:   IR %p = phi i64 [ 0, %loop.header ], [ 1, %loop.latch ] (extra operand: ir<1>, ir<0>)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT:   EMIT vp<[[MIDDLE_CMP:%.+]]> = icmp eq ir<128>, vp<[[VTC]]>
+; CHECK-NEXT:   EMIT branch-on-cond vp<[[MIDDLE_CMP]]>
+; CHECK-NEXT: Successor(s): ir-bb<exit>, scalar.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: ir-bb<loop.header>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop.header>:
+; CHECK-NEXT:   IR   %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
+; CHECK:      No successors
+; CHECK-NEXT: }
+
+entry:
+  %src = alloca [128 x i32]
+  call void @init(ptr %src)
+  br label %loop.header
+
+loop.header:
+  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
+  %gep.src = getelementptr inbounds i32, ptr %src, i64 %iv
+  %l = load i32, ptr %gep.src
+  %c.1 = icmp eq i32 %l, 10
+  br i1 %c.1, label %exit, label %loop.latch
+
+loop.latch:
+  %inc = add nuw i64 %iv, 1
+  %c.2 = icmp eq i64 %inc, 128
+  br i1 %c.2, label %exit, label %loop.header
+
+exit:
+  %p = phi i64 [ 0, %loop.header ], [ 1, %loop.latch ]
+  ret i64 %p
+}
+
+define i64 @multi_exiting_to_same_exit_live_in_exit_values_2() {
+; CHECK-LABEL: VPlan 'Final VPlan for VF={4},UF={1}' {
+; CHECK-NEXT: Live-in vp<[[VFxUF:%.+]]> = VF * UF
+; CHECK-NEXT: Live-in vp<[[VTC:%.+]]> = vector-trip-count
+; CHECK-NEXT: Live-in ir<128> = original trip-count
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<entry>:
+; CHECK-NEXT:   IR %src = alloca [128 x i32], align 4
+; CHECK-NEXT:   IR call void @init(ptr %src)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: vector.ph:
+; CHECK-NEXT: Successor(s): vector loop
+; CHECK-EMPTY:
+; CHECK-NEXT: <x1> vector loop: {
+; CHECK-NEXT:   vector.body:
+; CHECK-NEXT:     EMIT vp<[[CAN_IV:%.+]]> = CANONICAL-INDUCTION ir<0>, vp<%index.next>
+; CHECK-NEXT:     vp<[[STEPS:%.+]]> = SCALAR-STEPS vp<[[CAN_IV]]>, ir<1>
+; CHECK-NEXT:     CLONE ir<%gep.src> = getelementptr inbounds ir<%src>, vp<%3>
+; CHECK-NEXT:     vp<[[VEC_PTR:%.+]]> = vector-pointer ir<%gep.src>
+; CHECK-NEXT:     WIDEN ir<%l> = load vp<[[VEC_PTR]]>
+; CHECK-NEXT:     WIDEN ir<%c.1> = icmp eq ir<%l>, ir<10>
+; CHECK-NEXT:     EMIT vp<[[NOT1:%.+]]> = not ir<%c.1>
+; CHECK-NEXT:     EMIT vp<%index.next> = add nuw vp<[[CAN_IV]]>, vp<[[VFxUF]]>
+; CHECK-NEXT:     EMIT vp<[[NOT2:%.+]]> = not vp<[[NOT1]]>
+; CHECK-NEXT:     EMIT vp<[[EA_TAKEN:%.+]]> = any-of vp<[[NOT2]]>
+; CHECK-NEXT:     EMIT vp<[[LATCH_CMP:%.+]]> = icmp eq vp<%index.next>, vp<[[VTC]]>
+; CHECK-NEXT:     EMIT vp<[[EC:%.+]]> = or vp<[[EA_TAKEN]]>, vp<[[LATCH_CMP]]>
+; CHECK-NEXT:     EMIT branch-on-cond vp<[[EC]]>
+; CHECK-NEXT:   No successors
+; CHECK-NEXT: }
+; CHECK-NEXT: Successor(s): middle.split
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.split:
+; CHECK-NEXT:   EMIT branch-on-cond vp<[[EA_TAKEN]]>
+; CHECK-NEXT: Successor(s): ir-bb<exit>, middle.block
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<exit>:
+; CHECK-NEXT:   IR %p = phi i64 [ 0, %loop.header ], [ 1, %loop.latch ] (extra operand: ir<1>, ir<0>)
+; CHECK-NEXT: No successors
+; CHECK-EMPTY:
+; CHECK-NEXT: middle.block:
+; CHECK-NEXT:   EMIT vp<[[MIDDLE_CMP:%.+]]> = icmp eq ir<128>, vp<[[VTC]]>
+; CHECK-NEXT:   EMIT branch-on-cond vp<[[MIDDLE_CMP]]>
+; CHECK-NEXT: Successor(s): ir-bb<exit>, scalar.ph
+; CHECK-EMPTY:
+; CHECK-NEXT: scalar.ph:
+; CHECK-NEXT: ir-bb<loop.header>
+; CHECK-EMPTY:
+; CHECK-NEXT: ir-bb<loop.header>:
+; CHECK-NEXT:   IR   %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
+; CHECK:      No successors
+; CHECK-NEXT: }
+
+entry:
+  %src = alloca [128 x i32]
+  call void @init(ptr %src)
+  br label %loop.header
+
+loop.header:
+  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
+  %gep.src = getelementptr inbounds i32, ptr %src, i64 %iv
+  %l = load i32, ptr %gep.src
+  %c.1 = icmp eq i32 %l, 10
+  br i1 %c.1, label %exit, label %loop.latch
+
+loop.latch:
+  %inc = add nuw i64 %iv, 1
+  %c.2 = icmp eq i64 %inc, 128
+  br i1 %c.2, label %exit, label %loop.header
+
+exit:
+  %p = phi i64 [ 0, %loop.header ], [ 1, %loop.latch ]
+  ret i64 %p
+
+; uselistorder directives
+  uselistorder label %exit, { 1, 0 }
+}
+
+
 define i64 @multi_exiting_to_same_exit_load_exit_value() {
 ; CHECK-NOT: VPlan 'Final VPlan for VF={4},UF={1}' {
 
diff --git a/llvm/test/Transforms/LoopVectorize/unsupported_early_exit.ll b/llvm/test/Transforms/LoopVectorize/unsupported_early_exit.ll
index cd91d07120f9ee..5b2a95f1b368c3 100644
--- a/llvm/test/Transforms/LoopVectorize/unsupported_early_exit.ll
+++ b/llvm/test/Transforms/LoopVectorize/unsupported_early_exit.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
-; RUN: opt -S < %s -p loop-vectorize | FileCheck %s
+; RUN: opt -S < %s -p loop-vectorize -enable-early-exit-vectorization  -force-vector-width=4 | FileCheck %s
 
 declare void @init_mem(ptr, i64);
 

>From 06c3d39f4f2ce65569ec71fef8d15ab36aa2f24b Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sat, 23 Nov 2024 15:40:10 +0000
Subject: [PATCH 11/18] [VPlan] Print incoming VPBB for phi VPIRInstruction
 (NFC).

---
 llvm/lib/Transforms/Vectorize/VPlan.h          |  2 +-
 llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp |  4 +++-
 .../RISCV/vplan-vp-intrinsics-reduction.ll     |  8 ++++----
 .../first-order-recurrence-chains-vplan.ll     | 18 +++++++++---------
 ...t-order-recurrence-sink-replicate-region.ll | 14 +++++++-------
 .../interleave-and-scalarize-only.ll           |  2 +-
 .../Transforms/LoopVectorize/vplan-printing.ll | 10 +++++-----
 7 files changed, 30 insertions(+), 28 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 00c69dd53a3635..fc7e574a7d88cb 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -643,7 +643,7 @@ class VPBlockBase {
   virtual void dropAllReferences(VPValue *NewValue) = 0;
 
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-  void printAsOperand(raw_ostream &OS, bool PrintType) const {
+  void printAsOperand(raw_ostream &OS, bool PrintType = false) const {
     OS << getName();
   }
 
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index 5527ed3c1fad08..57649e0233f9d5 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -869,7 +869,9 @@ void VPIRInstruction::print(raw_ostream &O, const Twine &Indent,
 
   if (getNumOperands() != 0) {
     O << " (extra operand: ";
-    printOperands(O, SlotTracker);
+    getOperand(0)->printAsOperand(O, SlotTracker);
+    O << " from ";
+    getParent()->getPredecessors()[0]->printAsOperand(O);
     O << ")";
   }
 }
diff --git a/llvm/test/Transforms/LoopVectorize/RISCV/vplan-vp-intrinsics-reduction.ll b/llvm/test/Transforms/LoopVectorize/RISCV/vplan-vp-intrinsics-reduction.ll
index 414f39d557044a..ab541f6fa94e66 100644
--- a/llvm/test/Transforms/LoopVectorize/RISCV/vplan-vp-intrinsics-reduction.ll
+++ b/llvm/test/Transforms/LoopVectorize/RISCV/vplan-vp-intrinsics-reduction.ll
@@ -60,7 +60,7 @@ define i32 @reduction(ptr %a, i64 %n, i32 %start) {
 ; IF-EVL-OUTLOOP-NEXT: Successor(s): ir-bb<for.end>, scalar.ph
 ; IF-EVL-OUTLOOP-EMPTY:
 ; IF-EVL-OUTLOOP-NEXT: ir-bb<for.end>:
-; IF-EVL-OUTLOOP-NEXT:   IR   %add.lcssa = phi i32 [ %add, %for.body ] (extra operand: vp<[[RDX_EX]]>)
+; IF-EVL-OUTLOOP-NEXT:   IR   %add.lcssa = phi i32 [ %add, %for.body ] (extra operand: vp<[[RDX_EX]]> from middle.block)
 ; IF-EVL-OUTLOOP-NEXT: No successors
 ; IF-EVL-OUTLOOP-EMPTY:
 ; IF-EVL-OUTLOOP-NEXT: scalar.ph:
@@ -110,7 +110,7 @@ define i32 @reduction(ptr %a, i64 %n, i32 %start) {
 ; IF-EVL-INLOOP-NEXT: Successor(s): ir-bb<for.end>, scalar.ph
 ; IF-EVL-INLOOP-EMPTY:
 ; IF-EVL-INLOOP-NEXT: ir-bb<for.end>:
-; IF-EVL-INLOOP-NEXT:  IR %add.lcssa = phi i32 [ %add, %for.body ] (extra operand: vp<[[RDX_EX]]>)
+; IF-EVL-INLOOP-NEXT:  IR %add.lcssa = phi i32 [ %add, %for.body ] (extra operand: vp<[[RDX_EX]]> from middle.block)
 ; IF-EVL-INLOOP-NEXT: No successors
 ; IF-EVL-INLOOP-EMPTY:
 ; IF-EVL-INLOOP-NEXT: scalar.ph:
@@ -156,7 +156,7 @@ define i32 @reduction(ptr %a, i64 %n, i32 %start) {
 ; NO-VP-OUTLOOP-NEXT: Successor(s): ir-bb<for.end>, scalar.ph
 ; NO-VP-OUTLOOP-EMPTY:
 ; NO-VP-OUTLOOP-NEXT: ir-bb<for.end>:
-; NO-VP-OUTLOOP-NEXT:  IR %add.lcssa = phi i32 [ %add, %for.body ] (extra operand: vp<[[RDX_EX]]>)
+; NO-VP-OUTLOOP-NEXT:  IR %add.lcssa = phi i32 [ %add, %for.body ] (extra operand: vp<[[RDX_EX]]> from middle.block)
 ; NO-VP-OUTLOOP-NEXT: No successors
 ; NO-VP-OUTLOOP-EMPTY:
 ; NO-VP-OUTLOOP-NEXT: scalar.ph:
@@ -202,7 +202,7 @@ define i32 @reduction(ptr %a, i64 %n, i32 %start) {
 ; NO-VP-INLOOP-NEXT: Successor(s): ir-bb<for.end>, scalar.ph
 ; NO-VP-INLOOP-EMPTY:
 ; NO-VP-INLOOP-NEXT: ir-bb<for.end>:
-; NO-VP-INLOOP-NEXT:   IR %add.lcssa = phi i32 [ %add, %for.body ] (extra operand: vp<[[RDX_EX]]>)
+; NO-VP-INLOOP-NEXT:   IR %add.lcssa = phi i32 [ %add, %for.body ] (extra operand: vp<[[RDX_EX]]> from middle.block)
 ; NO-VP-INLOOP-NEXT: No successors
 ; NO-VP-INLOOP-EMPTY:
 ; NO-VP-INLOOP-NEXT: scalar.ph:
diff --git a/llvm/test/Transforms/LoopVectorize/first-order-recurrence-chains-vplan.ll b/llvm/test/Transforms/LoopVectorize/first-order-recurrence-chains-vplan.ll
index bcacfb358ec05a..517de8be5c9987 100644
--- a/llvm/test/Transforms/LoopVectorize/first-order-recurrence-chains-vplan.ll
+++ b/llvm/test/Transforms/LoopVectorize/first-order-recurrence-chains-vplan.ll
@@ -48,8 +48,8 @@ define void @test_chained_first_order_recurrences_1(ptr %ptr) {
 ; CHECK-NEXT:  Successor(s): ir-bb<loop>
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  ir-bb<loop>:
-; CHECK-NEXT:    IR   %for.1 = phi i16 [ 22, %entry ], [ %for.1.next, %loop ] (extra operand: vp<[[RESUME_1_P]]>)
-; CHECK-NEXT:    IR   %for.2 = phi i16 [ 33, %entry ], [ %for.1, %loop ] (extra operand: vp<[[RESUME_2_P]]>.1)
+; CHECK-NEXT:    IR   %for.1 = phi i16 [ 22, %entry ], [ %for.1.next, %loop ] (extra operand: vp<[[RESUME_1_P]]> from scalar.ph)
+; CHECK-NEXT:    IR   %for.2 = phi i16 [ 33, %entry ], [ %for.1, %loop ] (extra operand: vp<[[RESUME_2_P]]>.1 from scalar.ph)
 ; CHECK-NEXT:    IR   %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
 ; CHECK:         IR   %exitcond.not = icmp eq i64 %iv.next, 1000
 ; CHECK-NEXT:  No successors
@@ -125,9 +125,9 @@ define void @test_chained_first_order_recurrences_3(ptr %ptr) {
 ; CHECK-NEXT:  Successor(s): ir-bb<loop>
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  ir-bb<loop>:
-; CHECK-NEXT:    IR   %for.1 = phi i16 [ 22, %entry ], [ %for.1.next, %loop ] (extra operand: vp<[[RESUME_1_P]]>)
-; CHECK-NEXT:    IR   %for.2 = phi i16 [ 33, %entry ], [ %for.1, %loop ] (extra operand: vp<[[RESUME_2_P]]>.1)
-; CHECK-NEXT:    IR   %for.3 = phi i16 [ 33, %entry ], [ %for.2, %loop ] (extra operand: vp<[[RESUME_3_P]]>.2)
+; CHECK-NEXT:    IR   %for.1 = phi i16 [ 22, %entry ], [ %for.1.next, %loop ] (extra operand: vp<[[RESUME_1_P]]> from scalar.ph)
+; CHECK-NEXT:    IR   %for.2 = phi i16 [ 33, %entry ], [ %for.1, %loop ] (extra operand: vp<[[RESUME_2_P]]>.1 from scalar.ph)
+; CHECK-NEXT:    IR   %for.3 = phi i16 [ 33, %entry ], [ %for.2, %loop ] (extra operand: vp<[[RESUME_3_P]]>.2 from scalar.ph)
 ; CHECK-NEXT:    IR   %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
 ; CHECK:         IR   %exitcond.not = icmp eq i64 %iv.next, 1000
 ; CHECK-NEXT: No successors
@@ -205,8 +205,8 @@ define i32 @test_chained_first_order_recurrences_4(ptr %base, i64 %x) {
 ; CHECK-EMPTY:
 ; CHECK-NEXT: ir-bb<loop>:
 ; CHECK-NEXT:   IR   %iv = phi i64 [ %iv.next, %loop ], [ 0, %entry ]
-; CHECK-NEXT:   IR   %for.x = phi i64 [ %for.x.next, %loop ], [ 0, %entry ] (extra operand: vp<[[RESUME_X]]>)
-; CHECK-NEXT:   IR   %for.y = phi i32 [ %for.x.prev, %loop ], [ 0, %entry ] (extra operand: vp<[[RESUME_Y]]>.1)
+; CHECK-NEXT:   IR   %for.x = phi i64 [ %for.x.next, %loop ], [ 0, %entry ] (extra operand: vp<[[RESUME_X]]> from scalar.ph)
+; CHECK-NEXT:   IR   %for.y = phi i32 [ %for.x.prev, %loop ], [ 0, %entry ] (extra operand: vp<[[RESUME_Y]]>.1 from scalar.ph)
 ; CHECK:     No successors
 ; CHECK-NEXT: }
 ;
@@ -279,8 +279,8 @@ define i32 @test_chained_first_order_recurrences_5_hoist_to_load(ptr %base) {
 ; CHECK-EMPTY:
 ; CHECK-NEXT: ir-bb<loop>:
 ; CHECK-NEXT:   IR   %iv = phi i64 [ %iv.next, %loop ], [ 0, %entry ]
-; CHECK-NEXT:   IR   %for.x = phi i64 [ %for.x.next, %loop ], [ 0, %entry ] (extra operand: vp<[[RESUME_X]]>)
-; CHECK-NEXT:   IR   %for.y = phi i32 [ %for.x.prev, %loop ], [ 0, %entry ] (extra operand: vp<[[RESUME_Y]]>.1)
+; CHECK-NEXT:   IR   %for.x = phi i64 [ %for.x.next, %loop ], [ 0, %entry ] (extra operand: vp<[[RESUME_X]]> from scalar.ph)
+; CHECK-NEXT:   IR   %for.y = phi i32 [ %for.x.prev, %loop ], [ 0, %entry ] (extra operand: vp<[[RESUME_Y]]>.1 from scalar.ph)
 ; CHECK:     No successors
 ; CHECK-NEXT: }
 ;
diff --git a/llvm/test/Transforms/LoopVectorize/first-order-recurrence-sink-replicate-region.ll b/llvm/test/Transforms/LoopVectorize/first-order-recurrence-sink-replicate-region.ll
index 8ae538cf63986b..d0c811763a522a 100644
--- a/llvm/test/Transforms/LoopVectorize/first-order-recurrence-sink-replicate-region.ll
+++ b/llvm/test/Transforms/LoopVectorize/first-order-recurrence-sink-replicate-region.ll
@@ -85,7 +85,7 @@ define void @sink_replicate_region_1(i32 %x, ptr %ptr, ptr noalias %dst) optsize
 ; CHECK-NEXT: Successor(s): ir-bb<loop>
 ; CHECK-EMPTY:
 ; CHECK-NEXT: ir-bb<loop>:
-; CHECK-NEXT:   IR   %0 = phi i32 [ 0, %entry ], [ %conv, %loop ] (extra operand: vp<[[RESUME_1_P]]>)
+; CHECK-NEXT:   IR   %0 = phi i32 [ 0, %entry ], [ %conv, %loop ] (extra operand: vp<[[RESUME_1_P]]> from scalar.ph)
 ; CHECK-NEXT:   IR   %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
 ; CHECK:        IR   %ec = icmp eq i32 %iv.next, 20001
 ; CHECK-NEXT: No successors
@@ -172,7 +172,7 @@ define void @sink_replicate_region_2(i32 %x, i8 %y, ptr %ptr) optsize {
 ; CHECK-NEXT: Successor(s): ir-bb<loop>
 ; CHECK-EMPTY:
 ; CHECK-NEXT: ir-bb<loop>:
-; CHECK-NEXT:   IR   %recur = phi i32 [ 0, %entry ], [ %recur.next, %loop ] (extra operand: vp<[[RESUME_1_P]]>)
+; CHECK-NEXT:   IR   %recur = phi i32 [ 0, %entry ], [ %recur.next, %loop ] (extra operand: vp<[[RESUME_1_P]]> from scalar.ph)
 ; CHECK-NEXT:   IR   %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
 ; CHECK:        IR   %ec = icmp eq i32 %iv.next, 20001
 ; CHECK-NEXT: No successors
@@ -235,7 +235,7 @@ define i32 @sink_replicate_region_3_reduction(i32 %x, i8 %y, ptr %ptr) optsize {
 ; CHECK-NEXT: Successor(s): ir-bb<exit>, scalar.ph
 ; CHECK-EMPTY:
 ; CHECK-NEXT: ir-bb<exit>
-; CHECK-NEXT:   IR %res = phi i32 [ %and.red.next, %loop ] (extra operand: vp<[[RED_EX]]>)
+; CHECK-NEXT:   IR %res = phi i32 [ %and.red.next, %loop ] (extra operand: vp<[[RED_EX]]> from middle.block)
 ; CHECK-NEXT: No successors
 ; CHECK-EMPTY:
 ; CHECK-NEXT: scalar.ph
@@ -244,7 +244,7 @@ define i32 @sink_replicate_region_3_reduction(i32 %x, i8 %y, ptr %ptr) optsize {
 ; CHECK-NEXT: Successor(s): ir-bb<loop>
 ; CHECK-EMPTY:
 ; CHECK-NEXT: ir-bb<loop>:
-; CHECK-NEXT:   IR   %recur = phi i32 [ 0, %entry ], [ %recur.next, %loop ] (extra operand: vp<[[RESUME_1_P]]>)
+; CHECK-NEXT:   IR   %recur = phi i32 [ 0, %entry ], [ %recur.next, %loop ] (extra operand: vp<[[RESUME_1_P]]> from scalar.ph)
 ; CHECK-NEXT:   IR   %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
 ; CHECK-NEXT:   IR   %and.red = phi i32 [ 1234, %entry ], [ %and.red.next, %loop ]
 ; CHECK:        IR   %ec = icmp eq i32 %iv.next, 20001
@@ -355,7 +355,7 @@ define void @sink_replicate_region_4_requires_split_at_end_of_block(i32 %x, ptr
 ; CHECK-NEXT: Successor(s): ir-bb<loop>
 ; CHECK-EMPTY:
 ; CHECK-NEXT: ir-bb<loop>:
-; CHECK-NEXT:   IR   %0 = phi i32 [ 0, %entry ], [ %conv, %loop ] (extra operand: vp<[[RESUME_1_P]]>)
+; CHECK-NEXT:   IR   %0 = phi i32 [ 0, %entry ], [ %conv, %loop ] (extra operand: vp<[[RESUME_1_P]]> from scalar.ph)
 ; CHECK-NEXT:   IR   %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
 ; CHECK:        IR   %ec = icmp eq i32 %iv.next, 20001
 ; CHECK-NEXT: No successors
@@ -452,7 +452,7 @@ define void @sink_replicate_region_after_replicate_region(ptr %ptr, ptr noalias
 ; CHECK-NEXT: Successor(s): ir-bb<loop>
 ; CHECK-EMPTY:
 ; CHECK-NEXT: ir-bb<loop>:
-; CHECK-NEXT:   IR   %recur = phi i32 [ 0, %entry ], [ %recur.next, %loop ] (extra operand: vp<[[RESUME_1_P]]>)
+; CHECK-NEXT:   IR   %recur = phi i32 [ 0, %entry ], [ %recur.next, %loop ] (extra operand: vp<[[RESUME_1_P]]> from scalar.ph)
 ; CHECK-NEXT:   IR   %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
 ; CHECK:        IR   %C = icmp sgt i32 %iv.next, %recur.next
 ; CHECK-NEXT: No successors
@@ -539,7 +539,7 @@ define void @need_new_block_after_sinking_pr56146(i32 %x, ptr %src, ptr noalias
 ; CHECK-EMPTY:
 ; CHECK-NEXT: ir-bb<loop>:
 ; CHECK-NEXT:   IR   %iv = phi i64 [ 2, %entry ], [ %iv.next, %loop ]
-; CHECK-NEXT:   IR   %.pn = phi i32 [ 0, %entry ], [ %l, %loop ] (extra operand: vp<[[RESUME_1_P]]>)
+; CHECK-NEXT:   IR   %.pn = phi i32 [ 0, %entry ], [ %l, %loop ] (extra operand: vp<[[RESUME_1_P]]> from scalar.ph)
 ; CHECK:        IR   %ec = icmp ugt i64 %iv, 3
 ; CHECK-NEXT: No successors
 ; CHECK-NEXT: }
diff --git a/llvm/test/Transforms/LoopVectorize/interleave-and-scalarize-only.ll b/llvm/test/Transforms/LoopVectorize/interleave-and-scalarize-only.ll
index a71666d8c3167a..dd58dc81ccedde 100644
--- a/llvm/test/Transforms/LoopVectorize/interleave-and-scalarize-only.ll
+++ b/llvm/test/Transforms/LoopVectorize/interleave-and-scalarize-only.ll
@@ -227,7 +227,7 @@ exit:
 ; DBG-EMPTY:
 ; DBG-NEXT: ir-bb<loop>:
 ; DBG-NEXT:   IR   %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
-; DBG-NEXT:   IR   %for = phi i32 [ 0, %entry ], [ %iv.trunc, %loop ] (extra operand: vp<[[RESUME_P]]>)
+; DBG-NEXT:   IR   %for = phi i32 [ 0, %entry ], [ %iv.trunc, %loop ] (extra operand: vp<[[RESUME_P]]> from scalar.ph)
 ; DBG:        IR   %ec = icmp slt i32 %iv.next.trunc, %n
 ; DBG-NEXT: No successors
 ; DBG-NEXT: }
diff --git a/llvm/test/Transforms/LoopVectorize/vplan-printing.ll b/llvm/test/Transforms/LoopVectorize/vplan-printing.ll
index 6bb20a301e0ade..195f6a48640e54 100644
--- a/llvm/test/Transforms/LoopVectorize/vplan-printing.ll
+++ b/llvm/test/Transforms/LoopVectorize/vplan-printing.ll
@@ -171,7 +171,7 @@ define float @print_reduction(i64 %n, ptr noalias %y) {
 ; CHECK-NEXT: Successor(s): ir-bb<for.end>, scalar.ph
 ; CHECK-EMPTY:
 ; CHECK-NEXT: ir-bb<for.end>
-; CHECK-NEXT:  IR %red.next.lcssa = phi float [ %red.next, %for.body ] (extra operand: vp<[[RED_EX]]>)
+; CHECK-NEXT:  IR %red.next.lcssa = phi float [ %red.next, %for.body ] (extra operand: vp<[[RED_EX]]> from middle.block)
 ; CHECK-NEXT: No successors
 ; CHECK-EMPTY:
 ; CHECK-NEXT: scalar.ph
@@ -476,7 +476,7 @@ define float @print_fmuladd_strict(ptr %a, ptr %b, i64 %n) {
 ; CHECK-NEXT: Successor(s): ir-bb<for.end>, scalar.ph
 ; CHECK-EMPTY:
 ; CHECK-NEXT: ir-bb<for.end>
-; CHECK-NEXT:   IR %muladd.lcssa = phi float [ %muladd, %for.body ] (extra operand: vp<[[RED_EX]]>)
+; CHECK-NEXT:   IR %muladd.lcssa = phi float [ %muladd, %for.body ] (extra operand: vp<[[RED_EX]]> from middle.block)
 ; CHECK-NEXT: No successors
 ; CHECK-EMPTY:
 ; CHECK-NEXT: scalar.ph
@@ -716,7 +716,7 @@ define i32 @print_exit_value(ptr %ptr, i32 %off) {
 ; CHECK-NEXT: Successor(s): ir-bb<exit>, scalar.ph
 ; CHECK-EMPTY:
 ; CHECK-NEXT: ir-bb<exit>
-; CHECK-NEXT:   IR %lcssa = phi i32 [ %add, %loop ] (extra operand: vp<[[EXIT]]>)
+; CHECK-NEXT:   IR %lcssa = phi i32 [ %add, %loop ] (extra operand: vp<[[EXIT]]> from middle.block)
 ; CHECK-NEXT: No successors
 ; CHECK-EMPTY:
 ; CHECK-NEXT: scalar.ph
@@ -1111,7 +1111,7 @@ define i16 @print_first_order_recurrence_and_result(ptr %ptr) {
 ; CHECK-NEXT: Successor(s): ir-bb<exit>, scalar.ph
 ; CHECK-EMPTY:
 ; CHECK-NEXT: ir-bb<exit>
-; CHECK-NEXT:   IR %for.1.lcssa = phi i16 [ %for.1, %loop ] (extra operand: vp<[[FOR_RESULT]]>)
+; CHECK-NEXT:   IR %for.1.lcssa = phi i16 [ %for.1, %loop ] (extra operand: vp<[[FOR_RESULT]]> from middle.block)
 ; CHECK-NEXT: No successors
 ; CHECK-EMPTY:
 ; CHECK-NEXT: scalar.ph
@@ -1119,7 +1119,7 @@ define i16 @print_first_order_recurrence_and_result(ptr %ptr) {
 ; CHECK-NEXT:  Successor(s): ir-bb<loop>
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  ir-bb<loop>:
-; CHECK-NEXT:    IR   %for.1 = phi i16 [ 22, %entry ], [ %for.1.next, %loop ] (extra operand: vp<[[RESUME_P]]>)
+; CHECK-NEXT:    IR   %for.1 = phi i16 [ 22, %entry ], [ %for.1.next, %loop ] (extra operand: vp<[[RESUME_P]]> from scalar.ph)
 ; CHECK-NEXT:    IR   %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
 ; CHECK:         IR   %exitcond.not = icmp eq i64 %iv.next, 1000
 ; CHECK-NEXT: No successors

>From 552bd9161f07ace9083c3ab409219add05aaf2bc Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sat, 23 Nov 2024 18:59:09 +0000
Subject: [PATCH 12/18] !fixup update recipe printing

---
 llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp         | 10 ++++++----
 .../LoopVectorize/uncountable-early-exit-vplan.ll      |  8 ++++----
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index 57649e0233f9d5..761f2949126e49 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -868,10 +868,12 @@ void VPIRInstruction::print(raw_ostream &O, const Twine &Indent,
   O << Indent << "IR " << I;
 
   if (getNumOperands() != 0) {
-    O << " (extra operand: ";
-    getOperand(0)->printAsOperand(O, SlotTracker);
-    O << " from ";
-    getParent()->getPredecessors()[0]->printAsOperand(O);
+    O << " (extra operand" << (getNumOperands() > 1 ? "s" : "") << ": ";
+    interleaveComma(enumerate(operands()), O, [this, &O, &SlotTracker](auto Op) {
+                         Op.value()->printAsOperand(O, SlotTracker);
+                         O << " from ";
+                        getParent()->getPredecessors()[Op.index()]->printAsOperand(O);
+                         });
     O << ")";
   }
 }
diff --git a/llvm/test/Transforms/LoopVectorize/uncountable-early-exit-vplan.ll b/llvm/test/Transforms/LoopVectorize/uncountable-early-exit-vplan.ll
index 9df40d77ecc5fd..2583070fc9820a 100644
--- a/llvm/test/Transforms/LoopVectorize/uncountable-early-exit-vplan.ll
+++ b/llvm/test/Transforms/LoopVectorize/uncountable-early-exit-vplan.ll
@@ -41,7 +41,7 @@ define i64 @multi_exiting_to_different_exits_live_in_exit_values() {
 ; CHECK-NEXT: Successor(s): ir-bb<e1>, middle.block
 ; CHECK-EMPTY:
 ; CHECK-NEXT: ir-bb<e1>:
-; CHECK-NEXT:   IR %p1 = phi i64 [ 0, %loop.header ] (extra operand: ir<0>)
+; CHECK-NEXT:   IR %p1 = phi i64 [ 0, %loop.header ] (extra operand: ir<0> from middle.split)
 ; CHECK-NEXT: No successors
 ; CHECK-EMPTY:
 ; CHECK-NEXT: middle.block:
@@ -50,7 +50,7 @@ define i64 @multi_exiting_to_different_exits_live_in_exit_values() {
 ; CHECK-NEXT: Successor(s): ir-bb<e2>, scalar.ph
 ; CHECK-EMPTY:
 ; CHECK-NEXT: ir-bb<e2>:
-; CHECK-NEXT:  IR %p2 = phi i64 [ 1, %loop.latch ] (extra operand: ir<1>)
+; CHECK-NEXT:  IR %p2 = phi i64 [ 1, %loop.latch ] (extra operand: ir<1> from middle.block)
 ; CHECK-NEXT: No successors
 ; CHECK-EMPTY:
 ; CHECK-NEXT: scalar.ph:
@@ -152,7 +152,7 @@ define i64 @multi_exiting_to_same_exit_live_in_exit_values() {
 ; CHECK-NEXT: Successor(s): ir-bb<exit>, middle.block
 ; CHECK-EMPTY:
 ; CHECK-NEXT: ir-bb<exit>:
-; CHECK-NEXT:   IR %p = phi i64 [ 0, %loop.header ], [ 1, %loop.latch ] (extra operand: ir<1>, ir<0>)
+; CHECK-NEXT:   IR %p = phi i64 [ 0, %loop.header ], [ 1, %loop.latch ] (extra operands: ir<1> from middle.block, ir<0> from middle.split)
 ; CHECK-NEXT: No successors
 ; CHECK-EMPTY:
 ; CHECK-NEXT: middle.block:
@@ -228,7 +228,7 @@ define i64 @multi_exiting_to_same_exit_live_in_exit_values_2() {
 ; CHECK-NEXT: Successor(s): ir-bb<exit>, middle.block
 ; CHECK-EMPTY:
 ; CHECK-NEXT: ir-bb<exit>:
-; CHECK-NEXT:   IR %p = phi i64 [ 0, %loop.header ], [ 1, %loop.latch ] (extra operand: ir<1>, ir<0>)
+; CHECK-NEXT:   IR %p = phi i64 [ 0, %loop.header ], [ 1, %loop.latch ] (extra operands: ir<1> from middle.block, ir<0> from middle.split)
 ; CHECK-NEXT: No successors
 ; CHECK-EMPTY:
 ; CHECK-NEXT: middle.block:

>From 00dea4a96e5b9cf863d30f3f5f06aab6acbd21a7 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sat, 23 Nov 2024 19:16:35 +0000
Subject: [PATCH 13/18] !fixup add dbg message

---
 .../Vectorize/LoopVectorizationLegality.cpp       | 15 +++++++++++----
 llvm/lib/Transforms/Vectorize/LoopVectorize.cpp   |  7 ++++++-
 .../LoopVectorize/early_exit_legality.ll          |  6 +++---
 3 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
index 0267fb1adb16d6..0dcf5ecec13b0f 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
@@ -1375,10 +1375,17 @@ bool LoopVectorizationLegality::isFixedOrderRecurrence(
 }
 
 bool LoopVectorizationLegality::blockNeedsPredication(BasicBlock *BB) const {
-  // When vectorizing early exits, create predicates for all blocks, except the
-  // header.
-  if (hasUncountableEarlyExit() && BB != TheLoop->getHeader())
-    return true;
+  // When vectorizing early exits, create predicates for the latch block. The
+  // early exiting block must be a direct predecessor of the latch at the
+  // moment.
+  BasicBlock *Latch = TheLoop->getLoopLatch();
+  if (hasUncountableEarlyExit()) {
+    assert(
+        getUncountableExitingBlocks().size() == 1 &&
+        is_contained(predecessors(Latch), getUncountableExitingBlocks()[0]) &&
+        "Uncountable exiting block must be a direct predecessor of latch");
+    return BB == Latch;
+  }
   return LoopAccessInfo::blockNeedsPredication(BB, TheLoop, DT);
 }
 
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 5134c4ec7d225c..bbd560c75f5afc 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -9239,8 +9239,13 @@ LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(VFRange &Range) {
   SetVector<VPIRInstruction *> ExitUsersToFix = collectUsersInExitBlocks(
       OrigLoop, RecipeBuilder, *Plan, Legal->getInductionVars());
   addExitUsersForFirstOrderRecurrences(*Plan, ExitUsersToFix);
-  if (!addUsersInExitBlocks(*Plan, ExitUsersToFix))
+  if (!addUsersInExitBlocks(*Plan, ExitUsersToFix)) {
+    reportVectorizationFailure(
+        "Some exit values in loop with uncountable exit not supported yet",
+        "Some exit values in loop with uncountable exit not supported yet",
+        "UncountableEarlyExitLoopsUnsupportedExitValue", ORE, OrigLoop);
     return nullptr;
+  }
 
   // ---------------------------------------------------------------------------
   // Transform initial VPlan: Apply previously taken decisions, in order, to
diff --git a/llvm/test/Transforms/LoopVectorize/early_exit_legality.ll b/llvm/test/Transforms/LoopVectorize/early_exit_legality.ll
index f7fd55a0f039a3..2a99693523d3cf 100644
--- a/llvm/test/Transforms/LoopVectorize/early_exit_legality.ll
+++ b/llvm/test/Transforms/LoopVectorize/early_exit_legality.ll
@@ -11,7 +11,7 @@ define i32 @diff_exit_block_needs_scev_check(i32 %end) {
 ; CHECK-LABEL: LV: Checking a loop in 'diff_exit_block_needs_scev_check'
 ; CHECK:       Found an early exit loop with symbolic max backedge taken count: (-1 + (1 umax (zext i10 (trunc i32 %end to i10) to i32)))<nsw>
 ; CHECK-NEXT:  LV: We can vectorize this loop!
-; CHECK-NEXT:  LV: Not vectorizing: Auto-vectorization of loops with uncountable early exit is not yet supported.
+; CHECK-NOT:   LV: Not vectorizing:
 entry:
   %p1 = alloca [1024 x i32]
   %p2 = alloca [1024 x i32]
@@ -49,7 +49,7 @@ define i64 @same_exit_block_pre_inc_use1() {
 ; CHECK-LABEL: LV: Checking a loop in 'same_exit_block_pre_inc_use1'
 ; CHECK:       LV: Found an early exit loop with symbolic max backedge taken count: 63
 ; CHECK-NEXT:  LV: We can vectorize this loop!
-; CHECK-NEXT:  LV: Not vectorizing: Auto-vectorization of loops with uncountable early exit is not yet supported.
+; CHECK-NOT:   LV: Not vectorizing
 entry:
   %p1 = alloca [1024 x i8]
   %p2 = alloca [1024 x i8]
@@ -141,7 +141,7 @@ define i64 @loop_contains_load_after_early_exit(ptr dereferenceable(1024) align(
 ; CHECK-LABEL: LV: Checking a loop in 'loop_contains_load_after_early_exit'
 ; CHECK:       LV: Found an early exit loop with symbolic max backedge taken count: 63
 ; CHECK-NEXT:  LV: We can vectorize this loop!
-; CHECK-NEXT:  LV: Not vectorizing: Auto-vectorization of loops with uncountable early exit is not yet supported.
+; CHECK:       LV: Not vectorizing: Some exit values in loop with uncountable exit not supported yet.
 entry:
   %p1 = alloca [1024 x i8]
   call void @init_mem(ptr %p1, i64 1024)

>From 7b8866d8329d53e55239b7f824a2e2f0b186da1c Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sun, 24 Nov 2024 07:45:12 +0000
Subject: [PATCH 14/18] !fixup fix formatting

---
 llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index 761f2949126e49..7d13f437e934c8 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -869,11 +869,12 @@ void VPIRInstruction::print(raw_ostream &O, const Twine &Indent,
 
   if (getNumOperands() != 0) {
     O << " (extra operand" << (getNumOperands() > 1 ? "s" : "") << ": ";
-    interleaveComma(enumerate(operands()), O, [this, &O, &SlotTracker](auto Op) {
-                         Op.value()->printAsOperand(O, SlotTracker);
-                         O << " from ";
-                        getParent()->getPredecessors()[Op.index()]->printAsOperand(O);
-                         });
+    interleaveComma(
+        enumerate(operands()), O, [this, &O, &SlotTracker](auto Op) {
+          Op.value()->printAsOperand(O, SlotTracker);
+          O << " from ";
+          getParent()->getPredecessors()[Op.index()]->printAsOperand(O);
+        });
     O << ")";
   }
 }

>From b9ee73961bc3a1983bf3cc26d595e2acf751183e Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sun, 8 Dec 2024 20:51:51 +0000
Subject: [PATCH 15/18] !restore test checks.

---
 llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp |  1 +
 .../LoopVectorize/X86/multi-exit-cost.ll       | 18 +++++++++---------
 2 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index a639f806e8e6ee..92b0de4abbbda8 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -57,6 +57,7 @@ bool VPRecipeBase::mayWriteToMemory() const {
     case Instruction::Or:
     case Instruction::ICmp:
     case Instruction::Select:
+    case VPInstruction::AnyOf:
     case VPInstruction::Not:
     case VPInstruction::CalculateTripCountMinusVF:
     case VPInstruction::CanonicalIVIncrementForPart:
diff --git a/llvm/test/Transforms/LoopVectorize/X86/multi-exit-cost.ll b/llvm/test/Transforms/LoopVectorize/X86/multi-exit-cost.ll
index 3517b5c484e37d..4e768074019d31 100644
--- a/llvm/test/Transforms/LoopVectorize/X86/multi-exit-cost.ll
+++ b/llvm/test/Transforms/LoopVectorize/X86/multi-exit-cost.ll
@@ -5,18 +5,18 @@ define i64 @test_value_in_exit_compare_chain_used_outside(ptr %src, i64 %x, i64
 ; CHECK-LABEL: define i64 @test_value_in_exit_compare_chain_used_outside(
 ; CHECK-SAME: ptr [[SRC:%.*]], i64 [[X:%.*]], i64 range(i64 1, 32) [[N:%.*]]) #[[ATTR0:[0-9]+]] {
 ; CHECK-NEXT:  [[ENTRY:.*]]:
-; CHECK-NEXT:    [[TMP3:%.*]] = add nsw i64 [[N]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = freeze i64 [[TMP3]]
-; CHECK-NEXT:    [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[TMP4]], i64 [[X]])
-; CHECK-NEXT:    [[TMP2:%.*]] = add nuw nsw i64 [[UMIN]], 1
+; CHECK-NEXT:    [[TMP0:%.*]] = add nsw i64 [[N]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = freeze i64 [[TMP0]]
+; CHECK-NEXT:    [[UMIN2:%.*]] = call i64 @llvm.umin.i64(i64 [[TMP1]], i64 [[X]])
+; CHECK-NEXT:    [[TMP2:%.*]] = add nuw nsw i64 [[UMIN2]], 1
 ; CHECK-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ule i64 [[TMP2]], 8
 ; CHECK-NEXT:    br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_SCEVCHECK:.*]]
 ; CHECK:       [[VECTOR_SCEVCHECK]]:
-; CHECK-NEXT:    [[TMP32:%.*]] = add nsw i64 [[N]], -1
-; CHECK-NEXT:    [[TMP33:%.*]] = freeze i64 [[TMP32]]
-; CHECK-NEXT:    [[UMIN1:%.*]] = call i64 @llvm.umin.i64(i64 [[TMP33]], i64 [[X]])
-; CHECK-NEXT:    [[TMP5:%.*]] = trunc i64 [[UMIN1]] to i1
-; CHECK-NEXT:    [[TMP6:%.*]] = icmp ugt i64 [[UMIN1]], 1
+; CHECK-NEXT:    [[TMP3:%.*]] = add nsw i64 [[N]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = freeze i64 [[TMP3]]
+; CHECK-NEXT:    [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[TMP4]], i64 [[X]])
+; CHECK-NEXT:    [[TMP5:%.*]] = trunc i64 [[UMIN]] to i1
+; CHECK-NEXT:    [[TMP6:%.*]] = icmp ugt i64 [[UMIN]], 1
 ; CHECK-NEXT:    [[TMP7:%.*]] = or i1 [[TMP5]], [[TMP6]]
 ; CHECK-NEXT:    br i1 [[TMP7]], label %[[SCALAR_PH]], label %[[VECTOR_PH:.*]]
 ; CHECK:       [[VECTOR_PH]]:

>From 95f427629d84a772742bf0f23251bbd2beecc119 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 10 Dec 2024 12:24:52 +0000
Subject: [PATCH 16/18] !fixup address most comment, a few more pending

---
 .../Vectorize/LoopVectorizationLegality.h       |  5 +++++
 .../Vectorize/LoopVectorizationLegality.cpp     | 13 +++++++------
 llvm/lib/Transforms/Vectorize/LoopVectorize.cpp | 17 +++++++++++------
 3 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h b/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h
index dc7e484a40a452..fbe80eddbae07a 100644
--- a/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h
+++ b/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h
@@ -395,6 +395,11 @@ class LoopVectorizationLegality {
 
   /// Returns the uncountable early exiting block.
   BasicBlock *getUncountableEarlyExitingBlock() const {
+    if (!HasUncountableEarlyExit) {
+      assert(getUncountableExitingBlocks().empty() &&
+             "Expected no uncountable exiting blocks");
+      return nullptr;
+    }
     assert(getUncountableExitingBlocks().size() == 1 &&
            "Expected only a single uncountable exiting block");
     return getUncountableExitingBlocks()[0];
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
index 0dcf5ecec13b0f..555c8435dd330d 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
@@ -1375,14 +1375,13 @@ bool LoopVectorizationLegality::isFixedOrderRecurrence(
 }
 
 bool LoopVectorizationLegality::blockNeedsPredication(BasicBlock *BB) const {
-  // When vectorizing early exits, create predicates for the latch block. The
-  // early exiting block must be a direct predecessor of the latch at the
+  // When vectorizing early exits, create predicates for the latch block only.
+  // The early exiting block must be a direct predecessor of the latch at the
   // moment.
   BasicBlock *Latch = TheLoop->getLoopLatch();
   if (hasUncountableEarlyExit()) {
     assert(
-        getUncountableExitingBlocks().size() == 1 &&
-        is_contained(predecessors(Latch), getUncountableExitingBlocks()[0]) &&
+        is_contained(predecessors(Latch), getUncountableEarlyExitingBlock()) &&
         "Uncountable exiting block must be a direct predecessor of latch");
     return BB == Latch;
   }
@@ -1799,13 +1798,15 @@ bool LoopVectorizationLegality::canVectorize(bool UseVPlanNativePath) {
 
   HasUncountableEarlyExit = false;
   if (isa<SCEVCouldNotCompute>(PSE.getBackedgeTakenCount())) {
+    HasUncountableEarlyExit = true;
     if (!isVectorizableEarlyExitLoop()) {
+      UncountableExitingBlocks.clear();
+      HasUncountableEarlyExit = false;
       if (DoExtraAnalysis)
         Result = false;
       else
         return false;
-    } else
-      HasUncountableEarlyExit = true;
+    }
   }
 
   // Go over each instruction and look at memory deps.
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 9b3bae20c174b8..75c3d5128f2d83 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -3662,13 +3662,15 @@ void LoopVectorizationCostModel::collectLoopUniforms(ElementCount VF) {
 
   // Start with the conditional branches exiting the loop. If the branch
   // condition is an instruction contained in the loop that is only used by the
-  // branch, it is uniform.
+  // branch, it is uniform. Note conditions from uncountable early exits are not
+  // uniform.
   SmallVector<BasicBlock *> Exiting;
   TheLoop->getExitingBlocks(Exiting);
   for (BasicBlock *E : Exiting) {
+    if (Legal->hasUncountableEarlyExit() && TheLoop->getLoopLatch() != E)
+      continue;
     auto *Cmp = dyn_cast<Instruction>(E->getTerminator()->getOperand(0));
-    if (Cmp && TheLoop->contains(Cmp) && Cmp->hasOneUse() &&
-        (TheLoop->getLoopLatch() == E || !Legal->hasUncountableEarlyExit()))
+    if (Cmp && TheLoop->contains(Cmp) && Cmp->hasOneUse())
       AddToWorklistIfAllowed(Cmp);
   }
 
@@ -7857,7 +7859,7 @@ DenseMap<const SCEV *, Value *> LoopVectorizationPlanner::executePlan(
 
   ILV.printDebugTracesAtEnd();
 
-  // 4. Adjust branch weight of the branch in the middle block.
+  // 4. Adjust branch weight of the branch in the middle block if it exists.
   if (ExitVPBB) {
     auto *MiddleTerm =
         cast<BranchInst>(State.CFG.VPBB2IRBB[ExitVPBB]->getTerminator());
@@ -8248,8 +8250,11 @@ VPValue *VPRecipeBuilder::createEdgeMask(BasicBlock *Src, BasicBlock *Dst) {
 
   // If source is an exiting block, we know the exit edge is dynamically dead
   // in the vector loop, and thus we don't need to restrict the mask.  Avoid
-  // adding uses of an otherwise potentially dead instruction.
-  if (!Legal->hasUncountableEarlyExit() && OrigLoop->isLoopExiting(Src))
+  // adding uses of an otherwise potentially dead instruction unless we are
+  // vectorizing a loop with uncountable exits. In that case, we always
+  // materialize the mask.
+  if (OrigLoop->isLoopExiting(Src) &&
+      Src != Legal->getUncountableEarlyExitingBlock())
     return EdgeMaskCache[Edge] = SrcMask;
 
   VPValue *EdgeMask = getVPValueOrAddLiveIn(BI->getCondition());

>From c3d3b390ab75ee201688bea179b07ad311e8a9d9 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 10 Dec 2024 13:46:43 +0000
Subject: [PATCH 17/18] !fixup address remaining comments, thanks!

---
 .../Transforms/Vectorize/LoopVectorize.cpp    | 24 +++--
 llvm/lib/Transforms/Vectorize/VPlan.cpp       | 10 +--
 .../Transforms/Vectorize/VPlanTransforms.cpp  | 69 ++++++++-------
 .../Transforms/Vectorize/VPlanTransforms.h    |  8 +-
 .../uncountable-early-exit-vplan.ll           | 88 -------------------
 5 files changed, 55 insertions(+), 144 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 75c3d5128f2d83..b47386389c82c1 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -9294,12 +9294,10 @@ LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(VFRange &Range) {
          "VPBasicBlock");
   RecipeBuilder.fixHeaderPhis();
 
-  if (Legal->hasUncountableEarlyExit()) {
-    assert(Legal->getUncountableExitingBlocks().size() == 1 &&
-           "Only single uncountable exiting bock supported");
+  if (auto *UncountableExitingBlock =
+          Legal->getUncountableEarlyExitingBlock()) {
     VPlanTransforms::handleUncountableEarlyExit(
-        *Plan, *PSE.getSE(), OrigLoop, Legal->getUncountableExitingBlocks()[0],
-        RecipeBuilder);
+        *Plan, *PSE.getSE(), OrigLoop, UncountableExitingBlock, RecipeBuilder);
   }
   addScalarResumePhis(RecipeBuilder, *Plan);
   SetVector<VPIRInstruction *> ExitUsersToFix = collectUsersInExitBlocks(
@@ -10178,15 +10176,13 @@ bool LoopVectorizePass::processLoop(Loop *L) {
     return false;
   }
 
-  if (LVL.hasUncountableEarlyExit()) {
-    if (!EnableEarlyExitVectorization) {
-      reportVectorizationFailure("Auto-vectorization of loops with uncountable "
-                                 "early exit is not enabled",
-                                 "Auto-vectorization of loops with uncountable "
-                                 "early exit is not enabled",
-                                 "UncountableEarlyExitLoopsDisabled", ORE, L);
-      return false;
-    }
+  if (LVL.hasUncountableEarlyExit() && !EnableEarlyExitVectorization) {
+    reportVectorizationFailure("Auto-vectorization of loops with uncountable "
+                               "early exit is not enabled",
+                               "Auto-vectorization of loops with uncountable "
+                               "early exit is not enabled",
+                               "UncountableEarlyExitLoopsDisabled", ORE, L);
+    return false;
   }
 
   // Entrance to the VPlan-native vectorization path. Outer loops are processed
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp
index bf86bd2bb1ad52..81c76bc99fbf74 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp
@@ -861,7 +861,7 @@ VPlanPtr VPlan::createInitialVPlan(Type *InductionTy,
   auto Plan = std::make_unique<VPlan>(Entry, VecPreheader, ScalarHeader);
 
   // Create SCEV and VPValue for the trip count.
-  // We use the symbolic max backedge-taken-count, which is used when
+  // We use the symbolic max backedge-taken-count, which works also when
   // vectorizing loops with uncountable early exits.
   const SCEV *BackedgeTakenCountSCEV = PSE.getSymbolicMaxBackedgeTakenCount();
   assert(!isa<SCEVCouldNotCompute>(BackedgeTakenCountSCEV) &&
@@ -901,8 +901,7 @@ VPlanPtr VPlan::createInitialVPlan(Type *InductionTy,
   // 3) Otherwise, construct a runtime check.
   BasicBlock *IRExitBlock = TheLoop->getUniqueLatchExitBlock();
   auto *VPExitBlock = VPIRBasicBlock::fromBasicBlock(IRExitBlock);
-  // The connection order corresponds to the operands of the conditional
-  // branch.
+  // The connection order corresponds to the operands of the conditional branch.
   VPBlockUtils::insertBlockAfter(VPExitBlock, MiddleVPBB);
   VPBlockUtils::connectBlocks(MiddleVPBB, ScalarPH);
 
@@ -1047,10 +1046,7 @@ void VPlan::execute(VPTransformState *State) {
       // Move the last step to the end of the latch block. This ensures
       // consistent placement of all induction updates.
       Instruction *Inc = cast<Instruction>(Phi->getIncomingValue(1));
-      if (VectorLatchBB->getTerminator() == &*VectorLatchBB->getFirstNonPHI())
-        Inc->moveBefore(VectorLatchBB->getTerminator());
-      else
-        Inc->moveBefore(VectorLatchBB->getTerminator()->getPrevNode());
+      Inc->moveBefore(VectorLatchBB->getTerminator()->getPrevNode());
 
       // Use the steps for the last part as backedge value for the induction.
       if (auto *IV = dyn_cast<VPWidenIntOrFpInductionRecipe>(&R))
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index 84c46c726d62ce..5406c7be3eac7b 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -1842,50 +1842,57 @@ void VPlanTransforms::convertToConcreteRecipes(VPlan &Plan) {
 void VPlanTransforms::handleUncountableEarlyExit(
     VPlan &Plan, ScalarEvolution &SE, Loop *OrigLoop,
     BasicBlock *UncountableExitingBlock, VPRecipeBuilder &RecipeBuilder) {
-  auto *LatchVPBB =
-      cast<VPBasicBlock>(Plan.getVectorLoopRegion()->getExiting());
+  VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
+  auto *LatchVPBB = cast<VPBasicBlock>(LoopRegion->getExiting());
   VPBuilder Builder(LatchVPBB->getTerminator());
   auto *MiddleVPBB = Plan.getMiddleBlock();
-  VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
-  VPValue *EarlyExitTaken = nullptr;
+  VPValue *IsEarlyExitTaken = nullptr;
 
-  // Process the uncountable exiting block. Update EarlyExitTaken, which tracks
-  // if any uncountable early exit has been taken. Also split the middle block
-  // and branch to the exit block for the early exit if it has been taken.
-  auto *ExitingTerm =
+  // Process the uncountable exiting block. Update IsEarlyExitTaken, which
+  // tracks if the uncountable early exit has been taken. Also split the middle
+  // block and have it conditionally branch to the early exit block if
+  // EarlyExitTaken.
+  auto *EarlyExitingBranch =
       cast<BranchInst>(UncountableExitingBlock->getTerminator());
-  BasicBlock *TrueSucc = ExitingTerm->getSuccessor(0);
-  BasicBlock *FalseSucc = ExitingTerm->getSuccessor(1);
-  VPIRBasicBlock *VPExitBlock;
+  BasicBlock *TrueSucc = EarlyExitingBranch->getSuccessor(0);
+  BasicBlock *FalseSucc = EarlyExitingBranch->getSuccessor(1);
+
+  // The early exit block may or may not be the same as the "countable" exit
+  // block. Creates a new VPIRBB for the early exit block in case it is distinct
+  // from the countable exit block.
+  // TODO: Introduce both exit blocks during VPlan skeleton construction.
+  VPIRBasicBlock *VPEarlyExitBlock;
   if (OrigLoop->getUniqueExitBlock()) {
-    VPExitBlock = cast<VPIRBasicBlock>(MiddleVPBB->getSuccessors()[0]);
+    VPEarlyExitBlock = cast<VPIRBasicBlock>(MiddleVPBB->getSuccessors()[0]);
   } else {
-    VPExitBlock = VPIRBasicBlock::fromBasicBlock(
+    VPEarlyExitBlock = VPIRBasicBlock::fromBasicBlock(
         !OrigLoop->contains(TrueSucc) ? TrueSucc : FalseSucc);
   }
 
-  VPValue *M = RecipeBuilder.getBlockInMask(
+  VPValue *EarlyExitNotTakenCond = RecipeBuilder.getBlockInMask(
       OrigLoop->contains(TrueSucc) ? TrueSucc : FalseSucc);
-  auto *N = Builder.createNot(M);
-  EarlyExitTaken = Builder.createNaryOp(VPInstruction::AnyOf, {N});
+  auto *EarlyExitTakenCond = Builder.createNot(EarlyExitNotTakenCond);
+  IsEarlyExitTaken =
+      Builder.createNaryOp(VPInstruction::AnyOf, {EarlyExitTakenCond});
 
   VPBasicBlock *NewMiddle = new VPBasicBlock("middle.split");
-  VPBlockUtils::disconnectBlocks(LoopRegion, MiddleVPBB);
-  VPBlockUtils::insertBlockAfter(NewMiddle, LoopRegion);
-  VPBlockUtils::connectBlocks(NewMiddle, VPExitBlock);
-  VPBlockUtils::connectBlocks(NewMiddle, MiddleVPBB);
+  VPBlockUtils::insertOnEdge(LoopRegion, MiddleVPBB, NewMiddle);
+  VPBlockUtils::connectBlocks(NewMiddle, VPEarlyExitBlock);
+  std::swap(NewMiddle->getSuccessors()[0], NewMiddle->getSuccessors()[1]);
 
   VPBuilder MiddleBuilder(NewMiddle);
-  MiddleBuilder.createNaryOp(VPInstruction::BranchOnCond, {EarlyExitTaken});
-
-  // Replace the condition controlling the exit from the vector loop with one
-  // exiting if either the original condition of the vector latch is true or any
-  // early exit has been taken.
-  auto *Term = dyn_cast<VPInstruction>(LatchVPBB->getTerminator());
-  auto *IsLatchExiting = Builder.createICmp(
-      CmpInst::ICMP_EQ, Term->getOperand(0), Term->getOperand(1));
-  auto *AnyExiting =
-      Builder.createNaryOp(Instruction::Or, {EarlyExitTaken, IsLatchExiting});
+  MiddleBuilder.createNaryOp(VPInstruction::BranchOnCond, {IsEarlyExitTaken});
+
+  // Replace the condition controlling the non-early exit from the vector loop
+  // with one exiting if either the original condition of the vector latch is
+  // true or the early exit has been taken.
+  auto *LatchExitingBranch =
+      dyn_cast<VPInstruction>(LatchVPBB->getTerminator());
+  auto *IsLatchExitTaken =
+      Builder.createICmp(CmpInst::ICMP_EQ, LatchExitingBranch->getOperand(0),
+                         LatchExitingBranch->getOperand(1));
+  auto *AnyExiting = Builder.createNaryOp(Instruction::Or,
+                                          {IsEarlyExitTaken, IsLatchExitTaken});
   Builder.createNaryOp(VPInstruction::BranchOnCond, AnyExiting);
-  Term->eraseFromParent();
+  LatchExitingBranch->eraseFromParent();
 }
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.h b/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
index ee5481718cbfbb..f7b09c1311ef7e 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
@@ -124,12 +124,12 @@ struct VPlanTransforms {
   /// Remove dead recipes from \p Plan.
   static void removeDeadRecipes(VPlan &Plan);
 
-  /// Update \p Plan to account for uncountable exit blocks in \p
-  /// UncountableExitingBlocks by
-  ///  * updating the condition to exit the vector loop to include the early
+  /// Update \p Plan to account for the uncountable early exit block in \p
+  /// UncountableExitingBlock by
+  ///  * updating the condition exiting the vector loop to include the early
   ///    exit conditions
   ///  * splitting the original middle block to branch to the early exit blocks
-  ///    if taken. Returns false if the transformation wasn't successful.
+  ///    if taken.
   static void handleUncountableEarlyExit(VPlan &Plan, ScalarEvolution &SE,
                                          Loop *OrigLoop,
                                          BasicBlock *UncountableExitingBlock,
diff --git a/llvm/test/Transforms/LoopVectorize/uncountable-early-exit-vplan.ll b/llvm/test/Transforms/LoopVectorize/uncountable-early-exit-vplan.ll
index c0f684dc96a747..c45634913ce0b2 100644
--- a/llvm/test/Transforms/LoopVectorize/uncountable-early-exit-vplan.ll
+++ b/llvm/test/Transforms/LoopVectorize/uncountable-early-exit-vplan.ll
@@ -87,35 +87,6 @@ e2:
   ret i64 %p2
 }
 
-define i64 @multi_exiting_to_different_exits_load_exit_value() {
-; CHECK: multi_exiting_to_different_exits_load_exit_value
-; CHECK-NOT: VPlan 'Final VPlan for VF={4},UF={1}' {
-entry:
-  %src = alloca [128 x i64]
-  call void @init(ptr %src)
-  br label %loop.header
-
-loop.header:
-  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
-  %gep.src = getelementptr inbounds i64, ptr %src, i64 %iv
-  %l = load i64, ptr %gep.src
-  %c.1 = icmp eq i64 %l, 10
-  br i1 %c.1, label %e1, label %loop.latch
-
-loop.latch:
-  %inc = add nuw i64 %iv, 1
-  %c.2 = icmp eq i64 %inc, 128
-  br i1 %c.2, label %e2, label %loop.header
-
-e1:
-  %p1 = phi i64 [ %l, %loop.header ]
-  ret i64 %p1
-
-e2:
-  %p2 = phi i64 [ 1, %loop.latch ]
-  ret i64 %p2
-}
-
 define i64 @multi_exiting_to_same_exit_live_in_exit_values() {
 ; CHECK: multi_exiting_to_same_exit_live_in_exit_values
 ; CHECK-LABEL: VPlan 'Initial VPlan for VF={4},UF>=1' {
@@ -272,62 +243,3 @@ exit:
 ; uselistorder directives
   uselistorder label %exit, { 1, 0 }
 }
-
-
-define i64 @multi_exiting_to_same_exit_load_exit_value() {
-; CHECK: multi_exiting_to_same_exit_load_exit_value
-; CHECK-NOT: VPlan 'Final VPlan for VF={4},UF={1}' {
-
-entry:
-  %src = alloca [128 x i64]
-  call void @init(ptr %src)
-  br label %loop.header
-
-loop.header:
-  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
-  %gep.src = getelementptr inbounds i64, ptr %src, i64 %iv
-  %l = load i64, ptr %gep.src
-  %l.2 = load i64, ptr %gep.src
-  %c.1 = icmp eq i64 %l, 10
-  br i1 %c.1, label %e1, label %loop.latch
-
-loop.latch:
-  %inc = add nuw i64 %iv, 1
-  %c.2 = icmp eq i64 %inc, 128
-  br i1 %c.2, label %e1, label %loop.header
-
-e1:
-  %p1 = phi i64 [ %l, %loop.header ], [ %l.2, %loop.latch ]
-  ret i64 %p1
-}
-
-define i64 @multi_exiting_to_different_exits_induction_exit_value() {
-; CHECK: multi_exiting_to_different_exits_induction_exit_value
-; CHECK-NOT: VPlan 'Final VPlan for VF={4},UF={1}' {
-entry:
-  %src = alloca [128 x i64]
-  call void @init(ptr %src)
-  br label %loop.header
-
-loop.header:
-  %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ]
-  %gep.src = getelementptr inbounds i64, ptr %src, i64 %iv
-  %l = load i64, ptr %gep.src
-  %c.1 = icmp eq i64 %l, 10
-  br i1 %c.1, label %e1, label %loop.latch
-
-loop.latch:
-  %inc = add nuw i64 %iv, 1
-  %c.2 = icmp eq i64 %inc, 128
-  br i1 %c.2, label %e2, label %loop.header
-
-e1:
-  %p1 = phi i64 [ %iv, %loop.header ]
-  ret i64 %p1
-
-e2:
-  %p2 = phi i64 [ 1, %loop.latch ]
-  ret i64 %p2
-}
-
-

>From a875249d84db6e192633e7e9c62b46df0a171624 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 10 Dec 2024 14:05:43 +0000
Subject: [PATCH 18/18] !fixup update doc

---
 llvm/docs/Vectorizers.rst      |  13 +++++++++++
 llvm/docs/vplan-early-exit.dot |  41 +++++++++++++++++++++++++++++++++
 llvm/docs/vplan-early-exit.png | Bin 0 -> 131943 bytes
 3 files changed, 54 insertions(+)
 create mode 100644 llvm/docs/vplan-early-exit.dot
 create mode 100644 llvm/docs/vplan-early-exit.png

diff --git a/llvm/docs/Vectorizers.rst b/llvm/docs/Vectorizers.rst
index a4462e53edda09..f134a6df94a69a 100644
--- a/llvm/docs/Vectorizers.rst
+++ b/llvm/docs/Vectorizers.rst
@@ -399,6 +399,19 @@ small trip counts.
 
 .. image:: epilogue-vectorization-cfg.png
 
+Early Exit Vectorization
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+When vectorizing a loop with a single early exit, the loop blocks following the
+early exit are predicated and the vector loop will always exit via the latch.
+If the early exit has been taken, the vector loop's successor block
+(``middle.split`` below) branches to the early exit block. Otherwise
+``middle.block`` selects between the exit block from the latch or the scalar
+remainder loop.
+
+.. image:: vplan-early-exit.png
+
+
 Performance
 -----------
 
diff --git a/llvm/docs/vplan-early-exit.dot b/llvm/docs/vplan-early-exit.dot
new file mode 100644
index 00000000000000..63490b0cdb2e43
--- /dev/null
+++ b/llvm/docs/vplan-early-exit.dot
@@ -0,0 +1,41 @@
+digraph VPlan {
+graph [labelloc=t, fontsize=30; label=""]
+node [shape=rect, fontname=Courier, fontsize=30]
+edge [fontname=Courier, fontsize=30]
+compound=true
+  N1 [label =
+    "vector.ph"
+  ]
+  N1 -> N2 [ label="" lhead=cluster_N3]
+  subgraph cluster_N3 {
+    fontname=Courier
+    label="\<x1\> vector loop"
+    N2 [label =
+      "vector.body"
+    ]
+  }
+  N2 -> N4 [ label="" ltail=cluster_N3]
+  N4 [label =
+    "middle.split"
+  ]
+  N4 -> N5 [ label=""]
+  N4 -> N6 [ label=""]
+  N5 [label =
+    "early.exit"
+  ]
+  N6 [label =
+    "middle.block"
+  ]
+  N6 -> N9 [ label=""]
+  N6 -> N7 [ label=""]
+  N7 [label =
+    "scalar.ph"
+  ]
+  N7 -> N8 [ label=""]
+  N8 [label =
+    "loop.header"
+  ]
+  N9 [label =
+    "latch.exit"
+  ]
+}
diff --git a/llvm/docs/vplan-early-exit.png b/llvm/docs/vplan-early-exit.png
new file mode 100644
index 0000000000000000000000000000000000000000..3cd293bcdbcc822e6f7e7a6d36582fbea2cc4744
GIT binary patch
literal 131943
zcmeFZWmuG9*EI|yD4?hah%|}<f`oL3N=m2F-61V8;D|~|DUGyrcb7poL#NWM)BwZ4
zdya|E_uRj}U+;U|KU5s%sx$Upd#$xEe?@sod^|Ed3=9l>X{iUw7#P^a7#LVPIA_5p
z)o*vCz(1Id%98gm^1CUP!G9i at Jd!q*lfz&HKjUCv`dVOMp}zwDkbyrK7-y0&G0uR0
zG0~qTL4N-hyEy60 at 1L=D&|e&K(`>`Q5XF#wAg1~hb8Qm0mU#Q5<+~l;?J({)4E{Gn
z9^&-L-(!pr^3N4P)^|h-Sp~d-wq3oUHEP1-VSN5&W^R~F=Ls at l`b2wi%5<Ug9miq<
z$6{@LNQ>Kqhgto0{HCB;cNM~GK_Jl%zs0`!n$fE<5^PMY%c2<n+g~t4!fQ46igx{u
zX`W#~aQ at f7LRmy<1ay2h3I6v}U}6QxKNEH7i@(DE;{W<nB&ql9`dz#Z#sZfln%gF}
zYN!7pp%;-8^^d`WeI;3%s;lAKYNZWqNZq;oXGCetFd?ISg#GB}SA49$F;TUU>`Rqh
z8=ClQ+-Y23hr6pSQ*`(@{){tG1_o^Ht03zR9wwH|1O1o8>TFz=aE7qdFKj=LVz>xv
zI61E2<-f=JclxsBz+jgtmC#~cW{`x9+tzelAmhxWxD;<B at neQ*SRv<0SU7X?$~ASz
z(v|*9JnSp6esRlJA)cKJe{TDKEQv<E%dHFS|7n&lGgyL$6o<MmQT&I6@(crJo&TRs
zjsZ)#N)xIB&+zR=5AXlF)WGG*{(JeqbA9Tk{|^5D(@PKj{GYw}hPKeW at 5c68Nl&cw
zTe=wR^H-m`cn+#*a0z+raU$0%5*OXC{tYBFp`2i6N(&h6ko?(wNx9h7uA8>H-l*Nz
zXI&@keJ%Rm`!DyUN;X%kp4wtbBiK^R%4=qR$EP;sw-X4p_mO=jjSJpd7tgdTv_s=h
z7{SE4!VJ<uUq(nb?VoKN{<aaGrP8tdgirm{7a6f|j5QR$;s4s}s>F|KpBA~zz|P4w
zc%fvGd+S|EVm_U(Njb9BXU(uKXVSsc^EA~45=MR>fzC#sZ;1x4edVX#Is4<$U at 2Fw
z2|g{XIypu%9q#On+r?!hdX06)3k<_^AD0;NP18IR-NkWQ8|mwE6LQ;{TN%CXA at +A@
zlcc~sk+k_Ik^hW8L~)JN-X}J6veAXw6$?FycDm4AwSg>^jQOD=aMTu4;nx7BShEDT
zW(LG=sl`BNkI0F&7iw3-aXvz0!L_9{_-`Z=g<*qp?_(8u{2YS-HT|htw}pa+<E^zR
zaC11u9_ at vfVMpiTnMxm>mU^3 at 7IxLk4`>8VHr6oz&RZd5u9YQM#6$AOT_>4i6H#n4
zkzvZ5dWxUFsYVZP6esfMFOpthU1iaJbWieQ^8ZNUL^UAI7>eBAx%6`cZxG>-<>|bb
zOndl0VlXZVO=$c#LMg<5Nc1pe at CBU}v*_9Te at FD6pRS;h!Wa6`jlWCd-<wHeQOto~
z3jKKk1|gVu;MJI6U5_r$gZU`arsvqitjv1Q-9foji6Gh8=Af=vt9*;{X)lj~Vv~-P
zd;7=8%`Sn>TBC)oI5RL?n_j5d5E0pdbh)m>)dD-sGRt|d!MloINgkD3$Hd$<dbOIr
zy4XVP?W70tDjPmIw^IQ%RL3f>th1Ti&RYG^^#cSdV&EvwuKq5#Y6P<1LvmQp=PbVL
z_Ci+||7xz0%ZR}_1d6bMm-%W=W1{!5g|63u$@cEBUd^ztaLCF~p4Rt+(IO+slBTod
zL{^Apl0RupGzRx_D at zGs_m>;bL at jX83sg3iv#l1u3Df2NwB$>cWrOODK53IRt~>%8
zl}0lzmI#0t*zM|eBgq+#R|^^-s~S3wOHAbk(jJnOEGBqVHx*~ErXC;lNm9q0qk7sX
zh?sC(0Jjq2G=XRAx;oT#;Tl`xT5$)9k}KsyXnYQM?g_!|PL2f>Vwxv-*4Vm2x6VD?
zd37jVqd?bmrV(aZ(#4%q+BIsHXtPnXDV*9^xw5x0Ij-%oUS=Ahrk<r5LjBrpvksx{
zp(9dIyA^N%PISKrUZ6Mav;uE)S|1y%a~UhOAhfJuh={!N*ihH=yEsA!_3 at I3@q|-a
zggU#xdg)ufnP+F%hty^c7vk)=!HjamjHzR6H=en~NuTi4u<ab{F6rUiTZQVx<Shi_
z)`(R>U1ztz=33d9PWjXCh8!mCM5#UWb(aS7ZC@`5Ws+OS#d6x)`7P0j4I&EcQU?p~
zwRp8qx>hDi$4s5Cu8OQ?+2Ol?YNsUWL-web at 9v5J_{>jwrl^HV<wZYqR8&kh?|8h^
zED^deLXbj?lv-z6(I8huRVamQvQ*AIe}_mG9t}$fro>+<@_iDRE*H13vpU>UlxkwM
z+!Lu~yF7wXw+({9i&fF!vboyz^6}<=1U}D1Z`DGq)w`GHN%*-h&yOyEPeP4CP9{CO
z-|;0Nd)+9xtw$P&1NUpdg@=m7%%^Al4(msuh{<>mbDG^haWllLomh)bRZw$Ru8fe=
zJcg?07B!P~?<@~M$K?+LVmQoRxfJo7yqoqy=Jj7+-ChGz=W at 8Wz6#<m{Z5tDP;Lx|
z(~@G#6g(TQOCd6nalsR5|NS$G#@dIe2aan&veVUKo9B at 4106vY(I{1GwR4hJh6>Gv
z-p3my-V6E@%@m;!qibO{CwS at T4J>`75GG^fQ^@D)_VtthMy7njD~S-Q^$Ny*hcu2}
zhPh1I<cPh-vkVgiK4C7=$y?)g4K{~}O}p|jOC}Dlqo+JCC11%EYoeAj63NI*9jM29
zvN1z~;0xbdsO`XX3vPq;?ha?m-}OF0>h(CQkyyg(@Y~7A3%R-3jKimHqQ<tyeaHID
zQ4t!tRhDm)y at nXnf*`0K?_(o=*A46Ne%g&Ku)tzdLxjhmDKy>XT-my;LN;s;b5cCJ
zQY`DM at 8lB%`Euyi<fu~NmzKpBcS;B3Ird&j9)6XYJ~`U%NtX<vYM$bBRLOfV#)}yt
z`TCmDGXJHO;wcia>#If$1DPi*6+}>_eDmQdo#&`MFPFwFR@*h8hF((&3_;hcSMyEx
zzkM0xmeJa at 5^Ays(TqGTrY)TTzh|b&Cn$gPJZmi*>*l!i;b-o at L3f^3l%~eBn at chP
z19Iy|k}9S>k<c-fDp9Fl4nyX(TcLUIOCFnb6$fC7zpi|6SZBa7mo$shva1^$A(-yS
z>oI}ZUIEy at m1pGL!|^e0hQ?fq3WI>x#Ihx+H6K;=@`E96X7B8q9Xe836fauteh!8N
zS7+IwR`YAR at wp|WYi7rzdjd#wpEg;8NMH)G(ni%@R;2xRkgM*2yB`V7`_ at LE7!6kE
za90CWx|bp)c1Z;L{VXn-yv_t6fvxMPtq#@=w;{RLyaCGhZ`b+S^6P-$ovxmDgp$s$
zAE(EiKz;6W75Fe-=kMIjxA>`#!sb*uxU5NYP(t!jSd|ftWYVrD`D4s7Fl(0LSU0B^
z;b>Evn509~Dx6Wf!!-wf+oYf5*A*}g=D*c1r35MmIviW76h{j~53$b1IZjE7p25?6
zc^gl{g#6RR0k0AMc4q4V;um>Tj}%gCBhH~JXM+R7?+X?7J&Pb~%AaWRrE)hPLI$p)
za*w{Rk5`1;@{8v;4jN+pd}X&pj)$Dn!dhEwEj$Yf8Cb%NOAzviP4qgvUB<gtprLIq
zZY{Q^y4Wppa`Y&XTe|EYX!IOwi|2^eydd{Sf^5~Ci8czpi<t5#5XgE|9%K$_Qc)1%
zdg3UwmydfEMR)J~1g}jRUBra<32Gp6-#e$TuZ7AZ*ZXBDmyBf5l>2Jc+y3RJ+#~vD
zT$QDR9-ZvZhD=6L!7dGW2i++>(CZ?QqzEhbU7B98_eeuA7~=}u&gj2I^iU~@Z8&9C
z{jydT^@qsjAaZiK4;6c3RyB)yF!3OB4LrXnJ+D!7Rfp&lCxXDM%<Qg{&Kh%0=c`>1
zqh{2u{oQQHt!$(1tvJ-)c+ZGnn{G~t?$t$xgIs|yU;K!K#in!A7f_#k^K(3}%88C8
z-#^Fm`L*!C8^!R1xo;mY at o<=S`gwNIf7xH6{hJK!L1D?#y?w6$UC`)Z2H75il`|<i
zK2ha3d6Y+nO`*!^-YqY)aMqm*qS{mw%Vl-e#?T$Hv3}Ma09fbLnL>%g^yeSMLc*z?
z;Yzks%V+V)Di3^!lW<km-h0~W-;~u6Xp8N;3-DArY>?}#<}PQufXXwCkbNfC5(#rN
z6(`3p6OKLjb<1>d)`r#2s|yQ$wg8-ovlz}3MO91?UmIkY^(30dVU5&xp=c5a3b;u4
zDPO0i+~eat9u3atqpTto5N8>G$8npAs%0~F9TAXxL;Bp%>6|t(A6~Zo#h1Do=7jxu
zS64+}N1R8p-!Up<bLL<%(RJXPF`i+C)o^#0bpERRCdzdhIxHK_mi$#Hek#2_Do_G1
z%Ftr8I1NdfO|a;`HS0_5#nv8QfY8cM0}0!fP$|)+*F#Ccq4sbkC*5|ky2^zXzSpi$
z0A<vu6MncGlefcJeKA5^g2!BWI7!2&+F&29qChH;l{st~c?#2CZg_?|<NO+`^rNOU
zyi%A-OAK|;1C at cKY~EQOqcc~Ck+SOos2u1`;Yt{e)%udyG}NZFPa+t<QrvvqTdm>v
z(8>&emTemz=R4em3nMdzb9-jp at 0LeAdr8MNsMoq+t?Lcno5_RY_t}h)+`LO8o)g_5
zS`k}Pb6?&>!-{SI=VFT1!^0?JsIqP1S_GWpvdXu=51#Fz5J=X|6h^8QH_a-x7!Ew+
z-IIXnanyG-?0-GqGBtx!7IN3<>q&{_XJU<=i3<E?0q!R&RV>c=PLtztHxgR*05lQU
zOAl88g~j|BFKTB%sN(kE%h6iu9j_s?H(hNTBT4y2cEYOP?&#Kz6j?Y at 2rQ?U49E*G
zFUIkUs5OlBO+SXd8Y3r7Mi|(Q at VQR8nThM6>Wkj)@XN(<<693eOzn*e7If^!gcX;(
zg)BPjasCDVikuK5%aQ!oMcz0U%UJQyt6ua1BzDOzL}>4cRxxbt9o_Tu<MBICcbn9{
zK^c+Dl1f@$Rfb@#(m9S8_=-;jNwio#uu|;Hgd2Q(g{{_BDQ{y;Rww-Qo4zZNZFBQ+
z!*i67W%-o56$kWir%^7v-tcJu`-b^`V*nKsmy8ynvgPx3S at GNI!pOA}*};ijvasxl
zcCQ0BF1!-}DYvYxKzQeHH_@`5nKn1hb&%z;8oD!X+WC&pQ8td-W&%#-6=Z%xNDjko
zE==-J4Y%wFfJhEd^Q3PsnR6NXeAtjeyuv4cWyv86P at U%OSwd{J at jfoM*&rUWpxPeQ
zow?@{30D1bLRHBbS2&d`-USE`?2KM5H!rR3XSMh+!X~~sS<=nlF*5U{c_sEpX;~qK
zNJ#9m=?5vf6an`ga|A#BKs_C5(9cE)HLJ!6(Q!M_c$Dm(G1=$m>M`55{s!N;CbgyR
zu!a3kZ3%mG<q0+EYwsn+KCG2x95CdHD9FoeVR=fuWcW7T;%@cUjF>HFj~tqNTTO%R
z?Tm#;9H78v3_~RMb$Z#P?- at B3N!Siso#7jeyO4lVSbqprO8js&$XeEB6;Wo?5*#e2
zcez};$GvzGAX4 at XrZqq7o_N*AnO4o4(Q9%q8OzRZ8_^N!AQc3^Kd_Fk*{nyh>lU~a
zw~g#&ygHIFM#htSaJ2RL>B~HY719>lG!FF<VvJt3$>Bcgj*ncujV%;JkoJN!%*M`A
zm5ht39O`lZW?{o-?Y8_#x?xU>-`WU+1<vo1Q0h%%^a`c0!3lrHkL>x0Ro|yz;S-_4
zj?JUgUE8YptJAv%8s_hlP|S;ub@<XFym>AA7{nX62O}kJgi!FYTb3m3&KsZUX+Db*
z8n#M4WCtYU^zJfKc*`SNCm)&da+^tlwf2VihhcdV`*ua2uU2uYD36a}#G<S0Ga<|E
zOa+|WbrSmV3`|@pTmvr>$Z&Q1j%LZ`^J|;k+3!uOd?oH(^xcX{bQ!aF%#&-gOZ1=@
z$5iP0UBgd)xri at i$q7Wg9^$FU)X3!fzGPi_GaADCGiMsq?))rqe^ih(>VUy0a_GN?
zo=aZLG;{Nb$|AdSL^H~w0^=!?oy1bRj5)c*0ev?^lsanNwqJKut=GgT%QMVNrTgE8
zl7D-Y+|tL9c2|ikQugg))^gih`kE|eL6=z;O#n%{-b=r|C(^t*EN at x${4JhD8eRB9
zX4c_?nC{emqX%+*mz$N}y1Q&nO;%*nz1s08*tZRz#nTyPt^M{~DHdDC3oCrARTwkW
zaaLy1q3u=_R(YzZ3mli$hphI?EAk0dVKL{Up;3Cs>*u3hpIN!W^q`Ta3gFN at P=8y`
zk6Z*3%D|2pG%}cJ-jE{LftPKn6|OOuUh!?>D9Ps{dk`7dmNrT0H&Ec=ck<*WX>+I6
z`s`&nw_A~Oeo%ywVq<eeNK(1oEDVTe>nR2FP at z0Lq8&!bX((v^-V6>Uc7z7KyF?bm
z>?_;!!8$~N*3l-wudxfY)q2i0e7+rIy;%B0&wlHg_43E%jixbJ{7y^yYoDTHvR~?Y
zuViJMow}fO841ck{7GF!ah(FCEpLyqv>wWado<$;ujc>aR{QgpTZ6U2_dq6rLGa8~
zOC=<c#Ay_*=?pJlN$j{0V_#6<{eo4XMj9m-&DK;AEMagi2(mNDHWvVY at y=_|Cc(Nv
zZNnkXPT&co3lvslaZG%LLDm|U4zdkSq&hV&UFD+>Y%<!mO?wj7#}}b{qb&@159<Ty
zlrG?1WL)>RrJAo<LggnN0QM(wQzyb1NuuKvrX<SS{bpIB10XEojt%aKCm#d+2}*1f
z2}=$m0L3$DN8E9W*6>pUBzo>U&R3w|AyOC35)U{0RA3G_Rs7atCy at 4}@GY@>zWU)S
zP~dyyca%Ok+*z(ybKhAq7}B(2PUXZuc)GhbI^a63dDnGgqH)*d>%&wygO^F;GfWr{
z at lpBt8qbMJ`;H*S0=1k-QciQl5xOfntSY*?2a7cqD0tbPkf@}~;%X<Z%B02ibtSRr
zRL_kOji1A at 2Jl59QPMstuVQM<X=7rvVzd%6I;N0+iy at SfvqdZ)Y4VF(`jN!@0pFBi
z^-T!9WgrkT%5@$G#Z<otCIL&_*r#jn-^vG!z0=aOka-SiLf0+=cVp=2J6f!wbX;)P
zT+>Be(#auSwCQJD$qeSvJd5zrxBEPyS%STI)~lxXTY at QROW#an>v?{EX}3t+d#T-E
zy~f}ZaW&~zgszIp0aaL at zXZo*sQ*(bRmA0`!JMd;{-;+#9c){V-xb5rVs86f`(f`~
zxxu(?ZxT!?-}*;l{8eARBmzW|6!b^EIVUD67MK)%u42OB;d^Q7M7IS}9{rU;wfVU&
z?kBOgFRzs~tY~w4A0IVNn&2s$u3o7eU}TCAskNJ~Us%a0;J*Lr!d*P>h=;g%#&)&e
zoB1-7ab`!res9FxIZ80Z8E}c_kChF7;|&AYY2JoDM#BBv<l6c1tjev0bCadG<0LDm
zP*P|h*sIz*BUjOTRT=hHL3p&nY#NG)kKwgX**wf<dM;sfZau?NK+T(FPqf^@>0CsT
zX!+LF;T#QCbH|~1hHvW?(}(3rec%C}??r5ix;RrBRc)HZI}f#yive2c%y=+uC}rgt
z_0#Mv4TycX{EwZ8!BugX3TJ}_Vv}k!d8R!bGt<MX at 7)%zmB~@hL$ju}>Mu3-0JHNV
zTO(5@&bnB7CZB{wd#R at WorDDP#+=*d{<McsL}4?T)qZ}Uhj?$5dH|u!7B(5Tb##SK
zE1Vm)R@*nghK49VW<nGKmJt27_kAWHwbHy6?KQW+&S(HY^K}=4$xA&YmJMyH$E*vU
zIqhvifK_O??;16nr#0+~N)ZqA94@*+1*19n97xhq^7e8b)_Nd~F-{|vDsHvK8!H4y
zS-b at _A8B@a!M?fKsF-{+p7{_Iyf_aoFHJWzSoEd5G;8GNTAmdr(U}`h>Ax`n>dk~z
zE<8297{}WnCgM%h0t`kMEZq)q-8x~4z%vFQl%t(57rM7R&|<uzrzqpE=XLP;j#ham
z+YO%AUM|khk8(JkQIr+{#m&t1iM5(4q&=!(qk45AO(DkNyBS$ge3X12!=F*WfQU1K
zN?c0e!sI=Wj2ws+gBJm>I0bbp<FcLL<**)Mo7P_q;+ZlBG}qU%EWVY at RM~ibXTjl@
zIwO_#vyIsq?;Ha7_Gf&~tP(kxDAEktQ*byg$PR!C;-1Uh0;GCUedw)L at 1fks5{op`
zZwK0FmfFsyO();f({FxFnhr(ox$#{tqf~vKzn!%H$oJPKLF35Vc%ho_iFz1Y(8}sj
zL*sQ{3d19bm)(F)6x<szN>KMcKFCm_8PCbB-D+Q0N)6f5B(`|`mQD_`+5l=k*y{N@
zhrF^OytNM{J;LOb!pls~K}5w^IwEAZP=HogsPj<CkmnMs>L1qgM%5x<lyiEGb_oD}
zzss_LjM_5{oc%LOqFFegh>PH8vqvu;Do9R#bvED8w~s<YM|OR3Jd<-(8-U8;Jb(4h
zH*MEO%yZGa&zV-VdNbDyFB#j_A1p{zm7?0gzC2RDW$LDA8Gi3vG1&4QqAegPu|I)Q
zFmc4s;&YGC1W$$=lgrpS0a`Em<3)i^a|camI;YJT932pK(w(zaE{HcRc+S<GAU7Mj
z0OPab;kUao$Pr^3ePG*(_Xi^aO;r&DdE5lmi at 0E4Ns;g_L>s-H{uDsQbu=HPm#*Qe
z!oDxJm8ptPAMd1`c35>(xZN#)v^@r-R2-n!x?G{j8Vr}G0sT5{E1MuVDw`-g=?cA~
zj)lGA<8WW2rN|jjpjdMIyl6ND=e6Ha7+x4DGJ?h_Uv>cG8bU{}n`!FlEIvTr<Izn%
z=i=@fHAidcx_w at 9KSUGR4_WKxSO%)|%E#JuG|Y2=;?nmTptU{QrB})QGy4%#Lhjen
z{8COaCeIpA0O#*`3;oe8mfqaQ93=pGx>KcX;Y at pOcSQ_Y+|1b$@QBcHog6H+86UDz
zQ}1x!TU)M)moU<G?Bc3l4K(-+rk!de$gxL==Ls~QsR6a8<v8@%j5J7o%C=^`bEz-2
z3*1SVRSEI<Iqc$`DU7U<%-DLR0CMcZqjnIIjEFkBHL6y!b6!K<d8N5-PNlo7k9p;E
zxKu#~DFs|EIKN$tcb&4gyIKdr2sWY`Fw(E-8iR6<07Jh)fi1QU=8DOjYxPG4`}r4x
z0EmAkuI+sKKO}8J1;IW<At1ulx527Z%hh<+UGUCxtIaE?ShF6~Y}oRxu1(k^(JL1W
znRRP<`|Wqu$A?`@Ysi#WaIvGdl{V^;wk6Byaj{=M`jTTGp$P;>P}#&1&`NwNuTfKf
z{5iMqIU*4ca5`B^mM`u_dZ7-nH;w at d$g^TLF%JSbH=5?rF98*+#>}CEc9xSkm`}a;
zs}jS}{iL_QX|<-rT}2 at gJP)H-x~j<e)6o#c6Yx~^Hp{nTCtb$7T!olUKc6J#=81fV
z((@k*z04zhbUlVg=0P09E<0~Ah~?HJgm|aHHBb*lHmZ^(kefWpJSq^w6v6f++CKzU
z3rA@<$`bn)C?_A4fG9?WZCf#7cz!lYpms$!mdDOEnD?t+b|4cfw;aU5d6^D}12N3H
zI>gjC{)SuCQu70CaSQyTtz at e=_py6s8OX$s0Z&t7VHIADmIf{ju7Sm92LRLk>FS1~
zt-w*E5FtbS=Zq-vL}93`V(_;h?y=UTWo#J}%({XdA~E>ZpoZSOvlDdWcqu(LzbeTw
zF^d`d0~hWl8hSlaa~{(5Sa0OdeehQqN}2%6Hfo%7 at hO35k~Q{o2dxZ9g;!P4%c}_U
zHMoCo=4z5)VToCf%Ndd7)Mk}&Q>0qcO*y)X-65?SOt5YmraA$lu#s=_#Lf at _VOFt=
z3EFCzleeIyftoUj(&_ZMB)p_WzlJx at IV|T7!osvGAvRtFJ6(P;V9^e^ox$`W^Us%j
z1%t^0^c at GEd9wBFzB%{hYtHiQ#Bvf@;g`hbL9)Nw{`q*)bsAgkeAxzI_j%CjjEvS5
z)$l7VtgO&pm$dqg&m?-ChnJl{W?c)IY5_?Ak3w#JSV4zJr`qXm%oI;`vI}53_qjeg
zoC-wk>L3t}Cb(auz{F~o6Fta`2>6gA8^iuN-gvzpxv{NjL)1yZrvGfQTARf3!MfNv
zN}`d at 7r2B!WGX86rQ}BU7<EQO1>^xgl^h+9%^2sj9N4Vf)6UCGWL%cU-JtT{5$}LD
zfTF;4uFCeTdH56f7N`&_`3i|c at ns~FT)@uVZggT+LQsZJ=>u?Tdl=4O!&p)Nyoao8
zB2SCQaahOIZDF?_)HC<Ea&}no?wpMP#|*^tvPFe`=RX&l^bLesys-$SDW}QGq&uvk
z9XMW-`izk&Jwe<yW6>aA3d8Z=R5>n^rMdQ-q08pT?`-mX^F$IxW~wQWziEUI56;-)
zvk(o?I1Hp(Hj~!S>m8K!65m`lCfus#v#{|-%y+En+tZ?SSJF9gV?`BH4TxojAK16g
zPJ;STak3A`1bb<-YLSZ2L^VUt*1RB|Q4}?#W%olBvns2RZC*hzS4<engCYd+i0B=H
zN#-EM|2s?7+!da4<$8759X&u7%MNrnd~6|mB;m`r8wi>7rF4n*utw*!#d;#os33_q
z9k*qbY*#^$XyY{Rr7?1j*OGIIAyeBdgFW}hd&)HE=U~P(L!HhL|3YFCnKmJ9cb`Wp
zTRtJSernT0=z0=Grx)!qDnUXqHYSs{%UOp>M;3sYqw2R6^Si6VJTlU6<@_B}K3nhU
zIg`&1pp$i%^RUihI&J at _RA#MmC;I*HB3s?ASgsCq?qR^$bhXVX&p`~hEyim&7j5=f
zA}Xf69QC{+N_B@%01mcYfoIKXbU7XXrE~%=Uwsy}<-^1kntvY^{KzPX>nT~2%A1$J
zaUTZ69tU3NjS*6Wj~|qJckG8DfXx(WJGO<gS7r2);kcibiTum~I3tJSjMHN$hEJse
zHqwBnEjvM?n(<mz(!=QfY&9md at TuxPn6ERAZ^}rMUt5j$it))IS{Jh at P6>YQiKm|}
zVi35s0CL120O#ZeJa^lR@^<KejCU7Ek<KdWo_nKa5 at N{0i^~E7K><l^`~#~J2VTIv
z#6FOraB1SfUY=Hki{5H(NpRmMFTA;BZDYb0)_ at y`;jz=55gyR++W+Ef3T6){{*o50
zCD#Wizzv)LFy>X(6H^RzT}o?ux)5VFVI(yjGL68iT#Z$#G3WrEgNY0RV{-0Z((?5r
z_rnXkv#&WO$S;fSe$_=Jo*dCTwI^gFhs;gW{M$6#j=s0ZZBEr~4|-<0I2%2rE%#9-
zP9y8@;+vf7ccz}-ma|!<OG at CyZEwn(HX<XX8q^l^Oq;ISYG(@ScC8Pv^?Uy=T)}f~
zr08Ibc>OQ#CkknNgqr1Su4ni$Eq8Izh)zavt=^hOAYFad3auy+qaN;ZEUji`B#=#a
zbCep>i#l4{evv|*U-95xwZ1%Fb+pyNu><!g!yn;Cmjhyl-d|plxVtjGN&~<yZ*QC3
zVXn0mkf9C~9`}>RP&T4nZos*412HU*^LQO9S4Y3Lq}>wC7(B74&0WZ|TP&<Aup$zr
zV>U5#))tC1J=5&gkiTYJ9o&^1UzC`wZ`aSqR8U)N=dH5HyOblBH&?^zq0(K%<LY2J
zonEwMBN9x!C!r^P0v;il&f*NfT|d1hN&DE%p|s=25ejG_wq073kkoR=E;<EwHCSkG
zgiXyTD^+kR7K6?Fz5X46EsF=VH at K2hByO0ha29L2J==~@n8;Be)3LI{Fzy^!FS8jj
zA&bf1VI5Qock~3h)k0=!a6qlV{KOE>QBpW_7<pGAOgY^AL7DQ at gWF_HBEb5>5cf$_
zgSIDPFNHsFYI-#C-U6jYgGrhd2eruw3c<4{;b#HhdFBEa!TOt95AO}`=DZJ^@Df*;
zVIY=f5npFQ;hpkO!gxX1)RHBwg@))5tniOJGd`Ct4i13Ig~#d1EmfcEjJIhrwTD1X
zz*Q1RU>q9;3CeuR`vi(8+Sk at pOE91JQJ<+W?TW49B(7YSVahX>=U=|bQzpuS`JplX
zeV*#rl}UK3hONnDZST!c8S#`j=F!M<n{hI^jYpKXp%;aA6nThWC{H|K=J&4tuGIQ9
z%0oa8s at zzvkSH7$w+ZU1<>3Oox%ICT`arR8Rv})7COMKwJ_b at x5S{Gciwv1A!g2;;
z`TSc;P>PoC%TJ&0g;|}9QvIDTLGXl8i*AdVAY*r8%L}Y?mb5eGU@@9=mQUaGhLJZH
zD!=Wsz?uVS$(AU(Q_^CjFgcF)QIk~=M5FLdcVo%x2!vKs4FjR1DZhG9`mk|WyGWj3
zse$CMnI%uByPRzX!D=j=EjT5q0n*(rp65?yLq<N!V_+PPYI|_79I?p1LDTTuu|3Ut
zAg_{8Kmu1Zo!TeA3}{lUP^B_2*3@{Hu`EqQR{ZTK`*4D7?)g^&VwPpDa3kMp+)Roc
z0AY*b#sxbcyr=4_+)PA62nOo<;kg>!@%OB6+a$<s!s{8f5Zu^rHo3`26WT at AwQhgJ
zo5U(xR$zx4a{b9x7?3^yT_m?txWPw?S0H$*4A;n1gM|;xU2l9&;y=*N5S at mdqgo2)
z9Wu8FitXlNOPT2bqN%m6`|>SU$cH%F>b4Q>d^dp$a*7#!k+E<EOeXB5lG|mLgX}`?
zJ8UZjR7mQ(h7Za@!WDM42&-<FHGw*F>Fhn{kF+v<FG8!!Ib+_@!BiU`V-E8Apt6q9
z)(g2Bb^rkoukNwXCUN2Ip}9j~(?}?C`$j8=6}zG^SWtZx2;j>G**Wj&=HXnb at jPP6
zEg3r$pjgN!zkCrdaz$bQ0R73nUG79z%k7l?>f^)JAHs6{>z$V*x=(tN^SPk)?+>&2
ztJ9rpt4YnalWR7$pjXXrXx5!`AU((>hX7^T^}S<e9Gk;B;C at H}!BCJkHBjxJ+0&dk
z><5{v_9ubYZw5bxovLQf!pOKo5ZAQK%wM_Z{&1_}+)l!nr1Dt%GNc}w&#z4JVofv6
z63C$yafWkK9-CY;caxIZ0jDw9(!`~_1IQ%~yriotO1cI?F9vZe=k-ybSnGO at eSV?<
z at 2usERERXlt*&~S<)fx?YPCe4ZW|XhI8KUYO3*M>^4m=ba(EwmBGT%;jt>?i4(mT(
z)w)&}o?6`tMK~fsN!SUBBD1vz&KuvCqTw2-+{U`#hqRR{1*%Cs1$CY*Q4J9PYOnAP
zZK#}%NOhz#Oc<Nm`NGNxpdsz5UDhpu7v^nGeuT+5+Ovy<e*l<u(lME!8?Tg!CU?dT
zV8!gNd2qk3l4Bn0idn%s!WXo{$u)=H2#d^mw$rX1cO*}JczK>lB51sgYBKD2{>cQz
z9}QJ;0b&%$bWdr)%;zJTHqTZO#k?9+JwUrbrj|*Nfw!_;bW*7-`3Wj0<C{Xz<bJD&
zp)#!vbC)q9CGM=pMwQu(i;~CdV`YwdEfkKjHx9Mi<5kIGY|2NQp%MM|rg66E;TL$X
z{tnmR0$bOCm5VyN)E~^>O)1e3M218tedhQNj_Q<u5FO2>o>7dNI2H4$o;v(g`6Ei>
z55X#a`*diD<J7+T3q`=jk^o=mSTc6ZJpJiUit5Mm5xs)uslMm-0h{2z7yq4KUZX3F
zzP1I$QzY-{Z^CW at 30nT^<J6x2bO};iIAf~O{OJ?00WyP)kY1h>)KzH*z`W84YJ}w+
z2Xyrb6tTnn;efF+t2j`oN25&wptQVI$ij5`4rtJ&?PygI at t-FLlp8?n9H7|qD0%Yb
zgJPXGs7>z;lJhydw-_tU0tTPpEMWV}w8{L(O#cPgG_Onr#Qwc|T#{?To==x(T;TWP
z1zhuE*iB^MU6~<&w;KlJIv5mR(UiZ;D{!I##^#cnP$=*K at D;2N at cy|k49Gm11k>&j
zZ298?3QrcTu$|m;hv#XQwOb)iX`atStI(4EFh`I5AEm>D;R*0|#-i2r`PS9p0y}_d
z3u;T{QvcpFPIwK*TcJoKapU*Dhu!RbFHM-ba|5te>}WO$_;D1vB^v;IiUS!k2J_6>
zXnyCFxd|%#f2fcxux6ro3~>KEfhg{I^9Os4urreyxYTsMXlno00ix2lfJS>SPk+wm
z?}z{V6rKQh-+qA%3W7fe{quVoMP+cghbvAFY`;(X at 9&?9E~5>9b&l->r|9HUOBgUV
zx4`)R|GkManH6*1Yrl5^ja(AoAQr%6N^4!|sQ|(ymzGVLnqW}h-#PzrpP~|A9g_NI
z{=Ok;V)OCxJW?Tdr`$=q!E9o&wMXI>|Mms6-VwD7>y&{1+C{JzcxdTjFJUpYYeYcW
z=bvE^^+!K^5n=n6UnAbw0GX_I<^XP<eOIvy)A-leXkMwCL;m0k5H<ke8~_HLK@%?i
z<9`^iPq?2*pH2ZHOAdI03C%=(PwylQ*n1#5$sdxwKlyd(%M6#zXau^;Ap%`8zX#;k
znPk9ZG1-4R^J_B0V?}*0Qp(o2tQ+#(0Wu?7KUy;WJr+1Lmmh=r+?bvF_oKeY{Y3C=
z%D|Vh6Actf?`Jfe{`NCbX*3h+KhP at ndwqpAf@SBU?yE^6$tDO7{&(x*&=kHC&6|%b
z{Q1z_FyMUr;E9-YEh>||k3$n$*9h!mRzU2EcRm9Y0uG?hJRTY^xemekL|bUw_U0*B
z3h|%kgFOHvEe~H#DFH`v!oJV8kk^6wA=DEF*e?1L8eYhsul^X~WXSug(o6oS<NrLt
z-?b}Rg~N8EM!TD{1qAv*x?bQSM7s<u$EgMGVZgpYBq^Q4(MtaZyKg64KnoHt0o0$w
zR4_i6z6J=e)OK!OG^hMCuSw=0<dAe_CDDSY&IrjVsIMM%=wN<0|AhA<mW+%(sP)6n
zjK<C>@nrt2dj8(lOG275sV{4zzmtS&33^azH<e)jNJroRQ3H?-NQM&Ye#H<`E<8}8
zHv$@vXNPKaD9;K+y at iw;|4eZx57+>1sc8nkhKE4{#sISjn#l*T_Ab>~D4O{Hn_Ajs
zz=C)jZ+j7~1EE(1(L2E9yD<1Mh;1t3E2H`3Q^|#f37q?JQPJ<%aZ^nn7$xu`Sd6>4
zhB<-Us-=ACt=FG`_v4ZOKf%BN>%;5PZd1cnHe~w6e{TJms1rDUU)RX*?Q?~tH$#DX
zAX6!|F%^e!?V|Owh`+=5<EJ99NP>gjy!v&QG|~_;*a|S$#{l7ge)-7~(?1tb>_^A8
z!yShwzfLnlf0?M2F3&HK?6hVI_?i#sh5uT><M)n*oOc4EInbg%l#qyt+4kT+^835A
z&_9K0poe`v&HneWn_?C`+ck}|F&(S0)9ai}xBKVLMMu$bq(-G1^Y_%sG%|(CX at -Sg
z)cZFWd?f%1qTu55gx_0`>pa?0Uurd+->+Nud_02j&+h;IjWQ5F@?9KUe&6Efn}xs%
zsqT~kvW#hJ5O?-|jNR#J1=AjIAFKoWcjw%HqgZTo_ra6T2?f<F*#VmeKYJ4XtcIkg
z=+)m-l|=vRsT46_0M3t~CHIX4X(r`ogpDl!KF4K9**$nN9z>kJ(0Y`88xWKvIt@#g
z(eoq9jt%mjvE^X432^qCn|8m8>GVk&{&8yYTfL<gDkXqoCs9jWy6|&4r9ppH{9K7f
zGc-}eyWRr$I!MnyS^Dw)gUd6n4~11N2*JHFD8TGzn`5rue-*yi<Ou(Ht8-${;5Xbv
z)1?1d*{3!IY#-}d7-ixuW at 0J*IGggjpb_Ox at 6;&sKP%~*2#mFU{{yhv2|f8e>{MV(
z7BM5}ay0b8FmRA)KM~vA2(SA$OR8ZdxUbxXjH=1*6Z{xXSS1z!JW)5-f1T#vWrYsi
zbK+obbRSs|{TcpKcZ>dvh6SuWd+GlFv77#$NmLhoYcC at t{+W`~r~7(^CY18OHvtCr
zza#N`b^UiF{*FW at vBv$<e=v30?Lwzz<?RpWS)<VnD4sxh3A<D*AJ3nzRbjh;rYb-y
zj$f at 1`Kf&^N)u-V&e?uXA9Mhjwuj%|SVfC)=q^^Yxg#Uqh3rHz>N9bp*bnk_?gpEF
zBL;{4*H7B9Y=F^<dTdiRD0^~@a<udf`n#3eRX}`jOK=S)gS{bnRBY^zCO$iX48B at F
z<+eyU%PXHYD-38~AnQV9L9AqAUOe|J`0Z=V0QJXJ((t6_CUO%XQaMn>Z5Q489qSZ_
zK*H=e+;RMd6CV8RIefF>#7lhU5Ksufr*dG{d<HEB;u`<fJw*A=dx92>j>!uwW|x9b
zfh9I at n)9>Wx&)#$XJO#T7Ru|~pj(2&ZOfR$ZmPC5?-+0kVHE~v(9!HxA!vx<nfxGx
zm at ooh(T02KsgdL1az>mS_vlTvmjyUCb(2gwBK<|qUi>{l;HU#|iMQSt`5;*B$}^x9
zjUCVs>|{!EXc`vp78~%GIs*PvV@;QDA4nY*9IhMMDkY{}0rQ?dqHnM at D{O5*bBPrd
zu!i2GJ`4S8*psRR*!@MKXmtpv1O*S5Qn89UcIO-?aESc>cGTJZ?x;hUjyo^`kPX4M
zgl8I1dF>l;00wItSjj6DL~lc*5~MQuPadp%%dh+z0I%@;1uuRC at v9(+{{ZZRwBH64
zL`dhe;I#EXNy$!#zq+iOE*qo#UMOcGkI!-88g?0HY#vZ4A~d!L0coKry8L>_$xkDO
z%jzo3n)O=bEp^eRHMF$~`jXF&+^)6{5c|{y*~;hshJ2VJgy}`L_$`nnqZ@&e(g`SC
zvudYhL*Sq>2donL06Oi0rt6qn4<m_k^<GYWXQ^3xQ*_=vw*lBV(%rTfNLQP6#4z&#
z(uxE6WzYIYGOJtzw3mHhXOFz at sw=fQ=)>D$N+KBbVu7E@`~5C}d7yRgYJEN}8v-x_
zy8}{`8LXKON7c6xEHm5uss*wEwD1DByjT)F&mzMLJX;0OS%wx5h&$TX<A8oSxfGG$
zQw}tj4V+fA^R`O~3D$E>h*-$AyD4LCXz6gf{~@cIphMoXVW8Y?oGsxZoj_}5kt{lz
z>nKBCfZm1BZREKLltm=}K!PM$keHR}=wm<11~*<3InvLs+2H2 at 7Kl_)YsDBrw_;M>
zC;EyJZ*(#+_CEO&PL@)}YUcsGkq+>)DS*X{0Y+XxqVPoC1r8Z>tCAzoOQV72JVXH&
znd$DJ1|qKqxHzN|fE#IjjuKz!XIuO4HI2vG=(qME at r?VkXH4G!B at +w!%_ii;?|SZk
zdo5;d123~0E*@6Fs4?qFFzsNjxD!iLE-!=FnB+)^1L9;XM>p?BIjF-{8$IayJD{88
zKHUua`x@;^Aaw90I0si{VgWIm3*CMf3+VS)a15W*)T;B)<Ce+%%!{wORdFbsdc{nE
z#U^{7Z;3pOrV^A#o#<x7vzMr>fz8z?Y2{}#$f<e(T&5lU#)Q#$hl`chusBB(x3o4v
zi;5`-mOO-XvTSGuBr|^yw23lE at q=nCg$zcKy=|f at P3Tw;EV=1`<xdVdMDJ#FWA6dF
z4ax;Haclz%gYQ&iz)wVXD!>9C(fLr?n(!W$7Ii1c!^k^#(P8t4K(%#K at -`FjLy!}x
zF$RFW!QY+^XAXVVpCAa{aj*c|t?mMHp-Nyh)z<LEZ3W?j_kC7qZ4PaCTApt3PV;B}
zSSl93Mf|ALJgjek3Qd$fF4PzM{IDY;q)sVS!dCZyYgl`rE at lYb!TI5b@#R+s=i)-s
z at UY17{ztUA2kId9c4h_lY+Vb(_w(lWzL0X5RvuS-c^!S1M5K{tRZC~AO6u*x{pkt@
zH#6Ro%yVkEXB5;QwnLZeQdjfEe9qb)(hFgi0mBemqFBFz)2m~8)R=<%3CBAs^*@!@
zD^YF|OvoV3w+_~ZXwV8>^Ol#9)gfHD#>Iwb@{=@uyfFxPlqM<_8-Q}|0w8wrtcv&H
zGCjII&6EO_hf7F2vocvzfefj6PU2;9d~~po;IVNR-6BT5ghQTbGmsuc%5Ln3)>%-o
zEHU$VUQ4?m#?;(?umQZ?soPi5f#bew4R|wbdpCeS&k0(|3Ll$9sC}^39CF?fj^ng=
z<F=d at bx-TO_0Rs$cKdvKy5|AiU+!NLG6rS_W*)^{f?cHmx;yLrX at PM!q?(GgJ0z*0
z##B#dFcB!g;}=Ns+hP~jIIo(Xy>Lz6Wz-}}yXMW{9=}G2$Z at 3`S_{n}{ool1&(Y{X
zX|Dn9Uf}yWD9F?;ra at 0)c@>B&uOYM9IX$Il2_K<&EA0gJ4N&o*HEfy$&1_5N&65oN
zY66Wf5gQH`9-n2Y#y$EP$XdN=A?NolYsqy42u8*id1s!<s!b-9^}7d=^K=_q)&K|Q
z0=o6{@XnOJ4?cUj+)HB|qU|zjiNcY?g6W28f`T5WI at h{@sfWON6EzB??mG3Fj;pM?
z)*#Ls?$pR7ezDZx8QkFsJ(jQm?d%>La^8Ass5OL5IPtGVAL at yT4EcHunL-oF00Yk=
z|50;t*uI5QqZFD5s8yqrFV5B&X(<g^US@}uk~Mr_XXhJ9zL<CNJag{i>)OqodVETL
zxa$cw+r|h%*y9R2$?tr?R{F{gX`ffvBs49I_EFid(>V$3CEjfb&ULlMXsys&UZg>J
z2wdq$%OFN}G%u#~s??4^^FD=+*0SxWr`?%sm=n72=|(CxtVt=f1fRv9(CC%%DESC<
zx<n&8-p~Ei0`}QPXLf?+T!~7 at M~2$mfN&R-wn=VVnVgC!1zpc0q5)=cJiw-74IMVC
zoi0m5SX^mG!<i9(A85$O&HbZD at Vpz{pb^wa$ca3>JKKBD;@Y&=2u6&N-819e$DohY
zikG`C%5FS&Kk*s9x_d$eaO{*Z_`P|ueol<o=wyB1Rr0jTUUShl=-*W1e}H1CMQ+r@
z16vZPL*d_Ry=sL$Kx@{*(xw`@U;$h=*-PpKWn}k;IGcR!=Zgnm%0$;b`dK4~FJr?h
zu{j?n_WMo%p@?pUK~9Lhpij5m$L7SZC(8<Ly%M;`5ha1{UT`HUlE_wPrj>a8gc?~;
zEx6Xxem;M%0!TQ8ap4bygn~sp_n$a|g&SLB)DjCQr7?8(A-rh$t~WUink|bF;MW=s
zP`;yhOk4<Sf2}}yq&0q0<4;Imoyw20T)G{|8_-W`PUHX&14I6#^}26mYV_=qWOfj6
zP>jo&q?U5ewuJPI at 22(8lRsr+Z8&nU9Om;@ivs|*mJc*#Ok^n3l7;{1O)XICU>?Zy
zAP?u_*0-^4{48hpMmQ0c at Z>uaSst3PM&@1A&JTM<Mv&)u09bi$F@?`q+(d<2;4KQA
zV3(F6ABc&TwdQc1Zcm+)=;!X`ix+fr7<=<=dc{97m{LG}O!QBWYTCS#*FGQy<U*)~
zUe{SHq(Aa6W_CW$8X9gjt&km!END1CAVP}@76a``*%=4rz#CRE2B6Y<x^jo<hgEc!
zD#}B~Tg4)n02TC^VVwp#^t1R5)yE`HFni!~dn%RTyAk6M!RTI?wd;#0loXCoz)iJ^
z`@R>0B`z+qvzM$`RA8pGqNH}|QLCUo?NONpVi7nR7boiR;ZMsc7e5%1hw1E&taV*<
z#p(x*xKyJ9=^0PfW~+kb?3Btzi&3NUg`}f*QSJ)R24JnkCL7zqE?SdB3V=*^2BGGh
zHZ=~Sjf*u>fzolXfIG2#8>kc-lhAIF at itq^G972{!SCBH<2EGOC+yt|7O|BfO$$jb
zJ39~GeNNY~|61#X3VuxMu#Q#E=PU#@PM!8TiqwF9l}Hu0>Ah3F+C8<@wmc#Ooi(Hg
zi+^u5y?V&7cRWsB95$u5*PLZ!cY)9S&BsmXyDkTzWMexx-yt&l at -38OAi?NM-ZN`x
z%0x8j1$J|;{t0gqpk*#XVrf=@XU>&gUp4qKvc+m?h_l at m-R!lE!<dn`HPFmwG336Q
zM^eq|MI6ym2rywn&TK0|w*QCrI(W8P$4F9^Kvg_cm6y%TSS?38zaiTuqP at pG`+9Ic
z at KraOT9XAf?kcI9j%m1S0aREQ7cw%{`%v#))F#*0r@$-73HlwBtk=iG?`(W36HART
z8jq2 at A6r5rTebf+Fi1}6O1h=)Duc)xD59u3ggM)_8qBO^@}>CTC6iTjORDnAAeV5i
zqCW3>sUPp}t&i6vmW)y<46bu(Cce1<yQzy at E|y;QhEE5ALcoEZVn~I;{wlJkrf=Xe
z`t2jJ)UTfZ;!x6Pfke>H7eyh>b^eZKY3l at dYKah~l}q0l#6#jPf!1VmNQ<ZJ>xh*=
zNG}K_1#w?*mfdOBkjqTP2++_ZD0BQoAbCwdlVi2<nX<LE{bypOYSk_0-O6g+*jnjj
z3r?j;fEw;mA^>`|+Zl5jkm~~4`dR{#SVQ|RygW^H8T8lM7r4n?h_LDVl+7JtHM8LE
zG`f(4i0@>4GFuuEtLgx%8wIVeCwan-z-jX61kb|CDOHxI#Ob4SOKL%^>K2G64)j!m
zbEz`pGd!dknkozL9J}vwi_{<!6!fTek)U(CR}M+wT*JHSD~EV5ITe`p07W at FXh&J`
ze8k;T#Jb3lrjl at QtnXywK;wxN;nB)nue29R0YPlyA;?wN1>nUc=93G^pG2EPQFkts
zuom#|;bI_64MuvD3%F||N3}<F10Sm!L!|5WR9;K3G$;!Q0o+Kp7NicPn=din(nNkr
zjZ0t%ZlXL`W3u^8jPioI=*zpzm!dD9IS^Te`#N~9AQ{BP-qVH%_A~URlMd&kqG`B=
z7liUp&S;1nee)srRNR<ODh3vcnsJ6COZuBTdD)GTTg&x8r`yQgYB$Pm%+V`)i?}vF
zIVf^+==(u_#$;`F-D|MJy~;rV)Xed=36k>;lpLnAOMS`htQG_H(LbsS5>L>^NE&w|
z*;<gR`T$@nrvhi}65>!e!%UK)ibo~i at -EdNPA{d)NYh9uvshg8RGml7N$#oz9=0#n
zAty1B`pj?v#gE2bi}i;JH<uFE*u+zJL2>boO)Y53ir;h+j>AYsoaat9AAh?sr?$U+
zGM8X%l&FhTpT6){Q}0fApu>aJ^mp+X!;|WKpXZrfu_d^a?^25=s(rrF8BB|js?=xj
zd<2vSE_RQW76K&Lkn at W}12pY}9_XfC9%l|6kwcyL+fM=fk`UI(vT8}MayYY$7qD8F
z-dG*rkb<0_AM8TgY6WKTn?P+<#n<LMxm<Sw{M50ygmkL4896SREM)7_x4mFD^^pB?
z$|qXo*2~Aog9CVYrmLIssQApD743&Bo6(sH?Msdm=@c9Q!DjcVydwHlVM$d!L(u~<
z{VMFu9oW6O)?<LFD9E2VtTD{Dx*e at i?{%Xsf+No!HYG>+jLY97eR`q2#@gp%*rBCQ
zMlilLvOLH0<CyDpnWDwki$;b6*Lk at y=FsSRc;uLWOFKjR6L?upbt*!x>MHq#-BRh8
z(Uw at FRHghQ)f%-1+h4uDQ^O$UtdG#sdXCGjx11fKAlH69QSWeW9JiRgyg+y)?o8OY
zH&BEqkT+$T_iUc at qOC?t?>0e?FN0Zb-QDQl4ZbIPuk at C<Rcsb#bLzf)8IkV0w>w(!
zMp)p(PFFgn{aO&D!PGNq6_HxkL|{q1m;TO9U^Kr_A>rx9_}N*G1- at ZtJG+3V8;8Ko
z>$)a)yJf0ZCm#w;SALEia9z at +zX0_fp{F6motSp0lQeC1I6f*YG&e%7K}<6K^>ZL)
zoI{(^MNa`5!zx7jv{^hQDt>TtI)GAg{}sh3L18Ak0R at C|PS{<tt}7?rM1A~XHdr^#
ztD4bhy|o at CA`5<A<K<0(WUin+q!73_S`@+|DctO7n<N at bIZFCekbkQ1t<!Cst3*=D
z`t89(9gEko%XRQzYjDh!L_Rr+_qa1h`2r2|csCR5n at NKy`QBOPTi07Uh>4IeSES|`
zmEgpduB6A=wp)r+6A;0@^GZ^cODqMTv;v0wvtFESR^cf<<O0P!Mm4du%7k}JRTes9
zW|y|P--ZqO;v45syI>_6QAfBE&Fs4GZcb0TChle7_1M&oeb+RVG~nlk%BjQVoj#71
zm<gb9+j at qqb%NI-c;$`k^qrhdVyBXAL9C63Vg^V~74>zb%^XSV#cC?hU%cAOBkM$~
zB*uaL!6_e5J_HT<g at STPy|A_SdPwO_?-gY~vQ~8r56}&l)y3g8XgmxmImekr`IV9x
z;6Uvj(WM{;zPMzmUoTgB3M>M9#s&s`=T$Xmw8WN at l$x_dUJo=_68TF!9c_sT98+q#
z6=%is?UFb4P4=#GTk26KqGvKZQYZD`6*UnO{X~$oaLDLwk$91y8{M4!yeRGW^?IPT
zqKr$wF{t|3Ga^dje#V7tufZU4?E8+))mf=M&$8E7&Eg_I9)OfVyLm4)1~n$TF3FSr
zmBFEyu-AQ0q>Ob}9Ezu99q_Jk4{i&(+$fPa?jv+Ut8Fd?b$jiV1q?9j9?CRkIM-W;
ztV8FKLIVq~^9Y+i&AycI%`VyDoOo;Ya#U7wCd at j{wyiHyUd9U>j}pk!Wr;h-8Tt8z
zFl$s-R-D0TBpXlv&Wpf=xi;79q49PGV?QV~1|tx?O+2><p-Y1VtwXJi45@`S`DSK7
z9_<F+)GH<)?YA at b&l(a%D~Wyucxq3OE-qt8NwL%tgMQa>IA5m(Z^CWkj_=E~YpwE&
zij24d%lge>p;_B01!T!tNmhKsL9gU_G7q5?u$ClxN^7c(+)A7L!$z-Fe_!6j!(NdC
zF){C|+d at jwDf-D>ffOSrfZgDC>2GA~GRaLv*?=Bk7?LSNw7g4>+&tMaCWIisomCC$
zopzGjxDCq0$nT!7 at -B0S=4B|aeR^vUm!=yGd3nM3XURRl8qWqEKabDrXn&`x`0yAs
zp||f>C{ie}nygU3)@1MH{^Sv9tYCMUM!fF;C3xm~Qd=5lj9R*(&t&sLyAwTiNov$&
z+c>+8itH*HkvjsLFw&*XtG1G`bF`(KX|V5wRjgl^@S&!K+sZk)YZfPNcVl^9ztO`)
z`qiTQmV at vwkjk}^q?;F)0>sKIJNPEcNCgrN-iLvt3c-K!(!B at CmDHwZ!%x*S$X!wY
zPhT<6gu7nT^$jd4YJXm6av8s1*^_SB#_N_)K8#i90xz~x;r6bH;j~bmd0$*l?vV>#
zj)SNRjV0<#m3hqEUq+zHi5V*we?|3Hj&m%$!~?NWKW=F#)qn`tl;F$nbw;7t@%tC~
zZni{@2;xGd8}{B#odDBZ-GRv(&Q4|=vxeSV0zJ at Z+`+7%#|E0Hd*7O6*tH;jmAHx&
zfYS|}73>YfIzOUxvsw7!a{U|kYv4sL$$cFK4AFTQS at BLSd4}|j4n9QSNwy|FEqrwL
zQE}mn1aFO7kfd22Ht<qCwo&6zdk#TW^Q9(PmYeJ>^);hAktc%nxw+-S7ORt9h6o>K
z7A*^V<}ffsg~W+#*;b`l3}#1cdaX}j+A8)|d^jm6ta@=KXNgW9yha4F`as7*QacWC
zJ_okx2x&edsO{?6D7~=z>CZx@%VQ!}5h>74k-}KHAfig)?ubJjV at au4n~F*9Zc~dK
zDeO01>-2ReO00nwDfzDnWLd(yJXaIlSF&I{{b=>m+MR29{g0XOGqWPqNf$AKFUeJ$
zQJ-GpJXd?4aKGK!3vJW7-62Ow7AsZjD}fRwR!%O8MQ(DFeT!rk2tXFPtJ at 6c$GZX6
zJV-)QIa_iDq;n3CU>YnYtIMhYd2)Xpo__T%S(U1-cxnn4|5(Au4y{)XBx+omw+p<>
zY38vc=0`$#-X=$#^p}9C`<9oYGy=+`U7f^Lyf`L-LfkldfhTp4Z)8>L8nN6qmOC+T
zLQ)Vu at i~np7I9mxj&51Z at 4#C{HwiiThtPm<q?E-?z*^uSz36S`VfhJYpu09H*zVeg
z)Dd$Oy7l1pCD_l<3(r|g31nffJ|H%0b9%c0{NMqOuB9)3;qXBQ;4C658dWR)KkU6_
zR8{NO2YN(M6j4w>r3Ix!q@?jEpdcWff=aiv<Q4;@K|*BH-QBIEbPAhPx{+?Ub9vPF
zyzlsbyLXKH<^OGua|HHU>sj-e^H&e{;-t<rbR;~W%sAI)iIZo_W(4tQWIfd=R1jm+
zrL->NEZucIG)!AO&$E%)c^6EBf(xc4-`&lb+;a4zd~<FVyp)$gg2eRK+j#92?#w1h
zhQ*=T&fXjpY<imZL6IVnM9zz_I!+GlI%joI)MX`f%AB5gBO`7DzwAqZ^haTrvK4(E
z`yw?6TJ!1Vnw;p%H;^53F{y{Nmy`WN<cs2|atF;XPn^WEVA?UeY*#8Tq(q^lm9EUn
zY1kQ)BYnMW6iHYbK!IC&VEE9jJPf35-}W?BnEHIoPub3O-{?;o5We&4y<zy!3_Gdu
zMmfuJT(F7VEz>dmGrIfTIsb?y+~SbPx{c&_=Sk$BfJl}n+Ih_racbU8KHtS~Z;J9O
zZR;NGo+o|OO~;2^j8g+T{@jv*1hzI0TS8fVUtKiGD%F=i&mDNEIBF;0kk}<+M0z#5
zYvrkTWI!*)Ra5%w_|A(wrcMtsle at ZH`-?}bn?ooH8D^5S`Q{S9>4?Lo68=6$G^f3?
z-Ka{d?7>CFTR3@~BLqLlI4BA_7#23vHhu=jJe+b<exkukW)qZ0-VCVzcc-wkv!|zW
zwnlD_pB*{3>Xe<D>g?Yn3~_GKNo2POFL=(MA-Ml at vymvh=eRjfoamTP2J|}G!li8_
z#)0*>xF$dlHkvO21{)>eI9z2r5L{-dU_@?NM;N%)RfS~HfeeY4)DrP4mdDejm+q at A
zEyL(- at 6Tt-hCyI%{AUZyH$<?!FSFaN9~l!B(%tKhZ+z-a$EVQVgy63X-_(~&TlB63
zuZgZ~- at H_rbnuUXJA9AtFx}ixkL-3E5w6Ub?6oS;B)EPv=fq*mw>>j#6cW-*H3||C
zYXJPwAVmm+L?6XexiXPcIJF3~72omJ`2*NQu8d4>FuTff?DYAUMG&dT)l0^^{_Ook
znw1hB)UGSt^4&OJCKr({+{N~bo|{BM2<`8xGh8|$6qj|Tj_6!317ZdC5VrDt*{5p(
zU~Uy+V7$noQT9q03BXAa{2oLvd;XmA8~3<zD=dh1%9lI3pLkNvbtVS&Jl#BlFtzzo
z>dO at Q&kXb&Qz$HOtmd)TLy(UFolFFnujjpDx(4p-rw+>WMSBYcWRj2E0mpu3MLl>O
z at dhJo`OYFdXcepCOc3Xt{bqaWq029cZ?Fbzn25|B`de8}S^sqp at rIZGO)U`M at k`7@
zgv3U~331zGsN!tM?t<@Z at zm+;lJT?oFt2$mr(p at 4HO(wvE;GM*02S;)rP(zm<Lf$M
zgg(uE4?R^N-!8GHQ{>r9gtg2QFV8fmuhN$jJ-Vbn05BBk$(xRaiAJuRSIE1O$v$vx
z#Dh`t@%Im-Vl%PY)viy&S2NZD{d&R19{Lusl{`^_8a!Jr+&bg6(vX3B1L1hb98EHE
z-B-#=RInpW5^u*+6BLX7dNRAMGZ9Q52k8PRrXI at uLI(c`cCJ4ZjXy&i{4)V6qAYy&
zrYWSQX%7eHfmrY+V#7igU0*EfQ?lra6Ejy2emHlsm&%u at 3XG3w=_WTSsifBuzTgsL
zS3=I-!{8^=u%wL|{Ha!^ZB at W7s}!??hwU4x{9K(E>lSfh#t-H)LP8!Pe-$$3tdh9?
z at i^6_ieV_&_={4H&XT!QJz8TXn9NobL)`je)Tw3de>*JE&-J@@?^8_~<DDIpFltOU
zPb%Wf+%^u<`@R3ZIN|=8=!m at Y^&32f7;6Mi+*P51cG((6$ME7&N9JBRR<*o3Xyh8&
zBt}50#p|DIHBVB;@FV7^;>Tya*mA33%f_pR3Is&t=SEboDkJQ08{7nQSnx!<v)o2Q
zM#+)-kfxH{G!(ji3bC4&eVioDk&)g at DPVIIGa^Jht{r`(Z__peOM}II!4f(ORX*N%
z3 at kBc@9~9%SgY>$&fHBp!buG7Y^wlX_^SBi^vWX6u8P55e1_U`@-|blUZGOb&<y;%
zSjX-sXM_^N{NEc<izg8d?ap2@`{h&;U50kUnl}LlTl0i(1%fGz^h0yKa;kv)jAmF|
z3<ivf!yn`+4W9|O6=^|m=S_5 at y2K|#3Xe4{308zC5{R9;Y7jwa+mn}(y`F`pYSuo4
zo>u(U{l^w(pI89T5m=PCc8nc7u?q=j_S#x>NKRy}JN`O;5%{Nl#d+f^yrSe&6q5b=
z(>hy7dCkdHRaT0 at Qgb^;=9<bW93ApT4o-u1E|9k~>t0?jv%s0hQ+st_&=#&|bAIhm
zK>U;zua`WV<Jy~7qQk$pjTr^&rUHvG;bywng|wxZi<9I96u(W$F*%@`WP}V>b~!iD
z{gpXb188ZM4?%7o;Ws(NRw29$jbIojqLBD){By})r}h`XK(BY|Jh@?%^V)-s$3|S!
zr87|`ui(DWw8HHgvvwjmk`?_VJN4x2J9Xc)ei!SsK#<S|z48316I4Lnyc*!sQgjUe
zY at s*{8)X|XqSK`wP>OmO0+y6){1DGcwo+gyw^8@?oFmx3NlL0ZnfujEGHcibA^6E{
zA*f2e|Nb?p&dqqaZeRk;N6UF({Hyum%YEV&0>}UAu-cQy$S=ta{zyk77JpZ(Unx8>
zC5WhUdpFkp%;f>dJ4Bf8ndutg at prT|Q!Gc&B at FjsgE5f{9PD~eZc?A8^NkpS66gZ?
zA&>VEuj!q6XtW0yRA*GUyf!oP+t)N67q#?Q$1{6u!pJ}}__q-Sm%KI~h8Wudw867x
zsk7`kP=-k(@v5zQq<I~(%D{h*m^lRdDW2Dypz}io^cBa*Vd^QH5K*wNJo|2lY4_|-
zp;F4!om4p(x0KrtV#e)jZyBOf7H<8M9$*~QD?uIqs}N0`kxY+yVl6!Va0f~xk`)kM
zl-xXK9EE<!tHEsXN%r>}&4P5)Qx7}+-;;Ev<U<Sl5!u at e>+;5MAF;nd5OjvOqEMmR
zpocUE3f3vxn2)uG>HxgNw=M{61Q-aM6=!@g0!gs;NUXwgQXOvi!{^}NGym3?|LK-S
zign8H_vVwS>r_+ZOw^7LAruDFc{$^K=n>WR9d|{Bb^Q1mwi!?Ql74M_y%86D&NWDo
zNvRen$zUy^<P{{4Y-|a*QXPbv+0BB;c%1Qao4N5J{6zL}q~Y4To`HL|_w<x|mY+^f
z(49L$4RiMIwT&Zg?<Jd9gY~dVnlYdNpuhbr0~{>OSxD3bax^}o_;>06yax00`uXw<
zyGZW9JxBHKY>M9 at MxvXDa?;g$OSJ*(tR%#|)|)?C^J31riD34IzOeB7 at O6#f6w%=*
zx=!8p8th82A>~_E3ijRwZNM$Sj57)xq1EI70`kQZ$|n@@Rs<hRx)MGDBjzUHxR;im
z<pqRDsSadtE{z^^;-5>jjh&Q;fhlac2UjbT*)Wsv$DA0gTF4kCeG#<MNoGSuS`Y at H
zyy@~`^xbHAzoxbHUR>P17H{P%FL~mr{8_s9QRlmG8zGIR-9;Ah2<0x_VhDJ=dFsBY
z06r!lDqJq7Asf~d?=rq}^=2tszd_V1MOQJ#f>-A5duEMR*tgF7bB8!1qth0+W#7 at s
z`lZjV=m}lDqKI@`1>v^8mrfnBbao~?3%iLs?{oQfD#hHT{ffj7b)HWDmO{6q at KWkd
zk)~IX$YM^dk9gJ&G0ti*?@&6To1N{l^sU%nhWz8q-4)a^+FJW?kp1hFqoQ&uF_MaU
z=|=raEOX$dc#*CZz4l5}b~EBT5|3an0o#m8qUPq=&Rycl><Jc#+Ew`W#<@&x4S<-2
z(w3T{jonL$zk(44yJkGh2PWf at WEFjQ)3_b^Cn2MO0|W$R$WaDu?+9t14UIs))-#*@
zj&x at jkHlrmiSi)umi_s5c!%hrPr0Eh?nu))CL|J})A;MPfS})d{g)nm_O{D$UmC1g
z_gY8bMQ=sm!=d15hpspCe}K)Tm)j`qFM=eFzM|vUT;Z}oZH!_syB$qoT8jl)%9IFn
zwy_INN`err(h5S9 at xtcENyEbs?lL!An(qMVR6bU>_lc#wk_GEZPmRKTYM4TDHOYL=
z4}nFctaL^pm4xUU;+z?fPQCoP29X#Oacwb?GKMx6rk+^?o}Mq;7>QbOOXU*eZO(bb
zC- at r6buZZk5->QS%v!sL=4offOhQ2LLQ;d=H|5gfLn{xJ5pQ`KBiENPaYfu;%rwQ~
zSGm4qS%o<L6RWVIQ0+VmDjA#CGnR`|@l7G44~$GU9D#DU%Uuo_#OYB6rO_iWxYjnY
zWX1J904c|r3b*1eak8sIm7;g3wSUk4GfKR=wykpJ2Pz{TSl{>1N~oYy#C at J?_jDg=
z{FaZnVc`zcbpMOlz8m<H+5V7HWiX$C|DKPB-MoG^(XVGA9iKqYxZS=IpAu)eR at iT)
zJhR`6cl1SVZfW(&A#zAh*EwmSg`Tm+oV+0TZHOHmevN&<h>_TN`y>AcyX(oEpst$%
zDM+&vl_6L7%fp%e?FbAJzPS#hPRCeKIIYtRp1=FGD1M!S?B?c3b{4&WV at K|Borfuh
zH8)xSQwmik5(zc2ujUC0FTJLr13C%6%C4y)zdZ~3AW%896%L at C+7X7Vgx%?6SFVwo
z)reC47VM>&D at WjM?eucQILD8j=Am90(Clwnnt*p6uWu6ijL;#T&8xwCWss<Hn+IPi
zW$P6a=8S11XsmBf9GN;s#pu&y=hLzXZGX(}*lwa=>A|na(s*obH$HAm_~0LGPG${M
zNkU`MsU6W9*?W;XGeHl`NcR>X43Qiy%rxP;*fyXlyl~6*VYFrH1oRr3N%OzpD#Q+<
z!}a%jQM(s6jY&L38Bgaa)Y%aw=tvNsI+e3XyPG;6ST(qDni%yY`KVLo*jT~so-w<U
z1NZ`EV57hqDvFnggib7xCp9$tEv{}f0033zd5#m~|N7vPP_6D49r@;RPAY?72RgE@
z%K>^q3Y<GVW6Y^5#Da$~w0vG+cqT3Is at 1wW^>AU~6q)HaK^SBSHL^5Egek^n2McLG
zaV~cx>7-Uz*2wZ?qZ+n!O(n<#?1*edrAE_Dt6b?BVj`9kV$33 at 0D#&M;u(4QV%(FS
zW~p7~(X^)HT%w;e-_%f+pTt6KC<r!jiW0XL at 8z{aObt=dm#O(VawLiR>UKQZ+43?7
ztGyd~v|>+U_`QB26xHo_f<=pjy-g*#C0;9j9 at gwRK1m<({8jv4wtF)bW7~FGr)(Kl
z-iq3ddSXue#NKxi1KF5$^dc?0hp65BITyHKKdcs>Y`a8}ZZaOz*@KN9*;M1J)q at dj
ze#7nH(3f0NJk%LWDgk17`s&bn+7H;&1$bu6p6m}sONS7ou4wH`YA5{_$718W*O)xt
zl62?CQcxRVxu%O*c9H3*xP&=|$TzOAw3d0P7!+xKZ5GQ#k<w_>Ak+!8U0gR``rgrx
z{apmfHksi{!^muqrddFwjg6`BZ0BKa&=DVxZ-CBvzK5}hUJTi at r{3bCLz?@sgZ)7i
zj at s>E9JDzO=+B=K?2!UJe_gRW)l~$FtJ{+J<5V*F)S|<x!BSjuv~gXrk*{b0Um^us
zi%CagZokt&F)Ys7w5Q^Y at lX<}rK!y7&9*XIXby=bs(HKjr?xB2cV_dsjk_*kxkj(-
zRcsAKkIgvsjS<d?bVLg9ekI(O^DhirFyOy1=XYnOK8bt%pi;wjzqf;b8*{|=4<fzb
z=ttTlQyFb*tx)}e>lF$-^M0-(3lFZjpa5tti9SpVN{gOLZ}Wa^CW~{iiEUc;*4|J5
zT)=ZT4(`PhKDpI99&n71TOIBIii>$|2qQ<<AS at gaR%I|GH>J^6XNYK^0BQ1_19_C3
z-%<<>{r-iQxwKP0R<Z7^;T5fZ>NfPXU6ZyS>Bxhtt#FweWAT|h27M1_YDYY*FoRuO
zu|*HE6I_gx_mJZN7*M9d-V}PX(>P!2LZGe3t7Ik{u(yt8HpsBLX=3$I`qn*0trJrN
zrVvok<wS3q>!!l#v}GFqKyzJ9cyE?ghboc>Nj6FuDKPG99*`Rh(Q;%TlE at kH)HnOl
z8#&vNRK&s4NuJiGc%u at vNvVkXOfn@5e<wZH=-p at YXTdre)~C6Qy6XnIA{$QG`bcYk
zcRlZJdw=XB-R8OQ49-gP;FYC`AL6 at 9ue}yQ*Su5(2}%_CPd;JkNNAVO{OvFhPvWH0
z+KT37-_WOW-HFA3m+bGE+OI2D(bLU~AoXkT`<hi!6(T!y>WZ(+-=EqRvUPA37JK-Y
zx#R6>Nt`%q5m{kY=Aje!qCQ`LkHO2zxdj>b2y2}ioi&KBc>M=VP$Z^VcxczA0Y%N_
z3QBO4dnJU|nTQ<z6*P)E#80bM!&5VDrrlntkJ;56UyNR}*`DufG3y3=6I9in`3{5s
zc%EV+a2npLU;kcA(_FYu8mTi at x}4r?rQ7HrW7Zk>nQ at AEGaa7>+wOsbTYQmP;nB|O
z#K~<r+eE7q9uHg|*@~1NWdz;{?*3^;O)x1dTdS1Ra;P}$W|(wz at fgvf{T9r09sTTN
zQ9C3rU;M&rT79ce;cS3&2;|)>?>k)Ov(lZc1 at EetLDkYjyV5KbKO5g+KlQ~o0XU_~
zHWi40EdRyoc*<k8FMFh4!WXy+`nMp=&_=o8LHSlXrSAKEDlVG+_fl+M_6^=gzQc4i
zZOyazG-b({ZT&<?AL(Q1DCeM5<&XR;1>B0wGN>AlHP;_%Dm1g)x~{tu-bnCw62UF!
zo|ljpp%@tbp5coi&m%(lGoI)4&Jy3!qh$NcExTVWys$4)?Brkhm9l+wX0dW>-=VU7
zAtJwDy~8nTJHLH&+x2U{@P!jt#6(SNtw}7;Z;nURKU~OrKQ+fTG~8Rng4^5cdRL%6
zqcv<waPWr4aMskv^!O3+8M0E*qIbr^`^6u_pSimfJvZhox6_SAwzI=ke^kWAJxK{B
zv)K1xeOn$P2iNrcZHu4xqU?P?_Nfg9IqOfMw3n7;Im&tT8}&-7%kARAK1NLyE~_5~
zsR#o15-g-1owso=sCu}!L+xw;5$6vba*6bc?aGxl14RQy3w3_I)^GmF0S#$&t?N+b
zZ8BuWIA_|rJrh_uoH`0-Ug5DBrn4T}EcGuusV=V8iXJcAdFWl8|3Z5~9MR^jqwv^s
zYOqF9v?8%_38+P1)?C5G)%8D7rf~5JzMJWtPf4#W^_Gl+nG)m%1M|u}iuCLWJX}rZ
zodn}356PC^v(j-5CfihT5WG{o<+PY9p<plyLcJct<I{XtuQ1PYj7Dtx&C+}$2N>H!
zSg(H^*Oy6Xy87UYRb#U0iLZh`(5&va-=|5!F#=MU at jyn(7XK#?ilq`*J<+6rc8O$D
zOBN_6ewbd at 6t7$6CyuNw+gA&SdA)mVhe;e^3KwS6=;c90h{z8Ys6RUxZ)j8v6^};g
zV2Zl<?T0haFmOpM*x+{rwY|3}k?lHvXtktLcqn$*Ofuirqgn4{7$58)W_u3h0#@*c
zf!z}@?iz<tTI}Sy(u=<Q>jW0IqXt0o#f=gRxCN{PyVq%(c)HgD{hbpEykxN7A>%=}
z^|`Syp*118T at qk4`-ygIL+0^xy{(eOdD&=c)~DD}4i9hA<PhZ#<h{+7$2KUF%fr!I
zC;voP;ivX($TVMiUiTZH5ABM5YuLi%n9^joU&Vf4IiE&d9xd-i_@=Mm9*2&QMsE)0
zuH?3N3<^7fy>#-uV6j7n13|WL!J95XWCCYOm+PE%CYL-#T_<aO>CGT9=}pn=`<9tY
za6Cegicp$}2lT3DTxm0l^+EMx(}u$vhD9r&s at BXe|2mRQm33H#e|)UHxV?3GlhvHM
zaSsO+bxu+KLUb$z3geaAfTp+g%LjZYqqx(EERet4gbAAT|Bkx-WLMFq7z at ivmzVe5
z_u#hs8G8PvMZsgY_Wk8qHG)}0cr<kLHgqvGmW41ECxx;$DYuZ6o6HNU1yqK%v1RCS
zO0D<JNXb6RS%o<%V+mLs)@@cN4f8bLpp_4Yjiq)!KArCWtZ<dw?aKO>?APB#3_f*7
z)c}^nYm70SQ|B=$3l&OzG&ud;<;oFKJk(l9USvK7Jf;wa7nk0>4>;_`YMrs6II}~>
zsG=PW*79r0`|w6;I>96&o;e~$-%JvhK>-MAAq&Bv)$-zt6=d`=4piaMXeyc|qHsBM
zCo at mc<0Uf2oSQ8=nBZ?Fd6Q8eeiq~F?^npWHrQaG8cLb8WQSkfKz0}<q!)}jsxM49
zh!%C;qJYX at Xd2rtN9OURk+D2AP+NPIaut*yb~dVxn}ZfbL5H13dE^*OkC<&aX|xEE
zRd=+F1W5Id=QFN-ZM4mW6B54Wk+JMnALo&k7B(fKdgUbg^6H;1eB~x#Zw?e9nQwo9
ztkRP-&&NwL;_3B|83vg5<#9KBYXBqRXOu848qnbfQ^$VN5-C_=QMkG%#s%x|7sVKP
z5uIFZvM%a0jN+%!_lg3Hk`XUvOVNNP`+4gd->bcW^0avKNl2vQF=c7o3Uuy7vRthk
zjpVy36-5wMB)jLOHlU-HhYCsnLh(klTLg|_H;lA_a0F8TN=yThurdx-eLl;au;WGE
zr!%reQw&k$bdMp~j?rpg0yWM&NLt<4x;LxRN<+TqwR$!E;*r`-hH6)u4-N&kvwNN<
zjQSc9L$uLm&i-3~;>;Vtj47oSV4V at ZRDmtd(z(*_%3gd7Y#NiZ7hAV(z0-^Q8}co6
z`;VNr?AFf2>UWGSy5_Rg0;v?fLdhu8dfr00-SuaIi;1myfQ7;LUF`J6!opPEW*WQ~
z6OM&h91LzdCx!9p5lp#^H)YFYdyl(*!wV?_xbQ&fPht+AF$IjU(<c5blbs$|^qXH5
z^Mr|db>UwSq!iV_ at f)GSJD)Bnmj^jY{Hz{7%jwTDqFIxsCnPKy{(t`aKmWk(&Sioo
z$_-}G<1;^BFXT`D>qF-Re9iyAez<4j#Xgt+&%5yZEA5GX1Nq)VAgZ61!E^3Ls0i2n
zp)r!8z0SKAq(NA%@*TpUYR_>d0M~lc3<AT98m=0!jPyf32y$UDdvHO0R60V}|0%LR
zFIH3q2e^T(f^JFXM9}>5*hT@|3L}#1PAydu$Yw<lHJuT>x90O#1PGBT1Qq}y$b$%<
zNK^Uu{kp>K2KIrBIcmFfU&oCui5^H6{5t=1>sLi*q5~!|_e3AXzi+ZnQ4Nw5+ozyq
z+o$w6Q+w*4UnshQhpW4Nbj9e}zaNRC`V;Vltr+i<Xqe_^ea*J|byeFq*m+JUpMrpY
z-z_0l#GRb<(IBdn*(?IeU^jTd#zM-JB>!0<8~!irDfbOB3WERFPchzvaJz*2>{c*M
zB?Eg&SGhZlrZt~|St^=D^@&>nU}8xh^}~(oHdB8swONZ3Zi`2hBALG~^q;#bi(BWj
z2>+Pvc;54r5%xdV at rdz6su&Y at 1pnRty-fdEb#C)#;6yTuhnw&I{gwXQ;*g7gBKAI?
zKlkr@^3PAge at UZ<+gr)eNBi&F`+Mc!DoVn3Dqow*`RBL&`$I|;xM?;U6#f7Fwts(s
zFYUG{iJ#p5=ePa)LyRM`rpOe8X#TaP{(OJYL~KZs`0oY(y4(MK!vA}b{C7$Jc~g)N
z|L at -68m_*D_mqUxohw)fHO&uz`CcX2pzN<w!$3R$4O|a2e41tczJFf-W2hTTlCU?-
zU_*{rt_}D^wlvGRewU!m2X1g8n-q0<P|W<VH=KzTf<_WORA&BNB>p_t&SNZn-R<Km
z^C#RS at tlwM$7GSDv&8)r>wo at a%{N at c8fVlcc9|mL`~u^zVit23$_T|PMf?+3BZOg4
zU%R2=jzu>2{VLZ4SM*LCXI<5Mo=p4CpJJkgZ=vTdFYzD0#Up8`S;l_pTE8}|KbQOS
zL(DDsV<A^1DX#tb+W-0>$_ at KTI$xHf*nce2%`l{?=rh>9`CpIj_qXUHf+9U#GEe*;
zi!^-cfX5$WdkOz at kyd~r{eO4We>PnB+9^Izr2l)tzn{r}pYZP`_y5I`eyH#<Y8LnR
znypE}MeNXX(Bw;kebvDcod5Gth=oi>U at _<JAT-?b=G)IK&h{D?+SKCnCLqW29Zpak
zGnh?6o_{y^XrrOqsxGLzC>6YHLi_vo{^b^U77z}_&edP<quYs#FTh0J^EV!AFq|CQ
z=Uyocez9(_Bu4-NRph=u7|V+d%>C>Jro*);u>m>hZ4SXz=B@}_`txQODuIngxqk6?
zrMvRP4JM-8RBAf{AuveI0e5xvN#@bQ9?1R%t>P_8r$R&hE&u2BbyJ2HUV}Ja<k$Cn
z@)8H^rtK$|T?)&EAtu2F3=T^Fo-I0I_Qtpf*pSK~tMQQf2M8LHLD<1-2D6e8n6xF!
z7xScQEAkIJ+0Do`-QZ{jo96=Bt5F?rD5?=0K1IBexcsLwZKT7CUF{cPhg^}UHtr(C
zG#Y{4Np>b0<q9X7pu5!!B10gcxpD(E=o at 1D-0y3iyFrWrr}j6Codwry_ZkQS(De12
z#rb`sMW?V?wp2^6^<6^>%`CASu5#lu``Q+ufVv at lJQ9f*|BgP8iJ8G6(R}{N22^ax
zEo|j1LQt9KfWebO=+V8tY}dYZv;LX}EFcO{gTVLpz<H_B;FNXSfO$FzlngieU<E(`
zA5T^d<kbA`3(Kxk2aMcM?YoFPA|$ShrV_?$+iS~}+gfgmWw*2zPrE at 6&4}ovgTftQ
zD>$Po+dX?s6{`BolSsR^1(|GQgm)*uv+qa#c}}n@@3Y=wYL)pLx$CbP9)$`|!f87c
z_b$57iN17ges1+U3*gU>zy~wvsf+8Usee}7o44Fx#PQ3(lK7w1^Yc5NfZm!i=F?ZD
zpZANxEe|tT*(1sNfA)vUYj9m;6EVd9bE$u>89qFshU)&;gx-HF?gX>=uqBONIi2}u
z-Tto+Zdh(cXSKF(A&*c|^&8059s-hY_H)pK)I`2HW-Wy9>H++?2Sh}X)4)I%Kz>oO
z7>Qa!GS|<&8wmMi<Zi>ULD!CtfTT)5<~P=|**GJ((=F8!RKe|d6(G}{qdMM^Sf=dn
z00V0X3f#qPkhG<_yLoAB1}ypoAZ$!dO`1R6pAPIf0ELa at F#sg%**im?3l at +z@NmU>
zMxaMvbk(l_L}b$_k;uy`I_zi8jc<-g9S#0`I>-&WSpsj#Yk at 6CnI|zglr9 at xHpol`
z at yEB2qYb1rT6u;{9dc}5<MZ4HrK|FsrQ8ZTYPZD(X1p1<afH>kIsQ(T48cYPFrX$~
zaGAa9kYl>DrHneB5jp<Y4sU=BNZ*oS%*#r2m7sQlACv_W)ND{UNLpRUR$|LP7cSkq
z`^E>&_vY|sDyH|5eieWy?4%o^sx)TsY8ip#Qwj`M2Skm|b5h!pBKw#QdF%$AG1j61
z8W*H_fxLqWqW#?)i3r+K?7uJrVFA{TkbjDP_7NE>A)+x7c{L9P)r?aU!}+s9A`xBE
zMzY8u<1rfS_l;zf{3A9!iEs)4gUci>l~IWWb{3rP^u`95qXcnVBum{0!sDf*4;Kx3
z;I$gfF&9WUaAC+whPO`SSm4}52_H9{$T!2=4Fx#rz#U2M=Skx2b==*vnC1uG at k2K}
z&PJl>la?p-oA}Iy>+xGk=7<3Gy2`6NzMf2W1B9Z01#F<l4(LVzB9 at M(F?X*oB;aKN
zn06*f_|k;SA(*XYKoDTD2iMorYaq_WVE(4T=`QbRdiZh<#UFSCAlBm;K at J4#3aJ6B
z+(p8SgN2^xBOC3)$2w&2KQU2URU!x9FOX4nj#C0KtHQc3yP9Bq?y*#+YX??ZqJi*6
z=UoYBKSKqcp8U|ZQ>;QNm<Gh8T?Ant{dq6NBnI>0$ndXuf4MAy>6b;otg+~=HA&t4
z{h_hVEc-rWGZ+L0+NAn$$ztK_?rW-p7#%Yd;FSwev<;gk+WYE_?LBQ?M?XA7dh at 7l
zo{Fd+mSdoFnII|`33LQb;*ha6i72aSBft~NE#@x^HnmoZiYqfiaTd-lWR1JSUY7Ix
zoH?ux#xelh*!x}Af}(rj5bb?+JL{YuCExp%NmMiRc+VKGM)9a8Qe_>}ct1Zv=mzaZ
zOj~JEWInx>F`Q`UlsRfJ3|o&{aTLyF&77303Kd5o+0Kc}tF?_~i`&G?s<Gc^WVhbP
zunsCJ%f^F}-)@M=Y-N%i@$DrPxlD6L&*}EfLm&O+*d=fTd&!N&2<vBoPw}bo)YmmQ
z_EN$nxWeMb^5|n8_2N5$NF4JuwMa2y3e>@>7+T#?sQYRi%cQcw-;EjNEVBU}&&=oE
z;M=vok~e~_^}&kM*nT%W>~&{%&DVDa2M at AQhs;Zb{aSONCo*2xaXc*+sn$vDvYD<e
z-66bhTKU*&LDpqn!L}G5#i2i9a0e5NlhFg4-Uph>FO&VsU3_s-VVP9<GDD0UoE-Z1
zs%L~&9>BXM<E0i7$%Z;y(C&fU)*unN&M##;$}Z0JJ*P0fX at Z+g_vigNDxu;GrP1KM
zOXB{js^g`j^RW8ITlR!S_eP at Z;x(z(BLMvI73_LgWDC2SbCt$;8(a}zD#+*TTORvf
ztyl%~qr}w8ow2>I#od5MW2}VQ$UE8lQI%EqNFz8qAh<Z%3Bpz9m*n@<6Y%&qdllBR
zUxeR?lJ}(75LX{hO at K3_%oF-1jS|O&c<~f3e<kLe9h%#pB#v_3o11H*^^Z8XA at XO>
z at X38Cx^?Bk%brWrH}|jtnPM*8Si|}df_us)?cSrr5K%k9v}%CD5*Fv)%5Z;Y-MmL|
z6CD|OS|IQ0m<2}o{pE4GPmp>ef5nvY!HA`)+DpD}QZ9whJ141jM4R>PdGq%*w!Y}^
zC$hV)dRsVD_FbkqZCh{yjWawS`*xqox|L%NLLf{T4<A0&!y!W=e+nR4Jb~(PR$^E6
z^5WMYQ}@XN+Sm<Cv^fQafoC#;ME};4dToo^MY7oW`D!DKXj{#qp&C=~?OIrKtg^@5
zo-&QTF#!9CRCCyZrPzjxSX|`saV_gagG|Cpuk8;q!KV5~t`r8c0X{p2Oy*U#^VS@~
zs1_`YuW&Rv*R$jC+uvJmOfmKzYBO<kt(O!Fdry>lP1`Px1w^}veY!?0lEuY&xm~4n
z*$W7>u})~u`A*2D3Kv)6{ECI^I{GfV?~YUG`x|D^pe25qCX7x<c!eCJsk?yUtvBto
zdp&TRsW&Mi);<)*H{f~EEeZFP9wWMpw2so)r1gn^MECK2_3_ZwF8}5>`R;^@x>2GZ
zcCN?X<^0W%;2B*%^0{2LJM>bmf=57Qp<(mM_p8v}nAj94H4yxWC at Jk&-U%t%3no5?
zYLa~N{Ou>RiA7b7ZAGf&wh4OSMoC{TtFWdgUy81dOo`9%E&9{I6|g-Kw_DKngCV*D
zXAAO!HlQMM)xYvz3VqSKw;p}$Jog=h*{W4FPgw5pzQ5=#*)Xo$7W{(T88~(m{eD4;
zdZYnnm%M!FSwBb9M8NqKB$HbQ%=+8hJx9o%$k>t|E(|q>*LFEBvTD`WV$#3%vKf_c
zKl*WSeq=B1h%u^FlG4c2Rf1rDyZYFrN2v{V$KB7*El~SI>#P1ByEx*7T8_h$-*~Eh
zX$uaL;b*J_ulpQAyYWd&YL-($y<8U)K=Y|ox**551Airu2wYC(=yZ|x!X(RX5n0#C
z(?x4s4+PqLO?XIN`w;!?0)|p)HWxNUdNDg>dv)}}U8^Q9QjT^gdGX<;5)u}EO)vYY
zS28kCoY6d@!AVxllX?T9P$Kilzw4C~n|trk;)MKZ7dkbdU8v-yRKNSOh5@&3aT*No
z>=z2eZVF(%=fEq;aE1~h%h|@IKsoDsH3l)3)JkBAL24^l*a)`X52rnJw&or^x{XyW
zHWd_opc`e+|Ef8Vhem&ZTOm*E%i3`XZ~lt1hFQoqoRSjCJR+p8=^@>^W={0Yx1t-E
zKYhbuh4JaXiwIPEJlOJEZy7;5(P4d0;)gM0Mm78UMvN2sT-e6-X<%tF4{jnHW&X5S
za*d<=VtyR@%(D(a-FNZ5OG+<thIy}9H=1Hza2>-<Z0YIXDs#=NKVGArEQT#BwEULM
z(!t>hs^jDwA(4M|VQerhVF1(F2tDtXX`>gUIJqG7#0b(mXxc+-X1g~ub`%PTO~nIL
zPc0b*8-#AH{`hdHMNM$$7={Y23y<`@SEnalKrx)jFU33maeS&N^6=9I*PF;e;=4|p
zL}cil#OUnfopN9FyH(!)hn`p42xon_7ht5|j&3`G_i&1D#N$XmJT*DeWqh4gm`o at 0
zEm#)>WiMQslk#eYYe1h425xTaKuFkpQ6G=`@{(}<LavNh(QQLl1)g?dBkA!<no;`s
zkdlvNvhj7>P2Z_jY|s9gMEuX_9zPNKr(+Nez4f%)cm;#v-%DE}9a5#nW058uGvz30
zIBoO9-}F<(gPGRRq_H*YB2l%|?Q19{O<=7oQc<%Jn9q8JEZ at GamFB&ah0t|<<_!Ck
zBbFTHmRH`a{n0p{#%jW|?wb;1dFYd@{l_1w4-!LJod<G`SZ=GftXcMF!QsnE?SVMs
zCYZnV3ZW(zKOMO%u0{}_T9z+3D&5bgXwO?^z$<8s`8!Cuu+%V_<;Ad~b{-dX;iC8*
zIqtXFW3bT`E}oKrV>?#s+K=<E<GJ?<*^~HW>$z2w4Y at ZkW$iB}-5;sa`&6xNr;x at 2
zA at LQ7ey`8-rz~?Qx#UJxdpsAI47h7G#)7Nyfv)`NqZa*dJcqmyQ`fUKWHH`{&W8rF
zZM~I8?pb58E32a)S-Uk_ti1cjU2?U)kl<$NdEfh*$92=9G|FS1aW85rJxfKewm&bK
z*I2El<cBi`-|zDlPlofrc}!b at dPVi+&F==#%I46PZJTU3rBGn7>P7?t!yE5Wm-BHN
zIm_}*1#=j^4*F+2^Ew-Gn+-y6Fd_+C%~eELF0=&sh7)pI3>;3#fq2X4A`?R$H&tx5
zwN&vh;3n38Zd+bA{)z*gol<u$@4iT<=S5pRx79MGdYw+H{ei}Lb7m(F{l*5LuXz{q
z<#j$~1qP?YcP(zJcCzY!=h4XPh%JDimt<JVxf=mH=wpcAit2D at AIWWR2uq~ElW)KZ
z at s(_CD2KM5bSc!rpS&qh1IdohDo3?`_7|I*4*{o#aJ@?T4ZH(n__^M}QCWk9SD+#7
z2z9$hUWzp&d5a<Ky8iP9tQUc0Pp;n}nex^w7t4>2UuG%!*kMBz{#4}sIzEK}wB_8+
zaZe24mRm|w0%ppnKg!FrI{CNedhV>gU at 4*OjeAkscbHbANLI|+g2OBiOFLZHs!5(z
zpcy$@goPI-=E9mVn##|rcZ%<DBCpwt=I at m&E*4&byLwZoqZ!m%vhnyCFMX-WAwME&
z4oLC3h{xV=ZqH7#HT-CFyGrGSVTJ_33K=cyDsLH-yZ%hND4DXUP>r+EH&dNDakYH7
zS=>j9^F{59jwPOxdiVv_thjEM7XT(OZP0;*dD}m7g}cM(XLl|tf)_#LKVs)PuOL=?
zRMsbez_9JAHt{!fIA{g*?=+guE>cu3tAt9%gyIN_508Xl$T=tGBk7%5%eNrRuF%;p
ztW8sKrqdx$GnTbqW98-ZW~?LIArYG_L#cvP%tg+>Jp5SqsvrcZH&3D#otd}n`jjl6
z+q<1(!!e&TZy`!|z}vFzT%W*!lbyoTfl-}x6WXAXEz~-C%qGK<V<ER|b8wE{%u8SQ
z0##7#SU&neArg(I<3jnyD?Bn#sD&lJ*A;4fv9wj6l1krrrIlgEyo-M_QJ$CvnqNXh
z`&eYJ%U_b>GhI|%Q}-g59*1*sSZO5A1Zfm)d(X1Z;%x&#Ou)!rOoFm at 3hAM&83Gj!
ztcR5Ox%mZ8-p=gQv%7Z5yU>ncd=>-GZf&i?-PziK<ZT$YHwtS!74(jG6p^9z2bS6s
z){aCqY{F6r$ZMO7Ym=^~%x};0_buC(@SC%<veNgTzWntnz1PPkj{M3?HzM+CteamQ
zz3me_&ihO1`_>oUdz2I6oJ*sJ%l0#z1GLc#_az6A90Q}b#L8D5aEI`3f%Z%WF_sxc
zSFJ~`B(PM9&k1Lm4ui;zlr4^gGq#cD_(iLgzu5Ztmv=jAa~Yyx4X=FkWUIOObuwfL
zILBH at x_#)ckC&M#?(Ob%m={cXQ-*F at g8g0+@+lm>=r0a3s->k6$ue^b^i)M!*Kw%L
zCl^2yPegeHXWLK7N)Rn~*14;)Uz4&_wC{LvD`}*VVqSSx>^E at XmIa`Ry{~dT+#9qg
zk2R~dVMfXb;WuMDj!Z|}y1x|&?`Nv$M_4u#$*1V at Nh^d}murRWnyk)RC6Gf0!>>eB
z(#7EWAmOP|!3(VddP;47iG6QLmLIkN0L;wMd2Ja at ZQ>?~ed8gytsq}(>9cWVb-*cE
zie<hOj>95SCS$zhb)<au0_k`6k}TTHE<}6&Ih<VUIsq>OO<Vo_mWxs>fyq~yoV2|+
zXad&~Gq at b77N!<N%!_pM9r4O9Gg`X-cuhrQZee%#iUh&!?hCg0<bYWvuC$E7Gm+|{
z3Mph2_RbSrcw2t2IkV(J`fuC{ccTiRxE23El8e+gC9ybkc=g3DhcxAr-|4e!0T%?w
z!ANW`9M4LKgo9;H+g=0XjiKF3+;yjA=x=9P$+K=KLXvg#{EaRzlW@||G7O|dKrCru
zxh~#xBAg3TViT>*D}H`4 at 9IQgwLO7kYXm#mm*PCweqN|B&=>}@=BTLK%TexjzaAXE
z4T}EcMY$gZgU0EFYOiZa&r}>AuE-)nulSMh(JBxYC9>$re?Nl5!kmTo%MCqTtB+ca
z>?T&2*Y4QQr at kur62$sh{T?Q;e_|bJCz&&t%|SO~D3EB%W9J+SnXk%AiVIi%JaZ0$
zD?Z1W{wFdNE>d?!W98=Pw)(L#ao}Y|US#C*(r*;2c at AxcMe?8xfCj{rmpSLgyVlG@
z#OF at r31SkH{cw((Njj0sMQi0`ZrrowX&4U^o4e&sLYir<nyBUVmK|JLZl8r+Kvy6W
z_%%`EhQ3c|BFnpi3zq9CLpP2_X$?Vbl5W4Rc=9nSUhLV>C(i;&J>L28>3ec>GYiKe
z$GfsjPAFd+d8iZ*<@$#lh2+cX+TNLms{X|l^_h_g&i2;z3TDa-*4Ni5mXCJ%16njF
zi&8t89!5s~<wkia3=VTqNVvktM0kY}?}(V<vVV?&H}TgIa{uhc__d{AWMBG`gXkv!
zesE^&=CYYE0o at aupuOn}5H&~@8{lath3Tm%7QyV)jXo>Z$i2VEm>jVdsy5a0kW+dP
zV1 at 9^xa at 6!mWCvUsE$V106u;^#|RT&UiT91$Q4fI3H?q`TnKchk!#Zs at UkjDw(WZ_
zG&r=eRa`9;@;JGAe`Mus|ApC^1rhmMA&I3-Xv}cb#xX at 9h(7!#f4Db_kFMvT%P?^P
ztR3h4xhcG?bh6?2+C<(SQl5eHf3V4THtGPO`AM1kFGaKQ>QD*ZYkCbV<4qwW#>fG@
zXD at iF87>9iSCA*cJ%WZbnthEJ&&77aBuJWv(aa7GXpbku65~vgk{$fqp!#GH3^q=b
zO+JF1gadwPe6X&H;}veKWQl!>oR!1gXt7eYPwThjOqjJ`ZSPvTiplLXj3>JlIln;N
z-_!Q7LT}>o${jHLr$~);^dAGtpiwNlI{uKet+y~4Z`>%v?y?_?DctteT>&VJ=bbjI
zt0}={%^3CEIH}Hb(ZXdx<83*zJFpMypZwEXS^%4{JzZi5WSb5{&g6Tk(DrWr-N_&+
zgIauxJp}eU{m`SDvRXoB)b3=mFV?5ccHZ!8Vw?c?!A^$zn5>pZhi%UO1=xX9n}CLB
z4T8T%>Lf#3Z@=t*FwR;ioIyq8U|Iecf!zw4XuOG{l4cp*Kc7?|eiYgeQ=hh|Mbp`K
zb;Vcy1o6n?!puVT;tI_uFT^bmzV9+bDNMfi$83(UtX5gWX}&~JG$bWHXur1LJj}o<
zrX03#9tB^QKk%{Rec=8)PTf at ixE|o=<NJvAeGVX8)3RK>{M?rIo>}Zl$|gVZ5xqo~
z015|h<VftiS~Id(QS3KflC8>Aneuj7c`ru{3p*Ud*+5r{=Tq_i6)DXJSB#T%7k6(*
zKT7Vo at VjR7bHoHi8&<rHRw>s4KVR>5CJs?$;OW*22 at x;NZEIlb$@l#=%XgL|1DODi
zx;Q9P&t?>URcBl?APIr^hFHTMqHKwIuluWV*({Kk$4D||T#Pt#mniv}8oAX?P2nWO
zw at VC81r<N2$<!~t0Fyf2w!da!yi#)mzkCG4A^Rhq2HK^^ETIC>DHACxZ0O#H4PMV}
z(OmuXnx=J|lHo`yJ`7<}dj~Tj+NzI->x4j4dA7LGJ<QhyatOYT7;uqfWjH-!|JlSM
zE5b(=-txLPOfZF~Vd>>3(%yzueO&&upH@#y&Qmjn at QqQi&BE%c-4N%lWuSyDY?t8&
ziNy!x{;8KkkR)KkpnietkEV|S^Ru62 at l9tGP*JPNvTWM|{v<EPl73KC8I at u3D0^dl
zQ`_#+IxLFR{t>@QW!=Z=ef)NQDYMAbS*2<zmxvT}FSY(nFU-KEVukoG$}+|MWvWcy
z6^TmthIm+r1XcaT_qPkDGCW9J4yJjl)m}`$NI-ztta2g!HZhs$z+gC@<O5|@ue?-Z
z)3y-l4SBbF<~>b(<TG&YGpj=UR!Cy-yC)B^X<M6?MrT8I{q_GUUDVX$G%Kf%pO(R^
z%a}!g$DY3F&HB$MJz0CA$1`Ht5{Y{Ky2%1^c3E)?)w7$1L-)=7czTNCt}g3&7x5^p
z{BU{J)eM6RL;c?so6Yb>eCR04+U9cvAsJD7gBC2iZpcX0&X&yngMVze!LCVl?mZps
znmky6_S{F89&b?1sXm`a;Mk`*n;_ViBGgS)c~+!$AmMU7k;TKX7lGrFz}lsAJ$ZIM
zSI;dWY{VXbsst#XMd at Z&TAID}FZn5>n-3-e53anHIi2jj&3djm%JkiafaEdWu<QO3
zLbT0GN+48Sx1)E~dR%{eo>ujdPGE1`8k{FcVm9Bjuv#Ukt_SNy2H6~#nhjhbX)O^V
z<!rsk=T at WEGA&%vb3CndE_V<7768oRxot%ot#~gRU58aAPL~4-rzF$bKwn7o!0mjr
zjm=)UA at 3z>S9uFS`DCDEl1Gz5wV3hr?};IVjnt;^Ryz<e+H;J at fI$bFuWb8T`ugZG
zmb*R+ogF*cD$e3v2{*}NjFc`1a>A|>U#8Q=O^U5F!GyjPU{I+AHpgh#@2VH+koaJ=
zFspc?G*4g4o;fgs8b9l3U%Z6~{J_0kl9LB8v%n#64Ux~BFs6%Po)nyU#D6yQBVvN4
z<+0ozkjaVPp(cs+QhO>k)hKdgIU=3g*$bSKn*ET3 at LHfE4_VIg9a}A*q7WP|N1=d2
zm`r%Z*p}iD4cuk3d31k^e7uh>wNpK at 3XAOl=)yJ1Dld_d`68m)QO_R5Jiq%EM0d*l
zT^4m1Ns at iHgAvy0LT|lEZYG1shT-eFa4a#|WS;_7M7j8s7>^}K^r=_8Yt_-%Zo56n
z)-I5E(w47N$P!!2$Y#9x0f5LW;NsYKoaOh&4Cu{OwKgn&Wk~(-t1R6_1ZVLEOAnzr
zO|1dBE82 at h*+;E5Fx`6XBI8vr5(ghe{OJAR8M-l-dm`1)G_eZ`Q_i54OJ~j&`)|7A
z)@4KL!`rrZA49>^r}KTwb>I<63VVyM0I3TQIh*pBSN6!HQAXnI1EOMw?g#Y5b`a%Z
zAPr^;$M0KrMt=ala3eFXnaKz+dnq8?o*^J##Eh-$Vs4{+Ym;yPv!Q*siOxf+8uf*g
zX7e_sKwx!4YbdAsGb*?w6J|wmz9 at hG`IOJD#pTyX91Z}J99sTvMs;~5R{Ln}1D?OX
zB0VxARKY5fMYYVVcDj+7709WB%G1Mj^A9T;BMaR1zRfo-^j~gWm)@zl2rQTAj9e1$
z+=Jl4uxA>rx~$E#du|t;sVkwYh<bJ$c#sF@$X=$T%<o0Gl+R0*IZt7^vYR!iRIP>l
zY*0#7F7QnT5an|o&!CRz5jtTGn%65vg+YGoc)Ay=Pu!Y|k=wf_Ka8Z_yftu|jrEYn
z&M#M at Vc3H4f>^m44hBrP&l>ZPk-%*p0R8w>v>^0S)~@-pU=EAQd(W}Mx^}hE^t(*R
zixuDMkv#dWqi)!rd{7utyy~OPY=z;)SzXVLQXs&pgOqq4s|*J-N^uh9=g at Yt@!Ity
z*!|Y8Ze&8`89N{84nTZ37Q&$6$wKd&oP at lI-CKETCa1}t*CZVBuikCF#jFvqg6L%9
zuhuyNZ>TZ<70^JX+e1Q3UcHwHHJ8QtAO at fZD(eTD8j=&$VI#Yqvd%QNRy=UXL3>zI
zc-oP~67ua37TzY_M7qBeD60?4Wd7q40s at Z_!pNDhIL{Fz{QG%rCreqoi4hwB>tkL^
zUorl8nNxv7pZvLT?4WyoU_?Ebs<Wm;^TGkXi0n}}kw^#MOhh8D at v|A%$|G9bF@}C?
zpIu<Vh2B0Wuddsl0K#+E?gG`S<?1~}jC337V1mjBNoSAnt^7iVp5$ec7$zY8GsgIo
ziXI+6_IJqVLbjgD8#%yZCF7FzGy8*s-0SLdxo2(_ao?KZ+*HMI$#|_1UoG#qt<6}j
zgmqpu{Xhvtiz^jY3cY#{A_VQIMlP&kNI3tSshL9f;CkS~Cg?nNetbyY5t^?8&^+md
z+4bssq80#fH@$Y+)EsZPm)s1?;BnXm7w7^UepFnV at lu<t1~tK20e4{8G_a*+X at j^d
zRSS<-n1;7u8+|}^@a?n!DYoy%WkMUK7Q!m%<dR-E-uWm`eUvrM_)1xdrMtfkv)NWO
z!&|*8JqRKYh1Mj>2fJTnUEf#1FAh~E^u})3ms3OPX4k7vxdh`7cKboSvh?=w0%#*z
zPaf%^vTOb48deCy*qyTXMpj%^UJRDR{?Fv6co+IF(utJI&`7)zRWo0Rtud1`Uo_N8
zHqg0X%Xbt+d7>w74S1IX0M at O&)F#CCdG;Lz8z{WLWJ2%Fh_%s3>168lQX&|4TH^U0
zNH|Q=%EF9zVVfsjCd(hu5g$S5oX;-dBLsYH6G?TCWcnN%#bTZ(xD|a_cx)K^mhRZr
zE1EWW;eIp1<`#e)WAf7)V4ZZ)(v+Od@%|iizLG5B4nWTYFWb#T+9x&D9|18HyxiZ~
zfSYBO^XU|0cW7|PeNTnp4^@jLX%_pyLiE~Qo^V%S4+g55?t+gns9{)n>5tfGUsBv@
z%d75ECC`zI;guPMmv4C1b9*fBBCnFpwN7!Ag_!NZW;UwLI at e!GGVsd~akQncxz at v~
z<Iavit)#%7&Z??EY}mhs=1y9yK!1LDxn5>~vDK=Y20L80@*U9%*qjKvSvDlT_pDWZ
zALeIu^)^6ZKOimkMvL}Qo=vql8SS<`O9k<vXGJ2C(*6A!G}7wdi at xysP>Be;06YJ)
zTSH>fr#U+&^hH}QnitkR>}+zQIDrwr^KrXsyE1W3U0ui?^U4}hQzWB=6GQlEi;=9y
zuU0I3c2L3l+7=EG!Z_8Kwz377`^RM#*agqN*95lu_;b9&Ig4PCp;63OvX&EnJEV&y
zR2vo7;U{S^u3}47P}M(+2E)IjLfalPEg>@-5$|&Is{uL8 at jmL9U2M-+UlMv)?ft=i
zQag^(cpdzgCApi;%-LMSB6jcSm8yWzoLs?M#TLsBzJS`P-L>tJbfOV@|Azp1bj at v1
z<Rrbm_F1>8i%t5c8mzzU_JfXKuFAN)frq3?|Dz1)7(&$eUbs>(lvi*mXpqMSpJ!bN
zojTH|EE9G!wg`q4uD&AE*c^2d0+TW!jA_-NJwQzAB<GCMj;{H$%nonx<-KJz!RY*u
z?h}F5yEpIKJ=PX)b#)ZU%TztiY!kJ#prm;U<89c&wbd=s$@0m2 at H>uk{arFb6G<5}
z_@(gW1Yj~T!L)vMx5eM2tupXtB>Bp>>waZ|rA<n~)*w~fSgn2d%LVpB<Xi=7R=g5k
zC40Nq2_!2knV~GAAE-XGC1v;RhY#znMNjaj6{9dFYFRVtn%O#X;S}*-_HS=kZ}r|)
z36BuskZZBB at 6XfRlJ;GF<m3*2Y3}RMHtM)IRLD}U98l6VOP}hIo&9#J$^Jb0r^W~@
z&|_<`aJ68#1DXrO6_#W+zIUbrX|6&?2qGql`mLSab>}?Sa^Gza#I71`fqCL+>%fBX
z$TeS4B4~bj<HBmxs3|&+NIX*5rE%VSJ1o}K86o0TE1BlOlh?KKU;;gov+OHw^pDmm
z#l6OJBF{A<?C`E}_M+6aPF}2BL&dG=q>4&4YJqy4SxH;$pA0RegHBO2V`1iyA)&*D
zP2Lz`MH#a`=}SQhYT&32EKjqofTAt$k69cGJ4p7;{0{7+EUZ;K;|k7gz%My?1%z#q
zIoRsNRwEHyQ#gaqPBg3P-Wu#N^(4>WSO%U at J6!0xnBUS1Q|Bm$=?B1jTOZ*bLc1G6
z^HwbXd{8tC$tH_NhV`0@#x9>e=NRaL6FuG>B5)e2a)M&zes0bfc)`%@Pe>dFG+2T2
zuy+K9d${n==^tr5(Cr?TFpf-d4%6Cx0-2x4+ at 2r#q*?%-7^x4-lhEzhkK%RX&X#TW
zD%(O;Ct0J!afcSiINK<B#t+AZzIkgOJZm-=^(o0xW_r=#G};5l#DCvx2qFulOH#P8
zhk`-7C?vmJ!R(5bY{F0p43v16RVk{DC#$z7HmR2Ux7%Jsx0z!-9F0tJ^;26w=EEc2
zvBlP%B&K#dFSTzRWc*P%&^c7Et9r!Bp(Z#PNK$>cq$*WuloaeP(OamKG|A{0eR0e^
z98_c@;2Yuv2EaM_#hNkb-`GWJl>cd+W7OP&#zkB~VSy`&IujN+qCL at PY~th~ZnrU&
zQ+poG)kEi0Y__wG?8(Y!21iBqI}})3Sch|@+X~7 at T=M?<o7JhHI#XEp#89ZdcF|CS
zW24Ii*_dH^TN}9z=&XG9N($Dw?uODN!=k*hxj?Uv*VwwGEJad6zFBnsu>hP&;KZtN
zKf904-|(1)%5mt>SM4~GN$qT6=uqI)ZS&o*YYX~S*$^FFxJcLhu57 at f|M-!?3M?7*
z(74p}DvncX{PCgffviPpP7p=n5st}SS?zroZ!&(DYVT2Fd%v$&Ytyp3 at k+0exZR4+
z+fbx$0L7q8Fs;D;ha9L!ZpzrtuGNMe4n6e5SwMuG`gTiA!hwwfB!7`RK8vLdDSGr^
zveFla_=4b%8WO*~l`M{Y{<XjCnWJ}59UEiO&+N=vql|--_p2oejucwM4glC1*>f`^
zC**5HZNyU*ZeG7TIqY|Jhr=&kiH6>xHKkpCw7{l0%riVO%5W}BW|^F`1IDaw8D&gP
z*3Q0pvCXZO7n-!0!6ipXLtkulUuwUhb?3zxqXt*e$Fuu$d(jml-fU%t&E}y~vi%Q_
z9O+Sh^z7p<c_9~3 at vFV}lBGg#UDwtvNf{0E9eH^4BW|Mdr*;zo%l?IPi29$cSTeJa
z`e~=l90IKry^!#5?+J<lMyyw`S`^fwst7#NuvV%o%_A?KgI-3O%rxhY^=aZoV*j#e
zz!n|8 at uKV1a{8OJqo5^}4`t^OlXMHj#zmVw`01 at B)SVOeL|@Lu)lGQoiDq32wFkJ5
zk;J}L|F}p)tOuOPfjxka4JrS{*1&G=?4$Q(?XLg)9HP`Bx>KRt0=k7DBx_jt0`oAc
zYImA>Sh?W4LiC;@Kb%agFg(1V_|Yio<C at qxq(`*R7<DZ@@*opekK55Oz7g5;gWt>5
ze}N7CG(7nl<6!darum^S0!)e}Kg2lVy~X3aOsV at n_?k9I-M8y+B9m|>9c*9DV4;@&
zz{8BigN!Ir+jCzVU>E0&W_5&hmW<nK6W<ClLI=NZxLS=YKX5~BZ~Y)|2;3HU#h at VF
zSL&Z0CJhIm?9Y^<^Tk-uQIE&Y)P{wSa!TZj;S0z;rd0KMX+0U|3M8IFXhTxwlb#<9
ze{8lk0U}tt;QA61e!T&M&HX^KipY!ogK$hrZ+k2SADs`+pkcgUZ=d81`bZmjDb8s`
z{b2*A6ct-}x$iH-Ys)$kp!WO|&N}}E{@EDk2Gpc1<padWwT9*n#6tnUef5Eot^bn8
zLbX=ygprS`&Ui|^pQL52ZNiPH)_2=m at VYUhqJ1_g$EWY)-^i+LY8#z<&w466PmF3o
znJk)E`*2=m!F-+O4>);@XTx@@^O(dD(ZD9*JPS<1bq@`}&8d6lrK3dCSq%K<G^d|V
zkxgs3Uwx&xd>(n~+{=^a?<4tOUO2cqbdxZO at V;k~^7o~_k1aR8x}nMfZRS!iuCp1;
zT at Fq<-`j9E&aoEs$+*z+(dlQ5LC-q}P)p0n*v$4vz8^nWn$^eIah&>p*n97Ps{i*7
zJey=CqoKSgTU013M-gR}5!ppn_THRSDj}hCjAW)^@7-3&CR at p#W$*9xu;TT8eg1*(
z_xnpXan5r*9 at pcV_v?PqSO<8UvHL8YUD5*jp$U6@<X(B6y?Qu<+d#4`(1`rRCl(7d
zT}8$y;8PZ3#vsGD+V>AG at 6`-Bk^G$0Il%Freh<o9xL>MGSKVh5I{++mRmM%mbA_TU
z6&i+u_=CSEWn$TPT{FMd=6ivsn1MY1)0rUT(`&gZ-T!#h0Q^U*5^<$xv`wlf<x=!k
zrsfYSaeXjWA)M>Bifw3~_?<`NH~L8-A@|!)JA)S=z(0hn#GNrgn&E)`4}Z^9`|m!n
zz-n>6X!pr0=S~PJ7YR9Uq$n}bZus5lnVsxL4Py;ODleX5`c{#q=Y_q&Z&FHxZruC{
z_DkJiWFH=+&j#9un7_@>wp|K1*NtqS*vB#@ulc$?oWv~N;}DtlVk5&iU4b<)em2mH
zFLbub>zA_s6~`duZUBy7fMTHGvN*mX0yW-`R<9`ZOL6AKS30Xlb6|h at BM+k<Y;_p+
zz}tpR0Pg+lbK^#TvQtvu?c^-}X|s at K=@!%qHaYlc$>JYCK~nWB-8(I<)jdPnCR1{a
zc&1uC(dUu$$jcem+0P2MbGJ0)-o({RlV*RKF<C+J^NKiMR=x7n%gGi}!YHV>EGFHC
zpr7 at SAB2!6p8Ys at GUDg?2bYbi0;2b_ir7O8Hdn_w)9K}P|7rH`sQ{-!R<CO;$<Jo*
zhbz)t^xrYB at z}F)Ikqy0i^J0Wqe9%c|9<`7#e0?Lq%Xvb`;Wa!&Nur?fBwKki1>Ab
z2;N6woy_0pH9g8LX>P$t``l%>B16B&O8HOcpH{iEc>t(zXo~HI9yxxHk|!`_RR*5w
z2~qj8|2OXeOZ9c at s?inKaX)p>$$EPD#bg9#F;Q6A=>TY4&YNS$MEP&J9^3y~C5cs}
zeSlQ^!-KA%-n3Es0^A!u{P?s}`tEA+QeEOVWtJ|!ld!G()CB3DRw{*L`~9rX7J+~3
zk=N7>8I&0h=miqFvl6;1HNB)4KdaMyh1%-lL87!+D;t8mLpQ&xF_L&}z^@;K0-8_b
zizpu+ekje|&kNl&F6(f%{s7Et0%}f+!BFRU)7Oo0FPaYi&3f9)U;>6mb6<vTK;Ph)
zQ<Awuxx1pyso~X8Tc^+Scz<y)S*WQ<ym(84a&!t2D!e43AwrgiDn2Eb|J<m+VvfM4
zxrJYg{B1#s-iO~g`|0E#>CmAmBb0YS=B`LVcfB17`h&tC7xIx<)oHV)K&mR;1+~-j
z#t}B>+DGMq;|!vxdF6Hs-HrSS^?!7Js-EdWSrQcMv=>7{>!2x&n at cXJ^xG^fHPAwj
zQ%Be!&4#Yqfh}g3Z7Nv~{RR-v{G~83e6|1h9#D1)XV@&lz2xLq5G;t_+A%yCQwlCr
z)#Q-giimW}!*pB7LnT5^E_U?jF*zWFTyecW$%34`(<j_uzVL-H*QSEO(Xow1+JRk$
z_U+M?WAy|ZIZr%%kAJAiPkQ!n>+QAC>IB#?vH?n$s#H}JLIJrRkqOLK^1t)-HrMFo
zKhQ=d_~{bg=5I(RGcgs(r+?g{&2RifYKiccI<NGg6uzEbG2n)>TK4j{P5%L-&rFEA
z?+?26KTn>X0+AdtTjJVm24)lm+<#hzlhNOYBw*zSei4C6f%Z!CT*%E(JxC1LsACW-
zKpCU at oVM5I%8@?6VhGa;o|cFVN_2S>e2O+!TxB0XPsG0uzddsIv3=s!lz%TzIDe)K
z$_T5yI{DDPTn8RyYmm at qmcUo9(=VVgFm(s)Dr$m6)HY+!YByBtImxCewO*`%8pR`g
z1VL*7p0SCP3yv2PHx_^}pAFWm$wW<l^RwH2h@^&HxfLU_`T1=>MBjir>BOoX+Z3K{
zKiHpvJPhsq!HvVYnbTVRVGA%}`ybY>QB4L*t;q4x=kJl+dU1H}hwXxzbeoxrZP&oC
zL#wjr^A}qea?6wV<KTGxzwxCL2BeOl<;LU?E<-6H9x}BVS}@jbBi;TIACM!%FQTfx
zY^;VF4V?e4vV$a8z>dNANlrkGZ61&HAFyxf9%>p|f7Y$~E5}=wyP5&PlaOnPeY;!Z
z>TSAOsC5WyKr6-CmGrv^QMWyID1&liw_2c_VX6MjhLF@=K_8|WD50j2ra|@p6(o!o
znJjOuUUz)fzn^MV8W>N3lwkMUGC|kS{|X9x8JylGXH(v-qO<Ypgv5$)JiG2_`~LT9
z>49)B3F>Of{l}GeV6mV$59a>UboGCh3*Bq-2}qci|C7cIRj_$e^aHF2VLFLrnM2tB
zJ~RAg=?KX7|JPobU%^XI{RUZ~nm%|r1CZ!-A0kfKB4rr;Jw%|H`R^Osajh;nzXt4&
zk6=gW at CZOQ9{rU2SA*B8yZ|SOvY)D*_S6~&$=2(kT at 9t-XDv8>R#=1SDNKW`>pMM@
z_jWL|18o{coiGY00Z|WiuR{tH%uPepE)RTlQC)3f_BoPTalCxjW#6gCt6OM)MPK{P
zWzl1zpLKOk2Ld7en$8pFv_^Ii0g0?yf!#ie5(1Ve^TczT^;RSe-b9LzG!4CF^qSVb
zhvg(n- at m9*+;wuBZ1p3J7{y5J|9|LH7WgyE-jww-M!?Q**_ONY&>_i-J_M4ta5W?|
zXif4M>43!I-0kM`TjjGl9fY^skn;byPYtw1A5^gD`%jXH9oWaH0h7&c?fU<7i3bVb
zpqZG7!t7DBLDhBm^lrlgKWa{Gc~xRm{r4u>vK&0qr{aA(w>={_GIGavw at Cii>BPf#
zfTtKrcV2(Ze?Nw+G*~9}b7w@?E{Q$H at Q~H5!WToZ^%fV^;X_CL*4-Yg<R178wT#ZQ
zjm?GU?<avZ_hdX`vFU_uy;JE9U_PN5?-~;MPxUh|3D-Y#?)?5O7ySEm{!(~B0<qcr
zzrM+qH^q7)!|Z#hcAX7o%b(D_cBR59 at 1QD9-cYz(-|K&b;O|XWl_&uZI7OvCDMPC#
z$h$NIA2`Uv{}7dI6<TkM5=tn1;5S*PL#Zam&(eIufO}4{_O<o>=a+}QWW1~QpYMo)
z4ilhzxgnN$=fB0}4(M+xg5TW#xqhURk3mkY{Cyk$eXQ3XoF6vlDzoR2|1u3bupQ7Q
zI{M~!HT1S at Tb=c#WCRC8eAkDR|NJBKmIjCaeDe43UcT7bE%C(GS8$bsozMAn_QrqR
z7!(3{|I_@`CI4wVyfIeDs5Ls90KEcwIQ~0mfA+u65Ea~d57IsGF@`VB>(yn(Q&`P6
zLe?IQSGT_Iqz|m1#Dhmd|9LA=Okk#*#~n5+)Z4^t30h>^sbb^)@=t7CD at J`-eY}J2
zI-Ab(Rx!g!kUl7<7Zf>mqhEKaT4VG4WU{29hE>F_JNXd2mlLR)Z0<CKpE@|;*OHqF
z^jFt$P}2l2W8bJT$<}wF?!Q}lzRo^wU+9K7xL(xHs1%Yz$ON2aGgSO>KVQA(fq?zy
z_v at IyEk8&tl7pGB$5RVkdjpIWsX0LYn5 at bm4b${nL``<vi}%3E>^YsizGfagsNX07
zVO?Uy`_EYy#!{&6-MSN89MDSqR<hy9+S7KG;79HfO9B2^Q{X;dwCeHPrbw}uz#}_I
zXT-j4&OTj;4#t|BN`Erj6S?8Xp)AyPx+}~_qQ_T^o+5y$L)??dUH6^hB)PU4#8PiK
zu2f~1A-2^=V>HAn5=KLO)}0CHvR%hx|CRt at IrJ+)d_O<vxVLVPYIgTaF>7fC)$HT#
z+jdbc5Rgu at pX)f4=xg}oyqOnUpubP1{*@x(dztzjBwIDmzXWR6qf%M?8U&ug0rZCC
zp4>JqQLO^YEG~Fp-#WjNy`27Gv=I4%T!UMWG{z1-S1H`=w{{Tw?GVWcH-g0S&RhfQ
zt;kAtGspc5$%a&{p1D#jc*D*!KZ(}%1W;xpgmDH!2=kz$wtH#ojzAaxX66)$M>QFi
z)DZOu at v1c_ju*t!et)`61?&SL<H^J6>zUV!bXe$jD2^BS2MGPG5Zl7bT92h|N1+oT
zA4jT9VT$GI^#d^6Cthnc=R{_o+O8IH;Bs1i`=Yxpq|$`hfE^Qn=rh5Ub}nrbEVQ=4
zZgBk44iWIK-|F0z=%-H`{dluAG$E&QF7LYHb{4fMSdXEkjbz-5Ow0-Fu+emqz at u+l
zwSKfOe9X;+Utm3{!pMZB5c<x{i<$!2gD=O0eBNe{9=rra_QF<l{Ww%}<6l3K42=SF
zh at fohf=br5;EsR~H17D59XnQ+fj<l%AcW}_r7GA%8(aWBN%2i<FTb|pj9Ta=r<@$u
zc2WNUAu8o&!n~$N at q$bihbx6!4=(l?a at kL~vaiPqpERR8Duw{l!paMDkOu7necMzO
z_6xi#`}^^A#tU#ar|_GnbocYn6>Ss0F{F+=!c5jPD1bFb#Y;^Pz=TubnJg;SvzrZ-
zNQ;Og-T~V8(KKr>QmR2_4*lH0isG=3=q$?5w^MC>N9OANAm2sDC^gqTod-dsKoD?j
zpaSJ_*_Vd at r39H^NjmnDZ_pil!ssJfPUy<M>S;8W_E~>N#G|d^sz54V_u;hT#;I1-
zWXAsvSrQp^BDvd at A~#b~AV-)IB&kDXrYEt-_5l8yq!w`W5_fp5&0ziQFL%X1(Y=6D
zO(H-tC#sd!vSysnU<A~~|0$J7QDI$=_D6u->EmgT($^<E=sEkte)fkimAscj$PVmV
znp1#mAW6({1+v8+BG6D2*x|2%>6EML7XA!gnDr-3rT=s&s-K`xv?tY60NX)x3YxTP
zVFE>mC`Ik=H3{(smkbewBOb*4`gj|*=_MCv=!T#MKK$6jD4UZBorwOm%@Lc&FIryz
zWs;b^R<FVS^+Q^MzZ_auVvx8_a<_F!VfPqGVHdEBMv?#N7h+b>I*xre6<)j8zx)$o
zNSnAZ-?_s6->+B#;;<y at sQKT1Ar}0?gLkhso?n0A?GHAY0_(mK5cznkR^GI2koy9A
ze=W>mn}lo%;}Rsx+W-Go{%c46Ke@|TQ{tE>B9OGio at NN+zj`Jgm?r8F#|zMhBqL;f
z92Bn$s@&q|kl<Xrj`vJQ?Vygwh8}qUT{+YJ;i5>Z;^>`$e4`H1+D}nFmowlgxOjDd
zYW-~wEUBBR-BJzm+2MUdG}fN$G7Y3&ar8-R#9VYVcXv#WGdtQNx&t|c+sX%gCReRW
zJ2HIOm!z}9FHw4H{iH#_0rm2AuV4NjYe2;+{azT?I|>#6IZqT`d3>HJ4Q2yCSu2Ym
zuJiCXms)y(B0nA>VPTB8r|G>Tk2%_%GKB)v7WAMs*B-F6agf315QnNQuagr{N?rg^
zhvz)%EqbT+4 at Q5Ikho_o=j$__Sf{L0v>S)M)Ebn;4;I9djG-b!YAOEBy@=)|&A%i`
zy`6xMTO&ydvm6n-Jc8<i6J0B^^9aNm-)t1lYXL4UYtpAQLefkQeh#k^wdG+mo3fEj
z?NBWV5x&UXB$PC<*X)AL;eM0;jG!5~Sj<d22Q3N#d^1=i#+KqQy?_X3-Ps)3MHZm|
zkVV_@!e<ATjfi+)_1P6DbJ|yZC!|vHk?&8Wss>6qS_R+#CLT1cTu4+Dd^sf_aq1Z0
z!z^N5zbQtUzi#n at A?<OprZM0+dExs^&S*7MB`+5YW^SauF7m=EnE5AmfUq3H0(`hA
zQzqzO%%O7VXGfh`oq-Bft?=f0hC$Nvjq>lwcIB5cFD*^KH*Ny5mk7ihlL^?(#L&x{
zoFg!(k)r7a<KzvEl?~--zzbeQBWu?ph$9D$Gc<zBWhYD`k`Q}0J}b29Zh0;gtwQu8
zfwzz5fC${N$N=B1h at D^7t7K`sISW{5;$hoQM?!fHIz22eq&b#C9{mX#$JJ5boVmfS
zhhb(&{T at q>h2;_FNd>%1B0!U0rQW7t9B4|1Qh6fuAc^UCElmwzNe;^L70+I~ugV!D
z(ha!3;W<lK{m=gUpLhaAM?4tof0Qc!z#OT#C%UejA1mI)gs?8 at H&6Jy!4irvqX#Qm
zZl-%X2rlIqZ>-4Gcem`JD<ct3zyfb;;ifs^p9WK5AVI8&PQn>1%p&1K)WHtMcPpWE
ziTHB3#j+0xNii4e@}H(p6N7FWw_<XGnq|^E2nRW*egXq1er;E%8R426PJ{eh(Z9It
z>9&-?ZHbR2r8~$h00jVDSu%I`Mj at y4JLEh9ml#d(KuUHJUHkM0n4yCJ?w&shvlJ6=
z(`$096oZ=+hgf+kfiLIw=a#hx{&Xg~NuuCutuLD3Wgyubv1xb|zyUvrHDmw at eh^;@
zpuwn(WZx1?b;>gxT6V=@hHE1mwsuzpu)+Q-yNY#%Hj=ENkukvyy9fwtu$1CAjJNvw
zf2}1}2y9_1#%_~G?eCw^`F#K^tJD2gL^luf_CII-qo4K}hAN!##*C2xvDze at CqW<s
zxIPdhbMQQ>J_7~C(^|w7(E&_2 at h~EWs}iPq+@=8eXsTN!IfCt(gw}@yRD-TOUe03*
zFt9Iyoe)9PLYIV=b0H*J>=n0>OZ_S7nRN?DaR%SbSP5n&DIwI?^2xjnYAHMRLtQvs
z5CMBY11BQ%&77M)k1K=T4>V0P5!IYm?$6Ytqjbp6Ra;4XN_8Gu1j2z~EGrYJruxR-
zPfbtk+fZQWoi!m^wUjO|hG)@PbpR2^9Kz&2AxR#Lv<4tG;$(84M~w{$IJ1}b at Mwu>
z-mmz0DZ!Lum7ZT|6CTNdhX_$ApH>BoQjdz~Dy<R_tp(~RQ85o+e1fzuIz5QRX-uPf
z7;wg4eEQ&Qm>%T8ExKQqka-43iylOD(Sw~%_mFYZdeDiGx03){JVA9!e0jFp^xZ8o
z&c&bSN}-VW#Ovei8;BAS6Y{|kw#QK^ovnH;c?UZgn<_v-hOaE4$=U<Ju4a+{k)|xb
zdjK%N;X=)Z!3lvG1{V-jjR at fRYY__Ae&|h3f)PW$U&#PsqFNE{(D$LJMGC?a{Q5<4
zG#pIU#*Y6hY~15yI97||1$1LFhdczR?tD)BeOf0)%Gv`l#6g48!jQ!`J-;sZwyp<5
z+#TJq9i*9`{VSc7?uUo|F5WXH^Sd}sfd0i#WA$#`*3Hl<ngJx$?dqOP><;XCeALW`
z>V)h|y3=O~51~;plM9_I#pXHgS{1!w{n0*u^k=A`r&cU=ew8H%;4}lkETZ+k+u+j-
zv<8H+^t(gEfLNzfe;m6mDpiW8zN!egt}oD8EFhFN%lDa#XG^b5o?LPhzbTKpltsW}
zS0PM|v8oKo%}Yfc190e%S!C9nt2|H}>M>umq$9ca;|12)IcU=1F7f<1_BwL+i5%3D
zy?6txXN8qHV%wYRbP=7Rcz5jgGQ-K~pJUmPyA9|ZJ~TmgUs>ZLVkaWWDWBf!ISy=T
zPgl{#(0fhUIr+G=yZ7^1D)A5_01KRN{h8}*^}ynHoI(YMRRRw*&zVB at NC6bk4VVv@
zg%dXHnog=UZYrgS+AK$LA+k5DWIYkS8qM9OPL;%Iu~lfCd%2FpXl{2c0waLAjdUm0
zt)RDz|KRnL6*CQpK^LivnQy=XnC<iZ><HpP^YuIsJa)_u&Qg^;!Vp34B7@*j%cBu6
zyLnEXFz{NoTgCW+H??CUhj<e$BiU<bhC$pAHRE7ECu%xCCG9vEO5rhpF0W}{BQ2`w
zMaLxyJ)VD<r>kENSk4TfA)f<#YKn~ju53#9)!_2nPVUzapRrn+BQif1+>6JGxDoI~
zsQQ%pKG2FBnk^-%1;m6<%*@>7s!pnfnQ~)wu^JlyFaAn;_j8{MX!nHNgecG%XGRee
z%oOlnd~Lef{}|1}D6okE at i7;r<*^6Owvrn`BK2nY=3Pp<ihBr5z0*q>$ov_){X!E9
zO-Ao>&fH&#^8~c*7Znrvy!g4!bFWe=b6#YL8_*lY+1!oz8Oaf(bn at WJN=sAm<6>y&
zcZ~U3D*}QNA35aXZ^OzFb?2`8bUPP<H{EY;w#hhbd75*DojNI`c(I2s5LzTM&EiAi
z?{U3kuhl{GnVAZXp%$mUB!$ycNlNi!0ADf1nJxwk4=?=4;O@}-c~0t=lU3q}K27%1
zzCV+0nv}P8OlLdde*A5k7Qt6(aH*67v%^S>t-<;4&qy5u2o}xMF=Z2}qy3KMFbT48
z^tpkjcAWYZpg0$$|8Q{dVnwtl_z)A?y=PM#y4_$l$bPoiD}4a92=7xFHKKNVA#rTz
z4+3jOk$ClINiKT=!(#TH4*~9rLER$7fpG%iPHz1N(!vb6d%%_|r1cvo8qdhghsa82
zL2pkY9IyOPHZ{ji&)MPos?sCGX`;f`K~KbMEjc&sV<atqQJmdlGZu{gEqs~-{#T0A
z`ZXj%%1ZW;M`Wq6 at Y(;G^p|<Iko19d=Gp8Ab~fH$jsDqQGX<R^=dxTPmpYb{-#$?O
zcudq4I?Hbin*WwvMuw^HQDC at skcua`<`u at bI-p69v-p~kN6i`U;Ae-8m}L~F0|Ay8
zTq1T+0&)1AM~IdS3kS#t&UyB0$U1^pDI#vciKk^jy{txJGWQ?m-ebrJHTdL~b3yF)
z?q>v*9m994{GsLB`_$=YKiM?2gMGB;VY8GgCokL!=lKh_=>r8PYMjIdy>A at U8OtoE
z4g^khfIdL%mgUB8rStD0g2Bvbn3Z>2ui}_8nbheD=Lpc!GnEW at +~U^h{xl)5wncS_
z;E%+LMV}U%67$sg*aDxeWsVBsKG-9i+%3^Yv**4LLnuFL1 at aRLY#9o26B5Hk>g)~t
z`MKh2+1`ERX&;BbGuDAB;m#^}(J3p^3J3Xor`wP3h$U~XQ~iWRGw}J<0?Q%}PHA3k
zdpGX>(zVA<u`_pNX=s|RRa77Ru>0Kg3{_U%&onXzf_h<6RL=MZH at h~eyEA38^Yh>)
ztfV=yTc1?3=>D9d>$*prQ#y$wwErH*nLS5BVnY5=GCfSjd0bGulJf$~aVeZU=e at fZ
zI1ED0{NcFIa_{&pj=qxQDX%IQs~L~!(-XpO&nC2<RRPmU^ZS+?UNd{A^QK#xcE;n^
zR<#&DvF-VKkFqO?VO}7t$YsK)rmYY6Ot at zEfjzaAENw!Q8JZ==lXe9fY1e+xf4OJs
zIXharIIBx$)Hi=SFv3|SHF$mK<3n9MT6xB+%V^3rrXHUymzw{X>U7mFN`KcPX9fXD
zpX%wGtrW{Ai-ZVz8^==B!lO;2mE$i23=t1iuNYb9dJi;TiH^EW&Om&ho_A2gmn?mc
z275DYMfBsVIbP7Ocf?I4VCrd93N|)Cgv(s?kI3Nfi*hG4E|(JSecxzIJVzcT$wI)!
zOrKU<=rGise!cw8n-jHCB{>qc%XyVft}Bzn&2<)8ao-l8{EE*eE&ZX}LirRSJ)iD@
ziEM?J(cWL~?N9Txc%PsUel1yI|7CtWGnqrdDPsCZFMccxPe^nu-F26dL-oZ&gZBAi
z@!ub44U$DycB&-E+q9osuG;C5{7hyZx9^m-e(7YFME?oTv5q3V;Q4>}^-H}mFt#@~
zxpi`xvfnfDmGh6K{bR*Og9Y4CO&4;Tlw#^CK0fo#lV#%5J2Uh&s_S`^y@<pRt(gEf
ztM~dS`yiro)vT=%@ygVg(h_{vSB2A=yVL_jM^6p3=A<x9a<(mYWkNrM6hujUY>c!K
zd*)Mef?)!rCJaHQ!#$qCCJ2!>`5YTN?&<YfTqn!-bppLLHxSVlkL=ZYqbZp4G0yPI
zqgt4iypWhPc%y1g%I<N2MfKQ-Q|rl+iaKmv+o(wOk~4G!N{toYO;mkxQ4&s(xR&p9
zwIf%{9T at ss-d__NN&n^RK+D2+!twW`;R)0(5Qubt^?5U(H~GEs#ijS2=lU_ZKQ6=w
zXTNXQYl`d55|VTj?J~~2?ze}N1rfq6A#xz|mm$y}sAu#oVz1 at zY5@h8KhTfRisyBf
z)}@OR3zML~M at _h%46b8Rg9b+5F!JQ9tvc}+=xR!w{fe_ElkpYmXbTCLJMuNC at Cd0f
zJJ3H}`Y`RC#BF>R9-;eTYfxgcDY`}4T5Y*D2B<esN5#%WpIe(+RO2^PZhH5XC99|C
zTGzZ at Ovx*BsOHLvk at zn2fbk!k!O6$9(UJsLGEIVtH27g?rN(7{*DD}igG^KXHxqob
z9x#bEW;x($**lmWJML!%z)-_4(8?R`^hYvK(4-Z{;O=)9H#tWyQ6s>lD9!il<9u<Y
z-jl|wu5VlX?zl}4f01ZSIKl~&lxYP_lJSORJ1OQ)rVMZhEImw6uaPts<jYm5A%6iJ
zzOR at _>rD417+=Patkg>+{()H=BE;!1)y2&1QiZ8b!lu}e8Y(iUUF|>7WSRW{B<Z_*
zJkD2GxyCz3We)Vqk$v(G+?L`Qo=a2eIcgpfRc)Sp&`Ov)<e7P+NfGg#=K5S^YxkkJ
zDQMAB?;!fSV$yA)yV*G9O>B{NCDXNl%G&6fuD3o+eV>n?bt4VW6pRtijJ%)S11z`p
zxX92t!Oxj0=Np-h08es|JWk-efUoVcEdX(Qo`pQ>b6uQ at IsaO6xX{1GA&Wgli_dnX
zr?tdurSR2n#?7sR{i|h$x%Cuf=J<Go$GM|(zKPN)*w7?}aH at Q=p(zp<4lhr=`u-Q#
zM%y;&k&h;}A)?;`9q&xvZNj#3U4G3t!gYzaZ)RF1EBK&p*{`!tU=pfucJ(jC$Hxpl
z<#y2g$W4F0tB60wA)js}Z3&q1@^~MqO~`w?eO|hfs*mk1)G#&?p(@H?u at WKju<C@)
zfwaqXO at CTgOVnOnws{lobcBgIQ|Z}h7j`=5*VthVk_S8&$!OQ*ZdLf0p~}{L%qEQ=
zpLF&T#_qZ(U8TX^BonIltO2K3hOZSkjZun<Yq3F}*IOI)%$eBUeU0wXUpV%8*H0e)
z!sBV>b)5J3rKVqBf^}2`GA&v!Qvy|Y+{qE(3Z~1^Ep3T)oE~mI-<hn=T~AJ|c>P<1
za12a1RugEb9c*~j138o|C%dq>Sk{iIM-ME9oQbJU&*~q4neGsV_eV-4;S?RkHAJ$i
znDI1VUDK at Ua!zXIhmrWIFQs<iS&^BPHY7#Z*Pd6*pv39E)=2Y-B6(&qc;B2Ce1z~y
zy^%~W-0q){qOrv>HBFKq&Bg2!G~3gZKd1i3ZDC?8 at X)gxFUb;P#2o~A6<&S?JlKF{
zR<BW2s4bA_iuNWoMh&<gm>l!tE0*1PFM)fY at lCji=3XY!<4n>j%y}M-pX=_(7Nw))
zm-EZ(OdCfUE$v;EXzPffw0$r(^C2C64RJax)2_-u4K!GAacQPAKw+#l-mkk*$_TM#
z9=GeQkb0Rq1b!tMfphfDc)2Gc*=OwPZg at MaEH4F=A3lDzPFoCmKm*jwTQa}c=w??|
zyH~+r?>!1x-Kv at D*~?786%b=U0xrVd7^jR7F14?U+?ts$`k!?~#?-al>{e`*ZJ7KT
z%AFY3Gy^weZ+Wln_Qsc+F#UZJKgC~x#@3TjmnlZ_3bJ~8QxOJ0VEaPT1r+PKENvm)
zUynuA2{g0d^nDpc1En3i%3w6_5!I5;)@Rk<-1K{3YV_USGDofxMiqD6ye}q-7(9)V
z!<swf0V|F9U=#rfW$y8T$Xzg#JHsoP9QV`}tK`$Zul_VJqgrrL7GY=<z9z^zd_G<R
zadaBb!Mb!9lXcsG*$wPd48iib1 at YZ=cdl$ZemhBFCeRKf)67o at A9--Q3N>4F6gJy9
z4b~^IChZ)(v5$dC>Uho1nQ8X?m8ZI1OY>7tEpHA@=a at JD6p?5(y8P<0g20&FaX(%2
zTK!RA9AtxR#FOcf)>iNA>0VE8)KwZ=Pp_P=PtlWDiHj3&DlOEqDbVQ7J~*-M7&*c*
zN()aTM!QXmZ;6LfoyoP|A8}OE9W-#u(&V76E|uYpfKhGkz|-?DU`plTo`NEy%6$Xh
z(_$5rem-Uwzd~_ONLp2_m0Km@!H}8dvlGeO$7%m=3?AV%dgg~rC-!nPgVoLZr;9$C
z^HPk|1)2ci-mqIkGj0pC#AVh*V0C2fXmu6O8B(bZ77JQcG!$^KDMj(<6gVo#`Jf at _
zrX7WOyAGV<k8hRx)OTBjfVE*{TDV)4y^dzh9IdH^)9^mO^U~<i`%K|mV#`3p#p4&o
zLJo;ilS&ooY}l2g3*x~K+8f%w!5mJxb85w}&XRZzcb1g6gLOp)n^XH#*8BK=w`oYM
zJyM;naGWoc{q**ps#DzD7ZU;p^e*e}nRn?5gX~BOL&)lLxN}<rxvp at wj?dL39>qC7
zgD<9|Gt-H+Cz%{%_U%Zy_VK>*^E0>Y1*9n at 7Ol}Z?0A?r=@^b67vHF=)$?qxyFi}(
z7nJ>;JU{E(@|LM&_9uCB)(!Ow0q6U^MULn{bUpA$XL2IOygB_#a${rP<dr>b8gU0(
z-}cM~{(Yt$`1fFnx?<bIeX!fu*LyhBUWRmg4(zZ>;sKnu!n=kAbYKm0Z$3IAm!BOC
zv(RlJ%aVWeeMLQag!`W_wTViH3Z8 at 9mqE@%?@GRX(rcZ9M&c}|(KgQcMDf5Zr>x}_
z$k`gUW?M`v5fm-Vj0JwL25R)LFwtPx`ymZOfDJa3Tm3$z(bM}e4h5mW82rsbXu_Ri
z9IU}yYJ<Su4G}2=ludJ<O+>RCXdz}Jyd2E0wmds&ui-=%UTkke!`q*`c|l*tEIb>S
zYCn3|q?Mir&}*V~B%GboQ;OsxoGD&4^a?*tc+A_oK$fQmW=W at GEfXCap2BGmtqgFR
zf3Ww&FJK{f;O3D-mt~oAhPhSY^Ro$1 at ZD8+>dZEDA2SJ|vYVAN<&Jbe<Y;H_T(yNw
z*;buLC;F<KBA%5!;8aOCobGCZgea5sw1+ixm)~vuNJwF5Y**7!368=`iZ)$fsfod>
zs*RVED{`G07KltNk9%ceWmdGq0hm?30%6uaUv at UqabK3#%ryDO;M0R3GFrA=-8S4w
zE8Po@>OPfVx)fd8K{4kr9jHtCi3kQ(b$X>yzAsVR(RXY^ML&MDCz@`EpSKkeso}zO
zb&WMzzbyQzp(dwxZ%W1|!!f4hDCrQVIs{sT=%4qY0%rAPX+*Cszj*|MhEIK)nRp=W
zM}OXbpWrXZx<8^}Jy!+>p9|nSev9B83WdF{v)7#(Y#1q29eYJ=2xSKC{Zd|#(HmwC
zL}Y{tbdM at 5Zj9Pg=8dQdtYo(`zg8TQ#uYmZUEV9^Y#sOUT2zYg2f>f`RZOd+v3s~w
z%S?sp#Cf6#ibd!=Qo!Y2J+bglAt#2pHT?7K%m2Ws+RN}lB{5(RuV#H3Q!u*{J;nDU
z8M_Xh)`l9kZ=CAD`kSl{kmjxKC?g==WgRirw6|sGik=(JSVXzzEgfHeKZ|JfwYclF
zPfMJCU%QfR-YltB5hbp5XV+fa>P$m1n*!(OQ;A%%vp^P7-dh<SoJO8aSv2$u0vN|P
zDWJoXC!P-IfFw at mI}8=JT5GOOCq_s9SMCn%@BuHp)CE|6?_f+2i?lhFV&a at gkwUnT
zW9iA9>oJjul0{MCZs!V|KlChiEZ-IF_aWLRWX|Dx!1k_z+#xV`AtW{vmhKS8xIAN9
z`VIAbE?~5eG@<G@@jLozjFloH;U$_zef1UU?vr*q!JZKTyxL!0A05oMmjF2##l?!Y
ze4Px-v}|vgifMshm<x?%%v4K{_)LiON=?N0kNcF)`^w!;X*0>6-B at R8S%1vziQIZ~
zKg~5=#a5kXXWT^Z1;?f~{kq(F0Zi`I_rxff9sD at w<aZO0^V~z8ODS_cT3Kd2-`y$b
zO}l2GK4+)RR<jq)V74EqmHzsemwR6!%GMfwPrZ8Y at _t8;H%*)-2OMv&M7|)1fQD>8
zOTWVcN-ER0xCc94si#<H{EW&r{Ia{rK}GmfOm9~)<h^O<4_tbcZPEG_f|RlRL-`eC
z>=9l0yG|5wM{{0{(Df5_8V!L6mM#7_?t%=7a1qc94R@;Rd4z_zCJ}CG5;derTz at rN
zp_8x^uQJvR`atuJ3g2ktsd+mL;{{}zdLoR>S_mrHBVLEFxa4%tO!u`jl$>tVZL)N^
z)s&)VMc at mnOsVCl8NV`#N_~?h3_3Qfj+TsJkjpf=?@!4jQue2(JUF{ZUm83gveOUd
zN{HJ|TsjwUfYbG at 42h5YIh*~jv!w3rP9C`bC~XPGXIyB{cj%rMtEu8wm;xr(lw2Wc
zzPlz?j`vH5U}lHmXQsQ8`>eHpdl|cf<7NxvVZQ6<b#O)-T<F&e<x(5&yA(I|^si#4
z)&+QhGeZIk62`?8Oq^I+e%SQ8`nSIX^k*UPJa?U8nBt`*I};(F+Q+dGrBJ#2L2+PY
z`2~qw$M&|k^TEILR_31+LINhaTpBkAIsflFVu at ea^GoM+yp5F!3{cgnn4lf__*BBz
zp<=(1J`oegB^A at dI0H?E_CHYtQ{R-L=ZG#hbnB*Flg<MY*6V<bB<k&ZmTFqZhMdg)
z8xC)863rPiICsR#P`Mf~T>RZhm{ZRmd(Qt6Ozi%cse;qevddD3P}e^72iOAf;jRR}
z!tpcmQ|aK#uiMqq6|z0cCB9;4W_00^=$x6+mMrdJDoKl^Z%xb}p~Ax{bHGMQ+rMeY
z;Cc4Q!#E}3sF)lItJZ9V%*3k#(j>X9AkOl0CufG6X|v4~%Bd9|vW<Pk(W+V{I+kli
zIJtPdF2Vsj^tsmef-8lERSqQrx6hV%E}4svG4(6CX)^HXwjE6nKP?zI0>edF>JpWn
z08~;1(dZYdNx3h=b2oc5PTwf9^tnXLJ>j<Cvp}<$Qsm!otmR<l{5}fx$s)S)A(={`
zEaC`{V%7Grtb at TEoHbDkmOd{`aX5Nj&F|RV&_;VD=}Ja|R_JpV+*bn#oR1q-Fy4z-
z&rtDfyZF&Y?Bby%?fZ#`_elj9hr2XA<-dBf5U>EYpe^nZn>pyk at VfrKQ1{Y)q@`iX
z0ogtot?Tc~P4i<x5Oj$t517<_5iqI7fb+}_d^2H{{)KKcmRAZK-?)P=&3 at vUImS-m
zi6%_g<WvQY>9t>x at N|+EkwvLKgDTf0Pnd^V?BP~Z#hPfht0-8uq<nH|0zx0 at mbl0i
z;ame at tGh3i>DR`3!#>$cmqz3U at _X$;htCW<H_<mF-am~R?fqPfOy~vhzImS~q2^B_
zJ=02RSw2!S7ql0s)5-A at WQ?$tVQm>SLudvp0r(J<VTYa&H8zn!0sZ9-CMYsV;2S;6
zD1|E50mmh<T!iwJ{g at x`ZtD!$w0<_MJW- at ZkRYS+-BCnAKoSx@M?{jd!~F=ch{ff|
zf~6~#M4pQv(a1Lee4cz(uzowkx-3fxL%KyMzc??2k(1!rU1HU*^}b~u>yZjMJMX;y
zJr1o(&;aP2$GE${K1l^5VLW*X1$20ID#!I}MF=Y_78>6Z#>FO|Fp0i1FZ_5|InTBy
ztaZ0}@Bl@`aPO at _Hz2{hX7=QKBuy^l&hZnRvX<lpC5tZVyd`0~Xx at iPb69Y_&b`*t
zE4a5ud|C39{L)D$3c`x$2%C{RdYvVnE2H=AQ{@Mr-%a7R`^_3XHiE`$>K|<+me*au
zywS|U?~Sqk;PAfa^3>9!!D~lrZ?zZ^Us9aveQ{_*9m+l_B^?ny%PgwXW=?|Tp^;T%
zZk_x_5vJ??{1A+o-*FBH>7!WuuQi0}K2st~U4DDYD3epLW_20qnEhx%&aG)~4X^ZN
z2JXu|`mTfYCW)=L0Kah58rmEa+$Ab3nvYqW^|4fBVE!{2*x733O7iK~qt}pnb2X|6
z3wk0n_}OSjQ7KB*)+|*sJ9ZX(#9G?%kegYHN2m+b$yZfr2+`H0rxB-5<f!xUJmym4
zx|pOKk7;<RHqxze^hJMP{`tt=D&Z4+!}MjNa0D?Db$@b1pH>NWncAB4SzWHLTAE+3
zyfbz*$0x4u#K5xr at g(;)Tu6uuVS4a8*(2+^q)Qx2^Q%m##1_)0T at -i<ywo>d-dp6=
z1O2sp{u=%Pq6A at uS>Wh<|LuM at rGm$E7uSg=Qg$o7DSS13ILmj0tOhSX5l(zu>}RN(
z5KEZ4c1454U*PRGjmtC&Mb}&x&S`(H8fmJhz)ip9?tx(jK!k|1JVzoa3LTL at H6?07
z1*mcc8Z1<d4{NIDPC2an<V_%fLGuaj;tCn#AklX{i_MN&d6<7QjcrNxbTmu8%Jl1~
znsmFM^xeGb$Bz`Wp<Mk3 at U36(u}3kgFL`>d7`=CT(kdwmg(GQ|L-DcwLv`93PXd at k
z6AbLk2{!h=>;jm=D=r$%oP>*<`mT!~LkfgjiXI4gWi|HgA*~T>siC)PwZ=*tTq!C2
z%8ApjJ^Ml1ZthRdh`z~uw?wnFk2FrSm6IW<b$T+3R^j)J1%*J#@K!OLhy3T`IImM3
z%880h;pOvCSG%8cKdh<FLLuVRB_O2b29%H7HC>4ox=BHIAf}csa5l*U56kbo_#W4&
zVUphD+lK0U)jV*<3s7SWQgzq;W#xT-iW%poL1H106!oVnV92F8{kk;CQk~?2K#pVK
z$EvYT^SM!5QO9{)&2Od(9b!wrkK#&vZ3D~?Mb2S-DVcsI`_lc50i{R{C%C}1tRe;f
zoox`WBVwP$9}W7j>$aAD=jSfzyXKN9O1^l^t93`KuvB2=H*_T#(}!6qQ|<|S{Do{^
z$h{nr7sLz3RZ+Z43o{JCT4F!iFP<2QfAyASq$ufaiV3mJF3az2fB4u+tjA41tazH2
zP|EkmH(kt~xgs?yM&9oo+u}0~=@_yF&o3D!ZBz=nj-nUCiBqPg;@@5iW?>zjkJ0%J
zIL_T33Nl)gQ=+!N%1jsnZwLo7NF-1F)H&a2pd|MDRzJpBr0iP$eb0jfrS5Epvf7}g
zeu?T`c!|fLph-0|q}%)vtL2>W=f$?FF+DzyQ4V*OP8~}UMH1qM0>MX9x;5nKW+&}>
z<(pHl`h;a(x6z4nxN%}L_Qyu-;m^7Ah_%&CSkHt8KZ;&fEx^2efQX!)5GQzpzWOa~
zrLS$hmq=Ljfa%_9yq<TVX$GH(QRdHjALBQ|X9R&_e`HJJl1Ou0OXGHtp-FRiwB}T;
zY)phHkix^}+4bGg(IYwM22Rb0_ocL9_4FqVlCSJ9el_grZ_9VMfm*G}4nWj at RVSh)
zMc4_ at IzLOtf4nDHm>%KQPnf$I8K9P`D0os_pFr+04`- at pChcPVG8hM9*O^fZz0Z<9
z_RCEMm-Fohyvc@%?8hq%>6m1zCm&OW>DJ*fF$x5E)GiLT7dYjNo%N_Pdf9)Yg-}(8
zB&WXWHH6i~?<nHJh8+)`vSzl1vNK((Af9pSH=qwC$#)zvBT1F}#n|8F1SuEtVemVe
z3-n1A>|HI~0ZMl at Cou)juBOuST*Di!lhG-GKR^0ukuc3*Bn;{?5-Ttp>yLNdslHjJ
z-Hrsu<R^y~PHL4DL{LUjS_&JMJw){igKv=*qqAi8qixN_mkpSF-X)3uR%DlPEVO;?
zyB at zEWMH(pYuZIR at jg0oE*7~&m&n5OGwPFdT8}P3hVl#O8KwqTo{%E^-U2BowD1^V
zgyw*VwFeA8{fYi~$PGvfyuo&8zL~o|<yDCj>;dFpkVzdj?rbGEg}#?WvY*d=6QnAb
zj&5|X=sn}J2nuj|1z-Tz+{$p6xRI<B at finPuP)`XDW5qX9c?vTWkHI|gkVZ$f^hA@
zc(!OWx0uhieUdQ?Q;-sDtum{$c{6sFHkXdpKI5^=P@~uiF6OLTI at AM1CQmocq%T`^
z7VFes8S(Mz`5KxLSo!hYEoJLp7Bb79RT33Lp)%C_%=}q6CL8s~UhTUb{vydn!2ec9
zQgDFo{EwDWfid#_Fs2Nn%H1c*5<ON1-8A$T=C#MTgg+LNWRf_ID at lYGDhv4E3m|_k
z?dEgCjCSXSC;5;FpHJE;#e;sBvjDlwpfm6&cA9!?t}JRSc6dtQd~amvPF5diOsX(o
zvMfl#B at 7Um)xWs9qMYS#GSm<q-uo&*RUr3O(xq$X19vAWrc^fhk?kR5A?yEmyr}<z
z<Ys6!9<W0=y~vKoglyy1tGC<o4~7v`^3{uBx7K%g!`I#XZx_((H+KlrXKn^Gn-TJQ
ztjzoXqECJf`AwheZw$Tm6FddheCz<Z=FQEkZg~RqJL+=~KrrrML!tKnJOTQhvkc at u
zoC1h=|GwM59)pzi;;9OOtyg$>46En0q?RE6lx3*#O|V64_Ls?lI;Pe?FcIVHvCjv(
zPw5#SaQuE1)p-zWYY$*2oOB*P-TDAs3h3>{j%M!Mv|;D5f;SpvQ3M8=uS+8<02rZd
zu=OFKdJNf>@;em!<1RiwbLq|dGuy7igs1H1+^12!do!`qM-&AqtrtGu)2>;xWS$2e
z&sYt01DB1zqdgo4{GK`00Ycp0Wf at -~60+)uP`(c!n#1u^D#BaWD-JEAnRXK0#=~Nm
zDY5fYL!Z+wPrix(kZlcL#iMPH1sxjAQNnu!{%&p;<fK9%AsA1H$a5ZDexn&5XUQeK
zDN>NQtKZ50-N4KviRtfch_O)Hy_dl7RLBBX at k~OG^1vzT_bopdc$MSsMnF4lZHzQI
zC#05UZ-?FAy2VkDg&i4qf3|x=X0UCv)d!m)6`$#qmoqbbZ0qaYq6N-^Q*;Ucx0Jy9
zXB$%zQT*Rh!VXEgh at EvCx7&P!jrS8{g{;pB-<x-~=2EvlF)2L7Lng)Bo0+a{e?;Gk
zqJejMdRFr6|9O*lP!*s|d?&DVueXVF6)APubj9=Nf3|McUm<{>eh`ux`l?(-^^k49
z-}tY$F?_(S_hL2m|8*0rHU7WL728*%^aOlB+>XP9^#8gE23nVzf2f9SCZhiREM5OA
zUmFX(zBtSgpggR(wxol$Ed-o_2bil>nYUm+y!nV8^XVOh;j#gIt%|W5&K1_2_Isg=
zUG~WC1)q(*(17PEq=ty^AMB;rbN7}n{pVK5hVDp`Rz4zEw6SO#U*CL<^EA;ij>?Ql
zgxI#-9D2otkh5jWal{o#Grz}2xzIuY!=hr-ML9Uj=V2s|%9$z`Z|^6B0Lj8bF|9={
zU=}$6%|wu*&d0>u@`x6HzGKyRuHLhm#afn`n(?Y*f=>1@^#XSF0WjHQ^5H at XkmO^7
zycFe#W};%GVW~HsaxQ;U+*uB>@sQH$=V#+ at G$p4yjdffsfbn*w1I-!6{lZk+UK7hf
zq|1^e8=}m!wm+DBqKc13`$-F7Hscw|VTdW4 at h<B*{~)^gec&{+IUgGqC6eybasPsZ
z(5^R4uhjWainJf|76s3L_l=nzRyWNgjb}|POm|oBVS%K2c2TlVcp-p|E%e7>{NPT-
zpAz7~odW(`!#}^i90&hU7=n5WEs6PlR#b_P_gYzwvK00In+Sw^Si#AdZu}iBxV9y-
zfd|EZ!C;$ExW1-8fIPm!*hpy=K}f{z`G?S*9c2nz$rr%MpvqbT-z^9jSLH!v(cwN3
zY<uR?^Pm}mcdb`tWHY>{RUuk^2{_~v&v|n!S{sRXgrBrJh`zSS0s5QB1=8ZbAWJ|l
z==JHrUgad^BQD@*ovm};e%fwrQwDKYqG3mboW>y!ZJOi$j*Ptw3J<@)uYLq`Hjh`n
zxoSrmr`QF(N!gsXP&hR_Y1>tbS7WMx69 at vM5@-3o9#!r)#jhA?$D#K!-K(;`c$D91
zR6FVN8=M&MNk7-g15~;>-!Sx92?_X<kQxS;0#@-z%l-nr63^%DwH+-jqHg0|Z=air
zZP`57#+z`geReO(tnMgtB|Z=Ude^^FR{~~PyMi9j<6lrY0J3h6cOSVBmnUdWiJc_3
zAM4P8 at PrNW_&NJKbF7}3oE|Z%#C-uNt?gvazPt6Yqv+tVo6nwozbZB9YWf|8F3K53
z3NFAyd8PnC at muZ5Azh?nvX6?oj0nr6_VRA8?-&HrCQj^1QRZ&ORQrW^&^v9e1h`18
z at Yr?>vl%n1zcr<I20+~}m?Qo0qaQ;n?~SS(BiJQy80Ee^I#SoRPsrEXiBLdk5z-lP
zmhJi3m!N?0801^F{4wu!@S!_QIkx!{*ax6;zmbaWU$t~)f>>08h!k-^*>}p3{N7SX
zE#5X!GzTB<ZY6_+ at wWpmkZ|Dn3=~N$fI|;~bXIv;5bHl%ognN1*uTj4B+qnK*IG8P
z6tEjd!E<;7X{c6;gD$^<{(x|Q0U3#dob`Yyp_XK+3_eammv0#jVaaX~bsT=^IMQ-Y
zcd<FwCN^;T)>?{neOWN+pyS!)9=Wca&NB8?`vGOqux{X$XT;TkPP|g=o(C|3Rq<fH
zcrhCAK{0c`COSUyUwuayE~-`c`{K5PodehFYy53wwJLA5hsU8U_B at nYu8+3mIr@FP
zPZx};e*$EHbx}~^{=N%;nE}Cs%rROdvJHQLAnpr5 at mNGKgAiLUmG}(fZINYCsUu)|
zx!BfIbIc-G2uqX)n^O4D$Xb)zAWY4=-yx0fhNJ?+?22v4x>5e_Ho3G)0AYF9F$42a
zb0&_^Z7yUpA6#-F at R-}G_&sF9dM?eMhfGZmtaG*&5BMIt4vJ|2jOZ{p_;RaH+{_*A
zgBjF+2%pLj&AVPspZDX={$cMVtsKkB4kqKOt?Pk-pq*vy>@Z7Wp*SWB`QkVT!k^=C
z0;bp8t~w2WKej5S4|6e)P`?hMR||4>@j5EHRYtxcc(J9P1n(pYH8JBpo9ij7cY*bV
zu&H^H_>lWJw*49uV1GfY(Gw`=$wJPfu70PG4`!4MTvi!an<Hv3RntUQfUUK>WM#=p
z^x+`X5$yoter}6mE=Sj&!!w#$y}mN*I3&``VA9%AcsO#4E`ZBs6r~o}5A0r5kFt at a
zfZgGN0}*^s-1U~wakF|3Hycx+VfnYpSb?hT^vW^AHTzP_!w<@QKS%g!4_A|NAQpPv
zKLLFuC)QTtAhy_J;cLay6Fq<uN#EZFfqtfWv$DN+gT(SItGK^D_qJ2547P-`C*Brm
zYpnV1Szs!Shm3rTc=F2p5MRL!ihTm9MX3|h72gs(jP$6-{ZO<jJ<;Ga(jr*@>&JWF
z*0yHw2ozU^=I>IJJ_BvB<kDs$h(r*BBZ4B^HG*pp*HKtpal at Kf4qpi6x}ESFzHywp
zy2Q&1Ij*X&HEM)@L9OQra0Y1FcQq8b%@}3dnE&;2;p0CMZr~&n_iC-<*UeH;facV%
z;lh6)%x%$WEG*OmEQh3vi{0Cs9#W-z_>djQcDjIIDbLxUZ0;v?<RRsUEioDh7&I-F
zO?MuP{kW#uc2{Q-g28)SXiA3Mil>4%9)q<KRCuF*0z#!glw`i%Rf_!scH}E0;VfTO
zPhwCXgyaDBXHvMs>gKQi!@LCRP-pdxe)U9)9i_I6&V}K~7l94xL>?SG at eWrU1o$pQ
z0x3nk-- at 9gekRzV^s)k3h*N1}wfw;?3fSA59mLD+Pii&C>SoE4J=iDsb^2Y at DVu9A
z$O6Tu!zv<0)nBTotXfg(@jz6Dl$vN$0xX!KaL=CB at rGCG<sglo)m;yln^`rt1Og!E
zpnZ!Bz8zdev)!Wk4(bjHiJC3h7Tm2lRylG=AEsOXIOEcVC3*My?O|{X!!Zzhn~x2{
zLGZ<$)-T=BD(co-@$}!qJBAjw<JfcQ4ZG13st#ro at +!XBi@=iiWpQpI9!}WW_g2XF
zKoK0GI5w-|xdc>fAFT%6-UE92`VRG#L%P#{g^bw`owwg_uQ#o(b{i3N*f4<b`lGy9
zI_TX3YgEOCCdp8kCiC6ndM}H&cM1`zu$MpKdjf+h1Tzo8?C=MwNy;B7`}g6>wmB{1
zx8Ou59U$Jf>J~n<!~$)@`{{R$D{pO~;!_?Y?H8vQDf0F_SaK{6J%?^#?t=ru%AW$5
zxB>5!?KTf>EI>4&{jN0mihEnL;9q~pYbUHopG|DT>WbLxG(ooWjd)s?O!i~5hL>L=
zgzXU2BQWFgWpK_U$W1&KLHU*WpX^|4 at rUxqSIY611V!6b+XTqj39nryt12IZBNQNU
zjK2^nWp|B44)QI4H$9>Z2-U8`%dFlQ%AFw`m)>~_A at 5l^-S9j&vRg^&DN(2^PnhE!
zP}^_16J0>z)g1mpF?@pyphM(fCNT<Bn2GR_d4%%p{ptL+Ow-`@cTfi6g;I8qNs1iG
zwNUS=E)dLgnuf`;3=xK7jn!DazRGZhfBA;8DG-6c_`}r&!U~W>BV*0<yMuyeswU--
zs(Z3-rVg!rjhW-(OI6OA#X0bg=tq*?T>t&^qb>B!@Kc*p-&<K-(6xW!u0Sk~d)s_q
zRROsYLMswg9(c#`U_8^Io?TD_Y_xJvllTX`5jiE+ at 9@O4nq2^SNH5BOxkfG3o?-yR
zal~jaF+SdA^#;J_j68iKdo^VPMh|F(Ww_LndEWa{QCa*3rSQ0?{D~Zxsxxces?=@{
zo&3xP`%fwYQ~wc!?iu+B*pVliS!TyD=7+_4w=DNVDOm3FAL6)Hk9ft-MX*S<Nh<89
z`hFd(NcJ&0F4c!1<6i)W&ko=LS)=`BjWn3j9DJOyo}KYYs}8YDDiP8+O5!A+GuuTZ
z3q(X^NN!~99PSP~e*J#sZE;9IR?|Zv-JC!P71<QJkpxkvV4fboE;TU<j-Wi?!_8hj
z6?IBhP0`hvpB$jI%Gyjyu3qaBxNZUX_oP=(VIlW85T(jJIjV!gm=Ktn*C;dz9b&=I
z7obi|vF|Vx?58ceP4~ibD at Oz1Zkh%1)|F>QN}!4~ydxdVA^F-vYzpCFCD_V8JV|7$
zVpoX|j%rR(s-Qj-56m0&rQip^tiY+&&BxRdp}J-;o5G{FJ|uDohp}|XYcUOF5O;Be
z+goq}$a3Q#Vs2rCQt(&*r?=C7s8InpWo at B_%gTHKrn~MzrBi7YKa`;=Ze!o)zXN}n
zwjc0qOtRVMgV~;cf-15KAUI4CecAr}y(s*&dpF1j^`SL9d7KvX5}pPV>M;IEe-${$
zXU_C12nkf2R<!%vpBR^U63PP{w|CN|hp#{etOr;pA1^O0Bo+vp|3y_Jv=&@7)HgH|
zdAR8+2%J^>;u7nXJlptoNhaqJa5X}}9LuF$`<QN**vt(I+P at U4DOdEpn}JeW#=f)}
zQt)#|5+)qzM64fhUAXGV$JjIBt9wVeySgv~J{1Z8aW;V^VCK%s8ObrJVOfg>FbPDE
z>*uITP!N5=J`Hx74~3oL*(cghXa5Bwczf%CT3(nctFeT&WtJfvEt=6y(km%;hdC{d
zfgl;Y2A=~$gIHxQz}dBv!nVVnl#ro%wXS)ccC+U4@`6<!fYYT&VsxOQ(dp<ry=v^&
z9{QmToRGZ|gaWH;&Kyw+u&{X7slh+sE8jLkl*B^(_23j#3#=MXUAh;lNslTbgjMFJ
zNA{cjgu1Oo)CvfP at 2c~$Zl>W{EZ}1Wn19&4b~@-0%|@JVk!w1r#)2M*V!lG0#|GWj
z_ks5Fn5iX2IEtHh(^fAoBL at x;wcjsiT6LZtXv at nGxX~!zn5+}7(eoOlW at E820Vu)=
zBB-=PZ{tZFcG4=U{`D0V#CCVl4)J%0I%|dtS*&Y~S%qkDk&XjMWdP*;#Q>n5vhy;0
zDfZL<OMj9gC%lkcWi4jl83!3Ehap?cehhrsT1PL%+<I_OToa(84xHe^;<VoP!aHN@
zNhe3!wI1_aVR0C0%-a9G$SuddzgiMtL`R33Qj{vsZOLJRbwdbcB9b5-<cu%!q=G~w
z=@eum{rJ2+7p#cI(cy5*e9m<-$tG0=94fd1tl*Vsm^^_VCJTsmNYdjs<qj4FBMBQx
zq!6~MTOYFFQT(ibsU`<7KK&exLT8&A=5Hu=M?~eTfdfRKd-0g4FnqlYNh+U(^db3M
zo2(;R<L9#fq-BMC?02rsmEM7W5JkW>1ZOkQyPDIJc3fV0wz9~c8P2Pj31<-|R5h;4
zNAuB(vF9k}09Ykm$4yjzi;UKM%v>QwYHJ1)y8=rbu8xmxfYBtfkIsMwaMVOeThI<(
zz<o-4G>!HGXw2FcdLfkTahC3a3iqQf at 0^wd7-ghjnb$*KgJ%WWc{tRlmU2S_!D=37
zgWWTjG)FMtGF~hgr}JQsdVmmse8d^_q9H_mwcydOKW-jZbT<)?cJ4)i9@$jLhMfb$
zV@^^`q1Y|4<@NJ8;GztHA`2*+0Z9=^NZ3LrMj6Z`H_y?Ilcm{v-0&{y5ddZRq_;6u
z7#^s!6<@>?9VTg#+x3v?Sq;pjNJ_!zyvo_HH1zkRP|F5^#oqH)nHSyC`+G+t#eSg>
z0Jq&ag~GB#1l-?n0#9jl!TiNNOiEqQ!a`Arh8S9m4nx)O&bH%+)rOpHB)1H13F+rr
z9uyI{i7tZIW|E_wYkhU^DeGwYr^lrgC6*=ya_&^34D|9IXW%8i-uU{8a+aA|0Rc2k
zW at tnEa124WWoL2wGg0YRt4Ct(!S9|08*;$p^{TXW at uZqHaGAE{ra=HG{`~eN#CzpE
z(A2+c-SS}U at zFFx2qYM4!O^JR2~J4*2n3WpTTN;i%r9xqvkqyNL5fZRzok1LvNwO0
z7sh<EUx;TUDulCv-?n+pVSKQ5p-)d3w^UuxS%AF=flOI5o*jfzbZ)m_uO%N>^@VpJ
zBmx%t^=nko#=OG6(fB$D%3)t&3ds>L7O9o>ZQonS3m^ljYauj(41zm5^=O8}hr2XF
zp}~~Va$BUASqnMILqXR|&{+^5+qL)jhiS?P5eG99zd1LGJ4WO1b$EPEeAk?E2zJjp
z6}W?YYYTm<cPZl_n(l}*_qniT_s1W>k>X>bXhBOkE2|FzQv3SKiGlj0;NjMss%-6v
z+ at o6A!_i{Nr(2HTP>?Zu0foN7D1ZmI;0z47w0}{Q`+{I-+hU^Djb?j+W`?!JgfKG$
z`{+wByKnY)fE}*}VUPt}Q!zX6lju-$m>A$4Vz5K7d#(O3X3 at zOVv80$$C<ItXD!4R
zMYkLYQ)HCcOoUL1+R&#IiZbz#VXA$8mZTYUUwb at QjIStH1@GIO>NiXPU+t1x?SQf&
z6LB17G+TkNP2bLV$h%-`Hg at qSlq<$$9!?`4&U81Uux%X0U4)~1&U+fV=#N953KE8z
z8`1G`){E%$i8-hCM+c&!r at uy#YnHanM>@x at b`0~wr+3oS;PqE`1pax1x^c+vsv^-a
z%qRu6!FW*DNbNPJ8Tht0pbQNtpkF|2QP!(t+=;%ax3hni2q#(qvi5wMijlum_W{Hc
zMkbmpRFKIEEgO982UlBH#Fz^32 at Ti`h>)Be!Uq>EM`12V_J*EI58eJ*MhQ>%7dSYC
z8jw$77c{FUT|XY)IfUR8a*0H}g>-N{9L#JRZuR64Ildy*e5bJ}YXgVqPMA_5`os0b
z#;YLVGXY7I;r?igv_>EykQ)e!&Z<LH^3!Yz&KC<*;ex`gimyOKVKh`-nnj#?2-v`L
z2Mv#)C4n5MfK^A^^fyZYmz#8>v<Fkz3=AjOso>Xx^`t5U57`!6w$JJN%D1`;4>AAL
zWsF`>d7nqt at b2sCi$~FDWSNC(L(5gV*NSJ&+r8v;T!$ge=9ljQW;kCPdW<2|eOE1l
zJ7ZW8cI>&X$Md~wIo$C=@7`~XW49sQqS9OSj1K`&E5lE=>Q6#fUc96a at uji%0G2l6
zvmM+CX^7hh%AgE@?-xzRl3Vum=bqU`>J$Ctq#3par?~Z3BOkm#GLvdoNc53pnE_T(
z84zhc2|ZrvfSay4*w#{hRKuS7Gx&vaaNc}^*HHak26#o~=Ol&%9aK{zz{#7=IF0j*
za&`I!ogeht4a<6k&S?=4o{%VXZ!JKdr+2<r&vKqVUId<rIT(LmMA at Majnh&Wjvcpb
zI~7hYYDJCCz0hYN$zl0}m$H!)b67nZ at T<pNCrxS!tiUn3&J9Pess}-RPI;$vL<URT
zeM4t*pQcWjEsr8zXv at p~L8%3jcPj9!(iD8$d^gJKx4Mr6z3~y~<%8q`LuL3pkT7To
zS+p1$t0yT-qjVc|{Cz1oRkf<Y)1|r~v7D2aG3Avi2Cbkdmo0kmjJ4+Y3W&B;pD#D=
z+Aa6yABI~BVGrf;Yz^5}g7cB+>>_)uTh!7k(GGcY19Ab<n$)XjIkmE1>li_ at 4Jogh
zfw!RNsa&AjAx=Bbb~UC)23Z*kmDn#ZkHtV at V#*Rs+;o|e#L{7i?b6*|7iIcLllbq_
z9p9x`zM$vk0J;t5-t2P8`EL#3p**%~AShB^aS$o#<A<Zgf50K6vl+r&`vuK^sp5T_
z+2)-4h0IfjR9~w8KkU8tKh^*LKOPxLsF09Ri4Ynnn at aYc*&=(-kd>BXg^27ed#{6%
z?0M{CRrV~-A^UTC^qjBv<@LH;zJI{?mo75Sd7Q`NK5qBxy2*eKlO5)5ur at L2?+I!e
z-Jo!D+|<h)CW&CF38-scg4{zFbfPSP9Tiw4392siBnMp4ujcK0(D4VM at O#2BbK?<t
zy$%YFLRN&eV+eVGX#TV4UBHIYx>kS4s8a{Khg(=d55XT8({!%i=9j^sgji3Ggp>dR
zp8Lft2^#l_k*(p+DSQ)N(gkhIh^&mR{;-9Aq53?yPeN40`Nx^y;>#6Wfc!3Uzj=?3
zK at dmr<83F)-V{ka-2ujt>GqJIkl&Z{$17eq)^kw^|6~dBfD4Z2-Y>aVI)~|s7c#MX
z0CGPY#(qGan`^m$+k=ixKW_jI#|o|3R8j$_>}ZGv;`-0412Pr+7p2=k0Xs2Q0(1E)
z23b~+hID&{aiyn_&%%5ZA1rIeV-hyD`94yT5n4h=Yre4lQzty;XfO&D6>;FD2kELV
za>!Z-B!=y253&V`c)8tnExeAbp5kuDEfSXR$}*p1Zj!#>_pdcoSsZ?dcbXM>fD>n6
z39Us)E*Z--a;)?p+cI-O1B54;Y?#i)pXoMX!2Sel at k?`!!GCSqNq$ga;j_pi_Z|+^
zV5wm(djaa at _B3$IPK+D>VLb at b^ryXH#^QQ%3TS~gSbZZ0y^T!%THB8RunQk%#6u4`
z48l-GEXy#pqOd5mUY5>H!r%A9osgG78jzxCNX}B^_;k3}eb at pzigduCWb&fh{(kxd
zPO^R<8J!m$N=o4QTjQ+=#J^%LPYHYQd5DLM4mtg?NQ&2!zG3)0_?!V0RN3y7mmZq`
zqrw+&aK}$O^K<-s>PM*LgYcn`c^H(n88$=Fz$pXHqjY~?{rAL~vh_#s4M5rxi|=t8
z)M~@_8&kZK{f|+Oc^4^Z4zHO}0Prz~4+B|2PN^I?opw;EJ<gZh`29S;ok9?fJ?JX?
z+I%2u$OCG*hy7V9Dm>j!{<%fRrm2~w+ziNm<DQIE7Q=<f7UWB&(a`Ndmm3TtyYBF3
z?J80XQOgR-Ovsb>>n1=de;5qqh&F$-ezsH5j9ss?@XGz-yE({N(<+<v?`Z><YH%Se
zexLZA2voLAq{yiY_~M1M<&V%0hl8$gaH{M;4A!&=Ri3Cn=6q%YcqnL(TUZ<Eq61h`
z|2!0hz0S${TgNHR?2a%+T}5U}a0l%15dsXz!7t;>03dTyl at 3n10-o?KKj=>d<S<k>
z5~wn*d_CHmkQNp{4S6#!y}UL50Yh3K5^+Spy=BB0aD!(EsGbIAYQRv-voKy at XgWt#
zDGGkgRD)>3KPJmd4I?<G5EGUo-Kb)6dLEBdj5*24FBSeH*B9>soU?1>PIm~nFEa at t
zUCm+}bYU0Eui58>K{a*t+xiulB*<*aA%G&uRhi=r2!{B+WgwE#Y*>ds&uIU-_#jhv
z4xaklp4^cmaEb35pxk4FO at aiI4@B;{{-qrV)FG`oNBPI)wUqjiFJ at Jh1ss)H9Vy8a
zkFXlb=K`Z9=hb+Ue?NT$%A<IiiCn`yLg)y_g)CTEWRkC_!eOC)_GAe9JIY%y{z1H)
z{1MTxJW_HeTY9!Dp5AH)&=qzt!<`VB`!~^MOproqYJE_Xt(N)xexl6pcWXV}^LQ94
z+6ahOl7VcX6YL;n01)=V{Q)%!e9KckRCqpe&Lv13M36Mpm(qz1Fgd1yX)1uF at yo%G
zL?E02-qjHm{;q}aCP{#h(7-A(0%$p%EAHaI449iC-A%jqC9=!6kXs7(_3m$ao|e}_
z*@e{0G#epQfpZt`ql^9LsBuy;$!lx1ufVY0p#<4ItIq%EJDmRFQyl%TyY&0j{{F{@
z`tmvJMlal=<l3@!uQucFu?_(EFIc6fp|?`kE0JY@$x7jb#ku(`{;%zWV2?YAeJUTd
zsZ+m3v;vSh3(4nmE&0mHPk{U8k%`Ns`*W-LQPTj+_O~tlV`Ybc8-5pNOZ)gYF3((o
zFShsNjv0Le0(z<;OG^LOq-+24Vz-eoL-X}NR9b(368I~>OqfVsiw-?!|9tnqFZZvN
z&wmd}<c**o=l-74{|w3BU%^#?Ovm+>#fd-f`@diRkKyeDlWSY@(SNwU|9#0*?C=W-
zg6DXD1MC0i^?(1DxgIuzy$izs+T;K8*M2~RtBn!^Io;nHod0_nVTQ0V`J77l7ux*C
z?E8I<@XsR%el5==Cl3DCM)aR=(t<!u^~e6G%Ko}R|GqE6z%gUgUIcvkzi<BcJ5AHT
zj5B;X_wSGY_YaZ3N`QmfN_L}!$$xwO-``sYq^^tSlk at +2Vt9~I+p_up4-4ek{eKx2
zNe%}je-5mMZhYNxn{e>Nx4|iFI>sa<9Aru|z#i?_%9S$s=Tc62$GX0VWcZiNf_Vnv
z6%;#&em|VP^M%$!+?JT~Jm?wnHK~&Uj&R5+8xWi+3A6`b1`9Os8a~edmaK at EgYTV1
zH-zQ40&BX`kEn2ixG2gL!U7Q8(tSXHLP(2tkC__yZCTES;&J_Jmcp3=+p at V7o;t2V
z3iyMP8EEto`Ea7o4*MeR2`LoI>WIn#X~}cWspb5~R^aR4umuvY&N9gx=3SA%!&GrM
z%EPLgC(d85bkyGu*~$^wDjaHEp7n18BDP(q?$ZFS&u`DLHp>|8_Ry&gDXg#9fHDQ+
zybTOSE3#|5nS*?b6|qVoXL{o~FUJc7zC4W7Yh^M*4}qQ?sv{mOFkBmLK%`W-AwwRZ
zWZm^c5XtM`sQGFZ!cZFfs^3H1jv<5%(G{VL(mgh2jc2a|1yail85~4IW)@wD7{*kS
zIc_o&{H|f3vS}jNYorisffy8ev|zT*Ewz<7VJ;0RUa!URT8|RM!JQ&8DgCf7O{V<&
ztAvW(<R3d*jVf)AL2vZ)9_>v#y?!!UA-CLI-3mo8jQ+?PGM0cz1{^vpv+dz2 at s1>q
z;e@@}=Bmdzr)vr5{dUF=D!3w+LX&3lq1lryZZpQLu${HcZY?0btdg(5Hq&mvrJSey
z<5F(aEHYesa93TzX56~7 at em~I+xUJ%^*rQiU+A;lsgxkZG{bGai3z3ro1rgOfi;Vt
zQDc*xC5f%r^TQP=T8j;tRsA{^G^dxNjVVt32oW!@Q$h^rK<RFgyS(OVRo at j*3i>HN
zGye_bdtGfJbGXE)7kmps=^`IM(@>B$B=_t;?>7O!pfm$cSAftvph0-tB}LO6{_mhZ
zXahWg9So&q2%v2T9V1_QxahmTe0S`Za>LRZ`jHHBxM+hoEc&%YT0@@S_xt;c2^z9n
zkOAS{+oet4x+JDqG^Qu2Yj{}Y!8>9NqwF~><))WaUziiR96^Y0k8*EbNXvNxDQgvN
zy;4l^wZTm)kexTq0^9W)gk40GVZCF!2qcMwZ8-LS;W+k74Y`85>TB?{?`n4cs(xo7
zHfKpIwp?c+4hYH0R92mZ&57V?9Me%vavo36!VPy(2*@|&BkMmg$<^WS66b_l`TZdi
z at -70<-!C=|M9pl$0}DrTFE(Gh$O<5JfsKig at 5vSte>Ft`Nx)jaR~GC9TvL+_7!W+7
zae&~&?+_jXY!8Q55-x^C;T!lQvL2s+XadW=w7|!ZI$7+q?}=b+7P1#bCVw<mNwOld
zC#9fzOuHT|2`SrYh$0cuS0VQDbzsd$oF9vk!qD94m9xh{(yzt>WQ)vK9*;fLsW)`_
zp{7vtJqj-X&G~5%s={bwhhOjQ4)-34_zbvw_km<d`<>?}!V$SktmJ*zQiWmg`~ocf
zIHs`*sD3atx4$ma<VjhXtQT9}9Lm?1V;0IiL0O{G(7uK?eY8Ya;y}~sQaAz>6{`s)
zd)~$0gE##JuQdk`gplw8-B>CHYYfhtS=asfkneohI`b280FWdP*Uu>2mtqzwI2L*e
za%qtw{ga9r6V#;s=T7z{gh9$eFoNE at Jl%>=5*_(n`LBdd0?6=C{v(%n3rHz$407|o
z2B~Q6o~S|vA?DxeO#fkc!RFbfzTcZC<C$9^LzFz+Q+Hb(TgaU4(<C^3=EwJ4-mmc)
zf3TW=ZjjR2aB`z$P5bkk-)J0`@)&&cas&U``2XCj#oZ93CjWcu#Q)m8?<4B%C31G5
z|K(ONjfSzkESRuN_CIQ&FjxHhH-^8jj at LW{kgFJAjcr&4 at AwL$An?Ko6n(O=*UUir
zUj$&Aa$uhncD at Q|E)T54rM3r1g$ac&&3=I|B0YfYNp<8 at 0m&gx5s`cOK7i`A=A%sZ
zcX)Z00bjWcF(0UXw8<7MM#KA8Ac_Qu)<NU~!{2Gv__ZngU5@?Q-e6-8MLcp3XpRx!
z7eh3_HW(C4!NI(FF4>|t#R*u3c3SiI=fN=(0n6)H(YN}89XSN6K~yBbeGIP+LB7y!
z1Qi>q2XXJRK)4BE2R!pM5{HB^URjRyWIrFK1$+Jd_{@4VU^!NY<O0(tA?d_qdCg_N
zpx*uvSK!-vxEJcaGrEsV0?>sGm)nmNHys>;lnxOmIzhlfn`LIa*`f7&|34@*Mm$5}
zVz?A*59oD;@F0jjXQaa3u-^(|wSaIfwdlQ#G$zg(lKb)m%KRue0<;3dg9I1xA1Pp~
zETY=)vw;8=c>N}#3X}UcV;=&lr-Ug-4&Z?KUd&&Itid}-P62?kft9&L`7bD#xB>op
zrR@$xGm at VX3HwefsGt~&?CQCb at Pa`5(gvA-Y)GI;e@!x*CtYL at Wj3G-69xn?ON$f2
zP!O+J?6#ugRdlz4L7{i(J>w*7n)gZ`4f1?%>So$M(cj$&Ae%ZAAgq86Mk6shjHKRc
zi-dK+fsB$$?WBIno+sG at N#Zm}9?QhUQ at mH^t!E+mFC1pJpaz3uwZRlRX$*kt%K*^6
zu6*o(=N*dRpia=veq>A5LGbVt*kA$9Ti#uV^|V54s?k<!@&)jt;Se&|e&9FMJrDG@
zA?(#mc8)>{JUsx1>cfH9wdeZI{yy~XZ3nc4WyfPp9gCVslc7Yk$q{ajV)T=lo_nGP
zzf5|&ACrBW7YO$`lamPk%_+%4?5~BUt=rFz3xu1SRzt$jsZti({-8M$nNdDNt<*VL
z&jc(CuHo*MDX(hj at C%zFd2<6h3HiXr_leSblbtdD4lXh|uZc6lJmavss`D|p_N#!V
zN52X*Z7cRz`MuSi$$40n%2tpLw=A(6<48z|YTaWGgy;edV4n}$^!Qh3 at gojI0*FPb
za}(T`whAzW3$;s`i$w>F{rdyt{-gffqbZXfo)WcC`Ss?1LeP5gb%GA!jbj^gIvGld
z`QhBV=1)SQ5Hgts#snX>N7shEm&eLDhwC04Anm*TAvKND2w#-lwyp}Fp%Qc*__OVt
z>??!be5kUcVAVbm!^9zDTSFq-JaEtX!Tc~e`ok5Yy0N3Ig;dVt8B(4N1fC2_inAvu
zg()y~@R(SgZx9dQ5C(Ud-^4>C5!4)~3>!0uB^n4QDM#NfjJqpioL2&)#e6#goo_dn
zLp)H(3pBx(qZt)4W4NW=3B3mA+)3N#RXsFUMO?p4l-GqK2hj?Jw8sexr<R5fV5r=h
z!6 at N~<e8aEedC4P!7}~EpuXxXqtzimL2>;%xDtWUZYRnHawKC!g{J_wC?Ni0?;$Mu
z{y7>SzLeH&pJD*@6vgR at Ih#j`M5p9m1T;XMwk!~|bJuIHqv at Gnl?BaJn(-$Z&kjKE
z&Tk{K6aRi0f}Et*TRwZ}r18(hugz>ctzE(Heg_5WQ*Wh(T^tmbVisFi5o7Mp#89PD
z--1GrVW|Dk;HE^s--0}4kI7=xH{4LYPht$SOaGVc&JD4fG<rutT%<%=@8cFndRE4=
zrplS)Dx at O%Ej&KeLNC`^<BQ}feA?v$33BshzD`+Nna}>X9e15zequ$QVkn#9`}yi%
z(@tK7ueVotX?{j%aN(dj6(hX&D at Uq)^XWA)f at Nye4dd9-2a0YsYqOAi*8c0~ciXkW
zG>wCLY80edJn$KlE7eL(9k0u{gfPu9JdY4DO+=sb6oP21;Lh68uXCF#ViEnE2ir)(
z`lw0A<9AHFB5&DZ%@7);7_y|iNOi6(d3ujbU6U`3_r%0ah^`JUX?RIh;(i2WknQNK
zLNEt!klDa>gTuYvt-OikH`25~zr`>o#4vdf<}5&L)5<e#qkEB*rRJ4`hOlT|9{N?^
zgeV~}NB0ghJ|9?sF21OMs*!HAQBLdyP9#f22V0J=MSU%EuT{H7qblk3q)DxGF2<+e
zJ%Hz`1qLD*Io<?MZ8kpq(RLZJxKu7rbA?>VZal1adb6Pyfwlct?N^(_eDOzZC?r>m
zsqKF@?(+84S+<qHi9i8qZChE#iF>;ZHP*<1Wr6UDZKepePXpp$Tm;gsgbc)#qz8Pw
zPzEdaF)+iuZr;ze9jIZ!DRui}6^9{?{5FSr)=6tVfuh=sPkocsNKl08mR4xufj$Hl
zUw`z&D9)25oBnFlf<Wm)$N5B%uJ+{&3c~cW+x7nDLZ0PL=eF3-Zi#tacES0hCf4g>
zc#6C4f>!{tousKX-1N6W5q4m+N<1#85vECKqlGXBM|zoDTRG^`dN7NfO(CWl5E%**
zg%R<BjLaV0;?wM&K`O<gR-P|f;lZxO__PR>=?9F&a`t009CSWMqxp`di}^&T at Xo#0
zW!9Zz)4|^58+yeg>Wd|INs*k~qI)T_lv{FKJsnNS6^jqV!@|p2JuJ=<ghI`c>nv*r
z7UbVyFS)svR>^2>AY&U8k}dx8xp=ifjff|<kjBG=>;Z8U)=S#g!TNacBf08LzKKmq
z9i;&BSUbhZ(ALWt#0eti*WC43X7(Af6(BAuZGU6uvDkaIN8?vVR?yB%AX<^(Rd{gy
z)j@*ST)g|T`3#6fSE_h#w+=TyS~?4=gZVAxE0&@r<AVVFtw>^^1Xn at M0oq#bdK1{?
z3Y-989D~+tr{}t;pFZYNRSPeJ7Jlglo<T1O^>Sz<p$jkXHway1ujKWHycm9^x8!b-
ziz$ZuLwe4^ojmVyZ5IZ*ObMTlkEY>StaL`rm-Es%U4OMno(FiS>XYG*n--zXHk=>*
zg(=4ifDysqT_0cU#rt%ct2OIlFMpb|cm3mo`6CX2XF6pHj^;h*Y;92~@E?36TPzy!
zZN!at$$}zJd)-Y+&0M(MLR1rF^5h$XzYFfm08?Yp>w=St(g6g41jVQWQL>8ekCw4s
z^>7 at KA$>p$9 at h{Vc5~-<#F^>ekUYHO5iWxZ(Hl=)Vog1DJsl05uds2xWEf*wLFKsT
zTiO{_9C_%lZF5*aBZ0$D3Rw$lV|MFNS#v`dMc6@}ewxi1oNJ<>4?2fQvublxi)j_;
z>?j$v)k2988bZ3lZ_dkfi7Qqx3CU at h=rsx<(!(~V9t?2?kIG3GoLNlV)b8~UyATEK
zNqa()#(?jT4!ZZAsnaO%qpW<Fwa`ux`8^LvtsTLj>vva$dh0DbR~AX)4i-o>Yb957
zD(q~D(_U7D0Kq*(o}ZDb&Q at Y-t<(r at OXOD})IUJ=)aP#*1>Ou}oP94x=$_VrPE?X7
z|Fc at D4{AnG>s6wtFYl2&cQMEu<<D<S4d}Eu$*ZSxDo<IAl+Rn`isk8b{=3AAuWnun
zUX9MU^mFmq6^6Y&PDvgM)!K_mA653l?VY4OGgY{`dP#fe_5w2>?RzhlDtYQ+A+G&=
ztEgdXjR at J}^qgO){cI;0EtHR-l5}(+O}X>P!|3!<pm;h810<}hj%AV`VYl at o<{0XK
zxwD^fruWP~Lo$1z;;pX)yF$7`h6~Sz0rY6i!1dJFr?T%<nSXhBQo%C4-v1l>4u%t5
zZ`pq}qUm+Ead)1p5n4NF0xw^}1{D|dd-m%#p#5!bXg?*ZmJIk!h<?Zkzt=VJVXpf9
zX2MJCOtQcS-ovcT9>p|B3zK&FY?AqaNTS4}p7&9%K*oE!jb6W6+A(qLAb&+)h5h7H
z{1KfBqQ;IRPm3Qk9rt>Y%tq>o$2^SDt^c(#>)VN8T<J}>G`g^VIT!en&ZQj76CL7|
zDGMs#6q$aMETN>{!L03ZGm0;?(@5V9Yt=cFPa}#QltgijWX}^)h!BC}sG=eQtaHy!
zd6^I|(Se>M#@~AR8N>Kn1LofEdCh`)y`;BC(YFr`P1n&3py2#^roGzIXK(M?QQ8sV
zFwb7a(7f3lv at YwoEF}G{2*w6XaB+pxewN4LvQuNNyA4<HvQi6#sQ2Xu9f`5uA`Fap
zkG8ZygB*&?CjCt7Fnwn|>jrI}{;J at deE(Y&-MT|$O#*6LXwHwzrr3_q2>*dk$L6<c
z>R9>opBaQfahTY2;yp*K-Gx4Zmz$@T#%n4RJTeMA6!ep5gh3+Ed{y_jm`p&Q=TA5h
zRj0VGSQJ>JE~ncb)8eJbo*fH81`M5DBJYt@#@^Xu8h234xpU9WrtC05N}<^ylc$8m
zj#tF1D?s9q+RU4L&;3UUVchg$Hd5V6iqJ{|LvmN_17Fe(l$X+_*`rwQ80hxUmyn30
zsZrFt at 8`EFn74Q`yi+3~W{%4 at MyU<4|Hw^jjIDFP&iC?nny0Nvi_8rK9YfkubnH^^
z#nZ36+R=roVaM&t@$n2=zp?zB$>yD1J+(PYWqq%#-Mp--x`TM1A>u75=SD+QAL2!A
zI#1%a2b=wC-T+xKhn>Q6{wDHiuj*~>#gz~+F}RLEy}@=`C78n&KMrpL at 7#u2XRB1h
zH19y#K)$bFG479)=(Xb+G{(cWF+Bd_iK5>4tPf=;nl6g+d!!tlm312y4A?bsQj^MM
z3n!Fk=3CzEl#y-Nt0WcT8RmDrY52?droGQeB6<5?ek57cS&e&16g7&)Y at Wuv4(J=_
zjTHBepCuscY;|wYi<D{0kE3kzBT*HyYbW50C}t4Tc*B(_HY+93FvdUs$OeZ?OO1+S
zI(m(Pkus7rrlH&fg_!BYE8+uF5+y!v$xIy1l1E4KHS1kDR?}IFQEE1EKE-Q<pTLe$
zssPD#M3_JAa;vS1QWttHZR*-}l)2i(z05UQ+kowGCK%H+pUNfbFLp{!DeDH<l5b7w
zou!B&?IB$3_2!eHX%>7S!p2_cf0@<vn|Eye{aJEU;T+vI7w%D3`oi6*UnpyQL%bW(
zrVV<x99%jL?SE9!4qfm?r+7l%B;@jvlM0}GJvWyZ3h%A6nYVk~UVqr9Wg<L at +S&aE
zy0wb>JMX*H<eOvts at ktPj5#(-;(Yi`w$kh~JKxs+*tz-fdzOuS=(r!r=9gs??mZ%T
zsp711!1F#Uf04i#mRhJZoG4@{vfE$2X<|m$F%?Cew}!pz8~qN?C)H<s-reuuK(-Wc
z;g61n^37+O7javORrIZn<5TXDw3WAvi1OWX+4OI85C$mgDm2%**uGtX%JU}SJqwCA
zFB1>m9W%9NX8DD;h at HerE5r<71w$$sZYWEC!gxTg5`KocTZ3LF8Fq1i^D2;KepTzV
z?x<P*heK}7JL!zpci!WVC^pMxCc-&TCGkYedt-mRqeKK9T-JCZB-ceEO>7^GwR?Rf
zP@%WKr|mBCg_XyCY&XVT(pfk6yIThXISEQ}!>(B=v}9pJO3Yk7RKD3HcTIuJtR8en
zDhwA;$L2S`D=O{arf;cTQp3BBHW4<mD=1CW+IbgssC3j=F)=j5UCw`IqhM`w4EyRh
z()7o1UmMn!3t<d#Y3Qxjb at zDvzG-&olY|tcPgyU&k>e(bsYyBa0g1(DSh|WTXBd(j
zd at YYs3Rt;WrFWFoygpT;=O>^A6fyn{0UsoBlh{5ouuxrlF#gf at GiA%B*KX<)m-{UX
z`w?9LqQ<jTDtmcqUh%g<f9EwKx_Ba{pIT)tqP6*4kF%}w&HJCXN)F6qv|6!CNUCf;
z%^h4x=NRhrRrf6x`4l{75x0-s?GA^yZ%?agcynwQ1d0}@S9KEY?g+hpS3{SYbK~%~
znFH3ZN{#0mzl+ej<EC*n#rU2HC%bOkQZO`U%`-e0Zy$CB<#wuh<FQ974RKIxs^(}(
z1Tdw2J+L-nrIoDj>994<$Mlt3#MNq!)%o$xhqs-!W=4c;{s6^h6wAnb5JI!P{K(Lo
z;BJSS?Xb1QyV0QM at U!y3x<O^_#IY?#w58`qmLXYwpM&|i_q5gxKW{A+4Kf`MU#+~h
za6 at m6sMmo0tEXSa24CdDk$332MGE at Nt#>jvzLv(?XHd3;tSAe3cOzB-75!s^;E-l8
zRN4_l8|COaE`8*C{L7(2BjP#_dJPRlVDEqu8BUmEqWi|myUfHFifh}o=<g(^kR=va
z_wxOO*ursB^Y0$FQ<_;Qm!#-hM8Cbfhz|<xkeWcc9^QqgdXwFrQju<-WTfDJ8+s+p
z?Vo5r)E1ILg4|?MdxY*>Y$B9D{yD2W)4glj-u__Db+MmhUO?f(!|ntTe`&?)ae0Db
zoE>Ath4ujnp~M9z0}d$TTzD-=Au03hPqEoM{mxBe>k#nLgZ&i&YInBu@!24ij_6p6
z3AW4!<PkAUWQrv>`1c_+&vC3=hU?ocp7<LbdAcb_o#v;W?8KZ#`7Pi$X3uyxQ<vL~
z)46k_jnZSg6*kJBbH*O!>fQVCbrH8yYO}Z3+b!T+lNvK29kRzd%msP at YUi6$!w-4w
z(`JczEr~yM4e8Yio;9uYC~VYhyG!6CFTU}>nsHXTiJ+E&=9);br1L}#_5Ndbj@}bj
zR!Z}kGU9?3-5g9S%FC^Xy2yR#*XG`l$67zJaa$&>SowUTdu=5YT9uV6 at +Yu8>b!M-
zrFW81kU4d>IHY2J>Z#y8e~jOT;A#Wt^C;I?AD1MM|FY$NT3xQiAWtVV^zgyE?C;#~
zY6|tWdW#q?1Z$+2hyVlOosWADc~2=OlJmEY1yXgA+O4`!Rje)ET?}>Ccb2N0XYOZ}
zUeRtsL_5TOSAe<yejU&~&~tH3Rf(6A7bY_mE6zaIFe-*I31VV-&0eN+I+?m2phvw(
zZZKc&!!f&H6sXu_$;_5HqjpVS-_?knEJWoSWluvY`Q;gPd2THss|xhviUq;5nN`om
z9Z#X<`W?m3G)Fxay@(O>bzvR`(5B(%<poJ0hO^v<M)ra+!9+!!D{00<19%ttEFw6M
z`ahR6x`1y<bqgX8&Q%OTRB^M%M_NJcD79-9Xra!wR|}rT<FD_0t>h7W^r2N{^_JKu
zt!F|GO^`xtxP?}rl>mf#=EP%v+#c~sm@?j}jLn$4!78b&w=}CS6W|FU((e2FmVH6P
zct#uf(YB!%_YDSvidZ{!`rI*T_|(p9#U`j(ay9x}Zh8$JJrZr5<BlOgR1lX)etDJu
zN7eT>W3zclDzcrL{SeX;oi^45_ZPIf^75YXg_xeTE8g|<&t6(^XT8XK8i=4xu>`_2
zE&LTeRUxq-BtQc#2hHa6gzyU at YKWfmU5?91!DDge%-Mf}*v(hwo6U>}dpRd3<9fq7
zSF8y2u%tI{SveiJ33$uQ7;<ZLciP%NaQYwzT#9O0;QOqh6IpDmm!5uy*`EW)2*ED*
zxUYlsx|0+D?>g&>aL&zqn(H<R6=B_(Q^%G->a5~*hbi%zmoknfzQPc9%)iVbh>vO=
z;oM2cglqLAz=kkns^;qnWZq9+034|@2D5UfdqWf~748$6_qT at gZYEElKsY&{HZGAt
zgN<Kx3Zxl?VeDRyDmLJTvuKlGuUkw};OE!GVHSMJI8Xyx at NB+do%TYQRLri><aDk_
z&fE*TL@`#$cu;7wUE2MS*vV>GZaqF4F`5_i^X-_K9OT9}tz0NtY9qg)uy}H)rh4GY
zK+_2;D;{p}b$l#ROOScUzGy<^EAQ(3I}1?ymH48Vh>6WCgnynJ>fwCmS!13fn}+F<
zSFBC5)d{%6N|C<*>1tKw-GYO~#MY?G(7pKWiik3RAiaJm2bTvhBk~4T0t;yo%XvAT
z4|VDt-anD at ydIUEA{K at -z3pYGdYYz3w-%f7Ol at JPAaOqLOHrhSC!GEa%df<7CW?)6
z>Ux>iP)FGJB=lQToXyldiOUazqfTX==y>@@VK_G{iTm~oQHv<O%(xXV_IbzqbZ2>O
z at oR%=ccEx>zpE$t+l~}V65gb at uaPwLMrO3@beqTRjQEJ6eWb}3?Z7$p7a38GOUmi-
zkBZA;{OuXmI?&!wUYA)|g{V`bbTa_t4jHhX<3R;n)$7H2c)FLVv4c@>-ou{b6)okb
zYXh$`X5=0sN^3qe_6hWmc-{T(h7?#FzLg$BBQm3Il1JQOC@=^~v2<=ff-*j6LNxM~
z7;5}W9ujMB>-O1W)a=Gi0ZP(PEp47_Z#2&BU~fCckT?9556RL>Asx#gW7JMS`+}w~
z$|@l+r9x#v=0K80KQge>e1;!);T}*^3|k63uRf1{m)rOxH1mc3=;O+S%YytYq-LfY
zb4mw|sg~AbiZ-s>AUf8;l7~AqouD$YN4r#WvWy8rri*_+>0SDkkei3ji(AaDx;?t>
zW$v+Rjx|TyEaNRQCczWkd*zHHElmDz<U2<GdV)$nK7MtuNg)#9qj4y1hqzs4aLhR5
zZURc~&M?>ND9O~J4WS0soa1_WTCa`G!26^heE at vPr>;Zrz}#JX;L0)Tw(>G6=K+x#
zkHcI=#u}g{^r~etx@#ahvsepr8-1D3&ZAu at j@`eF2u=1_l!xVl`7Z8N`?Okg*UKOL
zkYx$W+cp6O^6GF&uUzx_ at bY<Px^V7eEULcw`5*jk6mV0KyLv}MRxlNzi*6Px!TYfG
z-cqe5yRcZPdZwdgwwo!lF;#*d^((F7^cSa}a%-o1nMmy*gR{KV1!4L9GSXgU%<CIe
zX<~_M)OvM4sJXI at 9Ga|&PNipciH3-6e)daId0iCr<+R)tqeg=Z9NH&O(I-itc!fHz
zEm0Kok}iE%oN$?tl<1T?l`^kek<rKJWSlB4lN)08Zm6y6H-s?mZoYFH{xw1~9q-m`
z-g(b<IQK6p&J}=rMQwQ2L_x`O*JQ<%nnyi!jzr_}tqXCQxi!pB_){hYWV>n9vAT{x
z&=69bIjioTp83qxPo;(`GPuoHKexQyz at 6n;e93cM3;EKoC_Ald#F_F#BR>kd08-q3
zh<-+n^O>+n4VK^j91UF$p9fLzJC?7V8>ePuW4PZ-e-Gik#r^R$1}+L=qUHT}b$%=g
zUTZDOqH*0?9pASYF|L at K(}C6}Oi}o$u^9aoTeSoQ{bMAYi`fMq_8n!_?QLdw?O{;9
zx3aQ(r?a;g=p5!^{&JNnFfLOGB|`l<1haHQkzN}p*H>&OqukOS>B^WX048B+(TEGE
zQ~&6l?#O;Gv?8rSj7seMjYXXB`SUL_Rc^?6m|K*)oKz9<rRTeDtdxR30(4Q`LWOL$
z9E`7vM+=M-!;SG)UA%DHhKnhYymY?v(A at 7wk-sW&(f8$U=$JRPR`<H(N;|?^4zK`6
z`64y>+;|lgVNs3i(kwA~+e4AJlFZWL6|A5vTbC%=<0X5Ng5^`Wq-(eAxf0A(Vs+>r
zyELcNzm&8ftZ!2T;1pLEzl*gH>SpZmbx?l2VLnN1#DSZORc)izc{6cvd#k>0X=uaa
zcKV9*xX-l-dt;2c=uFl|dZCe(wztf?e8n5a>F?d=C2cu7L^;CpA}@eTfC5t%o0u=b
z4IVztjonuA3x49ZB<dPg;h at K^%W-w4J#v}hv*y}RrQ~+K*8PXniNtzrGM at Q(%u!;x
zsE at ccB*GqA<9<{ZORq!n7|oC*T=oh_<z9+hP;m5yfFCbu#3$Au6bWRQ+Iv7QO<n2F
zk*F<~D7LNqA^N4~3)7knQ|QN74&C#nOGthzjyX6^QXk`XU8{WXnk@{wsfC at QG5(J8
zNl+&ERIH)WwpFrfgkCFwAjS(0zQyrUg!z$vfhv|9ya`HGvi(IGuOgDxftDpw*hHr+
zlImxFF*^smRL0un;Ce}9dc&RDvouV88@>3p>%nq}6aD6V??pEaID}<3kvv$so8>&$
zH3(=o1{!!h7!ZSioj75SV#p2cowFdV**W*&`We|saj>u>&E{^9{Wz-*5ytcOTBL&E
zsW;uihV9W-3mbD4s8?I_u=)N-jcVThnLd={c at S--T>6O1j2%dDW_SNA at o7kBj`w;d
zkbCM3!SQw+ow{ouhN)CZCRVc>NH{@7E9>FiJnh|68oqgM{Hm|g3a{Hw)E3^COk^y}
zD-7~hu^kd{$cqLm`_Sa2{G!|^28nb8RiFy;F>0~NcD5RSwGYd!=`nQ;W+BWG$(@tj
zT1w*MW@&ncZQHrFR^rcXR;(YjP}{ubSai&L2q_!&+DEZ`xpKD98x6Hrj{uX<KRN$-
ziHBYzKHY2C3O at z_hWx#<hXS~hE^FLHr}UpPMin9XEEu4HWAjzDx=T>?5!mgBc7HSl
zzIWZiC+#sOII?du1*&*pz7PKP*@#yW^m{Pper8}}w%NBqH*!<WzCjBwtaO{HuWT&g
zgp)@@<&<}^KDyv}2{5A;UO@;NN!*WMS#OmeUpTcT`hA`ehROAgW!XOSzIU%opXT`o
z!R)`X0Im&;uw_vyvyU3C3SvqvO at K4s5Xq<R(aLE{N*OBip%4bweK~YXCgl1Zww7c?
zki!wi5Ot{aKsMU};-<C847Bec8Q5MR6lpYzBZ{nq^ze%t3@`FKURTrfOg)a)a|(Pm
zlT!nk(959kwT`S;VzYpx51%Z3k-0C5sr_wpN}j&o_B28-=*z23Ea?S_h7R1Qfi6K+
z`EBb81lWT#So0PLd6l)bw}GGgWJdiE%Eo#F2N4;2-;YPA^OG36DLLd5wq^~X+v*#_
z??`{)7B@*kg^OCb>+e){(?hOT*RVvBI&UxMcSQq0PF-yU<{bPv$uj+w!MP10dYhA#
zc5m1Y_SbxGj$cYx4flaA+P|ot0HI(oWw(H at P~*0;+{%_%S`RH0{oAi1MuaRP{~WsI
zYl{T>+R)Q1o2Vq$_N<_b#r$>1bIuqC&V!)n&a;?s1 at TmarNP3&6ye2+aW~!65fxO?
z0Hv-- at e&I8;A7vjm|Z~6y=VJWVrjlB6cP>EQ|!_Qm%@UWB|NJXcEP*gtm~f+S`;2+
z3P7#*xS+O{qpSE0J`YIWI*QddN8mPWisY_dT3iuMt`5EDvcw3 at 2<8co$Hc9CtN(H<
zr|C3q2a?Ewzp5{;gH2Xy^ZC%)a?+cXnAc2Vq84SJmFPiX%=$8Zf;PV55Y+baV)|1B
zt7gNt72~&s<hcs*DM1+Me;k<^x&b4S at o8+A!uFw7c+S`cNA2dxQOauZkQ<BV3$#L5
zT#G8#%cRDyXHN_*oU>R&A;hI}v=zzS9MthjFx;cd;V!7Hk)%(lgz2Msc~DBpLTU}K
zb+-2c?<5U9b^3}N=lp{>pLK%iem<aIR=@P~X*mM!%)lM_B at h$LKQ`N|7w_l#Kv3)v
z#jMPTN0!B)$$Rkf2}}BA5SI9=<S2OV20c;!D7&~IeEwxs-<+j{?eVxx=oKBK3XK5o
zq7t=qEYshss=Q6{PS0@$l~!=>4p at C(y*GUQPB#3M#vn91Z5Z+0#Z1b7*MAmegL|GA
z-M;{Oq at ttbx0p+}A=WH`!ps*KuH^Qsh at d|!O<aSpm at t{s&see|&>N&2#w8!jc0hi>
zG<=5eI&Yy#(JQ-Wo?t@=(qO=`NQ<+XfIHvJBFHsp3?vYHd%$6}MhXdKEyMCL2%?Fk
z`w!zY)P>u=W=JTxN(I<is;!ZeS!EkI#b$VboUJNRE9c9=r#U5lda`*ZNRQglB at 1{v
zU at iC2I$c~<Mf3m&{AL$6acvdBI5i~^J{x{?ym&uFR at URtsq=o~KM9J12@!&h#@^)c
zgADuo;^4T`?x`?{#`be(XBNK-pKqzx=|VplJ;SRo`9a0Kg(#2Gd=w7kCg4&yq3;6y
zLQcd-V`=FKuEwWaurLH7e)NsLaL*>y(X;$E+C3TjrJy{)K=uH`Ekl}Q!0ul(Kyy`t
zP548-`8}Pu<ZI`7Gx|W+a=O|Y$$479o#Sh9m~Z=iB$vIS?CNhb<8+*Jkt9jiG^gsa
zG!`ZSF~7=D<-3G8 at U>pWWHII#V_s<o-{-rK)L=Kv<uWRX`!q-~Z`B=~Ctmg>!%>mh
zyd&nT(%q;RbySxY62(U3v9vk<;*eyq*&ylq0J52-trrVnox&WY5H?!OX3&hR5V1Mg
zSLnKE>Dh1YJNzuebKThR)a4g`b=E1O&5=7?R<9!-k0QZqah?^_sVu1drmI;l3<~v3
z^yO?M^=fqGH&?$~2`U9)%(yaxmaEYz+L8<}i^u&lf)2}cT-*)Rr#1k+=OrwW({Pda
z0bv8j^1vUk86MAF%s`)x=6u*Ye9v<~%Y0W;*Y at Edw6o-ZvxP_Ymt`w(3(ngueNt!+
zVc3tkl}vi=_n7k&A0R9qxWj9ebc{?<Ifq#@?6B5j;|c2vMYK%F0bx|P*x?vO;YnVe
zA<M-;Z-|YXt)^=q3iETKk&1UgD1IO8LLu|JClP|-Ii|f{-;x5zuj?OqrCYiTd2Fiv
zOl%9bZ2KE*C?*MCTvZws*P{O^O)3YKiRGkXkm&8IbPs&El#3WJ-LSn<FMNoe=V?)(
zp{LMf95)pKb$V*sjL1oKVn_*PuJOaaHuB|Z&z4+~UFKlZ(1VG*H`q;cvD*XncexVT
z2o|(39y-eOjTzY`-5-gW^h!%z7MZU at XZFI*5vUmGY3IrGuSwk4goUAHkVD^C{Z(g6
z)I~E;RBrer?Y at +}p!U!L1?)bX(-=)Ujfz7R6=D)9hcnAg5a*78vY)m`j+`TnGWW`m
z0BX|<IvtbfD_D9Wjp0&Ip|@{-K7kY%#Qsx;0|M&G%aVL&@2GdN?hk8CEkTGC$7aS2
z+(P^Mut_LR;3f6rVbcf&WS+KngnA}n&kKf=aDq(j(QxiC8iMzhl_Fo^?r?5CzhAgW
zfDI6`Qbz!VTcw at G7d2nxD?g$2G|YZ+J74msc~r`fRG*k{$~mxMJVbJ5^pTXtGNj9$
zOP$%}BWXkZs&ZV^)nkZt5owih%<SeV9n)~h#}iwu5&LSvrwf?)nl4ups%IN33NEl5
zu8AFPD_zS;CnvDFHwCiqz%d%Km|RlNDmPOLodsZBjgIe72@(7BVJ1OA&~3dfe12YA
z{r9a;&9JNurBu9?JmvfbB9#WZAloWSVcUNgS5x#hi2KCd{Z%AMKkv>9a>*5&6y5;X
z-Q1_mv+;|dnSc}v>dV<%&}R8Ubnlw)eiyf9F9V(|XU?QG9JJ`|DwDP2+G-MJ-s*Po
z-dcn_nR7ZXR;QQ2E(R+(QtdyaaX?|8SNn!Hkxe9Ve>s?ZdFtYYXs$0Ekkxc?#s_O&
z{%*ppv3|8#qAgwF@|W4i40hsSk?oh>I|)3xQ?Z1PUsS$@^oTDdcgKhCm6{BoUCz at a
zNykIuIrgCsJf#Pv;Y(#`7hH;{JIenkW=gf5%2g;Tt7FEObnNEPhn&-$t<?(dQDTLt
zg`wL$hVEYagP!e0eoG^f&KUIWcYLx-mJi at bJy9MD^hhhI8MtOq)?>LkxEm=KMRh+@
z&O5 at 1hVjnQ<$)7h7dZ>{R|!z+aj*5)K+8ru%#X?d$7jnhj(}_4GcbLOB3->_ZU|aH
z257PaeJr-mTVl`MquF2GuJW!XEX=aL#=B}d?u4MCCqv~&H4|HmeoK4l&HZ;V2fHx(
zn{pb{Gmhsr;!X#Z`J5-!*zsPpOD7-ODos9EeB48rx-qKYeQ)t`fw8x7=y*e?fc-_N
z5<OnT<(}L;U?1|(;YwiRJ>Mmq_hqBh<@;DtP|<{m=USDxMVmgaVgcQ5fgDYQle<{P
z*!ZV#OyBOX{@yEn`}3rlJGiwzmAg7Em|(96CkBn<BMSAa5KgBCC793P3cKd1O!yz$
zjG)Qg!MQ%AbV$#l&#Z2FsONC2Y}D$5q+NUZmh=LjrnIBUg=cn+!8~VbtlZh`+g!hp
z=E*f{tUZ&Z9tvbfmxG$NO10Cd<`}aw1OA;4`BLS(VOT9sIR0h4NR||cAEVKo_j{Pk
z$^R}{;wP^~!fwjXfL4V>QB>>cdJ#mC=<9X*rv=8gf-L^Shqh|fJmCk9L7usr3+QH-
zOZT at YA_GF7i0e!>9HqdnJ;QF?@^xJ@<cqxRnOyhd6X~T9LL9Hm`kazlB&ejD^q5N)
zraPR|@q1T_tEk92vi%)XRz-W6Q|Z*-MAFu`-Xp`G;Xb{K5%Sd)+`X7iRz05*w8xc9
zN1(Xf89+4CJC6ki*e`_!{j0xLWLhr9Q*cBtXlUtEdmXuftAzd|Xd94JYy?ohP}l!4
zomNqA<ab<4*?Nvd<^8~;gfjyZg&u9b1(U&aR~!IsG7jR4&5t~;Yg6=Wf&AW94XU>`
zLy5cY*8{c1M9<5zy~*8`S=U_`)y2fU&ZFW6;tb~E=v=PmT;3|{yYz*9(R&Oe;4PBA
zzrGUtx>u6EjrEL~)9JTMx9e{x9Qh*k3p06e=AA0vkS$Gd?F5rmO^xzto!|-5_iE4A
zk?N-Ha-junMHD)N8#HH$FRomvFW^A0Btmgh&vaSwsQA3;MMV`O?TVIp{%h%{0(C#F
z$MNeM1}NN}8CE at F2QBY5tBSAz=Fg}#E!3ak4^&?o!2P;P7%-;s^*!<Z9+DwI`lgo#
z8t%ywo~+o{kqIEM5)Uq<tU#Jjsl=g`Tu3!MYZfd=4s!IbzibOm$P3BZ9@$J^sFv_&
z=KAhgHB)Lo%0%|#{vzhYOeRyA3cCm0YN}l~I&{P8^16!7v&XNN at M62IiU#4~hPo+N
z6faHd;+;)DLBe_5=N=gmU3o%A0SHD#9q3#+Geu2s0V;_v+OL$ztGoJdVDHa+c285C
zpr{Ep#KXz@@-J+v>fa*cuu8-qZ!^hXD=E~Q-cd<gBN#f`4D|LH^#OczWPxgSRtmT9
zmBQ1MvKNxNg}kGmdUspY8D#Esk$aJuTE}q5ES>rKIDo at Sm%AXErA`S~mHs}Fj#nsW
zenYAv*7~Zhce7QJ7 at _7{15eBP*sgGw{4}HBrBm~haaBa3SlVopd}pEodcLy{tMi~_
z^Azjzjd+ys7Q6AZ)VsVMhEK-UYajdR*jUB-ys>emgZKB>&Z81>UN%thZPkZk4F=tp
z;e=?Pcu&Ek^D{eLiS*>!_FI;^16Q9+qdfV>S5A?fQ+ecii{hzCw(nDl3VDf?)kW7`
zL>6CW{M2`1Kd!vACo`vNESb0>NTVhznx3IjE8#y;m@>&iN978ciW%pI9fNAnf~zUP
zZ=K!WV8FHW{rl0X1Pp&pRx73ZT+$j#)|QlZvw%0-;@(~V9hdF#HJ`ce4LO{yD2m|#
z34Wl(+mg_C&6d=Qd)&*#Jz{t0DD<YPGYy2a?Cz>>oJ3BjA#KrQE8Yjg`6b=uGWVk}
zC)80j?qLQ_KB-1e+_3l6OvIw=g1&HA&1~N`v)ESp!BSr#v4%1$QixW%Dm+OoKUzw*
zf|gG|qi4>lUg*AD72|lgEmG9)uaxT4_1Ml9AAklo!O7#-1<cze`EkYc at A|9WmX(v$
zBAxr%iVJ)yZQm66RROhe95i7ibw8gTsnD8jck_qLApcFQ%`fe>DAl)V-UpSG_Y-w4
z=(dGEf9|=={WL9dJq1#m*=Y#6WOKR)LD+Jh`mI5h<-TYBQ2a!YopM|*&Kl3%DM5AT
z^37TCiGt81x9J-S70;?C*osCO%#%C$F;|vEtC$GbQ8y6`BC_vOrQ`X%YfdzK#rgE5
zp*tb$uIJ07D+}#BG&x?{u%lxcg|_Zo8-Qa)WR0_pe_N_*P}-6sO{gl;AhRk7i@#)j
zTiYreyCX<*-#V{MmHUPH)Q*gAVzq&LQQb{6BiSK`H--r+kT;L-Rgrcc?D3sMef*qO
zVOaA9yHT1J&&K;``?HU>!ki at _*q&DDQJQT_UWH$GD`G<R8+g`utz>-n>!CLQyZcYB
z&7Teo%zFaCeQpSOo{g}uht7CY{czBH>$Lr$#D|AZ*iAMdTyF98a~@A`pT*izWA72h
z8llvEk9VUBU(U-^1<|m38_b>lU{Oitj+bT}Q7o$YO07u%izzl1Q3-X%ZA18)YW^L`
z<sEuE-8riKRHMQD7I$bJFwNQQd8|LJK^a$>H!5D<GT!h&fKZ;!C+W;m(UYsIZ;Rd=
z-~r!fXkdt6RW6W7DM<LM at s(nWlkJ_Nw?nPU*EZU#CW5Ik(HX3(o1d?)rzq4zue##Z
z0(_GJbr;9%Y>lxw!CnqmnZCJDd;`aoPj8*sH7>~D?p(APuS7!%0Yep8r at FF;o%f8k
z;`U{Io`KwzkP<)cm$Oc%lFshBL#$G>rH({9#M;j~qnt}-Bf8yQ>lb7aa)eU0C=SuT
zy?INQSqN3feR<&*KUdigQE$-Ws;z2nyz!lw?yHhmT~*BQAw5YJdZ!O#NIGXJBdBEY
zYcz1T5>9ed%yPc0P5W_6O^ubfjA-YhMwxouKPn?huV|4L_zroAIM{@gs$?H<JjykC
zbY61OTIIV=RL)9{)?{MU+hG3D%X3 at e`Oq~tm(#Q!H=Z6ukbaq<ST0#M{uqm9lAyC`
z4MmT9udN}}!Ik^qrs|UCoI5&xZ`#u}ZoOkxHPRq0GIe)xP;LD5l46px<y%AkEAg-F
zTA9GD)`g?CCLCwYs;z-ic1G5tE+ at T`l>U<aE7j+f6A8%}M;g<;mB?gLb))AKliP1A
zw|}hX87^I#*^u(MKThI(zGiVqgS<8CbkucrE7bE1J?4t9=!Ry1Ce5d?vI^=sgfned
z?)BzXR$oG$ldNLaZ$N_uKqI8HDEJ6ox_CR^z+JS}SiGtNo8)YvO|^rzPj8lR4B1kT
z?H-*{nq~I0t!&cSIME2b?v0EZt<pKVo0o>1`Qk&HWURxcH;39hbX2=2*S#gQ+C6l}
z)O8m2``uTdMbJB7a_VJ|W=y`2JsPEy9W_+1+P^S-H+{UNnazqJ{j$eu)!bvN-mID8
zPV154bavv}zUPr2Duu%Kw<OAi#}zQCLqSX7<1S8vbE{oBx$S8*VGEF>+NZR!^I<JN
ztF+KVqfHhe0{p}^$Tx>e<1scR!QBs6?9A;2KbUrx<q54;Hu_pFgD%p;)*Mu;gJ9{X
z9Sqiy*{0=t`J71Ac|koF+=wbcJXd+Hn3vQoW77><PrvmN8se{F3?-dr>@Ev=z`f=f
zOH)$aQ_VkY6wu=VN#57pgDmFvWIJwwOkM%+m!2FPNjuXMT3pL&-zt5Y3w8SXg-llR
zys6hAJF!7>lm1qx&a-tm(6*XI$azI6sR<CdI%ZQz()jQlOY at Ph)HRYTB3XRRp0w7l
zdTvf{J$~uQJ>}LJ?~HTB3Ub^_H}xyjyEi-%Ii&J^AVEW8Ic4qEOjj4%q{rAsQCfNZ
z+b;AQFz2jU*T4`zz-Efg)RNM5=m-SibT~Ctq%H)Ded{}aM%|tZbua{{nvS);2Ldk!
zQqRrp)N&6tNqO at _@}c0_O2$3oIIc(4J|;CTEE%NeZM}0&?)PT)==CShR}a%x%zyGq
zmYfr6`X!=jA%w_*7sVS0sdEI&q#L_d^R<-Q$b4d)3}Xn#H@}fvPwlk1XSoozNoeGz
zj5W29e$b0B#smxL3xw&1wi3n;W-28PyVg)<MmjA#j{;kesGGhchQVE6yl#!?<8f>F
z9OFie$QrY|%xyJ2cA%%_5Rmf=6CP)$+Z{!Gzv|qFqRNk at s`+eE%O>gP8msl|$I?f|
ze1Vxhg}FM<mtxtrOQV6kf2Q1SY(cgrGVk)f^w>^Y(R(LN8mC={;e%=+W!1Ki`meo}
zMIVmiBc$JKe8G*}c*l$g9Tq(qfq7DaFRM~(_)+abcI4Y&OZ4)`@kxAt@!2w3G%-Ln
z52d6ZdegTqW9*xwUdr3>cQtWW8)xyC1!njLw)FBZ1+Em7ZIoJxDYfAEq73Tjy3iB8
zhx_lp)T$hObLkzv+V=1qE}@fODX~IO>eUWe)P%uUec9&DkPi}{AsXt;->o-WGiA{>
zzHrVfH>dJIAsT77r at Hz{!NA1w*-EGnruyRrH6;B7-8r)-JTy5^HhI*MKVx#LYFe0L
zbWY!WoUbcmUFUiK1&^Yl)A(f^%KHMv0n^B~9=XJ|LVOPGCnUj?=9tNDpRCBj+w)XW
zTuy`PZhw;Rah7J=xVLDUDLDFm-_nx!nUv!H9#UN at BZ;ubKVWd9idDLqk3}S0(=r!=
zG>>Xm>L%V^I*z$lho)xf6OU|STvlO=qdR*qAZQv>etS^Ou8vwu?-~++{bq(#j_Kz9
zK$3&;imN*juU_dQW6ddynw`s!7CbeV<ks}^Ea|ZP^V(&gdBWvy+2wB=;Am5~5(h!T
zY)`+sh#!ih<ppbim_xj%+9v~hvP^4bx}iI_W;}D#BZqD(s^ss14DJ^m1^uALYV!`X
z4R=rPxR!^vkzX|%8>x8UyzkTFC<IQmy#|M-wyz9xzX-UXd7$*nVP at 5Y$$^*f5b5Yn
zhqL?BX9iEzyF9(?7j8f7 at w!8^4{+UBkA$9U7a9b?kwk^Zbqv?W0RwGFWFlPA&#O~H
zT38=?%zOF~RTJE|jIG;%FxTdOa04dxx$B@)LQWeubLeMwP)omqoOASmiI|e=t~E|L
zPp6ymLH$eoGr7+<N+Ixc*O`QnAHDW2seXqnRl<$_jJ|v|;03A-f-cfC>lhV}zyV_m
z$f6|sz}fa)$9tbtD$#i7iZklT#ZZl&pK?lQ`^&-OsvYEJj^yvxWtS>+>yFwir8EP+
z_|11{aidcEQuO4!=lE<alkUnn0Vh-0rP+1H-k*Ij^v8#n9*Acj_g_|RRpr4Cq&iz2
zX1%Grh1cJ>Ps-J{GIy_TYeS!c(V1yAx&5uzbEj+U^~viNOKuEX&y0~1$|2Z{JK`V3
z)Kpsl$^PSzw-aa6wdX8G)jn!EWIZ^i?(FaEoXWRb&aoCX`W2sUwytzvtW2$fv5HAD
zqZE&dAcX+T?kn~sq_V~-x-*g1X#LW_oD`1Ps)-{RkMrA_7w>iPkBb(#oUy90)9>es
zA5ed at xvi$)R{Br^Z$>o%8i!UfaUS3bw*2bov19v5*S&cv8OPrF?$~{Jn^K+=%)wo`
zYLCi)Ti#^Z3@#|^{JB!Yetq>D>AuPR6 at Efun-%Rfc*XnMqtFfY!RnLXs)_6jDqGpF
z--*UHeJh3^kU9sj&plppXMYwkaiBUHS+c4lq$EA+q0>|3MzgXXBaDFI3*LFYvQbzF
zU;MRp%{zJlmB$;gdfQN$T0V$9sr&psQSX||OzL3O?H%`OpAt^$XI;*b_;S7v>p>Q|
zJ6XSa+qNSw((GE9e*M6ByxlDRM%~KJ-jG;)C_A-O<F8MwaW)TjGI=#dX=EJ<u|82X
zua=%#Af%FShcAEy(fEz0nOgGO8^0)C?71uMaYVnMi&gFLFxx5H+DI7 at D=TwAHb?rK
zbb~+LwBkv1;5Z)I`f0v)%HqORo3E^tk09ibgc5Oo*+8#j|GdE|W(1<25@!8Z5FMOM
zVADnZ38R8nlo3!ZrSw0E7cDoexB97}3h4t~C0y;l5%V9dJpTL>KXFyC{<6(T_bL+L
z6O1*`xIs%`f{trIfijc+8F}-sOa$OvPa_ea{=~to7sJlXgB7YOd>E}nzYk^mhbomc
z`u_}s`|Dkf;LAWBaQx at gdvT{6 at B#34n`aIQ;wq1Ut|Js|f879h^?$NCtZsutU*X(6
zw-iP~c!t7pV!l38`LN1<EeByNahJ)3zdrUqHvqnpL4tQmFW&P)-Uou-A*Y?A=K+u$
z6 at Y6K{m;Lm(&h~e&geYWpVI*7sudD~rbK_bEEKUwfCA!@!zo-Jl2fFxAPEHdte4pu
zfUTR+^?R2bJpTK`P+o!biVyq8dh4oB^)v*7%1QI%?k=EHqtJGcexL;49SqPcxe!?#
zoU!pwo34M|1b-GJy at Et4kbkh&&r=H$8*rB}N`w`}6pVWRkz4iezfpy3B<^%>*NZ3B
zj6m(N32jck=n2+0O+c>Eo~9|+zi#nAH=E-M0OFsB{W>o)`y-g>8U51IcRu_Rk4y^x
zh&}qxF>q2k4eZ!=8Tsk-t?`dPh`#PywkQTiC+pzg{r{Hnl11s?=Z2R at dDo57|G_b&
zyMQ3%f+P198aJLvl|?g$f(^I`f|2eAo#A?=%JxTM)gPn!pU10g2jhF at jJembr^l`o
zw_GR(2ilJB`Jk(`{~kDheJcNID(EVv&*<hx_uqaD-;;*+b<5M|IRD+S;P1(VylsCv
z{6e+x at -pv#9cwV-&cPM63TT!>SjAuO`yXFr$-ytUdJK<P{`a4YGYh~liEz%fVE-R)
z0V at eX@zQ!>3HqPO^dDb||3CKLx~<B!>mF7FK`>BCK|)Xo36&C%&@CX{&7wOM32ByY
zML|HMq!FaMO9YGVhDAw8clU2z;NEiI&+{C|`vKm6JXCb8E6#Jyd5$^e7&gcb9#?IV
z|3AJWh82k`W4gwP|LePi9_lCvNJ}?n$HxE12mg5#LMT{N5X%~+|1XW78boF{LSI<o
z|N07e8E;V`o{^D9Y)y_VTi|nmKN}xUl~?fp8rtA(*fGKyWj)8ocSQR7&n3d|u8Qik
zXomBGuyr_>rFuqc_TAr)v^}W;W{H*9o!6j|^C(JzT{M95_cBF)BmnUeda*&AUXYp-
zCa&gr>k20Bp?{3U(CS1NIZWP8QXk0L{ki0r66}X8@~Eoko&UW||6Q;g=U;WuA)TFU
zXsi|0q}=`2Y>%A4qGU3`hyLnN4>)SoI!a^t5=o`Wpph{vm>ZK0zoq{Yw;Px%7K5(q
z=`yF+N+z)2cah};<Irhcv;%*dmV$0Q?^tV3{PRLFcd*hm3R$Iv+hOGDHHj)ikoXz9
z^m+eo{+ORf->B>pED)FexC-rV&`8a%|BQlP?LoNFFlzZ2`aU+aM~xApX}>+jGSm!?
zq=v`{_OE~4$AD$=(qH|fneTu3 at SQ@0O$%lVFh<Y1DJ=8+`9YTuJKNEbSZT<id^@rq
zBpdBpgvku2%6^5JTZCH{WW(ojvj1xX1;{#t%8@(G_(xXol$H*l%$-1X<paH2c2XF<
z&Ie+p|I!t at ug~=eBAlj at 54-15$%tzfFq6YY`18HXq^5o=TcG<80S~K6^8a`Q2568^
z>jjp86*O}66Mn%=@a8zYo~K4&PQ>t{0;UR$oX!+j4-Tk+Sn(j{9xkOpVx+w~BbR98
z?+<$G2~pv0v+92=2rv3apaHN+)dhs6*i6Oe4d9MagH-CnmVbv4R?}vE#lO)FA=ns6
z;6^owth at c7tHU<r_S=8F$AVxRp)NTT9C1)Nh9xcZoSW-%MK*APxLmhvqv<GUu$itr
zf at RtRLUE?xjFvX|sns{ns=s#*MDxTsJS~6kp^AM74a at RJgEu;d;1i at CfpghT`ib67
z<z@?Iz&wekUnE0&;mrUGNT8z{E_<SIAEX!5!R|N>a6uB&bBFd>@JZ}oz=wY{*2Sb@
zfeqgC`JXBGE-Q6vK9Pd%Th$CSEEvuCx-VkMVF5up=M>TPZXkWWRhvP~gTOwz7l?(S
zq5qn>G5EnVUAmJ?a%2S%KEi^7N&%vb0g|}${KUkHLdY;}B`!LJxM*joj^Yfj6AVag
zmY$*lN>hpjo6n(oRE#nb at TLxxss9PbNwjEKbsgY4V-BQ=nmn@#kK^`Llnw?q=Z!(C
z8qGvB0VRwKXRKxq6BH-~&<>I2GHH%sGG}Z!3>Go=$j8oQ8y at wNO2S8jn#;k0f-$y0
z>n7+WS^!-s7s?G~;cXLatjE|$9;L1qfEjys?;EoZL8oH|h(?W)2aXs>v<O7(Jx!0=
zdqSLvs1T!%H1MQyN<wrY2I8PCFA($)C_fALX#BB&bmkhzM_^Slc|F?fYUDD%KcDb#
z=fsB|@GP+}Uky7_ at CmhIBO-*+PWLunv>{Fq1wb=sLg0ymSN{P2GH`R&MgwGeVY7~7
z_CZ^HLuU<i1}+o}avbJQs74 at 5e3gs!IkKUyKGXpr;{?sGlV27<an=+{B)>>t-<;|t
z2=fxktKh;|j41ek49K<Im{woJ;UIMUAJ;ncFv!BNMqT4PV*4q(js at C_*`U{ofjgXK
z+1pz$-&UkWI=lUtW3tXzK&H<{n!(Wb`C8wIa$W6k(`kb#c$OpKqzLZ+>zU-^|Gaw0
za3y3<VLMv_l4?!dtRTA$RZ#)7zVhc>k0n{6+obs#$~!sVCVQRa>Oh at B7*Uq<cbpFm
zl7%k8YY#aeE_L)Wy|Kh8a)8Z=q4T>t?2rliCkZRGWSWoevCOe<|1A{bF(>d|z_r9w
zNFfMFm;+~dCusN}N}UKX{-<mmMfCZ(*@BPeL-a{3@`}e0=<|7={Mtx{=n;4B7fk3R
zf04iYAVvUNSydNDFvhgpZTB{x3q({fqMV(9{ZapCDUE_|IG+Q1=aD at hGlzo+i%x@}
zFT at MSOWpy}yfxP)-|N7}tVRCkDnm2K;!}V?*W?_KB)a8N{E<c)6;HSE;db<*h1ARN
zM)5!%<}kep?c#y)Ok?5&G2F3WO&c)^P)I<5g2n3diYVH*!aDG@*H1*w0kh7nX5~jT
zKmi770X at H04k1FNefXbFtAq@XV4M{LUXP}^#!YL>g*`?T)M<Qh_&IoJtIS!zfa(Es
z$_li2TweaHXK&)bDF&6A>H0%M4)|=)#|5c(A62aXc=H?JBI&x2t~)mfTG|+B=$axu
z;{NSp9zuZ?fQRTpCWvE!bn2E3mcMO@<e^}E)oxb*PaZi5*@;4Df$-0V9>*pnehN{}
zh3P!bpd#@bid%YrpP{<@^vjD-ctmI{Bv(P2*;;=``V^F(C7;KgCFfxHb5an}hwJp=
ze|l)&`MZcYgUwnzdI1AO&{^oJuPSirL_T{Agaqp>;&Z^W^Q{=%TjP%QN(9h8^oI=0
zX79U&!I=ojTZb=O2l2fi2)lVCFTuLs0N<b)pwZ+YoGblBklp!)n@#cttV)IUuz)&|
zf90>2228TO=TTR~01x@|aWUDjjVh_`9ubOym2 at 50ByH4vP$69McHf=WPH=~wGJ|gg
zjNw~4Wu`;Z^7B`OOWX^rP2i8PHJ(g5ydE?;oXk-AxPkpgP6#oCXk=u#0At06U}`R$
z(74LxhY7iafo|k;GZ4kGUDR0+PFW*KlxI}vJ%8rofq)y_GrAIaG0qDharRF>f|`E=
z@)qdKS=qzbgz=iTV^+|VP}u`UIB%1q5&jo&imgETr`|%yRFqsxwzhugx5la+at87}
zCs2AsP16IreMEiJ(He at i)73zbummH70_dt69hgjr(?8mpOvHd%lmXmD&fu$7-w9V9
zfIV9+1H%pr;fHULSWL-$U{~<FP!!6>K}2FOHgznsz>e|DbOP6qWk+W*OIZukslRAS
zE8vyQDfrBQp1Ipk$VHuJ?=A>UgIUX3klNwWMw5fuC29osegBcSLn9dj7KWXmO;<ky
zEXD4`3vvTmfHWwI==>m2$wNlHz^W$Pv;vuzfF$kN5XH~;Z`f=PhbwjB8=hhN_aGwF
zPXNLFTOu>UAgvrmh(JiLg8|aR%$*bgIrM}D{F?&kq-~2Z%)XNML9D)l%!xG)<5~>j
zNqXZ|Q^JvR0YhO09Dyx?khspDnLmqoRUoZjJ{b9_?I$jPsH=v}Yd2*8c0jrCwg%WX
zfoO+;iq#OI=LU0z9v%RMW+8oKl<C(}9SO`3MSvr#3huHqkUv(JNv?vKVF{AU(RJ*=
zk7Z)Z0#_LfxC_jJ7FZoe0yvo1R~*Of2K6fTf9f!ybPxi~Sf#7q`}4`|Wfh?HWdW%t
zA4xiwya`x~DiT>h#!L8M%fvY0fCrTUoyeOkVN$j4+%_Opi%iQo1II0;uqE$sk)mml
z(>d*Rr9U4`BWsBT3di0}seFdD#DjT|l{x~=3xQ|c(W%%AqN{4yV0{3~!2<ZsZZ*)i
zZUgEfZYgl(a?@%o4wwErL_c-2>Mj3~uumg91mi1t-_G*Y!@3_I2TW{001wIgxU5YN
zfFJ6Hmg4I9o**4*21WnVglt6P%zY2;(%>Hp6*&9AGBXzqJaVc}az-OgBTyrnAnoqT
zVVG;pMyQ>T{tuVM!-NVbA1ug=?7*ZploA=!+36<(=AX;I!6oS$gsS}Co*ai~DhO2<
z`JM948JRx16GWn{`UP=!;)77I`(zIY at V)0J5OD)2syo$;Da#cAJXn}_A8SoG+*GpW
zu+Ge9U*!n?DNgKe9BfbUurPsHfYp=YS8jvA9;Cs)`opqD at Y+i%Anr^n_*{NeaokM>
zz!eofn5LZpN?rOY%6R`Erc6mfQi-H|WKZ^QkcnBthKkt`s50S*JWgmN-^d&GofzNL
zv>frnrND&~tZv5G)_)OMuSU3;B~wfwEI%uG;ve5M2#Ij}kBED4k3=pKgrV-rga-dY
z=jVpOYL!4)!Z5 at r72W~iWxMM!1ghr*He!%Y=9;sB<C4Mt=1nk};|<VpIM`ceh at vG6
zC|VwvnH at aS7*=eU$6$tb{O$}WKCN$;0!I=9gMOBfoin|6jp@$|>D)u}uXTS*ByQCX
z0=%pe0cP-R6b=LG!yJeSSE>1X|Aa(<BM{%Sd^jL&t<OjI>?3l6RL(QEG at dkY9`2x3
z#u%!esnGtLPx)cM5d%gzv*4zYB161(P)O1&!mA>3$Lsm`i5^2cUAPDm(=sFrz=PW8
zw*p0K!0l=wAHH+a)6s_P_tL}0=!QdqjY;Z9LBW-f!$Jg#T0lN#U$y)Tp+ccYa`C2)
z$GjYm^O}WqbAhEsIImp_rET*)JM*s~7Y-%qaoo#83O*)7q9m);%1sul&A*q>+pF+W
z#CX;7NdCPrKu!WrXcT9Gm1BMV9*i<!INoBQKn^)PxX?TtVsqd0=7%;>LX(fJT(3Xy
zcALkWrDaBb2hk2Br-b>PwfqyNVgJAzhME=#<%NZ+7TG^$UQ$?P!6<cC*_mSiDTR9o
zaDz>y5dllyTWvX0Q6!Us?_6y<?eAJK1`CO)9*sxb1qff!JpzmqS!G6`N4ex}o&AFp
zIV?_hrfWoWAX=4#szO7r=zJHFMYwtlhy>@s^f3#Gt{Ej$DLBD~2Od<1Lr$e(z9%h@
zB<YF+aaL&7k|7+i+f<^Ic7ezdzo12g!tgLuREz55HgGL}nF0MpV`V`&uuI*WLnPP#
zO)rW8u$0Vr$@BhHCs0k;db`6F&O%42NfohJvIl0C5r7eJxeSUr{=%f$=jlYck=}K(
zcvFy>0XTMt{^NQbqYiIhrOrQw^2nBFLmX_~z00juRa(;b5z#tOdFwoQu(IUGSHDNy
zc^qph^e_lW5{=rD3aoAj5)TzEGTilF_njnxhGw)HOr_0&S6KDTKAaimtanxB5p`S|
zS at Gjz)t$n*AT+kw0B2FQgr*oMPCo~R$0P1^a0fP^HyuetMsNf&lhs6n1lz`dA4Ksd
z33_KrxM29dEqxzK9if=ZSRnnE=W~g@^5p4 at Z+jwIeUZ5oE-<10x4 at M}<h+C483P;f
zACSq8?GYF%bpxy25=PK+3RNMF%_1`)`o25~bC$=TOsd6OnZ<M=#`PMY9qf7neBn;H
zXInyo3Nj_sIK-re++j^QGXDFqaDzr at MJ7X0D#wqMa5M~Mp$3U#WJO_&!YzLz7K-<E
zpc%K4>;saT<J`!I72lA at 3CVj_zaMH4JOLD=W5FL^Ac!822R_aB-+_ik{hqdckD+}X
zOJO&-v~2&r%OGM^)A%5ZzM{uSUs{r#wP*+n1EWkc at O1wina7ZiW;HGNBT5b at M|>@a
zV87PDddtx}zf-*qP=UvMusNp(PJ*<5lJs$$ObCVc<{(UI4Y-TI1Y0FPIM;Xd=%~Ly
zig4LnB#Epw=Nz%R=(rlgK`Txln at 7t8RD-3$IddA$gZJNng%qXHDzN9$t$%@tmnC at 8
zWr6!ZR#><c=3oVwA<4ssQq~^#PedufM!Y(ap)|=8d<k_G=o6MuKXroH(#q8XmYEVu
z76k2Xn5ZE?Ba)g&2W1<WS<V(J_1lvl97ts;kgFWIlSB4r6(})0f^td&aL<`g<EX`S
z4a at wF8IWMeZj%u#!`F}qfa?L at 4;7SM5TjJ<eFBzIGH`~@li|GWxHLL*BNzK{7vR7N
zpY at oZ(ve~fkLb?NzlqYo3WEzAK+CI<MznRqAW);eD(mvXe|w9E26p&Yq>Ko+$a!r&
z4<)=V at LeO%T)KVr{A{BC!By5E?VtJ)kt5D&DT+eJBasLMbyJ|}PbhZHk&ws&gOtDb
z_&eqpv^h!r9K<jqZm0D*OAu$PeuMKi^dH%NFR-yH#XGdI`n_~Lu&v+~yL*={Ri~sC
z4SNB|w%(&=961)fjJRybN?>`jmL&B*`gX>LweJkIK%e{B#`m}4g6)G`4?<oN7Hl!4
zM}#K710r0#&=QU`-z>*8h;<t^=N at Fs3#NmgU6&ku59%#iY$%5AghOOWhmjMvWF)ru
zoqGi58IiOf%)f&H(v}J*llT)1+TT}zCzM(3dYCn0LB=@03fim@$+6ahpVwe<_KM#~
z4?IjWF~K;2@?yy%YcNMt9u69eg%D*iP!mV5Tlrn)X+`qz`c~Qj+9RuhERN}?Ioy91
z2M<0XPRphD9Z$h;O0y2=2!^#pd~Q2W%co$F!TiAL^x{pLu9O4Ig@>Pnpa)|C(ZNUH
z1lUrFW59LK68hXcvx5+z43LN*)4%~JO+=@mE^>G1UIg0 at uL>&rBi{b%3St*&Y*U&d
zns1|7#R8~jf*pX?pP at HjUJE^NJ^TU_awHcd86WQtT0-*vW317bJUVCuEs|{wmoU8I
zM;6=$#Inl{oWTbPG)Wg;4yVhbBc8`-ljEzER;r*pWQu5we-k6Pix5aGz-ZU3ePjV(
z$i=dpE>(RWoM2<*mCE{IL9v=B!<hrs)^`6sGC%-n0t8vh(=H<e4Kv_1+`zmJr89^4
zVBqhihAu(kjf!V@<i8L;;X?w3SGz#QOo-kp2P?*O#`l!U?ccJ%M@?WqKiCv%7zFsn
zR{dJ>9?B;>mMo~)56+4RA+ho&=<BSLod7NAk@~!s=a2(oDPS2C(o23pdt#F!3<vLT
z^#&|(H$Q&oe+#ho^a?1Z%m6)g9NGhnneox1+h^`{es*<M at UsYlZP}T40aUFeboeC?
zOjtJD(dZMnz3>Agm=s<o;<%V0 at 54~tpLGD5!&&iV06G8l9}nryMj<=Mjy|iJXFQ_q
z%j{}`UE%o55!01^e1HuFV4O1g#ay|SsW#MmmaxVPkdYolby$Jzi!IMw(TD|zdlmHA
z)FHqk68C8C>pVZhl?B*$mzK+-urt)2v(UuImWvbVnRi>~GY3h3SNO|L5c3abH<mVG
zfgoLADpbQ#*mv9Z(!n$aUVB=_GC{n2@&~JRr}i1vqY)a9gHYD*GlGJD2^{i7IxPUj
zbhigAz<Fnxz%<OtaUSy1g1F?ttE*;e21teCw!uTAVgzMG_8_!i8zc#wv#M#myWt?O
z2hx$!-L#SimKaG=XkFM*%N02)e|FSyEW{Ok7Fxi^pXA8MpA*8#1_=Dy48dU_75a!A
zaA#q*kE5%Y)uuQml>E^;h+v%y`@wOzVMs2D_|Ek57tMfK@$bMTM0EVj!h4y`alw64
znB2VbD)JoFH1f0KSfZC7|1AZs0*F%UO>U=mCkHIw&oMfgg6lY>t#&U6?dm-5W^n&}
z*2fAk0Ww20<Y_}rg%{Uc5C6MC4~f<uLQz;Z((~T!u9xpOm|MobhHkd9)^yH=gP+|7
zq?3NRsKx9sXd!$1GB$z~0<S^rtT~5P9smqb1gumNIUZnFvTr@)y<K45*0Ey|aLD)1
zdXQ4)7<vooV+dA-@&CJBrj%(018L8EA+Fy8r+9Md;ak721~j4A<M9|j_JL+Zf+pto
z{|8 at K6m?Z-*}q0YQ_4dyBU%X1(ubklXlRcyzLz=(*bI_G5Pq}Zd{dq!zE at b_Wati~
zU&6`Wht`rQ8jyqSsHxQt!Q6v1?@@uA|G{C7DduHms_(^HUtgZS)cTb65ZBiu08`(#
zK>3fVV}KLF*2un at j3n?R8zeKhd6*zZWryV#AZR}xGPc at IBYg_k)+Lh$hb}1J31ta2
zzKrVyLv_#q9<9N8%3`R4|D^=<iBkM?_)>pjC4=VB8}`O5I4pi%@WL{a_40=k)-9d0
zNYXxz{q-QbATYvLBQg#YqX>jh?`Kmwh6fLNiWDAHf0bwFA3$OBN{mnq)D_FB>;p^?
zz`YPX=S9+kf%Rj at o#EkF!nyofzy at sRhqvT!qnHq=CIzuEwY!X~{>Q>c_5oV{BeC4_
z-h!uKH_`_K!_oq<PtJJ7l7QHV#}wcI49L9=k<1e4DG-CU-_6Xxxxz%h@(rU{zv4j`
zOV$znLO!`&w(AX5kTw2MgN>L+Xps8r0S!a#r^5TGy6~8CVb5ZCZ6}8INz(P0kViD7
zssq-A_5fZO?d?LDE!?7N7^EcW&;Xu|pBPr<4(tboI`B@@y+v_WJ$w24&A at vmX1WQd
zWaLPMpI%9fCx)BR;r;gD;3&(B1|G>3qGshs&Y;wbV<|au at lluLy}#2CpD at KZ<fL+!
zDeuognnn-}9)jI at rfo~=j&MY2#Lo0Sf4V94d>W!x-(FmS#6X6mU8rV$U9*8E0|v^Z
zfUc5*AJfPNK~7Fx%4%l#v#la<kdyiJV7a^Wv?U-Up+ou4h7Q;M)P;wM)KCpM&j1s}
ztG@`r#}G~m(xjZRQ$2v8V^UzJs;vI}@c5slcnm8W8<}^9Xlj{e2>55 at DJ|=~7Ln{u
z-75zxrIrA}>xto>w;_zz^~NAzI6#`YtW}5W`8DFj{Oa2Sx<Az)Ee@%=$%pDqq{cm`
zW!@|jPx#^B0bkV^0>HQ7BMo9*H_^zj(Vu}TZQeYXlqG!l1|Hz|%S_~dx|jgVflY8X
z+*N7CCn!KVh>JR7e8 at i?*p<`BhGQYair16)L0(UUuXt~3h{TKMA1#1s3<43Gkjorw
zhYP?0;PdzN5&2U|Jw*;x$O$O21zO at PGZ1%IzDz at u5nzwRJ$OE=R~DePwH31lW`AKl
zKau_ixj at rz<X7k&f+9?sv?#+K=SRaf91z%9_|}WLwT1`Vo*_U8YQ1!%!-FPYork#T
z8d^|qM97fo(K^DMTYr13-vq7UJQ*J{1F$_y7OAo*jXN5F>A)CKZ9fwtW at QoHrbf<n
zSXzY at Naq=mPfsoNe^KZwWdHMJI}%Gq*&bD2@$62Li(AU{;Qajt0KbWH{B@~~5?73g
z+{C*2?G-Vz+m?qR6<UC>%d+A4c`av_hr_A+D-Uyh?4Q-}- at gk)>9pin`=2>T8QA!J
zwrx at ckngbnFrwO{D*(w>WOuMaL2566InR#4dj?=P0lScp!M_4AI7b3UN*QnJwYR9q
zsu#*IwoQqTX#A7H7#MHg6Z?ONIM1*JpxYI8$^aoM05EtdFC0XJ;Bz21+{F%7)q7n+
zU;yM^KQjE(KRfoneitYMA!#$M=O8!1Gy1O|LoTC&jkPSK{~t}`BM9g*G-46T8qKNk
zC)ghSF<ehI685NmyEh*O_5b`PSpkUpW4T5W|MTmA|3gQ_ef at -w(!uil-+rkDbBj`!
zPK!VB<nT!xJPza+nse|SjxpK4kInz{n}jxDiH0<VvHXeh|Mf6NufVoA$Dw=#w)xL5
zVTguJxulkRX!G`OAo}+jkoN*~2{ahM{MSeS`^PZ^3>Gji_`f_lX#Q7X#L*`b;{q?N
z&bT4?=wJTFbuJ-62$%f-UljkJ76mEGU_$qQY>%sQ2c$nBOm at Q&!PI?cgxb=Fvoi~c
zhObNShyRJ~7noqhe8BZJ`V&ZLWX;e(scZDTGmJ;UZX_8eg>*#`f=~}63JR(5qh7!9
z7l2)tY>@m17(a&on}ETipW{_JY73J3EHImL;M{lpr}M)@<IID%{*G42Z|37=#$LoF
zhFEO~%BGyxMD)Fg<N-8(8;jSjg=n_g_nOiJG8oR1*L<HRvk4zBP+|zW6j=bBVu~J*
zAaM4%J_~?4X8<}XMetqpa_B3eGW-cwA|=onkwdy`aij;PvTyGkZww%Es5W^NiT@}{
z+Z{Jb$bOgd$r|GOxqyXqy8B at s0LSzVoTU-qe!4qb|K2LtvBnd3Ls6=~N?rz?{&bM1
zFMv}<U=B~ak5DYO0Q9-4*O-jC4i2%L at D&H`hkT|AN4IpUo`qdn7<W7K1nwCfMuK#K
zU1VnTW`-b&ddr=$qmjLUMpz5VgnVU>wVF&%?a?mmV<FZiS8>oY52=hm!wC!Lj*Rrs
zy|@}XM)*u1GD3+HT at _g-atzH&_7or?mLTztVysf_b67C5ZOcD%efyPA4R#Jr4(J{1
z2U}ncY)=*Mdn}KNC*?|E+mH?26?Di|SA7nRg3H2d2tT4)P6w7p_2V<7Z21+S)PS7(
z5n5$0pnOIM_XN>oh##<M=o$n!im*XZdqT84K6BYhtAEFhGR1g;=;$B;EDLIM?}eee
z#Rb0f&I+Yi5#zv;@#zJokR0zp7u`%z2dbt5P(w%*SqGiW4$x&npu!pG_GcprH_+V$
zs5p5D(>9b(@ml%-e0{Ye>RQz^qpJ!C56u6Jwo#}d?Rbd(_2}p^StAO(cE4leHLFk3
zdfE&K9z{jZjD%QEUz)k4&C`h_nhVTX&G!j<5Ud0GriCF|PBl=Hu_L-QQf0kg<$X16
zYOb9c7 at 4vvdDa22(>j(<1iP^>Ke%gw5)6jrrr)VWY{+W2ka}6FICIqr at jkIYN>Rx4
zm8l-_gh@}(U at 6rPc0HF;VmxH7A&;Wn7=zcI02h`I=D4Z7L_>GW*L+PQ_(6(S^tB<f
z7RZU4#hhSe at 0Q;wbwH3?P=}#5mJ6<t6C%6d1`LRb`~k;tN~|9A?M3>j{LheDH{8`F
z&}>*ei at T~hpK*No*HpuA>fRsfzrvzXkOu{T67j31Ca<O3$Jl1d at UFx7^JY|iz#vFl
zAD5$Yj<DJn{hjtOs0Yf^FuA^RI)}7((Bh|N^1HOw006-tA}X-=3ObZE8un2Dzor4%
zXw6e_=Yzb|GG=T!H+IM3Uz<vXRLCSbHo3PBlZXw`2Eg}+VnD~xv;=8 at ye7Dd-EeWc
zezY?~qYhqCajx$Vv0x!#oLDCc<viVkkA;(!fMDv*u at +EgJj~BDqL2}Jo at M{zIQnl6
z`X at OFIU=N-uJH8#J0l`Ib<vxo|EIAfL*}vP{K5ZxM4;FZEW`p8Eyo{-DcUx??HM@!
zt+}smAYcW&hWcPNqe~iqSX;s{X%1+n^&<4Cpk%w%>`<Upeurk9ZnW!KXhSG_)&4FV
z_brjGJLqJz!MS~GpA~S;*T;}nw&l`j&DwzTd=CV)iS@~I?i<gOcW<O+J+p)!%InL7
znd*zkSbR8`43_~&wdb0)p0j7V1?_iBz{)i%wdMyoJ5}S<9bVW&0Y-vfAI{wb-EmH5
zWK4KH;3RH`pljtsE@~WiYaJNsKY)Y9zF$m~M}Zi}BY=0pvTvk)Zw*Mg<j4FF=VD17
z%#TP6nz?p9b=YaOtNRqMXE-2|`-x9ZM<z~{eXeCn?M7H_puu~_wY=)9;fDthN24RY
zi5wy9KERv6okV6ipjDLvmLgwqD^~P5LSie-U>a{0ktz8ytJ!JTvrqPR9|`q-0$WMD
zfOTXmG6e-CK%=Dq`tlmUXG#M!t^jlsxYZMp-aLf4aJMw`9xyP&Kp)5ym;&<@EGjAV
z__BR2%MEVjpWzWzH!ujfgPu>%Yx<}O40-WQb~3`JFuIELIJm%$#`#yM at eCvyb)C?x
zQ}_lqUgd$eFa}r_R0XPyZ5=1`$B~W+^iNvBf7cvwzB1rPfTZ%G4_zs4glv$6KGaRq
zHo;3bvo2c=W~3n<=Z~xH1abE1fwIzcXrX<uGY<bi;Np}i0L?D}j}Xhvl^x(&bRRfG
zP};uDx9GXeA6ky5SmrTcj8yIi!;qpsC<ztkb-|No7p5ZlFi2M&S}GCytYH8rH$)2#
z&ToU>%2?B1VQzjT6xUxPZ;E7F>8*yV*up-fzUii)Rp7aVNFjDo!kA}9>6{r%d_3$l
zBq{m~cp^erQJe03k+xFY2Le(-`Eys<7GMo-6FlCM^mmu_uYz`{4)n4$nk at vSGBXjW
zoP^~&k(sGlk!=&2s7QX>jF_{3ZJlOW9oILZ`^)H26g8GYLqLDclI*(Q;c5Cf8hR<J
zasvBJI1)_F&o;ts>2HM=Bw*6YK}XPRM_fGX<MfA6Ug(m`vsPT{{`}I?XS;i~QyMIe
zZj5Erhs69KP~HS)_TL4&z$H+7^nxj3_?d3<0sJR8+-uI$wavl_Ow7RPOCdJ&A!xg^
z&{?p?A$x?Erhq~8cGy=-gj{NInD2-9^wM`}+_3}oEW at ecdwCVm>sEmEVO@*ky|iTI
z#LU%i+tv;wxKNwp;}d79-cPe;5Vt2lE97shA2^i?8KUk3tEC<`wWtb$bV0M1rOhE*
zBh>rv*9!~>U{WDTD$r1i#l=nJ9%x`1hU$;9&OKmJ4_fvG!!^lmlunACr3)aU@<3XU
zNnnu at WcS+aL+LQ}xLuzt<?@k*@#jg`*IRXtHi6Qg99bD6yPVrmCTIIS2r?2hMPCPg
zW_#iqUCPI;F!xN!q+cw05khm7{bRC8`8nTCk<uAf>;w at X@-aaTK;vq<KhH^b2R8a>
zE_{-6{oy2UJ-(T7;$h_gDv5<upR<cSkg8{{?ajdpdMkOHjDcgFt|w>pU4z}cZRr>y
z-UB5=9x#?sIEl=%e$pLdSgZo+uUpMIW?GV|qI7 at Yj99$B7K|58$%87RHpqomZx4id
z>Yf`MIkB%ok;$6k0J&%zI=$=&qvS^D%?*G&kHz3Nr-|VzE&tX;93uKBRV7kZ0fcBh
zZ;VFfqzH(ALLVu?6&#e@#b&~-*k3o<@y&w=_)q6jvfN#yGgw}#2aT-4mN?OEVy?~h
z%#lQ@;TM50jTcTJ66R#a#R64rv5Z`styAB)Q+moCz%t)a*K+%+{pnn-lk5M!OLZ4g
zxMNxnhADq%Gc+7qV*EzTdJhO222XNETJt~da)v(n2rIdB at kh6=>tlCW*3b{TpNTDX
znQJ=Wjw$s0coaR5{<CCju6cXF?v2SEp2R9~(ITk(x<O8+0kzR!+JBWft*P>5xoB)}
zTHc$IIKu!bu0?NtVE5YBGA4FIkAyg1edtq9t}zDqvpeNT!w8y~&vMpUf87;a$hvAq
z3$rtntmFr&@GYsVhe}~bY2A-WG2#7fgm+7%+Aq)t4Z%-SD!f>c9~tM31cd2d0qR;~
z+#xcZ2H{D7^V!lfveZ5(TkSz;?d8dEf_`a55ADf|;&Opzy3qSrDpVtlbL;ws(SCIY
zTJ_#?D5;JQ>o2EU%&DO`u33{1v_j2Wlma!Ues!bKkq<wQOnv22yf?Iur?ttF#M=m1
z#J{|gX|e3=&@$Ux&h4Ewk9P$#*eo0Oy{Y>~w<P4t%>!(rl<W1Cr0lLW>?4lly*y>5
zC%%=~P7YU at GOoO5c%L44NjzQ7d<=N>O^zY9QE5-y<IgjT$dO-)Uy~gVypd7#6&W<T
zBHp;{{kWY;yXtF at HP&y05TrE`sL_P}lblA^>wJmh0qX_C)%D!3C_6GV#~F<yoqiFg
zBG!8aFsl{9{3<d%lJ`7|Ffc|Wyhy)G7tTW$n8nO*)wWD*&$&ZMW%F`w{As;JSKE6A
zAh*VjlV`*7<6 at pv@ik5lMOj9XIVse~+C&pc4>Pv>txdJrx%^fE*QoIe-<9Va`guN-
zzX)`hA3fD;^zPucNk_E^+TQ)rPMg2lFC70xjkEh{w%1%r+K*VY#S_LYsgGasy-B`H
zTWgT*plXG-p&Fm7q7{>2`=Q;qEb&2ok5|IEIBsYA8|lGuZ0Z3`Bh5`y{E+2d+h=KC
zhB(NJ<()slnC+f+M3ll5ON={otc*))yWQ<5wDO4~JxJpilwP*FDdsTjO2~UXBR^<c
zL2|tE;}xID6lMBxr4iyYSqVBhSf9yFq})NVS53is7>*ka`)#w;x+jP^`(9$HvpN(b
z$nY6 at Q32&+>SZMWlonKveKj(BONSD|7rzl}*G?MGR=bW{cv8C6FUQ4eO~O<xWfRwl
z#m(*4lQdO&hvTcU?G8$cEkcjUo28xyXMEn8+Itq at bYiOD35r?Ci}1{7(!6_rzuerr
zmHFO}P-1Ks1)DpIEq6KW04Zw%cfGM|0 at C;L{P at aH>Skw~ZJFLcLwDYsxPS_|;29T+
zLIw26Hde!yie5xzNamKp8(-{r3-fO!JWbX~a#2-)C5+T7AC!z<%rXAC{W>lm@>4`R
zKtpXv#tV!*C!TBHBe+3h4--D&R$tyQ)rLgK&}i^DrCz(J at Fw6s&I*9AX$&bM%Yo9m
zFyyhsQ$j*4Iern)zjLlP<xS5ArWSTPHd1iL;>iT+Yw|Y-S-Ze^<Vq%ef5{eL(c2o*
zLDOtZ4L;8@&I#^h6(9HXY7QG!z6GsS>UO_eTq_+e1?vZnKr|}qw3!-<oW=6ALMhEX
zU2XQ&uqs<s=7Y|<OS2{#T at wJ;x9Z0<mHp8!P=lR`#UE?BcAOvhfNdzE+H+1&1bHg6
z5V<Byh~^J8S?Mq<++>Z8r75-1oL&|~^Ny9DzA^Qabk&ifK<h)B`RsD8?72=qwwR{p
zNu?ib&38cg+W<D(Fjmmi&ONev`@YAb`!Wt44EY`uE<K48>N+njNG82Fd__YGO2R>6
zD>CJCc2 at DkHdeBF?jLwv-QuN*b$KG8FY!1!gIR;n89I6k<2Jm4D3E at WG{uG!<6JYr
za7j!?)Yp8~_AlcIgPAOkq`s5Kw^7ViOUuL*NEey3Q%~-gQ1H^XY!)=i*otZt<BxBS
zy<=^)@ALfnr<^z*l0(a0n?(`$5sT$jd5sx`PyZ at yeRpx@_j>)VWnRulLluF1SG>!g
zSc&<V?LiI6qagE*x6KbVbUTqZKa1e0aA#;nX}f#B-x7`pMU$N|0I at xR6i;tY?-d2?
z1=fj1gu#4RnpBaH0iygSnGUl#YSYqu#ZkrCQ)kr~%s7^9cPGnPCqj{V?`J8d91Uj#
zpknZ^UMuax_;e;0(nC8!OFV8M(em3~3H6&~;Clb6Uxsv at s41|Owwihdc~Fh3i7Joy
zt>r-|(Yw!g`*DQL at r4zp?7b3~4Mwu=v*}%{<Wi=XAciyLspM4L4xSQX;R+Jb(VO>+
z(f8RiPdWT#8#H4oh at yDQ)8<BYl~IE)R=^KswfAX2g4H9~=J~t$l|8Es0h6t#a2#PW
z5i}nw<zgH+#i2|)dE-fxMY2m{00p6u>%?5vX_xs)zFHjV6XWrN(Y%6q+oyK{4VRzG
zNDnMs_#{LLg|SnoeMc+Srpx@)C+%^o=eXyji+w2=9YQo;8bE`D(cy!@*vWp$V()o^
zjRZfLw(^X12l43Q%|Iu<CWpu~w=<xit?^_wojx5eTHstId$1+n(PzPVvIijT9n0-0
z*On4H^FjUlWmz50v|X`U-{!FEW39r&IZWS;g~>>tz)ev>J8`(d5eD5LpAwKo^%K!B
zx<}_&T9GT09E(Y8E2G1r at HdR*`<AU$=JaAsRV;Ik^<?)%OI$h}OeV$D_L*j%$x9`L
zq at 5g1{m#;N&!=7JZ$z<@*10{QOQA`1RaME)lI*IKjMd6IoD&xKU*k8F_a?Ps^S8vr
z%ayt1-<YzD*Yev8wChx>qH<Zdr|s!v;z^SKW%p)2T+1yB|LRFzHz4>fJb%iBYbx7f
znJ~4O+;n}nLAkwDyR7h=JmsY82jXk1YrV-qO-&Y6(VIU=WY1M(HR;9^BDQqPPHdBX
z_oMZJ;c%;;^1MC0+?Dw@^{osk5Nvr2qe%)H{F~G3LaHtE&q1uWa<GB8;LY^IpYt=k
zz>MB0MxP|t0?=aDG1&=M;VVwNMn7t3`Gh$xOZ?y!fS0275t)O{Cp*xF3!6T6A at 8YC
zn0!=`G;6{NeLPddc!+qx>D3Z82`6AoZk?DF23YF6Nq3zORZqubRmh{`^-7lOoP877
z1Sdm2`cuRG$IWu|We`jS8H5)rr)brj!H}#xh2cFhlHQRy;0j9?`~S?fN^R%QL5V*X
z;TIovDyEk3w{$3eJEE+lP?zla!D$A&%&N6blWH+`Cf8{J{35Q{Xqb8TDn4wn at 56at
zJzM0VT#Hji$30>d=ktl;dwg8YbpFNSmdnOmI~n5CY`ZLWelvF(B)^UuN9^Khyrk;U
zz5TNdWi{QrJ_c3e`OkW1pJ<Xl50q#kDx!2a&g&UQ&ZaIgnD4Wm_OyxVaTICdYDXs>
zpLF=LTEe?MUH%*jP;zqV1EeF+30q;9;QOq9`f at l>wr;xpkP2=uNs0TpXtt&55HOX|
zpeYeS1q|gVZ9o1T0*ZG%Wvz#d47~Pt9yYo!Nmj$ss$$VAjdw=gRHIa^34HW2cD}s`
z9Ne9A_*~cr;sEjwIdRfcBP!=QKYg+}w?5JG?Hn_C=dln0S_@?<8I^g8^}nv#Qg at 7O
z0Mc+aGP>^cYMAX88ijMSS+ND0Fqf&Dt1s1M->xwM6qZw{0i4nXoJNa@<`3w)BHJ4R
zo-W-&616R<Uuc#ao>LadU8j{D!Kz&*SAJ%r=gC6BiE?mf%*?Q9;ASD$<c*fM9?ajo
zXiC}GwiI-u(MfDUg-yo?6<eCH@?Ku^c;r4q^d?dvJN!^raYz;E{}RimhUnRUDm-66
zJHDxVyCzin$WcG=p3w7(zk{;cX>{wlYHiO5jXUwboNEMpViwoio4lRXcFg0_R?7z=
zn=8q(SSddIrqH<(pp=*)A!nX&A_#rfqZ?19{TG6jm|oq=8eXaiJE_<nBk_YtTqTY-
zt`?Xg;|lH%Scr_HPClCjGuDY%{IJr2UwfUuUJ{sAD8zF(0bPVby76wOhku4~;N<XG
zz+i_79=MX3>U8Ll^vmxz|8<UYE2DM18|EvTK5 at yx{X1SM4!R>#r;>4JTB)@B^FCrn
z%SKCP?3Wy$>>*!KTuL7<-MCpSk6-fGhqg<BhOg^59o-FEcAloD>x#R}HU6mGs#l~3
z?XywFm}BpjeojS8KU?XFf3zsb8v at W!^tLMfr!&qc7#Oyz1osf8lQ&Mm7C?k7H`A%E
zLpjRtUz+UlEw%Jh+z)0}yI1qKoT251t&CZCkHh+Q{K4vNgj5z~zQ1o~=B%1rCA0?3
z at aZSdJwubKY#5*AgB)}6Jmo%|!f>tBtL_Wh2Zfh3x0buR4^G#eAtg}_67WVm%c<|E
z2t4J^3M|It&O%jwO4AKt=8}2#rB5Lc`7x}YSS5Ezl{u8Z07u1}bhOuPdsfQ9JlP>u
z!pD%D?H*6wGUMtBDtztdT^1I((DM9Wne&n;&0fIMZ=6ua)#!&7EAxydeRRJdoU~j&
z&mfQiI(2#-17^LhpO-3dY$B>1-F$VFO75U%nD}pU5FGTl9FF67w%4_eU0FLZUj~F(
zHQW#dA;m)S8$mDj7&qdHe#QvdcUMRk7jp2JGjKiw$-fznrxJ`_b#>Fu9ljLYR_Li9
zn-9do&mE_RMXneEYK?~~gJo2*E0C77uBUizEo*gH+MzgS7Azd_P<>-Htl~5p6tbBX
z{ZcX1hPuM at B=P6vWTv4r%l_!rs=f25zo;Zx2kh#%r4`Y8EA&r_l}_NQb{<RHs+ViB
zKxs0Gkl%1U2V~jT#oT#c$XAz8AgA^Gxfa?pe<qVdQ2cRXX(&TH5kfa-yr@|ptJNb%
zb_~&{h{eg_X=3~3pQ?!hp0;sQ at IjUDMY8}+i|vS7@@!51^cDS^A+cl78=l>t#J-b~
zG%j8i1OqGmf#kGlAcVMw=DGhZxXG at Bf}yF8=3Qr&3PM*g13=y+L+OXQRvd;*9o#Hd
zH^`kpwClcD2Zj1Q`Z7NWIooM>MVf6mj<Ze~1+i&-nMv~IBSYEBO>nKAkeI}=Rl$R;
zvP1-?e+Y4Tr%0DGNu^+KaxM+zaRyfgG<08(?A$pQRshGSEq9o;TyAUqvY54nAE{M$
z06lF at F<9(6Ep)ACu!h}m;E%V(0xezL7S=s(i}=PeI|pyKDjX7=9B-vNO>DsihSOKx
zqSV|A4%ln59v)7dQ7~=)fuDjPDNJdfo-nwa`%E5qrGBIi9?irem{Q9OP>me20@?y{
zs at op0kMGuLKZbr>m>A_z8-z+3vgor{{AN?qAux6Sl at pbU4b3+_+#JJ<_A6U*>355Z
zHH(^Y2>aDjyY9kW;u9gR*1I&RJ*-wY47*|cZEW8V6DyFqvZpBP4AA?^B--{C>(sDe
z0dL!~`D$tKa^A}MjQT;R#V(K0l1EaE=|X@<iWi_kaEP7bZTe#;1R2%<IuHJU!1yK(
zk+Luj5Icr%Hsc|<HChvU<(s0T9ncUfHI?;y?qYM$pcLh-C*{e;WCo0*U3bdmty5Kt
z3%y-2hRN%timS#1je%yRkEbJn_0}i+L|ythAJarU at yQ-6)0C%UK`LwaEOz6e&HWRr
zmK|0caG!L42JL2^^vV9<;kAb_!bJS2X2;Wjb!z|h6#d3}DXZQu1+!V?PF%EberO~P
z?1=qP`qU+ at C`BGqqIeDS^x71$+#4aT at y&SNXJhFOKbNe0e?#c9?>(d&LDp7;u=HkS
zx4GzUk+Q&77#ym~@Wz>ziRnGjQ`>?{X at z<G=rx8$u0ZLJ7t44h^4Z$Gg)STjv>+sH
z at qrZ>4pIkK4Hu_(Nw<#2lFLIrjz|=yoNR6SR=!fXTJl0(%R(C{JhW<Yb93IB{-K<V
z&=3r}n>IrXEq<VaOa?5&GrqQVc8XLd^73TnNrTowQWo`%do&#s3j4?uvoly(>a9k+
zDf>yTCL8y{lO(=5hKBIk0^kgy4H+As%0YVQn&tDktIgY2HJavO_FVOrl>^IUqbv`|
z>B!Dcz&LSNB8_)#kak)>5a5ClW-73dM-@(w$y=wpblF4&*U7Q%<!q1*29moIF^p|c
z_Do%WyNh`|<bMfmp at nnMhIoCx2ryd~X+jP36i^8 at U{b&`HNC(q-yOz{^5IN}jG0-E
zR{O8PNMfaWW+&O!H|jmY5^uqsg})~58qv_8U95B2JhgaNMUxBS*FBw{8xiQ4Z%;KO
zM at -db0=*3;q$jxGpjqB$>-in%!4@!|Uka#j`BMrL`GBQi^DGsV&>*z0!t2kttKUGL
z^b6_{oBA*1mupu`&%~=RDb*-D6l}(uk*z8xLfdBQE^8kCK{yr~0`4!t`z_2>IGo;w
z17<X}#cUx at 4>e<X)HCU=bpXeEp?enO8qcdrYc^C2Jjq^MY*JKU+iTvZjHCJ9JxiAW
zY%VdJex0UxM}j3kaI!38poyG=Lt}fX*R-$|nu#vEB{xY688+gn&B!Z)0gL=W(hbDx
z-4_cm4%`iIiA}I*<jp1a8IW|lG52y$1#_$F@(Awpc4O%X`GdRp!P6VBadN-4M?QCx
zU>R(l&BPdTP%BNH`lVNWVp~&4hC+-xsL06=$cW9dL%@2>ft^<H^P`9#=R}N+0 at 8Ky
zNub{qV|4cYk^Oq>ae9<7+)9aM)|ZoyQ}jZ4iL2M#?t-`744nBh886|)+1-+I%zVPK
zB-=D2;JP(h!c>Qgr?|Du9wR21l2rk`eIuA2T}hWEe|f<1ah~HrGznZ}H5dg}Wajl<
zt0w0`XTT6zneqFHI^F|uJ++9Ku(Lb3Ot52O-P~AQx;m#F)zeOBzI?I3cETpodKj>q
zTW3CMc*T~)iMJaYv^&+ON<jk*X(HZ$&=T_t`{h|m@)8-u!=vfBnzza{=p9rw at 3K~%
z9wYW+0vA2{x0E=F<I4!uhViChZD1I5IVw7m73iG-AH-S*o1czlb#z{qPWL6_h at a1m
z;UU at UP)fdGlbvj8+F&uP5yyk+%{ly*@*-i!{nforl!o|7jF5wB%k9S}dh!=g8kys!
zx>e<UZHsJ$Pj at Znk>LUuElj)0mr)W2Qe_O0Tj7O|c4u!pBOE%Kw-1i5hT-2Bk9gus
z!u|?1*ViPM%)><aY7=ywjcTu5R<87+Amj3$RHBKY@`MMOdoBSHpH860691A5(ATzU
zSfZi05^PRV#}IIR&X;fBE(8G#gwBsM*9s%3rpPp0Bp_oj)A&EEIIhb!L`RqBzY`rJ
zm9?G{3%I^nN&(op;g2m=CDv((6N3o;0vv}o!ex8ye{oqQ1N@;bAmi<P`9|^Oy`c6c
zcTA9gOkMmKK3B*vcPmuG!+cj?<i|s!DtJ~;ySqd(6L~}XT?3I7V)7lHC){sz+2AwN
zc<S64BMj0XBlJi4;t=zYHq+dbz2DA27)P_ALU&92!5KL at LgI5A*Y$*iScM7kLSkra
z7-(o{x at _?9p6cvRs~A<!Sg6?9Ijl-j4{o{qVrN%^Sh}7*6&0mjwpI4?Zl;s4$1(H=
zqK(x|_x?PYMHvIh8P%=}`#S@$vFwyolB05j78RRXDbdxS$C8mn?JsbJs;*!qTIl1j
zV at Il1kc<;KT|Tlah`ZXL5BC=LsUAx5RS6tV$1zSF&!I1voHd2SUu3H71qRpfuN|T_
zZue#GO}qvpOW&@iZyMhaKg at o>x(7{Tc0}l0ZPBH_N?<M9_WOBJVynWRY*@QHdy|)?
ze1twxaYMgl=VgC(6;(J)FYM<5r28xR{*;B>Xpdh6Mp$BW(D!_wQn2oZ248)2TS~;Y
zWY%x)DNRD#Rr4WDrb-%nz~%dhSOAzU){cFKus%K+>4i9VP$EMtig`U-=ZOicslEhc
z)M4WhUgSV;B(6Z`)w*}aFa%X#`~6W{q_}b=UPr8c&`f7XLXME6<XxT)3GDvb;B&4M
ze;J0C4j?OPEKY&$W;UP|V?=gJXU^KXE*wv%5up`n&a0Jr`F?@fN;!|+DT^`~R2hg#
z{rn#y3Ispb?sXHo-kFGbzT{HW&`U8%07D{q94)#K4Wwb+OMChE3fIBxM95i)_puF~
z##p<1dy`kCK372dB_IP}{LQnMi89 at Q3>a;VqAU;WPx9Wv6kp=6b~pFjeWFg;CC)ZI
zG$_$O(B3Z--PSw#vwUy5JOL~dvLaF9b$e at t<qgsIZ`{a3NGX;Dme^2?h%S7bzI_}E
z`=k_&h**_Mt|6c|o6Nlp1^K0{B6{WH{PU&`g&B3wk{M=vhH40Ys>rc-FSOPW=<E-@
znR6cM6491b1302uR2F__@!>`#g>{6Utr at l^%&?}c_&R)|bKPo-o=fQcFu<)v1X)8{
zqf1It|CZUUy$?ywJ#e>eK$68z<p*6yC(;Mj_RUB%?wRuK{IM-RTH(|3K)8;qeB;Mm
zYx~?;m`io_>XLa=$*jJ&JGjrk3%|Jjbk=Eci_7^uI4CGOc6UWVaO9V9?$~qc9UZUp
zFYH(mYQAO1nWe#A-Teq<jM$u<@QyP!CeCbo_K7-Q|C{w@=+gx^o|Dc0yfL$xz+J}J
z568(DrQi3dGoAaV at e46G!>}6m&8ega%B~B+RuUk2wQ>bAtc&h6h}RE)wN&EPgytS2
z6$)W~q|V7}6hGC>Fu4!_QiQk94Rk)vy7=Sr<e9xi>it{$TRlx~%E`TO#^W#Bowa6T
zL85KK%{24Z9%dikydIhYyUzlld}xDCVNIuPcq57~fnHcVh9WTQsIv8y?6a)$$2d#>
zu1By4S^Bv5{9ji%=Pqj&DTGtFEd at k>ED}LRSBTL~FsXg at g+gH+-{5BBN<5oua#olO
z{EJCTYiEt0Yu$vKwa`7=$*aFzM;z?!|IvNj!JYnn|AQoWjNu$TDO3c+QWY2HZ^7`6
zLAq!;wAv-6Z){-(EE4bSY4FWNw}nM!x~W%{M>mR07p!2$^Ez3g${*bQvi^&^yg0QO
zci5FzfcnRHbk4QfG*}6S!WI<wj-zMJ-<>Rxgok*Km?3<01f~@wK>tNXwBJiiLQg*b
zVLBn*)dVxg8VN1=rxTfOtEn$ADHgAU+(+kq+>`W)h2I$YW~zJ|CYj8Q-n9r~lK*&)
zksxmuBq}8RnSKJ>KT}a#?E^Hqw;eHhwCS<eu=0iDR=n3P1+5BhwfOPQnPIy)XMazc
z&e?hCk73_adp(_$acxh`OYt69P)Pz*rRJ9IS0?kI7hS~j1RAsUE=5lV8J#a&8BiHc
zkPEujTJhbEI{BSfaJ4BFqoflLk8w-(wySG-x%*n_AVWTz)!njb)O^b9d=(76psLBZ
zhw9{UIWdpl?suNu9?vrxPmS(eoKMV^8whsWiBKLG#wn~E--S_|0$YyNXU at BZ4RC@F
z-yiIl+7G|@lu)Ks6;BevRTRUp0~Um<2?=!9r(c{eX1!{r2Nqs(f85Yfw0kWyAty>1
zq=&8eG5!72kZh0s6YagFkmZ#VO53Dkw1xJg+0K&^+F>Bj896>-8LYDPBzjvj-b_VR
z_r=Qo-r)WX77A`0z0q0c!R>(+5Dp3nwk%kLKWIgr;Ir`!<~O>y{dp-UlUYioC2dbm
zjcihd7j^wt&}?4R>uumSI8DMRRz#80=fNg`w(_7sNGkpQj`q)Y+K at 3jcc`QBtSSwH
z4e73z!-oX6D}I`Eop;vWsy7x;P^FPa2TEaeSya7$&wgEo#d+)M-lTW9yh5Z^lG=8n
z4GJEtbi9u~8v|iL(2tRs{$Gwh>wY<x_YGxYnY&ZU(=Lsc=YQMdNuP*Vt#jJjwYjcd
z7)LFbm~XZE?Aq{h2jJ_`O=FAUgF8lFu!uUpUw+{K^_BpU7P$Qo6|ioYyL8?rcfLnv
zF0XzOhGwww-XsXUQGRpRSV=UWi{RPIJ~#merMNu3q~NPrd~53FTux!`3 at 8A^$5GQA
zD+G_cUz-6VEk9rTEsMnPis<hRla)U_e|ihTZ2#IsQx^HO`I{WC^R>do>6l54Kpzfr
z;kdK3CM4*v>L1(5GOj5%qph&r<Fs$R+XVRMas2fMXXhR!%9GxuNM*okm$SYcXL2ge
zME{M`wx|1sXC9ny$G_CXE}eh)>Xfy>-lE?)PnLJBlqNE~BBR-{v~GeSlDX^ePD0{4
zyLfN=1)Ga5hHmmePkQo}p5o({xY<QsFLMT}6IyT}6 at TJKmY?0R_0&~ZJWM*+>I9!*
z)m<Q>v;n#3+s<_fxnc;m{N+Y^f7 at t^LNiTRu4S{c$|u>{by{N*d7x&-ijI7lg9u%-
z{2r0atp~MlW3O3V-mNR&k!bnVy1IBySMqc*q;Jw-Z-L5u(zq`p<Yo at 9*S`XXsVH6N
z=}KA8g?TCc`PU5v+!|!R7WXuRxyyRo45v^2+|5nfEs**wv=jLzJaN%L7+az?>gD_H
zlEMAGbw{(<4GNXDOH8fD?Q%{}K~&$4`1NFI)Lq)jP-~?fg5$Jjxv-M<{O%S{y4iMB
zh_|Dt9;;tbF|{d%R%#^7JR>wgCOT^0kNCMJ#24)`?x_*?{G9dr#nsAverlLpsmg@*
zb&^Y?^{HF<I5`2XHfx4gkhsrCSiR)UnN!ZWsj~LdQeOQLP^&m{hGgjoXz#kuWOGS&
zt~2BH-2sv!c at J)Dt*dWN&%|)8r4~$3Qvh#DiEdk{qk3+Kn-nx4YPXf`@V+rW9jF$u
zRhbi2`@+0?ua3)z`ZPt)sHYE{&Qtxzb}S8wUr<0{Wk^SGI=`<_t^8|p<h5;~Fm1tx
zDJJz0AEzcvc)X2?K{6 at 1T61#tWI{Ms4#jcGd>)F17U=+reMmShPdDqd2dc45EGgM~
zL!=bDtDk+0ui}H8*jvI?6%orX=gw7QV!AtP^=4Xs=HjfIACwRw2yU3Z{25|CH%xK1
zRg2u=-kTlVOZVrm9ITdq#F3LoOy1)YEyBgiQ%;59FZ_8Sa}c_Pv3aFEf|WkZGR}0{
ziMcFoCNiH`_cx>Wi~VuX5`O0?;;hx2;zYQT<;F%HY>$-Pl^|-**<*Oy|IrlDt?`+;
zE<UE8=e(=P673UgZ6Nbp(afRa{_}-BwS2abIzw*TC_(KWhR=)PCx^$GeX5pco2&w*
z#KUvNo<$291)1M2%^s+h*XPV>>F}9(?JHvc+z4%N^d-ziW6eOGZqKS9g<C7UpZWPl
zp}nd=;%3B7$i9R+YDB3(WjA66yaGRELq#jIwSV1xRmHuddP&J)S$@`J&}}b*G&(mW
z0;3gN6V+&Lz)jDD@$DVod403zSloD%ntg!%@Gsq+-O(aC+PC~~5|yK&s>DMl;~5w`
z6h-grch#M{qBQjxJR^H~WzOGBleaE3L}+vceniweB`DgYPHCD{j9cYi4_&7vH{Y}K
zAcrW25wXkT#(F->+=Knn2Z)4esRc%pjQHm+-K$knR*O#sicuJE2;Q8%S)|WaW-g=D
zbnW%E(3NSISkav)yRT(jVokRzGy8xN%Uf`n&nQ^l&?Sgq=kmUXPtfejw)@_=JFD#c
zcap{4$-F(SnL>c>xN_);uXE*&4C0RM=Jub(Hz>T(X_7}#9re`JcyosW1_0$p4B4F3
z=p^)m_Ak$0BB~?VrQ-ga<L^1k?edlC`AQ*3fqh%xX&4{v1OZe*dSjU at N^Y(sWpli!
zXnu6pD+;B6;+5s`yc{9>wG{)pJ$nZ;lwo-hV`RKnnhUSU;*-4x5pt&u>ii?i!kCfD
zoCN*!G8a|+Y{<23&&2eE at A|1Q`dNzUO^p2N&wBN`r#a_y`&?d(m~pekzG{dMjf}sW
z?(N{}Z<`SKu9PiD&Rc9h>Ji*vT-p}yeOsfRBgek!Xd0C0tmmwEyS!+wR4vE<{)^J8
zt1tY$K89bL@)KpBR?j(KPpLveWWVP0dhG}HM}?sEn at f+XzI*vg$5=RmdRHru;<c1N
zwiY0l5<gaZ{S9;f<GxDfSA27YzXaXJ`36lt>w0yHghkF68Ci-_2d+2u@}|W`oqA9k
z0Z1&v59cR$@u>xk(a*)J>Ym-*j3B)gYExK8vztyiJssmNz0Bh{BgwTt;N4W?Uor&^
z086(DF;xmvF+Df08qF;z@%@GK_|k^mUuiM-9LwB!qGBKS(PlMngQxs<BOw`aHPvuH
zsyRHp_Y7}+)=)GKE8lMiY&z3_DSfXxnYq7}X>M&KnP(43<|t9J;pFL7=)m-M-s)}G
zL at 7E-K6@8`I+ at dbW<y_i;pTPpn;M#2Md}gm{MBV36b6mg`c^n|Ii;t&Vi+Uh{}xl@
zeRnsexdwONBF~o3(_Ed4;&qp;YucMNyV3_#Uvl*GG~9RS5NpE1QjIV^2di3nnY=P>
zdcFr|XNooh;@c(+)_vDr>qmmU&7`s5wi?n^(CGB{8I?I7IAzaRJISML9kFi}!gQ|y
zssH<_64rJ#dh(nr?m6yT6l&KN(#v)Yj;#5HE#1W+3Yl&SCH=16wdZOFdlzS^N1IFq
z==}r(miPNon`#z$n5=pw$K=-sW0hSm{oQ0L>{{KL5dU7Aes7?2 at zNdN+)8rukMFw$
ze&Ly}v$rs~HL~$?)8z|n58cSG{+_+*Mla-1arKm>u$jNbg%42z7lL=sr)#>8#?2Vi
zT)$Db{MCp$hKV{g3DuJXVkvqy=mY2BplM%Q8h?qx#%mOd&9Cm}2!pSM>zd!AD2WY3
z?I>(J7h`WsWWqJ9K6h2-v7F#=%MT0M^a3h2<|$FW;*RkAMCSa5qXqLEUF+T116!Si
zq?~0Vt33v8KGnDG*uPO89Fc286qrUv>`L^xOm*qPUGlTPoTN~+GEe>dW>5fH>>?i}
zYMymbaxQ{Cz+4H+pW?H{>&smun7*2(#XIh)*INB-<sCBDUc2nij#gN7lrLg%CwHH?
zl!ouZSF;B#0o%`^|D)D)&%}2Tt}o_I8ROXlYukgp+4hy|_x6y)yAwS^Kk{S=luiVa
zGkX@@yM~vIxE}9r)H%qz&2=@I8YT<p9LHPkflf1}&%@|osf&Xxo8J3Ra!%z@^aKzt
zcVOn&VEwv(YGFtq^`~>*AsI4;N=!1RLJ>QMZfFbC9LuwTmg=zbL4U`yT-wdIFTh`6
z1LWz<z8i at 2Gv9iwDM{XAr8T+HTmpRoj+~azO+k%@-US%x=R&LzTg4)C<S;(WWg=QK
zxx6JPvVdGyI6ybiV_OvZ-8y9`nL|STaJv34jn2gPG>nbri9|A$S8Z?c7)yRy1}q_v
zGUflZ_myE)rfs{*prVW-f`}q9ARrA6p at 4uvm(mRiD2*T`>B2E+krX79MnV_es7Q!N
zvs|PING?!Pa_#H(eH}q(AN$unzHfi~onIWt^UVF+aoty(=Xqt at B0QAD3$sT{nK+x_
zb3sgFAV<(vFOwU^Fatc?diD=CX&V-@!-plId_bq`{-A9|tdI80BAIW*j_#xoU8{ij
z-VYXOeF7zV<qW1TU)f!csgne$-(t`}qoX`NbH#6|F*;F at L{l?2?)V|x+47yH0}wo7
z^LJBzUIst8J^Ix3D=hu$nMc{#-ZsVOSeUW&(CPXowyo3&%j|0j at t#jwF3=mHt>C2E
zJ_T5Ww4}8)Q?HC!ua<tvfR$tS4UegpOBks)eR8;mb8xFwjw`-+gbM32=S}4^3Hae+
zc?#c!$${=GSIzcIe!Cf~E`=?hI_1b*H_#aE`CQw_gRP6sC*b4EyoS=^$wj^Kx at JoP
zDYkBfGNAw|F0CC!NU&wnu}}~3w>SU|dnPKD6KfN1*WYCj`8-tdILBN=ax`Q)=rWUs
zUe|J19{JRVsm8N6w{0g0<9-If>NFd*Cu`~WyAP>D1ogTP-8=d^bWWJuAO$K#e}D!7
zUvt2t9ph>=Z{@zc*Y%W+ACXfP0Ny9H<!?JJ8)O<&k=Mqt`Yd5|GVoDcYt`4&t5-#5
z^o6m11bLY=GNomC;I9U(iJP%hw*!44wn&8T#)FSs?_L1+HeS*<PWfI0u at d<1$zT1C
z7PYb~R*>N3lAHijng-HsLXwB@^$*uto47y3VtqK(hRdhYSZB>;-i_8L(Vw!)i#@Vz
zEm~Q(a2 at nZQi>~wRt}flVP+(}kFrircz4Ao-~4{RB)h*k@$=|-#AUCy%Fp07SK at BN
zRn?W#B&_z1&I(@%JEWqw2V+C>EIerT?R5iLg=}uO2iVxMWsh37XWZMuB-t1_?qVsM
zIl50SE^$`MZuGjT`Ypvj&xNGWpTtvi`&$-GKM#fU5t`90Of8Y->>=S%B1trwa4~k3
z^imOn)RNk8seR#jh2pQ}M$UfJ4?;!x=+fKT1^?3Q`7>*T*|r~%k6mX_wkV!>LuWO1
zVUij%^@l`RDagzc$;r%?h^N}lq6n0UUz3Ccug*GCjPB^u7}4MGNogWNrx{*L6*e%W
zebT$G@$JvRVMYPfex~m~q#p+=Af<x9mS6t;uhB;!H<01r`rq*3XV+dk`cwWr(jPzY
zlakDRYEndb at lvSjw1db-46x|RUmDSaXssm(Pu=b at eFb>(b}&Qt!I2K50Xjt+R`|e}
z2GBdzPp$sLTWR?*K%M5X1?9eRU>Ia|%tF#MPpt$pntx<t-*Aot|4ANnzAmJAQ8Tv$
z-|S!}Sa2x*JlRZACO3CLf;B{Q-{qp7CLpXyBH=m0bgDQ;0oE at fnwt6h!fg7WuOyHm
zH&GRHz?(-c<a<Yi<lK~69E<lj4cFgK%SkJM0l4x~ejSwXTvR8um&f*ynT1T3;I99&
zz!*v at 6cnKhJU+~buWSly3ArnRd><#P304;O(~Hq?FqD)?(Mc`&&?(3cwS(Yl=*HTp
zq-)<CoF4A%!fq=|fYYfcaz8(hTgbR6^(SneE1X^bG at WV~+R%z-iPd4_bKTN?N6v1~
zkiPRddE&s<&H3*+xFavc<PrTYwerWd{V_XICS;H<z5AbsH!bjg<%F3GUYZC*D`j$j
z2Pl<c@;|@qkKDC<)Jkl-uyjG(cP#)k+H~~~kfBb`E9J<Zga+vfz?bO_FMRQ0H(KXv
z{@p0=@v0+E!HZHLqb7Mj><xFmXW$XeZ!iUa-}%ub7|^M3+Y>x-|6gVeo|EG_p>$Q<
zc$1a;v0eE8B9Sqp7?kg1h1|L<qSzvfaI4*fhxK2tOg(P`1^f61LoU}_aFvS%<2(5H
zT{7v;tsaP0!T^s<0*Qt$|1tV5E*3<bZ#RgSn^H2h+^z-*nV#4ExAG?QWs)2myLxZ!
zN^8(l`1yP?T}Z1&HI!h{iS+U}kcHv31w~qCtz2H15GSr{{yjr|2f7pf;qala=VZFy
zr*0HM_2YBCPXqi$st7Dd-=6<p9$qmv0X at a_0Xd#yQYOi$VzM$nDgKZ4W5pQkI<YyF
z=D^Pr=g!$;A?U7G^#-<FOEw4y6!|XxYE;ovn0PRxOX1ohn=j8Fuluif7_)IG8sN`F
z5jFDN`)Mt~*oI21i>m&-<>WG2Elkk<Fh&l;!g%Y+O_pNQ8QEX&viBDQD`OyK6-rsP
z%_*UJ8yT4yMYVj}`G0&o5DRzG at dPigf1JMm{lijxJCqjRD;hdeF<rO|3qbEb at ncpu
z?QU3r-7x$>t=B&<0OrMhe*BQhBlhfL{BPh0BzZ0_#Qoy|`i+U{{^@P(@>Jgp%;rC-
zpuW#i7F9aICY87k=24Wo^UTlF_^(l&rrKXWeK_0ymp6PH)qft|w4eSnVgFM$$*n*5
z0qOq2B3<hM6F(M?7>mb*^P|n at 2krjPhcGfp7+?6c7Z2Q1xHQ?JUv|T{QzFIGBeeNs
zZ?f6{*Pb-FMEbMc*iQ0_<8yn$h9EsaaCpR)AlJOMe1dVM<!&1wnc|5RcnZ)hR|E$1
z<rt9D&uc=CY@!R8hi-XI=*+Qc*zoEx3Z%h(EY4?Rc^rJ1%-+NqD5vo>R(=Vxr>?Qf
zNQS?6-UEGx(o#!*nHDd$XHZ4L^*=G{(Dh(}msei^V at J_B-f{S6V_UsO;=C&kR1n5B
zT;t}7-rK|fTjv7!$7iUle|hgY7Ji7w^P$~BXIBDL&x;C6HO|9bmI-U9nG(+O^D6wF
zE)~a;KAB}LbxH_C<T>_3iIc?X?y;Z$PAOH&@Wm+Tn+p+u>>P%7s)MjaikIm=;p{KQ
z`}dM+;9IsgLhUohqXb-jC&RmYV5BX6VC~th7Eujn%T)dzEk&P%olG~aelHjWWqnGp
zxM5U}5C6P=7^6K-bblEEi at ObY@$HRlnX&Mq+wf_(1%-dP$nMA@?Ls+79XQv~KhR1x
z6%{+cbm10^Veh at nUkB|gC6a_K!@KUc$q(Iz*`R?j%*-V@|1ySdQqjFKsHwnsM6Rc~
zE#U$sd`tJi{q=U*N;iI4yPJEmfLR9seHW{;g*N|u<tw{LNUh-IIfpfVeYZEwn3;wP
z`|5lirjU|}-wnR(mg~Fx=&jQQGx=Pq?94b6tA(@k-igvPHV4Bn)6ap=vrpRjmx<VU
z-UQ^?6oHqZJ<_GXrS?$a40x811?W3xp!thuxpFZv?joKLPN=K2qJk6i2i%}XM=$dI
zvehDXFrTadpnMT`6?nC&fP*VBKLskZOfA-MVvNY2{^HZNTqQw3mCOexk`*3GOvZeI
zBt|lP<2m=s&H+Dv;{~=BPV;(lqtCt_nM%6rFdtHhD(I#b>I4|omi at Dzc0UFQe`JGZ
z?CtCzrbWn-YZmuG?+-GiRB%$vti))xJ^=3uA$_BEH{5nIiPvJ!b`ln5_)KPYJ&|85
zIMoh+wYx|wtj%AkW>#!Fi8}b?r&HGUsr)>OXi<!A-jx(c23^POq~1|{=(q)F#gnq3
zSoT38{hgl%&D0V?(xi4zP#+g!i(?}pm63(Nb9z at 0|BKH`vp at ReiaQWtl_9AyM>3KH
zySG{cyi?VbO4DB!FjdC{QXF#yNPBN?efkj0!aUmbl8<)S{<7_r9#;cyb8f8_gzpAM
zeHMR%0k25IMlyc)m&-3ZDOJvdyP_V6s6$pHmc#1yD;R5{j>+Ih<-%Y7m at Lq@dMBOD
z{X&5K3W8C(IF=&;x5-Ud at Za3p1RwsG4$R=8VqhV*ffT{XHTuqTFa#MBsOc)93fxMA
zs&|`+ZQFhl(mTc`(2z~OkvmVRF&GMC$JDkgK^WgPKvE||mz1F}9~0T{HcaVBH7Ef^
zxd2TnQZ}5Wj5YM<Q~K|b at JB$P`16z|`c?y7DKru=p?g>lem7n7Rn;hgsUo>PUwDM`
zejiQL%gu%&+7okb->G9rQh4)7=A}M#sH at tF-RCKgqfq&a^OwE$?H!2{u*+AtJHc%K
zylK&IPJ at Y_-k$lNhyR|Q|4i5~w)y|hO`=o0%Q^GGmQ%CS-~+&D&Xq!8y$!UH!vGpz
zS?G}mpyOo7nx+AYmLIqn*@SfhxHHxmpwo(a0VhfoBs}e6MC^^)=|NR2L-6XmNBN)=
zE!1bniZLP+JQCytnpmkInIi at uS>=?w_o^sS3lUKe=xK+vkiK45Z7W>z41~GdrOk%H
zf)lxYqucML(sAX8Lq~?T6OG(qAY7yGK=GPvzlE#`;4)P~>Rq$Z5HeA at Ko8dAAOJXz
zr;!r^RSb}WBq|UR^l2u1h!|KyU0XuZXA6`7(;L;d-)vD@)IOlz46>JtxOE;Q+^YKH
zaAs1nd at cl+(b#i2q;s<1B-`Ms85!!wXv_EsT3J|lFp336!j)+eXJ7H}^w_t}C8dag
z@)XN!(?J at r&e|V<r!_WEYl)X57l+=l<A60iYWZ8-Oc2~N_6D7slVBLkK^@Sf+*L?8
zqGF;!+68Jy7soTb_eEDj$vX}u)V5m}eA?#=|5K(%thV2+Ho8u#kL{^3(?=}{k1 at 19
zhUwA%(3$I9 at CZkE!Xar%0?_>VWco&ojBK at 8NYeG3h49TwA3+LTB_lUhtB7K#Rp#>0
zAjRqV3+|vM)CTLOAMH2{O at y9m6rCj{>tI3h(aDHRDm^{vmW^b9#*3=fZC8fbC3Ty(
zcbrWm#{lrlM=lp6HrmkzGe2oe6g>?(nd3-QbVH<OAb{6I)>9jBl_+(xc_2-s%+aTz
z6U5q6{G#8a1dtlj5Yv=Odo^wwhG9?5q!Tn#uCMyY56RF+QZ5t~ntkz7;(b)cR8jDS
zf?fzQSlm5Bst2(|+XK0Ox)WfFMJvFqk<sC5^Us%?1qZl$|3wc!yViJM&sO&U^9S`;
z2*kpn1!5|k8485WPXU1IF(RV(#|W6p=mDE;b_UdA9lHS?-%f7SVr=?iXT|zCH~GCb
zQ6R1Q&<ScIDd-gR0VQZ0%HAr9yd`FO0P<=NFq(fdKcQVEirizb_9}F&4FPI64ppJI
z#${htf^v0;fZ*l#Ap{qA0RdYD*cn#_^4DQ$O*bm32wn(c0*5W$CnO;OScLg#e}JF>
zFY0h$S<tDa*t+3Hf$d=Dug9sT?SYju*yyeVH(1T{wKe<3;%jHr=sFF-B`g8U+F&dh
z$6$J5k*Yrack{X}P8g<gKWehn26|J`-d|rarUIT>97)+lbQerv8&i>!4_rPj6n0sz
zFW_?Xjr(q|WB?7q$43;r!8Rm|>kTGLgkVK_4ta6VFH20QkAVv~x_Brx9ZCTWv{R>{
zI}gW1Q0yM0M9gp=>BP-S8IkH5eeu_(?lL{MO5(8b&EP=)$FvdaOW6fo3cHS8lX7qN
z=nsp8*mIGhYlOkU%X777;GJ<9vQUT+b)lq|%&Zw&kr4nbyF6Jm8!SW}IEe(<-Wjta
zpzrK9Pg1oWU3BUNU8j4U0Au~>1;J%8JI|)~b1_5 at b2ux~Gr(AXv6d>^yB0vlKzS`B
z*DbDg()sain#{S+hMk?wIMs5W+5!h)OMXht7A=JyZmIOHy#fT_T4wuyIy1 at V{Uu-=
z!cE7<(xG+tDWQH<k(^JHW=X9lPpx9NY&<E(-A6$;C1@(4Xl)X#<4jVdkiEhp#pgK!
zy|t^SB=nGqnc;7+MoMKOSSF`-;b43F&IDu7A`k%)4uAPc>8b)EYS?1N(!q6u7s7%d
zo8)m%E&Nz at tq4T^wa`wf6(n+5IXkIF+2|g3p9HB%I^EBnl`CtrhcGtb-j7GB)*7qC
zo96*Io%I~(GKV60Jm}3-IRz_MI&&qAwR3%n0q;kLbYob^BV9WB{k-sS$<P6M-1P{O
zANJ^;x2bU+0$7Ee*%_i<H~o6OjI~HV{If9jrlV?)MCB~^{(+MqJa7a`e2Oe(B^o7s
z4sl08XftT4cJS-OY{I}|VUbYwRUqQ(B-#{l?HpWb at NH8*&1O_a<<o3eOEYUGvTN?T
z)`FM2XCIzwdl2mGoM+Re!e%cPMxiON##1#y0|yr<3Ex)OlCMyD0vEvP_jtMbT1WvT
z5U<`?lbm#3D~ISz2s?jlL9kGsXT5s^oa1Dk_Jp-z_U5H&kRZ3W0p6u8VPMJt>GB6b
z&1GZReZ9pZe~($+-oM=J8)V+N5QrEG&&0GBA8hjNS?p+q#Fm`1dOYWv=s-F_R+Tq4
z*K>p`C?!%a^Qx`S2$wPbD_j+wVTB=@M{sRGE$hDb!Lg{Hl9V{Y=W|NS+4Ka2){g6I
z02Chk%GLy`YQ*yK_Z0ZC=~}QP{R^i8Ok8>c$4A=anaZjTc$(+_PQKOfrl0%pXTq|Q
zdy}<Mm^Uc3;w~Dtiy{cde5Q5<rxz$O*_T$tMy&U4pv`0J%Hz0w1^~-9tnQ*ViG+3b
z>HQ&t_Sgot at xB>vSAWmJNJq@)W|CLqpjqbT?^)8vizl0zZw>Lz at 3D%RX0-JA*emlU
z%!mgs*B2i2PUY$&2bt`<^)eo5Hpd(rHF)}t3YKBQ5W7aa%0*;>nh?7q?mBTymOXdD
zZ$V~HY*fXR`Er4XgFc@(WAY?>*&md*0<ACA`+l at UahC4QvdI<Zs~*Xo6GhTYWdrZ-
zEp9zF+9aV%qK<<M at ISB}X(h}jR;~8U%$7g#SuOI>Z~U_J at j4h$BYgwPEI;|liG4~k
z+r|*IJqF0J?f{DJv1(60C;|N?W*>cWUR-5iT$YoNH;Z%jUd&5qy533zrb0$ucdGL`
z0JfD;o+5kuGWT9tTTDZ0(8fT-ml*fC*a3sp=iZ-hF(&gAzGv=q$g}iZWl6gcX~kNx
zR53$eRl1n4i?HIiHtNhBDv4<GijwQ&s*~xwxh#qan)+a`%&>K($2!mb9X6mJ)OkMx
z;9G#=vhlSSJ0g0pAN{#LQH3E*K#s=Am|b at mfD-NmHS&=&rL+&V%ufN?P)+G02;8Qn
zM6YFqnP2EmI9(c#!axn7_p~B3?j<$Dag?3`OudRmvk#0I6#9lpFPkk5toIG1a960*
z;ns>L)FR(7C$wB!D}9nMBt$bR%9f%JjFPz-L}ZaD=>zFJz{JSV98x|nTG>wlpS)~M
zB-s0`e(j`RKT5@<Wr%%*;~;q`aCjuZc<m##$ZM<<`?7Xq*JE>`FB)e(E2f=ut#u0(
zFm4ncbz=Rk?d(S-7BW;dEfr+VcYay%vtClRcUK1tTV?0P1k*IQAh`g3<6V$Y#9bj*
zXFJguOoFd?pvkvoyDODS1^VY4sELQPsDGknphe(C8)?iaSqG9E=V-hUy9>|UVo>M_
z%cKN)_wJ(LK{fgxw4)1Ol>I<}TUSZoGM_J=vb=HDWc1A1%XgZ+_mzXAqEP>KuIVpP
zm+{HzmT-Bg66Yj|Vb})Qo^IE0 at +$CvoBE7^LXpPpdc)u3TJrI)&=w;;jpp8mE4mZ6
z$Y`(LXjYHhRl-$kbGBXlxKYXjn+GjU&_r^Wz{ADJl9OZ**k-%Xy$(*`YJQsn*9c2~
z<AhCtEu`ZV at MbZ$Ut=4V)FSmIDU5&vEV5*$^%ZEbZ)EvoGaq0_s1m-O=fO<54FoRL
zWLjROF>)KER=x6<Zuym0D<FX-hdK?9FQ|1z*%j`cU6^A8l=t{K#+3^jF#)mZ4(9~z
zssk&gCDsNh(rg^tQpFD$dpfue(G9#magRR3 at S{*A$nvFd%X<6I3x;Z?jmfC4DF?C}
zuGlqPP+E-sLuYeH*P=?o=3zs$F?%tjKxIG=Ef0gh<tZZkR#S6L_lU1T-O1(QMPetz
z{35#ZBW$qM^>ZUw6M48k1hJkUg1DKw at A<u{jYNDd2Y^$FTt1rz7wDH|uiBY`sZpDG
zS5@{uj#?W_dh^9jIXuy%xoKlo(x>k-guszmfOSdP5a2KsX$0q at PY0xY6+$QpA=a#A
z&pQ?$BW8(=(mv5vlaDj4cL3i~MOdkux!>1o>Hf%O*qNnKwZGnOEs(E&c9dJyfyF~F
z*)q<Q5VHHXGTqC}wTS6APwSB7R&nLUk_?T3y%}aQ^{yv)3A2+{U0J$3lXTX^_e;?_
z*f8_xoP;au%`(#>1#j(Ygt4(?%0)pBYn^={FDCS~FtpFj!c3J#@bnTQ9mP(okG at f1
z^9UUCUiC4Yv?<t{fj8L>&hid91#L5`2SP~EzRhPWkMggeX1HEc7Buj*+ed9Q%*UTI
z9}iF2nXYDNbfu+-G0sBdKK+>nbQNMR3R_-fp(E%`NYIoo7l9Rgv#?M7MJ8s-hV&|n
z;zRY4N&NBFHWL at pc5G;Q#AK`vzhXekZ26TWHTLPQ#Tk4$F0$@MqkeyzO9hqdSMVG{
zjh}+Fjor~3!=XXk3(DFe+E_t}6vFgyEnX)!ueUR3uSoB+{0%olXbz?oWaInxc^{`&
zvy8k*7j){2bPlPo6WeP>(X;R;Wzq5br$2Q~t-}3F_a$D}yn)TP$)2`Wxw^O&NvUe#
zvnS#1Go;GgVhGnE&D+<1<2~@v6>qWPlRAP>F at vC~rzYBXH6}#GhDM53KT26xSMAkW
zEV$vVvGB3QyZ4LyCTf`3D_7rUN*zo~m at mHd%s4`75gH{(4Ad`WuKUMInc`gXX7I<Z
zg93GKFR<<UW(&ec2IK7$RD2rR{uD&ysqjS>8G6~+6<a(YkI8%JU(~5Y at p%rC-(Cog
z8%_6FYd=6Z$|YlW)$*zy150qHJd+1?PJ+vCcqEp}5^piSloBSjNRB0c{SC<YBi`Pr
z#YCQ%0$^(*r!A3Pa=9V=^kqZ6)VQF~Fu~c#NFLn}eA4}&v>FqOsx*nU_95j at Ln(ym
zQbfI-^(E^np=EQC`tT86J&+`CogY{ADYclZ&uNaQt~cg_K4ca>JAux5O+w&OYcRl3
zOj}di78t))?}~5U(VO)Fz+n$np!?dD*lwdkIO9ka)(W8h0Zov6BZa$Izt}5N*mIbL
zkwe^RSa8Oy!8dL^iE-UxJjbEG3cSEnm7Is^Clzr3J~XfdJHvHaC5_HdlE_{JO)^sI
zEq&VL*;BsWppE+Ix_)UYTVe~|s=8%&4QYV6qS7`uXzmkraNI&)>0Lz71MXfCwy4!^
zT%}gAm(8ohBA+Zq%}Qds<huGBnFMVPJw3KY&3LTms}ytQ`+d`Yg{B<b_oBAhYx+6|
z+XSGiWp1aES<&z~%q8}*Hl{to=F{CSLjW)iBSwK!hK7oyTKW~AkS1Sb*l1^GeC9%p
znU}O8`{G4yQt=rG)1FwV3%g6c7HTIP7 at dI_MNu~<)b44Fy$`OL=uqSA)xa8+TvS1@
zB^Ei7`5dTcco~+d_+u%*(GX})>k1zclOYuDadWXcm?V}bcqpYT0V0-^o?R8|DRHsS
z93YgI!`ED<>T=nbguLxVca}eV-|GhVzoXzc^Qc|uCZxYdu-pqNVI~u<;KYQdtRBz$
z)7KG%#`${t$L}bM^yND_-I!<f^{vqR=$w$!D~D*2Z`cHt at n)Xmkg`zz;#7;o6|j$9
zlNXnNzRjlu?QAW&leq_Ov at c|9MOL`hE&#pGGo>)Jg3_YN at kWuAntqS$!pg&Y`H+Q5
z1%M)-E!1PEME3U0K<&d-!TH|ibU_l!ePxMAtlt50u{FejMQR7Pd&>Iuv(Pm9-lB{y
zg#;2g#h+sYzA2rsy`e9ed`+Esv+dL#K^@YW!7g!959(vHf)ssDPizF2fH&9a(uusq
zK?wo>A{$b-!Qg`;W+hlf#VaLIibX|vU(j6!j>MsMvHmZ?-=bz||ERBT9M7f&33nei
zr{YLOpePQKsY~UkGZ^i5A~?+_eSG}VB(b}{s*!TX^2EKD{alt6657Vvtu=~m67EU1
zdD+#Sc{E}&?ROi{Y*lr5<pd5QFPE at j4<PqGX-tr9b}wX96E%(cA%ZL$J&yEu#|3yH
z$a_h+)xYsFSo!@kP?S!i2iNmu_q0zO0I(Uhac9aitrE>%X7;3T-=|Ls>@h at o7B3Ay
zy6Zxiubw<M{u=k_)b%|f^mNk at CAJZ=g=J!^-~^_ite;%y17)3uD&k*ioIvI~8S1 at H
zI;WTKP06iNo_T{fIVzMoyrq^nzjfq(%>(=6VBrvCDR_Fjn(m-o(>EnCQ2EMp{VlH5
z*O-~Yg><e6u%f;PUKP0y4o*H`*m at q*$q?lJwxOZh;B7^9RqE;YpYD*|do4Hg#6%5$
zZ|aP_k7g!_5~o<T7B(X9O%VmoG1G at K=s?0H3T4Prdt@!m at uYV(=}{fRGx-{+Wtkz$
zfl!|c4v2(q)`>&AcLq$@T=f#cOhxy8u9)$%Ux7de|Lza=f+?uX>AID(M(RAd%Hnyo
zDJCKTCkbxJ?Ydm-rRdxQ&h?NJkZ5wUaz2-8Wq3>N9SrG|dbj+R`+=M+e1|XUla`~-
z!F{cojY~_<GNo<zJZSB`U<0;nC)m(urc}Z;=^aKq*)r}?I}|-SQ at yi9W?$o;cSJCx
zS~xk-+h!#NBhDegig{oOno at -`+saGsdY)uzKBE}AaZD|C{<7cv at z4huJ?6Bz2`<Xa
z_ABW;3*`YpF)<rkiegg6WHm`k(v2w3^F+BImrqPfx7wnm$N1n0$Mr=kUBK%pKBcMW
z9eIciT4%Tyc(jkeO<5xWIgq*C2YT at KnQtO1c;BeiceM7)6|@mf*x*!)7?QA69n49N
zsS9D7kK?)H7Z%;zm7;}p6_X8)>oLEUZ#@BLZvt1d0OvlsIJ0m-ztfQB+0$%FPAmNn
zusaNUR+T>OBPcnYq^a2e4MU?6zfhu>-OHLKV2rU68K|UWHl}FzG8lu`?NJJZiaAew
z1XqsEvnl6`i{4t#SK2OT8|9^l5oc;Im3n8+YlHGQHBpH5r+Uze0TY8dpB~c3+&TqV
zZWH5z;3tmR6Ltj^=|+<tTrE#K4m#(%LoP at eU0EZUl|af$<~%b+rcni81toiMMcRN0
zr<t*VF1>M3mr+Dr<3u4rt)T9!k@?w&JYt702xES6$+Rl7X|={$#AB}PqD`Gl(<NqE
z0}P<A_qE=Z%p>hK3^ts>eEV=|nU+fynbAQWIL%MIl?@n^6cI1p at 2T~2g(mNisEkin
z+l7d?>@8L#??A{(vQyy9i03YzujXJkn&-x4-wmGp1X=t3F4D&dD;;TjtTq}aXdURy
zAxDy%57%KtWL&X8_dHCr1o0dC+lRR1qsraZIs?1Pc|@JhN~hJjFm7$~mD4))Dc!0>
zNHqJhb!~}nt8b$1?E at s#6xu<Y%C+P$J0e{83W(`Hn1g`TgN1NRFV(Tx6a%@l4d{Hr
zmuyd0$@G~kK6Jo)7cOX-fF<ERUA@}BR5=f^RYAUzq|I6akS?7-%l?osE1QZq5>bD;
zL8H}@v{yjhw$%}`hSav1=If{(f%EBX at m(V;<3}#na00gNUfi|5&FOc5xQ6dAy&Uc|
z97R}g{ARR(mGYV2I=evY$IyV<$d;8cgVS;*H^W^uysB)D^FBHXGO1Z}*G at m31mRHL
zEHR^1lzm?1y+^;7mz>nteLRK3u4Un}U#vF at XmFYojSKBUHTN{3$bFgJz;$y)fnSLP
z2&tBqt_WP;MsT(fhr3bnDRgLc-ctlhx8!2Nm(G#Kf}s8QZtF7Q0&qzif4eO$!~-oy
zmXEnh_mt@}QmuIrtc?|s>-H^o!fe98am)zZl24PD^~0YF9 at 4SONKv?zaqB?+2C`t~
zxA5IQD``Fo&Z&hNb3)Wq$}~KoQDSJwr{J!z&T!GmNzmh$Nk0IocTs%lmeRu|s%U7D
z$QjH3h1~e-*_HJfpMg9(Nf1XF2Vq8zEJ>0Kgbo2UkbkYM8_3GF?Ph<(f5~>Ks+QCv
z^lYjH{%^gKlA(oAg^!xK?wS&o#)0)n2TxsmJL-C#Oxtv1^77fLCXoU0fvzu at JDzpl
zv{>#I^*Sp0<Fu>zkg8Rzumfmcy<>N=DSdt`B9v_$>Mdg?&7aEN#-A=*zC$!zMLwpJ
z2RohVgF3C{nw|_-T5xk$p4upo;B%mF_@<DMRtFP(lE*hfx)G at qFh}=2W%WHlnaraH
zP5p{cf7d5X%Qg15dg1;Q!hc45!*LMlx51|5X$n{g%9Ka)pv)ltQ*fblqUbDxF>G|6
zCA8&ZAV*b3eIuNQd=CT=S6 at UB%h+V{(8<5uvwG>AIOR2vZxpdrP)aR^G^}u6SHm0H
zL1U*Zm5BgrHxQja-YcZ`Bz$CpxA(c(E0q3rf~Y<!+`_&+(O8nOpfwKFYZv;hhfj(e
zv5r#+#ClnY2X7dNe0?QmLr5XR3GU5^a5+R$;OS$a10Rn^>}%By<`2-Wx|cfXM42J;
z&9C4iWe6Te{m_zeaC`PKSXHi%!o3OE-74z3+|u)S$dyY<f9N|=RSgs?9nr&+fOz;b
zLu5NLoy&CZKNiul(i=BL7Hgqw&o_si<@vx|{1T8P@%tR8_}e~&^EmWLfG)ndG^c$)
ztSI#KJU=q4xo6+Xf_h5Go40&$R;um}Y+4_{!dH{_uYD3pTj<iyeb$Lu<hj41>%U;l
zB%mfY1&Yh#(Ce8)d|J_Xr41?T(AY8d at Q)D~CuJjM1Wue<(f`zy8Bg|C6~WeC5qg_=
zTecq0o5*|`8ENS{goH>?9n-~CQQ(CkU&8MeWoNvwui%^;xaYCkk<<j;0{&grRi0ov
zHKaPIXBs5b_A!7j9-7C8QID3qIWT?>`4KOlpq#{DVJ01r=&)-UVWlK*hC)_zTq~^C
za>>^`p%j at 0Q^a0C_aQ;26_EO21J5QuIZHl&_tmQ<H{psGHpc*vBE5B5TlVJIbqpDs
zbhkft1lC{L-!rpnxyk;Gzh*bh3)C`NLc03_mbHz!CjG;|BQG{P$e*>h!_LzejdA}d
zVOn+fM)Jg0RKF?A9A6 at nLuo&o((KrXZ_*+Cr%6&HckH;_;jGIrSAT|HgmvR<og{DZ
z^}E&|ugE1&Ac|hMO<q$Qa9Q!xFS>M)T+cjY7EkxN4FyG5g_u~iIzpoKw6Xoghffv+
zo)7Jk_>5U|4{7bI(D^8%PaDpI+ at rY$CH;zlgPjhDqq{sjsl;(&L+6(Fdf-ezf<EA?
zi-gq>^6|&1Trn^KDW3XUN#;#~Hx-mB53w8-GpvN<<j9$aP=YDR_s4-5ump)AUY<X_
zhadp+G|pV}M1^E@@6p5Ni?HK8Z}$OdugpO6&o_~G-9QLLd(~p<<QPEjI%nTY?_id)
z(!Id+ZXCS!;tzKmtdWQ<Qu;`p at f;N!>MA4-!F3Wd at WBm~TOO#^9>!g2{T7W_w0lk(
z&&A;0F0Fnw{@4)Yb|g8D>001d$%*u&HmKLcBa%`|{lWgm6wUbMlP)I_OW{U!)x>a#
zfIpIQdOHyH>alhs9ODYd!(Hx&7`lST4{iQ_GACY$QCQL(E^grbgox9wRk6jK#C6EM
zXHush?YRNieGWGH0LlUa?*N>PcI0q~lAIuUB5>rSuVSd!D#FvHygIKCh~%9(WY`P!
znB{1~VhYNBcVF!x*e7#+U4pxP{$aBxo9gKPFr%E3Pch5G(R^+%$khVn)*;^?fp*Gp
zlG#(EfY3v$P at lS1)|8<kk<)}YoN9Q#+Y^t*9544>nu89}!^Tua;2ic0t at sR*8|#QR
z4CpL>86ZMippo&@mo=O&2G6-s++%0>xce3q{&L#d$xQ1`LRxbU*9Fq7rwXCn+LvQB
z&<ZF{HUDr}mL0SiA`iDLWF~nv0LfLg^2+YR2N`iD5v*)ZNREp<pmuK{ka$HZhUjPN
ze=Fm2Zw>gwMTeOHPf#_eCTu72ym}bC7)E`jEW at I!9UhuT%4_y8CSfUnv*r2Mis#<g
z&x*sV!PMLWd{V<3A$~N*3z^y at ICbhE;hKTK;)`woa2i>^m#;$Lc8HUf{5T^eh8t%x
zmK<!Kn6YhbCku7;nJU+I4xVJrdBM+6W3K1&IPQ_q+J`eX<-(gmWF|U0K#O*49<+SK
zXN*X%q1v7NxK*G|U~8y=`zaDC_2=iA*hsX%az)K1>WJBX%gG`@*qh~NrW)6hkNRDV
zKxha(@Ga(EN#A55F at cK{a*1z$%hc?qTy|s`qhD~r{_eQi43G@!GZh&ImpkkN-v>(>
z at kK(@BM9JBl*GLQj|Q2T$0?Fp40$o<#Jb2#-%%y?HSKWFW%z=C7q7<_T_9D2m8+Tq
zgxHDOx)H4Lj`!#;QeMl&)_8n`M8uy1AQRd?mw1h|hK28j(ky5-5Q}+YPr8sUe{?=d
zuq-(Lc>yUYm?r_RO~8H*XmJmjZ58tK#y&|sH9ce-vUs-%MJXZEyqqG15{}xk#-?fw
zE>Y2fju|PDZw9Wvdh(7{22;1U&h2GN=ZSl`X2>3d6Duk}kA`hwhG4wjX*_~^{m0#-
zZT<ymJ*rUEMXsTcq)hKx`e*8Pj_uC>Ry6th7-1wJ^T88x+;Jmf2bMkC9B<Jz8Y1Sh
zma*dfV#gt;ju}WirHAhDW2<1)z4puj6xUrlK7A3}Yqgq}c=hoO8XLm$sRl=S5iIq-
zAr5Qevi-&<`#r1gC!8Pb2(q$OrP*d{cBUq{2MXMfd{ld%%3X}Fx0`l?>=&KAfsRk!
zUOZ`h5O=PpcAbqggPv`(Z*`EW=SQlh813Teth{$I;ljC)^08%PH;U4X1VBjA^Ot+L
z@(q2sn*Dn6<gfLJ$}Bpmu*8mG6%HM_<+5&;G}wcUw!k;d;O{NTENUpR;*1Wi%)%Ob
z67!^7B3?Z*Ae{13s@<Bmd&RTAM3rTiQx&)Fwe+M^aF4_oZy!#&&Tj2T%_@*N4F}yB
zclYT0qR4Oe1W7}gkCBH9_4F>3ioiv~QRa6aD`kvxj?mn{KIW9c-~B8*)AYp4%w_)o
z&fw5qX~jUAV2xva+!uY4?`M?$H3Q0=2BHe(R)%rm0ZV}>cf5Rj-eoa_ow6U?<f1%9
zee)rXi0DTr$U6!PjHz>CRLoIrT-(4wTH-+&;g&}4AMu`+MHB*h;xfG2x;w{L{JfE}
zp=N1k*oiM47t7fxx<QV_;;NFzW>>m}1!Hr}EM6>6wzJ64R&4t-zX*Fs^xSX{w;?6e
zC>IbnP*(YdXn<RIRgQT}&%oPDP^f#We!3<(2qho$m~C_Q;a*o0&g27M)AEKLp^(es
z`dzYU)Xu?nI-;$&<a#?~A at Pge=3?hLAK67=#Y>zYCCM#ZbP2pd2#GyI>DdQl at fh3b
zhSHN=pmG|Is&OM67e!CiLpd~I1Jb6YVTOuJe&QXW6CC}G%yDmYR+8G{YHe+<R$}T$
z=re9)CTkpay{8~qYt7y!d;Z7+mngt1Wz6zIWwmDVX`Hv_PKzXyi_-+*%;@<iB=|6u
z>6<_9OF+=8V(P8M4r2x~E1KI5Xz+CB8w at 7~T?`BzEsYJ$Z{iI3U=a8+kTOu<xhd(?
zgb}2jo5U|4sE$sbiPX1ixc*8;<%>#W^o2PjK~@TqiL>I>aUHGW5^0Yd6|Ao2`$Wzj
zYhLOf|Kh(G;GQSAS2~s}d%z+oXip>94!i3?vL+&q$BW8p%$x-D1lc45V?`@;Afyjv
zmc2%rYfA0bYolZF__nBoM!AnS6mH}|XgbZh<l>yab~&@xQrUnqXoWf-5d)PBZ(Lcw
zW=W94bw}`ya}6Z+)T&dV0J=ZKt-__O#+uc0=!$xI+UvhE1YVX;9KhWej<Uac_^(O!
zoB{v<<i^=`>IuJljl5IqxG*){$eZVbr#N+W!oR~!k-rRJC?(C{DRgxP0p at 5u$Oijz
z^t$#H;v<#rX1wIm4WoXW2iV$nRY}9AUjdxjQ!lea7<=&={Sv$5PDY?*262DYwC>5&
z=$aw$fw)W1Gu!UhHjc$IG=kP^Ly{Y&rVu*Vp5N%L?>mAsh at 40a-LY$~yh4{hk8;^8
zkLePN;-4+~ISmF6mEYm&NoIrUA^EaWPm&S at QdiHvK#pu7%Mz(G3<cSHn(8mt!2!-k
zat)SdVa$<*1W;$NI3GXBJ*N4-8Ok^$xj`%;;@Hp>c8=_-H?^M|WfVoQ7uyX-Nkb+l
zQTl2KQmwW%1-PfIIjz6#JDEuE92hJIw|02FiEYNFyS)C87x-{OSSWHe%L`kTg(^qK
z;@a~c_;WEr4P~vM1bSZ{Vt9&Q4q5sFsB9r at tY?s0wvqv}v1fT<EJ3W0m)vD^2KS{B
z*VG08li~T0rAnLG*J=R*VWO2+MGWci^{chuX?N_k=2>-l0EH`;;jlmN-OA(J3Iv$<
ztA=jcaoF9nvt4Fkr$2>+FUhy>tUQb-zPRzOla|#D%2O#waR#X;n4gJV<C4*@vuL7y
zNIPKaG=LgkW2=?kkgTcq6TNMT2%;FGX1|j<gBdyNS7Kvw0`gBdFreaNj!c7ac6n_C
z+#?#Lppev#96e)MftTVkqjhrQwDP_0>f4XR3gv4`8x6YcVKyoY^$|15GtKSeri~71
zX}0 at oILX^|*gh*Dw8_-?i+lWAR>wfucLeTh at pb?~D$fqZiFbpiqM9s6L1o<f&dusr
zzp3cq7yXkGuRT<fMH=k1M%G~;?Ls*1XcQ|^C)EHDs8d|h%X0vf<=enf5E`-kGv?v%
z-3#qm6tD890q(4fbjs#<rMn;QnIn4yrcg=y=4M(qzaU}&T<4TcWpUn#mEEZ<3wDzK
z2}v9&cBG!6H9)#(v)%lgI>LV(9=qk3n!hDm_qTOnK_LAn>_-0$A10?zI9KrVsK*#F
z2m<#FQ3`1FaoAJJ5Gfd48bS@~1VKRNCE at v{mHBbYyYwz{fF_hjKrTyNIy5;Z^Q1tA
zoq04V at V6uJ?T0ai4-ix-A~8jGRA}$KjtYRBt_UTMa*=(|*T53Ntnx$7qM74ALZTKB
zSbL*OaZ^|WzrPS$jYMMKoSAZ=K<yjSkQdU|7mkRZm_H5y&UKb5%j564|Mo+o9R{hL
zPIHbvoq>E}?2K#GzoLGO%`ZX&Es at nz_`Dv at 0lPskTxETR|ED*DL15wmtc|mFEUpNl
z<Pg(|-TCP^0O(F_fP>!hn9l!+ucqWzt-zHX4kD?LZHPr^u6gJ`R5Izp4ULk&Vfvt`
z?y3jat<oIT9pC1|0QT4`XNiTMs2fWDQi1jTP)(oBl|Pku>zj3!BL at g>Tbl9cKkn8R
zBD`tcCpiE9mXPs##()LrbEp5OKkRn!f#9}nBo6ZD&uDCcKmz;b|JCn*_E~PpXv>oG
zZzJIY$nLJhh?wt;!E`pDoM#?9s;$7}ar6%3<_!WAAcP&26jqG=z8AvSU at us9?Ax5~
z$4rnQDhv|uTA&aA4w3#nu^JUX6td$Z_YO&%;<|AyrESla($kO4hG{r>^0iq=82Plt
z)^qy3%F_ZwDVJCi|ILx$_kRQDV;HfGa*C4v`Snt<u)S at 4Iewu;{cD}WxZsmY`h#VD
zyzs}!wv*VxyNh<Gp4 at 7@zHbpFBz-dME_URf|2ZE4o7tj2{_|Jymyi${T{;$fD%O%I
Qw!we$(kkb3&YJlCFRK at -AOHXW

literal 0
HcmV?d00001




More information about the llvm-commits mailing list