diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp --- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp +++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp @@ -547,8 +547,9 @@ /// /// Returns true if we need no check or if we do and we can generate them /// (i.e. the pointers have computable bounds). - bool canCheckPtrAtRT(RuntimePointerChecking &RtCheck, ScalarEvolution *SE, - Loop *TheLoop, const ValueToValueMap &Strides, + bool canCheckPtrAtRT(RuntimePointerChecking &RtCheck, + PredicatedScalarEvolution &PSE, Loop *TheLoop, + const ValueToValueMap &Strides, bool ShouldCheckWrap = false); /// Goes over all memory accesses, checks whether a RT check is needed @@ -689,158 +690,168 @@ } bool IsWrite = Access.getInt(); + if (isa(PSE.getBackedgeTakenCount())) { + LLVM_DEBUG(dbgs() << "LAA: Cannot add runtime check for loop with unknown " + "number of iterations\n"); + return false; + } RtCheck.insert(TheLoop, Ptr, IsWrite, DepId, ASId, StridesMap, PSE); LLVM_DEBUG(dbgs() << "LAA: Found a runtime check ptr:" << *Ptr << '\n'); return true; } -bool AccessAnalysis::canCheckPtrAtRT(RuntimePointerChecking &RtCheck, - ScalarEvolution *SE, Loop *TheLoop, - const ValueToValueMap &StridesMap, - bool ShouldCheckWrap) { - // Find pointers with computable bounds. We are going to use this information - // to place a runtime bound check. - bool CanDoRT = true; - - bool MayNeedRTCheck = false; - if (!IsRTCheckAnalysisNeeded) return true; - - bool IsDepCheckNeeded = isDependencyCheckNeeded(); - - // We assign a consecutive id to access from different alias sets. - // Accesses between different groups doesn't need to be checked. - unsigned ASId = 0; - for (auto &AS : AST) { - int NumReadPtrChecks = 0; - int NumWritePtrChecks = 0; - bool CanDoAliasSetRT = true; - ++ASId; - - // We assign consecutive id to access from different dependence sets. - // Accesses within the same set don't need a runtime check. - unsigned RunningDepId = 1; - DenseMap DepSetId; - - SmallVector Retries; - - // First, count how many write and read accesses are in the alias set. Also - // collect MemAccessInfos for later. - SmallVector AccessInfos; - for (const auto &A : AS) { - Value *Ptr = A.getValue(); - bool IsWrite = Accesses.count(MemAccessInfo(Ptr, true)); - - if (IsWrite) - ++NumWritePtrChecks; - else - ++NumReadPtrChecks; - AccessInfos.emplace_back(Ptr, IsWrite); - } - - // We do not need runtime checks for this alias set, if there are no writes - // or a single write and no reads. - if (NumWritePtrChecks == 0 || - (NumWritePtrChecks == 1 && NumReadPtrChecks == 0)) { - assert((AS.size() <= 1 || - all_of(AS, - [this](auto AC) { - MemAccessInfo AccessWrite(AC.getValue(), true); - return DepCands.findValue(AccessWrite) == DepCands.end(); - })) && - "Can only skip updating CanDoRT below, if all entries in AS " - "are reads or there is at most 1 entry"); - continue; - } - - for (auto &Access : AccessInfos) { - if (!createCheckForAccess(RtCheck, Access, StridesMap, DepSetId, TheLoop, - RunningDepId, ASId, ShouldCheckWrap, false)) { - LLVM_DEBUG(dbgs() << "LAA: Can't find bounds for ptr:" - << *Access.getPointer() << '\n'); - Retries.push_back(Access); - CanDoAliasSetRT = false; - } - } - - // Note that this function computes CanDoRT and MayNeedRTCheck - // independently. For example CanDoRT=false, MayNeedRTCheck=false means that - // we have a pointer for which we couldn't find the bounds but we don't - // actually need to emit any checks so it does not matter. - // - // We need runtime checks for this alias set, if there are at least 2 - // dependence sets (in which case RunningDepId > 2) or if we need to re-try - // any bound checks (because in that case the number of dependence sets is - // incomplete). - bool NeedsAliasSetRTCheck = RunningDepId > 2; - - // We need to perform run-time alias checks, but some pointers had bounds - // that couldn't be checked. - if (NeedsAliasSetRTCheck && !CanDoAliasSetRT) { - // Reset the CanDoSetRt flag and retry all accesses that have failed. - // We know that we need these checks, so we can now be more aggressive - // and add further checks if required (overflow checks). - CanDoAliasSetRT = true; - for (auto Access : Retries) - if (!createCheckForAccess(RtCheck, Access, StridesMap, DepSetId, - TheLoop, RunningDepId, ASId, - ShouldCheckWrap, /*Assume=*/true)) { - CanDoAliasSetRT = false; - break; - } - } - - CanDoRT &= CanDoAliasSetRT; - MayNeedRTCheck |= NeedsAliasSetRTCheck; - ++ASId; - } - - // If the pointers that we would use for the bounds comparison have different - // address spaces, assume the values aren't directly comparable, so we can't - // use them for the runtime check. We also have to assume they could - // overlap. In the future there should be metadata for whether address spaces - // are disjoint. - unsigned NumPointers = RtCheck.Pointers.size(); - for (unsigned i = 0; i < NumPointers; ++i) { - for (unsigned j = i + 1; j < NumPointers; ++j) { - // Only need to check pointers between two different dependency sets. - if (RtCheck.Pointers[i].DependencySetId == - RtCheck.Pointers[j].DependencySetId) + bool AccessAnalysis::canCheckPtrAtRT(RuntimePointerChecking &RtCheck, + PredicatedScalarEvolution &PSE, + Loop *TheLoop, + const ValueToValueMap &StridesMap, + bool ShouldCheckWrap) { + // Find pointers with computable bounds. We are going to use this information + // to place a runtime bound check. + + // A computable backedge taken count is required to generate runtime-checks. + bool CanDoRT = !isa(PSE.getBackedgeTakenCount()); + + bool MayNeedRTCheck = false; + if (!IsRTCheckAnalysisNeeded) + return true; + + bool IsDepCheckNeeded = isDependencyCheckNeeded(); + + // We assign a consecutive id to access from different alias sets. + // Accesses between different groups doesn't need to be checked. + unsigned ASId = 0; + for (auto &AS : AST) { + int NumReadPtrChecks = 0; + int NumWritePtrChecks = 0; + bool CanDoAliasSetRT = CanDoRT; + ++ASId; + + // We assign consecutive id to access from different dependence sets. + // Accesses within the same set don't need a runtime check. + unsigned RunningDepId = 1; + DenseMap DepSetId; + + SmallVector Retries; + + // First, count how many write and read accesses are in the alias set. Also + // collect MemAccessInfos for later. + SmallVector AccessInfos; + for (const auto &A : AS) { + Value *Ptr = A.getValue(); + bool IsWrite = Accesses.count(MemAccessInfo(Ptr, true)); + + if (IsWrite) + ++NumWritePtrChecks; + else + ++NumReadPtrChecks; + AccessInfos.emplace_back(Ptr, IsWrite); + } + + // We do not need runtime checks for this alias set, if there are no writes + // or a single write and no reads. + if (NumWritePtrChecks == 0 || + (NumWritePtrChecks == 1 && NumReadPtrChecks == 0)) { + assert((AS.size() <= 1 || + all_of(AS, + [this](auto AC) { + MemAccessInfo AccessWrite(AC.getValue(), true); + return DepCands.findValue(AccessWrite) == + DepCands.end(); + })) && + "Can only skip updating CanDoRT below, if all entries in AS " + "are reads or there is at most 1 entry"); continue; - // Only need to check pointers in the same alias set. - if (RtCheck.Pointers[i].AliasSetId != RtCheck.Pointers[j].AliasSetId) - continue; - - Value *PtrI = RtCheck.Pointers[i].PointerValue; - Value *PtrJ = RtCheck.Pointers[j].PointerValue; - - unsigned ASi = PtrI->getType()->getPointerAddressSpace(); - unsigned ASj = PtrJ->getType()->getPointerAddressSpace(); - if (ASi != ASj) { - LLVM_DEBUG( - dbgs() << "LAA: Runtime check would require comparison between" - " different address spaces\n"); - return false; - } - } - } - - if (MayNeedRTCheck && CanDoRT) - RtCheck.generateChecks(DepCands, IsDepCheckNeeded); - - LLVM_DEBUG(dbgs() << "LAA: We need to do " << RtCheck.getNumberOfChecks() - << " pointer comparisons.\n"); - - // If we can do run-time checks, but there are no checks, no runtime checks - // are needed. This can happen when all pointers point to the same underlying - // object for example. - RtCheck.Need = CanDoRT ? RtCheck.getNumberOfChecks() != 0 : MayNeedRTCheck; - - bool CanDoRTIfNeeded = !RtCheck.Need || CanDoRT; - if (!CanDoRTIfNeeded) - RtCheck.reset(); - return CanDoRTIfNeeded; -} + } + + for (auto &Access : AccessInfos) { + if (!createCheckForAccess(RtCheck, Access, StridesMap, DepSetId, TheLoop, + RunningDepId, ASId, ShouldCheckWrap, false)) { + LLVM_DEBUG(dbgs() << "LAA: Can't find bounds for ptr:" + << *Access.getPointer() << '\n'); + Retries.push_back(Access); + CanDoAliasSetRT = false; + } + } + + // Note that this function computes CanDoRT and MayNeedRTCheck + // independently. For example CanDoRT=false, MayNeedRTCheck=false means + // that we have a pointer for which we couldn't find the bounds but we + // don't actually need to emit any checks so it does not matter. + // + // We need runtime checks for this alias set, if there are at least 2 + // dependence sets (in which case RunningDepId > 2) or if we need to re-try + // any bound checks (because in that case the number of dependence sets is + // incomplete). + bool NeedsAliasSetRTCheck = RunningDepId > 2; + + // We need to perform run-time alias checks, but some pointers had bounds + // that couldn't be checked. + if (NeedsAliasSetRTCheck && !CanDoAliasSetRT) { + // Reset the CanDoSetRt flag and retry all accesses that have failed. + // We know that we need these checks, so we can now be more aggressive + // and add further checks if required (overflow checks). + CanDoAliasSetRT = true; + for (auto Access : Retries) + if (!createCheckForAccess(RtCheck, Access, StridesMap, DepSetId, + TheLoop, RunningDepId, ASId, ShouldCheckWrap, + /*Assume=*/true)) { + CanDoAliasSetRT = false; + break; + } + } + + CanDoRT &= CanDoAliasSetRT; + MayNeedRTCheck |= NeedsAliasSetRTCheck; + ++ASId; + } + + // If the pointers that we would use for the bounds comparison have different + // address spaces, assume the values aren't directly comparable, so we can't + // use them for the runtime check. We also have to assume they could + // overlap. In the future there should be metadata for whether address spaces + // are disjoint. + unsigned NumPointers = RtCheck.Pointers.size(); + for (unsigned i = 0; i < NumPointers; ++i) { + for (unsigned j = i + 1; j < NumPointers; ++j) { + // Only need to check pointers between two different dependency sets. + if (RtCheck.Pointers[i].DependencySetId == + RtCheck.Pointers[j].DependencySetId) + continue; + // Only need to check pointers in the same alias set. + if (RtCheck.Pointers[i].AliasSetId != RtCheck.Pointers[j].AliasSetId) + continue; + + Value *PtrI = RtCheck.Pointers[i].PointerValue; + Value *PtrJ = RtCheck.Pointers[j].PointerValue; + + unsigned ASi = PtrI->getType()->getPointerAddressSpace(); + unsigned ASj = PtrJ->getType()->getPointerAddressSpace(); + if (ASi != ASj) { + LLVM_DEBUG( + dbgs() << "LAA: Runtime check would require comparison between" + " different address spaces\n"); + return false; + } + } + } + + if (MayNeedRTCheck && CanDoRT) + RtCheck.generateChecks(DepCands, IsDepCheckNeeded); + + LLVM_DEBUG(dbgs() << "LAA: We need to do " << RtCheck.getNumberOfChecks() + << " pointer comparisons.\n"); + + // If we can do run-time checks, but there are no checks, no runtime checks + // are needed. This can happen when all pointers point to the same underlying + // object for example. + RtCheck.Need = CanDoRT ? RtCheck.getNumberOfChecks() != 0 : MayNeedRTCheck; + + bool CanDoRTIfNeeded = !RtCheck.Need || CanDoRT; + if (!CanDoRTIfNeeded) + RtCheck.reset(); + return CanDoRTIfNeeded; + } void AccessAnalysis::processMemAccesses() { // We process the set twice: first we process read-write pointers, last we @@ -1396,6 +1407,9 @@ // will be executed only if LoopCount >= VF, proving distance >= LoopCount // also guarantees that distance >= VF. // + if (isa(BackedgeTakenCount)) + return false; + const uint64_t ByteStride = Stride * TypeByteSize; const SCEV *Step = SE.getConstant(BackedgeTakenCount.getType(), ByteStride); const SCEV *Product = SE.getMulExpr(&BackedgeTakenCount, Step); @@ -1781,15 +1795,6 @@ return false; } - // ScalarEvolution needs to be able to find the exit count. - const SCEV *ExitCount = PSE->getBackedgeTakenCount(); - if (isa(ExitCount)) { - recordAnalysis("CantComputeNumberOfIterations") - << "could not determine number of loop iterations"; - LLVM_DEBUG(dbgs() << "LAA: SCEV could not compute the loop exit count.\n"); - return false; - } - return true; } @@ -2015,12 +2020,14 @@ // Find pointers with computable bounds. We are going to use this information // to place a runtime bound check. - bool CanDoRTIfNeeded = Accesses.canCheckPtrAtRT(*PtrRtChecking, PSE->getSE(), - TheLoop, SymbolicStrides); + bool CanDoRTIfNeeded = + Accesses.canCheckPtrAtRT(*PtrRtChecking, *PSE, TheLoop, SymbolicStrides); if (!CanDoRTIfNeeded) { - recordAnalysis("CantIdentifyArrayBounds") << "cannot identify array bounds"; - LLVM_DEBUG(dbgs() << "LAA: We can't vectorize because we can't find " - << "the array bounds.\n"); + recordAnalysis("CantIdentifyArrayBounds") + << "cannot identify array bounds or the number of loop iterations"; + LLVM_DEBUG( + dbgs() << "LAA: We can't vectorize because we can't find " + << "the array bounds or the number of loop iterations.\n"); CanVecMem = false; return; } @@ -2044,8 +2051,7 @@ PtrRtChecking->reset(); PtrRtChecking->Need = true; - auto *SE = PSE->getSE(); - CanDoRTIfNeeded = Accesses.canCheckPtrAtRT(*PtrRtChecking, SE, TheLoop, + CanDoRTIfNeeded = Accesses.canCheckPtrAtRT(*PtrRtChecking, *PSE, TheLoop, SymbolicStrides, true); // Check that we found the bounds for the pointer. @@ -2134,6 +2140,14 @@ if (!Stride) return; + const SCEV *BETakenCount = PSE->getBackedgeTakenCount(); + + if (isa(BETakenCount)) { + LLVM_DEBUG(dbgs() << "LAA: Cannot analyze strided access, because a known " + "backedge-taken-count is required\n"); + return; + } + LLVM_DEBUG(dbgs() << "LAA: Found a strided access that is a candidate for " "versioning:"); LLVM_DEBUG(dbgs() << " Ptr: " << *Ptr << " Stride: " << *Stride << "\n"); @@ -2152,7 +2166,6 @@ // of using gather/scatters (if available). const SCEV *StrideExpr = PSE->getSCEV(Stride); - const SCEV *BETakenCount = PSE->getBackedgeTakenCount(); // Match the types so we can compare the stride and the BETakenCount. // The Stride can be positive/negative, so we sign extend Stride; diff --git a/llvm/lib/Transforms/Scalar/LoopDistribute.cpp b/llvm/lib/Transforms/Scalar/LoopDistribute.cpp --- a/llvm/lib/Transforms/Scalar/LoopDistribute.cpp +++ b/llvm/lib/Transforms/Scalar/LoopDistribute.cpp @@ -808,6 +808,12 @@ if (!PH->getSinglePredecessor() || &*PH->begin() != PH->getTerminator()) SplitBlock(PH, PH->getTerminator(), DT, LI); + if (!Pred.isAlwaysTrue() && + isa(SE->getBackedgeTakenCount(L))) { + return fail( + "RuntimeCheckUnknownBackedgeTakenCount", + "Cannot create runtime checks with unknown backedge-taken count"); + } if (!Pred.isAlwaysTrue() || !Checks.empty()) { assert(!LAI->hasConvergentOp() && "inserting illegal loop versioning"); diff --git a/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp b/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp --- a/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp +++ b/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp @@ -560,6 +560,14 @@ return false; } + if (!LAI.getPSE().getUnionPredicate().isAlwaysTrue() && + isa(PSE.getBackedgeTakenCount())) { + LLVM_DEBUG( + dbgs() + << "Cannot version loop with uncomputable backedge-taken count\n"); + return false; + } + // Point of no-return, start the transformation. First, version the loop // if necessary. diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp --- a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp +++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp @@ -1224,6 +1224,16 @@ return false; } + if (isa(PSE.getBackedgeTakenCount())) { + reportVectorizationFailure("Uncomputable number of iterations", + "could not determine number of loop iterations", + "CantComputeNumberOfIterations", ORE, TheLoop); + if (DoExtraAnalysis) + Result = false; + else + return false; + } + LLVM_DEBUG(dbgs() << "LV: We can vectorize this loop" << (LAI->getRuntimePointerChecking()->Need ? " (with a runtime bound check)" diff --git a/llvm/test/Analysis/LoopAccessAnalysis/uncomputable-backedge-taken-count.ll b/llvm/test/Analysis/LoopAccessAnalysis/uncomputable-backedge-taken-count.ll --- a/llvm/test/Analysis/LoopAccessAnalysis/uncomputable-backedge-taken-count.ll +++ b/llvm/test/Analysis/LoopAccessAnalysis/uncomputable-backedge-taken-count.ll @@ -4,9 +4,9 @@ target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.10.0" -; TODO: Loop iteration counts are only required if we generate memory -; runtime checks. Missing iteration counts should not prevent -; analysis, if no runtime checks are required. +; Loop iteration counts are only required if we generate memory +; runtime checks. Missing iteration counts should not prevent +; analysis, if no runtime checks are required. ; No memory checks are required, because base pointers do not alias and we have ; a forward dependence for %a. @@ -14,7 +14,14 @@ i16* noalias %b) { ; CHECK-LABEL: safe_forward_dependence ; CHECK: for.body: -; CHECK-NEXT: Report: could not determine number of loop iterations +; CHECK-NEXT: Memory dependences are safe +; CHECK-NEXT: Dependences: +; CHECK-NEXT: Forward: +; CHECK-NEXT: %loadA_plus_2 = load i16, i16* %arrayidxA_plus_2, align 2 -> +; CHECK-NEXT: store i16 %mul, i16* %arrayidxA, align 2 +; +; CHECK: Run-time memory checks: +; CHECK-NEXT: Grouped accesses: ; entry: br label %for.body @@ -50,7 +57,14 @@ i16* noalias %b) { ; CHECK-LABEL: unsafe_backwards_dependence ; CHECK: for.body: -; CHECK-NEXT: Report: could not determine number of loop iterations +; CHECK-NEXT: Report: unsafe dependent memory operations in loop. Use #pragma loop distribute(enable) to allow loop distribution to attempt to isolate the offending operations into a separate loop +; CHECK-NEXT: Dependences: +; CHECK-NEXT: Backward: +; CHECK-NEXT: %loadA_plus_2 = load i16, i16* %arrayidxA_plus_2, align 2 -> +; CHECK-NEXT: store i16 %mul, i16* %arrayidxA, align 2 + +; CHECK: Run-time memory checks: +; CHECK-NEXT: Grouped accesses: ; entry: br label %for.body @@ -84,7 +98,7 @@ define void @ptr_may_alias(i16* %a, i16* %b) { ; CHECK-LABEL: ptr_may_alias ; CHECK: for.body: -; CHECK-NEXT: Report: could not determine number of loop iterations +; CHECK-NEXT: Report: cannot identify array bounds or the number of loop iterations ; entry: br label %for.body diff --git a/llvm/test/Transforms/LoopDistribute/uncomputable-backedge-taken-count.ll b/llvm/test/Transforms/LoopDistribute/uncomputable-backedge-taken-count.ll --- a/llvm/test/Transforms/LoopDistribute/uncomputable-backedge-taken-count.ll +++ b/llvm/test/Transforms/LoopDistribute/uncomputable-backedge-taken-count.ll @@ -8,7 +8,6 @@ ; Making the exit condition depend on a load would break current loop-distribute, ; because it requires all accesses to end up in either of the loops, but not both. -; TODO ; Can distribute with unknown backedge-taken count, because no runtime checks are ; required. define void @unknown_btc_distribute_no_checks_needed(i32* noalias %a, @@ -16,6 +15,12 @@ i32* noalias %d) { ; CHECK-LABEL: @unknown_btc_distribute_no_checks_needed( ; CHECK-NEXT: entry: +; CHECK-NEXT: br label %entry.split.ldist1 +; +; CHECK-LABEL: entry.split.ldist1: +; CHECK: br i1 false, label %entry.split, label %for.body.ldist1 +; +; CHECK-LABEL: entry.split: ; CHECK-NEXT: br label %for.body ; entry: @@ -54,6 +59,9 @@ i32* noalias %d) { ; CHECK-LABEL: @unknown_btc_do_not_distribute_wrapping_checks( ; CHECK-NEXT: entry: +; CHECK-NEXT: br label %entry.split + +; CHECK-LABEL: entry.split: ; CHECK-NEXT: br label %for.body ; entry: diff --git a/llvm/test/Transforms/LoopLoadElim/uncomputable-backedge-taken-count.ll b/llvm/test/Transforms/LoopLoadElim/uncomputable-backedge-taken-count.ll --- a/llvm/test/Transforms/LoopLoadElim/uncomputable-backedge-taken-count.ll +++ b/llvm/test/Transforms/LoopLoadElim/uncomputable-backedge-taken-count.ll @@ -3,14 +3,17 @@ target datalayout = "e-m:o-i32:64-f80:128-n8:16:32:64-S128" -; TODO ; Make sure loop-load-elimination triggers for a loop with uncomputable ; backedge-taken counts when no runtime checks are required. define void @load_elim_no_runtime_checks(i32* noalias %A, i32* noalias %B, i32* noalias %C, i32 %N) { ; CHECK-LABEL: load_elim_no_runtime_checks ; CHECK-NEXT: entry: +; CHECK-NEXT: %load_initial = load i32, i32* %A, align 1 ; CHECK-NEXT: br label %for.body ; +; CHECK: %store_forwarded = phi i32 [ %load_initial, %entry ], [ %a_p1, %for.body ] +; CHECK: %c = mul i32 %store_forwarded, 2 +; entry: br label %for.body diff --git a/llvm/test/Transforms/LoopVectorize/X86/vectorization-remarks-missed.ll b/llvm/test/Transforms/LoopVectorize/X86/vectorization-remarks-missed.ll --- a/llvm/test/Transforms/LoopVectorize/X86/vectorization-remarks-missed.ll +++ b/llvm/test/Transforms/LoopVectorize/X86/vectorization-remarks-missed.ll @@ -121,6 +121,15 @@ ; YAML-NEXT: ... ; YAML-NEXT: --- !Analysis ; YAML-NEXT: Pass: loop-vectorize +; YAML-NEXT: Name: CantVectorizeInstruction +; YAML-NEXT: DebugLoc: { File: source.cpp, Line: 27, Column: 3 } +; YAML-NEXT: Function: test_multiple_failures +; YAML-NEXT: Args: +; YAML-NEXT: - String: 'loop not vectorized: ' +; YAML-NEXT: - String: instruction cannot be vectorized +; YAML-NEXT: ... +; YAML-NEXT: --- !Analysis +; YAML-NEXT: Pass: loop-vectorize ; YAML-NEXT: Name: CantComputeNumberOfIterations ; YAML-NEXT: DebugLoc: { File: source.cpp, Line: 27, Column: 3 } ; YAML-NEXT: Function: test_multiple_failures