diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -803,20 +803,14 @@ // while(1) is common, avoid extra exit blocks. Be sure // to correctly handle break/continue though. - bool EmitBoolCondBranch = true; - bool LoopMustProgress = false; - if (llvm::ConstantInt *C = dyn_cast(BoolCondVal)) { - if (C->isOne()) { - EmitBoolCondBranch = false; - FnIsMustProgress = false; - } - } else if (LanguageRequiresProgress()) - LoopMustProgress = true; - + llvm::ConstantInt *C = dyn_cast(BoolCondVal); + bool EmitBoolCondBranch = !C || !C->isOne(); + bool CondIsConstInt = C; const SourceRange &R = S.getSourceRange(); LoopStack.push(LoopHeader.getBlock(), CGM.getContext(), CGM.getCodeGenOpts(), WhileAttrs, SourceLocToDebugLoc(R.getBegin()), - SourceLocToDebugLoc(R.getEnd()), LoopMustProgress); + SourceLocToDebugLoc(R.getEnd()), + checkIfLoopMustProgress(CondIsConstInt)); // As long as the condition is true, go to the loop body. llvm::BasicBlock *LoopBody = createBasicBlock("while.body"); @@ -907,20 +901,15 @@ // "do {} while (0)" is common in macros, avoid extra blocks. Be sure // to correctly handle break/continue though. - bool EmitBoolCondBranch = true; - bool LoopMustProgress = false; - if (llvm::ConstantInt *C = dyn_cast(BoolCondVal)) { - if (C->isZero()) - EmitBoolCondBranch = false; - else if (C->isOne()) - FnIsMustProgress = false; - } else if (LanguageRequiresProgress()) - LoopMustProgress = true; + llvm::ConstantInt *C = dyn_cast(BoolCondVal); + bool CondIsConstInt = C; + bool EmitBoolCondBranch = !C || !C->isZero(); const SourceRange &R = S.getSourceRange(); LoopStack.push(LoopBody, CGM.getContext(), CGM.getCodeGenOpts(), DoAttrs, SourceLocToDebugLoc(R.getBegin()), - SourceLocToDebugLoc(R.getEnd()), LoopMustProgress); + SourceLocToDebugLoc(R.getEnd()), + checkIfLoopMustProgress(CondIsConstInt)); // As long as the condition is true, iterate the loop. if (EmitBoolCondBranch) { @@ -958,20 +947,15 @@ llvm::BasicBlock *CondBlock = CondDest.getBlock(); EmitBlock(CondBlock); - bool LoopMustProgress = false; Expr::EvalResult Result; - if (LanguageRequiresProgress()) { - if (!S.getCond()) { - FnIsMustProgress = false; - } else if (!S.getCond()->EvaluateAsInt(Result, getContext())) { - LoopMustProgress = true; - } - } + bool CondIsConstInt = + !S.getCond() || S.getCond()->EvaluateAsInt(Result, getContext()); const SourceRange &R = S.getSourceRange(); LoopStack.push(CondBlock, CGM.getContext(), CGM.getCodeGenOpts(), ForAttrs, SourceLocToDebugLoc(R.getBegin()), - SourceLocToDebugLoc(R.getEnd()), LoopMustProgress); + SourceLocToDebugLoc(R.getEnd()), + checkIfLoopMustProgress(CondIsConstInt)); // Create a cleanup scope for the condition variable cleanups. LexicalScope ConditionScope(*this, S.getSourceRange()); @@ -1020,10 +1004,6 @@ BoolCondVal = emitCondLikelihoodViaExpectIntrinsic( BoolCondVal, Stmt::getLikelihood(S.getBody())); - if (llvm::ConstantInt *C = dyn_cast(BoolCondVal)) - if (C->isOne()) - FnIsMustProgress = false; - Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock, Weights); if (ExitBlock != LoopExit.getBlock()) { diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -517,21 +517,29 @@ /// True if the current statement has nomerge attribute. bool InNoMergeAttributedStmt = false; - /// True if the current function should be marked mustprogress. - bool FnIsMustProgress = false; - - /// True if the C++ Standard Requires Progress. - bool CPlusPlusWithProgress() { + /// Returns true if a function must make progress, which means the + /// mustprogress attribute can be added. + bool checkIfFunctionMustProgress() { if (CGM.getCodeGenOpts().getFiniteLoops() == CodeGenOptions::FiniteLoopsKind::Never) return false; + // C++11 and later guarantees that a thread eventually will do one of the + // following (6.9.2.3.1 in C++11): + // - terminate, + // - make a call to a library I/O function, + // - perform an access through a volatile glvalue, or + // - perform a synchronization operation or an atomic operation. + // + // Hence each function is 'mustprogress' in C++11 or later. return getLangOpts().CPlusPlus11 || getLangOpts().CPlusPlus14 || getLangOpts().CPlusPlus17 || getLangOpts().CPlusPlus20; } - /// True if the C Standard Requires Progress. - bool CWithProgress() { + /// Returns true if a loop must make progress, which means the mustprogress + /// attribute can be added. \p HasConstantCond indicates whether the branch + /// condition is a known constant. + bool checkIfLoopMustProgress(bool HasConstantCond) { if (CGM.getCodeGenOpts().getFiniteLoops() == CodeGenOptions::FiniteLoopsKind::Always) return true; @@ -539,13 +547,19 @@ CodeGenOptions::FiniteLoopsKind::Never) return false; - return getLangOpts().C11 || getLangOpts().C17 || getLangOpts().C2x; - } + // If the containing function must make progress, loops also must make + // progress (as in C++11 and later). + if (checkIfFunctionMustProgress()) + return true; - /// True if the language standard requires progress in functions or - /// in infinite loops with non-constant conditionals. - bool LanguageRequiresProgress() { - return CWithProgress() || CPlusPlusWithProgress(); + // Now apply rules for plain C (see 6.8.5.6 in C11). + // Loops with constant conditions do not have to make progress in any C + // version. + if (HasConstantCond) + return false; + + // Loops with non-constant conditions must make progress in C11 and later. + return getLangOpts().C11 || getLangOpts().C17 || getLangOpts().C2x; } const CodeGen::CGBlockInfo *BlockInfo = nullptr; diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -1187,9 +1187,6 @@ void CodeGenFunction::EmitFunctionBody(const Stmt *Body) { incrementProfileCounter(Body); - if (CPlusPlusWithProgress()) - FnIsMustProgress = true; - if (const CompoundStmt *S = dyn_cast(Body)) EmitCompoundStmtWithoutScope(*S); else @@ -1197,7 +1194,7 @@ // This is checked after emitting the function body so we know if there // are any permitted infinite loops. - if (FnIsMustProgress) + if (checkIfFunctionMustProgress()) CurFn->addFnAttr(llvm::Attribute::MustProgress); } diff --git a/clang/test/CodeGen/attr-mustprogress.c b/clang/test/CodeGen/attr-mustprogress.c --- a/clang/test/CodeGen/attr-mustprogress.c +++ b/clang/test/CodeGen/attr-mustprogress.c @@ -1,15 +1,18 @@ +// RUN: %clang_cc1 -std=c89 -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=C99 %s // RUN: %clang_cc1 -std=c99 -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=C99 %s // RUN: %clang_cc1 -std=c11 -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=C11 %s // RUN: %clang_cc1 -std=c18 -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=C11 %s // RUN: %clang_cc1 -std=c2x -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=C11 %s // // Check -ffinite-loops option in combination with various standard versions. +// RUN: %clang_cc1 -std=c89 -ffinite-loops -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=FINITE %s // RUN: %clang_cc1 -std=c99 -ffinite-loops -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=FINITE %s // RUN: %clang_cc1 -std=c11 -ffinite-loops -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=FINITE %s // RUN: %clang_cc1 -std=c18 -ffinite-loops -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=FINITE %s // RUN: %clang_cc1 -std=c2x -ffinite-loops -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=FINITE %s // // Check -fno-finite-loops option in combination with various standard versions. +// RUN: %clang_cc1 -std=c89 -fno-finite-loops -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=C99 %s // RUN: %clang_cc1 -std=c99 -fno-finite-loops -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=C99 %s // RUN: %clang_cc1 -std=c11 -fno-finite-loops -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=C99 %s // RUN: %clang_cc1 -std=c18 -fno-finite-loops -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=C99 %s @@ -25,7 +28,9 @@ // CHECK-NEXT: entry: // CHECK-NEXT: br label %for.cond // CHECK: for.cond: -// CHECK-NOT: br {{.*}}!llvm.loop +// C99-NOT: br {{.*}}!llvm.loop +// C11-NOT: br {{.*}}!llvm.loop +// FINITE-NEXT: br {{.*}}!llvm.loop // void f0() { for (; ;) ; @@ -38,7 +43,9 @@ // CHECK: for.cond: // CHECK-NEXT: br i1 true, label %for.body, label %for.end // CHECK: for.body: -// CHECK-NOT: br {{.*}}, !llvm.loop +// C99-NOT: br {{.*}}, !llvm.loop +// C11-NOT: br {{.*}}, !llvm.loop +// FINITE-NEXT: br {{.*}}, !llvm.loop // CHECK: for.end: // CHECK-NEXT: ret void // @@ -75,7 +82,9 @@ // CHECK: for.cond: // CHECK-NEXT: br i1 true, label %for.body, label %for.end // CHECK: for.body: -// CHECK-NOT: br {{.*}}, !llvm.loop +// C99-NOT: br {{.*}}, !llvm.loop +// C11-NOT: br {{.*}}, !llvm.loop +// FINITE-NEXT: br {{.*}}, !llvm.loop // CHECK: for.end: // CHECK-NEXT: br label %for.cond1 // CHECK: for.cond1: @@ -102,7 +111,9 @@ // CHECK-NEXT: entry: // CHECK-NEXT: br label %while.body // CHECK: while.body: -// CHECK-NOT: br {{.*}}, !llvm.loop +// C99-NOT: br {{.*}}, !llvm.loop +// C11-NOT: br {{.*}}, !llvm.loop +// FINITE-NEXT: br {{.*}}, !llvm.loop // void w1() { while (1) { @@ -141,12 +152,14 @@ // CHECK-NEXT: br i1 [[CMP]], label %while.body, label %while.end // CHECK: while.body: // C99-NOT: br {{.*}} !llvm.loop -// C11: br label %while.cond, !llvm.loop [[LOOP4:!.*]] -// FINITE: br label %while.cond, !llvm.loop [[LOOP4:!.*]] +// C11-NEXT: br label %while.cond, !llvm.loop [[LOOP4:!.*]] +// FINITE-NEXT: br label %while.cond, !llvm.loop [[LOOP4:!.*]] // CHECK: while.end: // CHECK-NEXT: br label %while.body2 // CHECK: while.body2: -// CHECK-NOT: br {{.*}} !llvm.loop +// C99-NOT: br {{.*}} !llvm.loop +// C11-NOT: br {{.*}} !llvm.loop +// FINITE-NEXT: br {{.*}} !llvm.loop // void W() { while (a == b) { @@ -162,7 +175,9 @@ // CHECK: do.body: // CHECK-NEXT: br label %do.cond // CHECK: do.cond: -// CHECK-NOT: br {{.*}}, !llvm.loop +// C99-NOT: br {{.*}}, !llvm.loop +// C11-NOT: br {{.*}}, !llvm.loop +// FINITE-NEXT: br {{.*}}, !llvm.loop // CHECK: do.end: // CHECK-NEXT: ret void // diff --git a/clang/test/CodeGenCXX/attr-mustprogress.cpp b/clang/test/CodeGenCXX/attr-mustprogress.cpp --- a/clang/test/CodeGenCXX/attr-mustprogress.cpp +++ b/clang/test/CodeGenCXX/attr-mustprogress.cpp @@ -23,20 +23,22 @@ // CHECK: datalayout -// CXX98-NOT: mustprogress -// CXX11-NOT: mustprogress -// FINITE-NOT: mustprogress +// CXX98-NOT: mustprogress +// CXX11: mustprogress +// FINITE-NOT: mustprogress // CHECK-LABEL: @_Z2f0v( // CHECK-NEXT: entry: // CHECK-NEXT: br label %for.cond // CHECK: for.cond: -// CHECK-NOT: br {{.*}} llvm.loop +// CXX98-NOT: br {{.*}} llvm.loop +// CXX11-NEXT: br label %for.cond, !llvm.loop [[LOOP1:!.*]] +// FINITE-NEXT: br label %for.cond, !llvm.loop [[LOOP1:!.*]] void f0() { for (; ;) ; } -// CXX98-NOT: mustprogress -// CXX11-NOT: mustprogress +// CXX98-NOT: mustprogress +// CXX11: mustprogress // FINITE-NOT: mustprogress // CHECK-LABEL: @_Z2f1v( // CHECK-NEXT: entry: @@ -44,7 +46,9 @@ // CHECK: for.cond: // CHECK-NEXT: br i1 true, label %for.body, label %for.end // CHECK: for.body: -// CHECK-NOT: br {{.*}}, !llvm.loop +// CXX98-NOT: br {{.*}}, !llvm.loop +// CXX11-NEXT: br label %for.cond, !llvm.loop [[LOOP2:!.*]] +// FINITE-NEXT: br label %for.cond, !llvm.loop [[LOOP2:!.*]] // CHECK: for.end: // CHECK-NEXT: ret void // @@ -53,8 +57,8 @@ ; } -// CXX98-NOT: mustprogress -// CXX11: mustprogress +// CXX98-NOT: mustprogress +// CXX11: mustprogress // FINITE-NOT: mustprogress // CHECK-LABEL: @_Z2f2v( // CHECK-NEXT: entry: @@ -66,8 +70,8 @@ // CHECK-NEXT: br i1 [[CMP]], label %for.body, label %for.end // CHECK: for.body: // CXX98-NOT: br {{.*}}, !llvm.loop -// CXX11: br label %for.cond, !llvm.loop [[LOOP1:!.*]] -// FINITE-NEXT: br label %for.cond, !llvm.loop [[LOOP1:!.*]] +// CXX11: br label %for.cond, !llvm.loop [[LOOP3:!.*]] +// FINITE-NEXT: br label %for.cond, !llvm.loop [[LOOP3:!.*]] // CHECK: for.end: // CHECK-NEXT: ret void // @@ -76,8 +80,8 @@ ; } -// CXX98-NOT: mustprogress -// CXX11-NOT: mustprogress +// CXX98-NOT: mustprogress +// CXX11: mustprogress // FINITE-NOT: mustprogress // CHECK-LABEL: @_Z1Fv( // CHECK-NEXT: entry: @@ -85,7 +89,9 @@ // CHECK: for.cond: // CHECK-NEXT: br i1 true, label %for.body, label %for.end // CHECK: for.body: -// CHECK-NOT: br {{.*}}, !llvm.loop +// CXX98-NOT: br {{.*}}, !llvm.loop +// CXX11-NEXT: br label %for.cond, !llvm.loop [[LOOP4:!.*]] +// FINITE-NEXT: br label %for.cond, !llvm.loop [[LOOP4:!.*]] // CHECK: for.end: // CHECK-NEXT: br label %for.cond1 // CHECK: for.cond1: @@ -95,8 +101,8 @@ // CHECK-NEXT: br i1 [[CMP]], label %for.body2, label %for.end3 // CHECK: for.body2: // CXX98-NOT: br {{.*}}, !llvm.loop -// CXX11-NEXT: br label %for.cond1, !llvm.loop [[LOOP2:!.*]] -// FINITE-NEXT: br label %for.cond1, !llvm.loop [[LOOP2:!.*]] +// CXX11-NEXT: br label %for.cond1, !llvm.loop [[LOOP5:!.*]] +// FINITE-NEXT: br label %for.cond1, !llvm.loop [[LOOP5:!.*]] // CHECK: for.end3: // CHECK-NEXT: ret void // @@ -107,8 +113,8 @@ ; } -// CXX98-NOT: mustprogress -// CXX11-NOT: mustprogress +// CXX98-NOT: mustprogress +// CXX11: mustprogress // FINITE-NOT: mustprogress // CHECK-LABEL: @_Z2F2v( // CHECK-NEXT: entry: @@ -120,14 +126,16 @@ // CHECK-NEXT: br i1 [[CMP]], label %for.body, label %for.end // CHECK: for.body: // CXX98_NOT: br {{.*}} !llvm.loop -// CXX11-NEXT: br label %for.cond, !llvm.loop [[LOOP3:!.*]] -// FINITE-NEXT: br label %for.cond, !llvm.loop [[LOOP3:!.*]] +// CXX11-NEXT: br label %for.cond, !llvm.loop [[LOOP6:!.*]] +// FINITE-NEXT: br label %for.cond, !llvm.loop [[LOOP6:!.*]] // CHECK: for.end: // CHECK-NEXT: br label %for.cond1 // CHECK: for.cond1: // CHECK-NEXT: br i1 true, label %for.body2, label %for.end3 // CHECK: for.body2: -// CHECK-NOT: br {{.*}}, !llvm.loop +// CXX98-NOT: br {{.*}}, !llvm.loop +// CXX11-NEXT: br label %for.cond1, !llvm.loop [[LOOP7:!.*]] +// FINITE-NEXT: br label %for.cond1, !llvm.loop [[LOOP7:!.*]] // CHECK: for.end3: // CHECK-NEXT: ret void // @@ -138,22 +146,24 @@ ; } -// CXX98-NOT: mustprogress -// CXX11-NOT: mustprogress -// FINITE-NOT: mustprogress +// CXX98-NOT: mustprogress +// CXX11: mustprogress +// FINITE-NOT: mustprogress // CHECK-LABEL: @_Z2w1v( // CHECK-NEXT: entry: // CHECK-NEXT: br label %while.body // CHECK: while.body: -// CHECK-NOT: br {{.*}}, !llvm.loop +// CXX98-NOT: br {{.*}}, !llvm.loop +// CXX11-NEXT: br label %while.body, !llvm.loop [[LOOP8:!.*]] +// FINITE-NEXT: br label %while.body, !llvm.loop [[LOOP8:!.*]] // void w1() { while (1) ; } -// CXX98-NOT: mustprogress -// CXX11: mustprogress +// CXX98-NOT: mustprogress +// CXX11: mustprogress // FINITE-NOT: mustprogress // CHECK-LABEL: @_Z2w2v( // CHECK-NEXT: entry: @@ -165,8 +175,8 @@ // CHECK-NEXT: br i1 [[CMP]], label %while.body, label %while.end // CHECK: while.body: // CXX98-NOT: br {{.*}}, !llvm.loop -// CXX11-NEXT: br label %while.cond, !llvm.loop [[LOOP4:!.*]] -// FINITE-NEXT: br label %while.cond, !llvm.loop [[LOOP4:!.*]] +// CXX11-NEXT: br label %while.cond, !llvm.loop [[LOOP9:!.*]] +// FINITE-NEXT: br label %while.cond, !llvm.loop [[LOOP9:!.*]] // CHECK: while.end: // CHECK-NEXT: ret void // @@ -175,8 +185,8 @@ ; } -// CXX98-NOT: mustprogress -// CXX11-NOT: mustprogress +// CXX98-NOT: mustprogress +// CXX11: mustprogress // FINITE-NOT: mustprogress // CHECK-LABEL: @_Z1Wv( // CHECK-NEXT: entry: @@ -188,12 +198,14 @@ // CHECK-NEXT: br i1 [[CMP]], label %while.body, label %while.end // CHECK: while.body: // CXX98-NOT: br {{.*}}, !llvm.loop -// CXX11-NEXT: br label %while.cond, !llvm.loop [[LOOP5:!.*]] -// FINITE-NEXT: br label %while.cond, !llvm.loop [[LOOP5:!.*]] +// CXX11-NEXT: br label %while.cond, !llvm.loop [[LOOP10:!.*]] +// FINITE-NEXT: br label %while.cond, !llvm.loop [[LOOP10:!.*]] // CHECK: while.end: // CHECK-NEXT: br label %while.body2 // CHECK: while.body2: -// CHECK-NOT: br {{.*}}, !llvm.loop +// CXX98-NOT: br {{.*}}, !llvm.loop +// CXX11-NEXT: br label %while.body2, !llvm.loop [[LOOP11:!.*]] +// FINITE-NEXT: br label %while.body2, !llvm.loop [[LOOP11:!.*]] // void W() { while (a == b) @@ -202,14 +214,16 @@ ; } -// CXX98-NOT: mustprogress -// CXX11-NOT: mustprogress +// CXX98-NOT: mustprogress +// CXX11: mustprogress // FINITE-NOT: mustprogress // CHECK-LABEL: @_Z2W2v( // CHECK-NEXT: entry: // CHECK-NEXT: br label %while.body // CHECK: while.body: -// CHECK-NOT: br {{.*}}, !llvm.loop +// CXX98-NOT: br {{.*}}, !llvm.loop +// CXX11-NEXT: br label %while.body, !llvm.loop [[LOOP12:!.*]] +// FINITE-NEXT: br label %while.body, !llvm.loop [[LOOP12:!.*]] // void W2() { while (1) @@ -218,8 +232,8 @@ ; } -// CXX98-NOT: mustprogress -// CXX11-NOT: mustprogress +// CXX98-NOT: mustprogress +// CXX11: mustprogress // FINITE-NOT: mustprogress // CHECK-LABEL: @_Z2d1v( // CHECK-NEXT: entry: @@ -227,7 +241,9 @@ // CHECK: do.body: // CHECK-NEXT: br label %do.cond // CHECK: do.cond: -// CHECK-NOT: br {{.*}}, !llvm.loop +// CXX98-NOT: br {{.*}}, !llvm.loop +// CXX11-NEXT: br i1 true, label %do.body, label %do.end, !llvm.loop [[LOOP13:!.*]] +// FINITE-NEXT: br i1 true, label %do.body, label %do.end, !llvm.loop [[LOOP13:!.*]] // CHECK: do.end: // CHECK-NEXT: ret void // @@ -237,9 +253,9 @@ while (1); } -// CXX98-NOT: mustprogress -// CXX11: mustprogress -// FINITE-NOT: mustprogress +// CXX98-NOT: mustprogress +// CXX11: mustprogress +// FINITE-NOT: mustprogress // CHECK-LABEL: @_Z2d2v( // CHECK-NEXT: entry: // CHECK-NEXT: br label %do.body @@ -250,8 +266,8 @@ // CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @b, align 4 // CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]] // CXX98-NOT: br {{.*}}, !llvm.loop -// CXX11-NEXT: br i1 [[CMP]], label %do.body, label %do.end, !llvm.loop [[LOOP6:!.*]] -// FINITE-NEXT: br i1 [[CMP]], label %do.body, label %do.end, !llvm.loop [[LOOP6:!.*]] +// CXX11-NEXT: br i1 [[CMP]], label %do.body, label %do.end, !llvm.loop [[LOOP14:!.*]] +// FINITE-NEXT: br i1 [[CMP]], label %do.body, label %do.end, !llvm.loop [[LOOP14:!.*]] // CHECK: do.end: // CHECK-NEXT: ret void // @@ -261,16 +277,18 @@ while (a == b); } -// CXX98-NOT: mustprogress -// CXX11-NOT: mustprogress -// FINITE-NOT: mustprogress +// CXX98-NOT: mustprogress +// CXX11: mustprogress +// FINITE-NOT: mustprogress // CHECK-LABEL: @_Z1Dv( // CHECK-NEXT: entry: // CHECK-NEXT: br label %do.body // CHECK: do.body: // CHECK-NEXT: br label %do.cond // CHECK: do.cond: -// CHECK-NOT: br {{.*}}, !llvm.loop +// CXX98-NOT: br {{.*}}, !llvm.loop +// CXX11-NEXT: br i1 true, label %do.body, label %do.end, !llvm.loop [[LOOP15:!.*]] +// FINITE-NEXT: br i1 true, label %do.body, label %do.end, !llvm.loop [[LOOP15:!.*]] // CHECK: do.end: // CHECK-NEXT: br label %do.body1 // CHECK: do.body1: @@ -280,8 +298,8 @@ // CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @b, align 4 // CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]] // CXX98-NOT: br {{.*}}, !llvm.loop -// CXX11-NEXT: br i1 [[CMP]], label %do.body1, label %do.end3, !llvm.loop [[LOOP7:!.*]] -// FINITE-NEXT: br i1 [[CMP]], label %do.body1, label %do.end3, !llvm.loop [[LOOP7:!.*]] +// CXX11-NEXT: br i1 [[CMP]], label %do.body1, label %do.end3, !llvm.loop [[LOOP16:!.*]] +// FINITE-NEXT: br i1 [[CMP]], label %do.body1, label %do.end3, !llvm.loop [[LOOP16:!.*]] // CHECK: do.end3: // CHECK-NEXT: ret void // @@ -294,9 +312,9 @@ while (a == b); } -// CXX98-NOT: mustprogress -// CXX11-NOT: mustprogress -// FINITE-NOT: mustprogress +// CXX98-NOT : mustprogress +// CXX11: mustprogress +// FINITE-NOT: mustprogress // CHECK-LABEL: @_Z2D2v( // CHECK-NEXT: entry: // CHECK-NEXT: br label %do.body @@ -307,14 +325,16 @@ // CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @b, align 4 // CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]] // CXX98-NOT: br {{.*}}, !llvm.loop -// CXX11-NEXT: br i1 [[CMP]], label %do.body, label %do.end, !llvm.loop [[LOOP8:!.*]] -// FINITE-NEXT: br i1 [[CMP]], label %do.body, label %do.end, !llvm.loop [[LOOP8:!.*]] +// CXX11-NEXT: br i1 [[CMP]], label %do.body, label %do.end, !llvm.loop [[LOOP17:!.*]] +// FINITE-NEXT: br i1 [[CMP]], label %do.body, label %do.end, !llvm.loop [[LOOP17:!.*]] // CHECK: do.end: // CHECK-NEXT: br label %do.body1 // CHECK: do.body1: // CHECK-NEXT: br label %do.cond2 // CHECK: do.cond2: -// CHECK-NOT: br {{.*}}, !llvm.loop +// CXX98-NOT: br {{.*}}, !llvm.loop +// CXX11-NEXT: br i1 true, label %do.body1, label %do.end3, !llvm.loop [[LOOP18:!.*]] +// FINITE-NEXT: br i1 true, label %do.body1, label %do.end3, !llvm.loop [[LOOP18:!.*]] // CHECK: do.end3: // CHECK-NEXT: ret void // @@ -336,3 +356,13 @@ // CXX11: [[LOOP6]] = distinct !{[[LOOP6]], [[MP]]} // CXX11: [[LOOP7]] = distinct !{[[LOOP7]], [[MP]]} // CXX11: [[LOOP8]] = distinct !{[[LOOP8]], [[MP]]} +// CXX11: [[LOOP9]] = distinct !{[[LOOP9]], [[MP]]} +// CXX11: [[LOOP10]] = distinct !{[[LOOP10]], [[MP]]} +// CXX11: [[LOOP11]] = distinct !{[[LOOP11]], [[MP]]} +// CXX11: [[LOOP12]] = distinct !{[[LOOP12]], [[MP]]} +// CXX11: [[LOOP13]] = distinct !{[[LOOP13]], [[MP]]} +// CXX11: [[LOOP14]] = distinct !{[[LOOP14]], [[MP]]} +// CXX11: [[LOOP15]] = distinct !{[[LOOP15]], [[MP]]} +// CXX11: [[LOOP16]] = distinct !{[[LOOP16]], [[MP]]} +// CXX11: [[LOOP17]] = distinct !{[[LOOP17]], [[MP]]} +// CXX11: [[LOOP18]] = distinct !{[[LOOP18]], [[MP]]}