diff --git a/clang/lib/CodeGen/CGLoopInfo.h b/clang/lib/CodeGen/CGLoopInfo.h --- a/clang/lib/CodeGen/CGLoopInfo.h +++ b/clang/lib/CodeGen/CGLoopInfo.h @@ -75,6 +75,9 @@ /// Value for llvm.loop.pipeline.iicount metadata. unsigned PipelineInitiationInterval; + + /// Value for whether the loop is required to make progress. + bool MustProgress; }; /// Information used when generating a structured loop. @@ -205,7 +208,7 @@ void push(llvm::BasicBlock *Header, clang::ASTContext &Ctx, const clang::CodeGenOptions &CGOpts, llvm::ArrayRef Attrs, const llvm::DebugLoc &StartLoc, - const llvm::DebugLoc &EndLoc); + const llvm::DebugLoc &EndLoc, bool MustProgress = false); /// End the current loop. void pop(); @@ -272,6 +275,9 @@ StagedAttrs.PipelineInitiationInterval = C; } + /// Set no progress for the next loop pushed. + void setMustProgress(bool P) { StagedAttrs.MustProgress = P; } + private: /// Returns true if there is LoopInfo on the stack. bool hasInfo() const { return !Active.empty(); } diff --git a/clang/lib/CodeGen/CGLoopInfo.cpp b/clang/lib/CodeGen/CGLoopInfo.cpp --- a/clang/lib/CodeGen/CGLoopInfo.cpp +++ b/clang/lib/CodeGen/CGLoopInfo.cpp @@ -418,10 +418,14 @@ LoopProperties.push_back(EndLoc.getAsMDNode()); } + LLVMContext &Ctx = Header->getContext(); + if (Attrs.MustProgress) + LoopProperties.push_back( + MDNode::get(Ctx, MDString::get(Ctx, "llvm.loop.mustprogress"))); + assert(!!AccGroup == Attrs.IsParallel && "There must be an access group iff the loop is parallel"); if (Attrs.IsParallel) { - LLVMContext &Ctx = Header->getContext(); LoopProperties.push_back(MDNode::get( Ctx, {MDString::get(Ctx, "llvm.loop.parallel_accesses"), AccGroup})); } @@ -438,7 +442,7 @@ VectorizePredicateEnable(LoopAttributes::Unspecified), VectorizeWidth(0), InterleaveCount(0), UnrollCount(0), UnrollAndJamCount(0), DistributeEnable(LoopAttributes::Unspecified), PipelineDisabled(false), - PipelineInitiationInterval(0) {} + PipelineInitiationInterval(0), MustProgress(false) {} void LoopAttributes::clear() { IsParallel = false; @@ -453,6 +457,7 @@ DistributeEnable = LoopAttributes::Unspecified; PipelineDisabled = false; PipelineInitiationInterval = 0; + MustProgress = false; } LoopInfo::LoopInfo(BasicBlock *Header, const LoopAttributes &Attrs, @@ -476,7 +481,7 @@ Attrs.UnrollEnable == LoopAttributes::Unspecified && Attrs.UnrollAndJamEnable == LoopAttributes::Unspecified && Attrs.DistributeEnable == LoopAttributes::Unspecified && !StartLoc && - !EndLoc) + !EndLoc && !Attrs.MustProgress) return; TempLoopID = MDNode::getTemporary(Header->getContext(), None); @@ -577,8 +582,7 @@ const clang::CodeGenOptions &CGOpts, ArrayRef Attrs, const llvm::DebugLoc &StartLoc, - const llvm::DebugLoc &EndLoc) { - + const llvm::DebugLoc &EndLoc, bool MustProgress) { // Identify loop hint attributes from Attrs. for (const auto *Attr : Attrs) { const LoopHintAttr *LH = dyn_cast(Attr); @@ -755,6 +759,8 @@ } } + setMustProgress(MustProgress); + if (CGOpts.OptimizationLevel > 0) // Disable unrolling for the loop, if unrolling is disabled (via // -fno-unroll-loops) and no pragmas override the decision. 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 @@ -22,6 +22,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/IR/Attributes.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Intrinsics.h" @@ -736,11 +737,6 @@ JumpDest LoopHeader = getJumpDestInCurrentScope("while.cond"); EmitBlock(LoopHeader.getBlock()); - const SourceRange &R = S.getSourceRange(); - LoopStack.push(LoopHeader.getBlock(), CGM.getContext(), CGM.getCodeGenOpts(), - WhileAttrs, SourceLocToDebugLoc(R.getBegin()), - SourceLocToDebugLoc(R.getEnd())); - // Create an exit block for when the condition fails, which will // also become the break target. JumpDest LoopExit = getJumpDestInCurrentScope("while.end"); @@ -768,9 +764,17 @@ // while(1) is common, avoid extra exit blocks. Be sure // to correctly handle break/continue though. bool EmitBoolCondBranch = true; - if (llvm::ConstantInt *C = dyn_cast(BoolCondVal)) + bool MustProgress = false; + if (llvm::ConstantInt *C = dyn_cast(BoolCondVal)) { if (C->isOne()) EmitBoolCondBranch = false; + } else if (CurFn->hasFnAttribute(llvm::Attribute::MayNotProgress)) + MustProgress = true; + + const SourceRange &R = S.getSourceRange(); + LoopStack.push(LoopHeader.getBlock(), CGM.getContext(), CGM.getCodeGenOpts(), + WhileAttrs, SourceLocToDebugLoc(R.getBegin()), + SourceLocToDebugLoc(R.getEnd()), MustProgress); // As long as the condition is true, go to the loop body. llvm::BasicBlock *LoopBody = createBasicBlock("while.body"); @@ -838,11 +842,6 @@ EmitBlock(LoopCond.getBlock()); - const SourceRange &R = S.getSourceRange(); - LoopStack.push(LoopBody, CGM.getContext(), CGM.getCodeGenOpts(), DoAttrs, - SourceLocToDebugLoc(R.getBegin()), - SourceLocToDebugLoc(R.getEnd())); - // C99 6.8.5.2: "The evaluation of the controlling expression takes place // after each execution of the loop body." @@ -856,9 +855,17 @@ // "do {} while (0)" is common in macros, avoid extra blocks. Be sure // to correctly handle break/continue though. bool EmitBoolCondBranch = true; - if (llvm::ConstantInt *C = dyn_cast(BoolCondVal)) + bool MustProgress = false; + if (llvm::ConstantInt *C = dyn_cast(BoolCondVal)) { if (C->isZero()) EmitBoolCondBranch = false; + } else if (CurFn->hasFnAttribute(llvm::Attribute::MayNotProgress)) + MustProgress = true; + + const SourceRange &R = S.getSourceRange(); + LoopStack.push(LoopBody, CGM.getContext(), CGM.getCodeGenOpts(), DoAttrs, + SourceLocToDebugLoc(R.getBegin()), + SourceLocToDebugLoc(R.getEnd()), MustProgress); // As long as the condition is true, iterate the loop. if (EmitBoolCondBranch) { @@ -896,10 +903,16 @@ llvm::BasicBlock *CondBlock = Continue.getBlock(); EmitBlock(CondBlock); + bool MustProgress = false; + Expr::EvalResult Result; + if (CurFn->hasFnAttribute(llvm::Attribute::MayNotProgress) && + (!S.getCond() || !S.getCond()->EvaluateAsInt(Result, getContext()))) + MustProgress = true; + const SourceRange &R = S.getSourceRange(); LoopStack.push(CondBlock, CGM.getContext(), CGM.getCodeGenOpts(), ForAttrs, SourceLocToDebugLoc(R.getBegin()), - SourceLocToDebugLoc(R.getEnd())); + SourceLocToDebugLoc(R.getEnd()), MustProgress); // If the for loop doesn't have an increment we can just use the // condition as the continue block. Otherwise we'll need to create 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 @@ -1143,6 +1143,11 @@ void CodeGenFunction::EmitFunctionBody(const Stmt *Body) { incrementProfileCounter(Body); + + if (!CurFn->hasFnAttribute(llvm::Attribute::MayNotProgress) && + (getLangOpts().C11 || getLangOpts().C17 || getLangOpts().C2x)) + CurFn->addFnAttr(llvm::Attribute::MayNotProgress); + if (const CompoundStmt *S = dyn_cast(Body)) EmitCompoundStmtWithoutScope(*S); else diff --git a/clang/test/CodeGen/attr-noprogress.c b/clang/test/CodeGen/attr-noprogress.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/attr-noprogress.c @@ -0,0 +1,191 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes +// RUN: %clang -std=c11 -S -emit-llvm %s -o - | FileCheck %s + +int a = 0; +int b = 0; + +// CHECK: Function Attrs: noinline nounwind optnone uwtable maynotprogress +// CHECK-LABEL: @f1( +// CHECK-NEXT: entry: +// CHECK-NEXT: br label [[FOR_COND:%.*]] +// CHECK: for.cond: +// CHECK-NEXT: br i1 true, label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] +// CHECK: for.body: +// CHECK-NEXT: br label [[FOR_COND]] +// CHECK: for.end: +// CHECK-NEXT: ret void +// +void f1() { + for (; 1;) { + } +} + +// CHECK: Function Attrs: noinline nounwind optnone uwtable maynotprogress +// CHECK-LABEL: @f2( +// CHECK-NEXT: entry: +// CHECK-NEXT: br label [[FOR_COND:%.*]] +// CHECK: for.cond: +// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* @a, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @b, align 4 +// CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]] +// CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] +// CHECK: for.body: +// CHECK-NEXT: br label [[FOR_COND]], !llvm.loop [[LOOP2:!.*]] +// CHECK: for.end: +// CHECK-NEXT: ret void +// +void f2() { + for (; a == b;) { + } +} + +// CHECK: Function Attrs: noinline nounwind optnone uwtable maynotprogress +// CHECK-LABEL: @F( +// CHECK-NEXT: entry: +// CHECK-NEXT: br label [[FOR_COND:%.*]] +// CHECK: for.cond: +// CHECK-NEXT: br i1 true, label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] +// CHECK: for.body: +// CHECK-NEXT: br label [[FOR_COND]] +// CHECK: for.end: +// CHECK-NEXT: br label [[FOR_COND1:%.*]] +// CHECK: for.cond1: +// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* @a, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @b, align 4 +// CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]] +// CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY2:%.*]], label [[FOR_END3:%.*]] +// CHECK: for.body2: +// CHECK-NEXT: br label [[FOR_COND1]], !llvm.loop [[LOOP4:!.*]] +// CHECK: for.end3: +// CHECK-NEXT: ret void +// +void F() { + for (; 1;) { + } + for (; a == b;) { + } +} + +// CHECK: Function Attrs: noinline nounwind optnone uwtable maynotprogress +// CHECK-LABEL: @w1( +// CHECK-NEXT: entry: +// CHECK-NEXT: br label [[WHILE_BODY:%.*]] +// CHECK: while.body: +// CHECK-NEXT: br label [[WHILE_BODY]] +// +void w1() { + while (1) { + } +} + +// CHECK: Function Attrs: noinline nounwind optnone uwtable maynotprogress +// CHECK-LABEL: @w2( +// CHECK-NEXT: entry: +// CHECK-NEXT: br label [[WHILE_COND:%.*]] +// CHECK: while.cond: +// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* @a, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @b, align 4 +// CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]] +// CHECK-NEXT: br i1 [[CMP]], label [[WHILE_BODY:%.*]], label [[WHILE_END:%.*]] +// CHECK: while.body: +// CHECK-NEXT: br label [[WHILE_COND]], !llvm.loop [[LOOP5:!.*]] +// CHECK: while.end: +// CHECK-NEXT: ret void +// +void w2() { + while (a == b) { + } +} + +// CHECK: Function Attrs: noinline nounwind optnone uwtable maynotprogress +// CHECK-LABEL: @W( +// CHECK-NEXT: entry: +// CHECK-NEXT: br label [[WHILE_COND:%.*]] +// CHECK: while.cond: +// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* @a, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @b, align 4 +// CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]] +// CHECK-NEXT: br i1 [[CMP]], label [[WHILE_BODY:%.*]], label [[WHILE_END:%.*]] +// CHECK: while.body: +// CHECK-NEXT: br label [[WHILE_COND]], !llvm.loop [[LOOP6:!.*]] +// CHECK: while.end: +// CHECK-NEXT: br label [[WHILE_BODY2:%.*]] +// CHECK: while.body2: +// CHECK-NEXT: br label [[WHILE_BODY2]] +// +void W() { + while (a == b) { + } + while (1) { + } +} + +// CHECK: Function Attrs: noinline nounwind optnone uwtable maynotprogress +// CHECK-LABEL: @d1( +// CHECK-NEXT: entry: +// CHECK-NEXT: br label [[DO_BODY:%.*]] +// CHECK: do.body: +// CHECK-NEXT: br label [[DO_COND:%.*]] +// CHECK: do.cond: +// CHECK-NEXT: br i1 true, label [[DO_BODY]], label [[DO_END:%.*]] +// CHECK: do.end: +// CHECK-NEXT: ret void +// +void d1() { + do { + } while (1); +} + +// CHECK: Function Attrs: noinline nounwind optnone uwtable maynotprogress +// CHECK-LABEL: @d2( +// CHECK-NEXT: entry: +// CHECK-NEXT: br label [[DO_BODY:%.*]] +// CHECK: do.body: +// CHECK-NEXT: br label [[DO_COND:%.*]] +// CHECK: do.cond: +// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* @a, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @b, align 4 +// CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]] +// CHECK-NEXT: br i1 [[CMP]], label [[DO_BODY]], label [[DO_END:%.*]], !llvm.loop [[LOOP7:!.*]] +// CHECK: do.end: +// CHECK-NEXT: ret void +// +void d2() { + do { + } while (a == b); +} + +// CHECK: Function Attrs: noinline nounwind optnone uwtable maynotprogress +// CHECK-LABEL: @D( +// CHECK-NEXT: entry: +// CHECK-NEXT: br label [[DO_BODY:%.*]] +// CHECK: do.body: +// CHECK-NEXT: br label [[DO_COND:%.*]] +// CHECK: do.cond: +// CHECK-NEXT: br i1 true, label [[DO_BODY]], label [[DO_END:%.*]] +// CHECK: do.end: +// CHECK-NEXT: br label [[DO_BODY1:%.*]] +// CHECK: do.body1: +// CHECK-NEXT: br label [[DO_COND2:%.*]] +// CHECK: do.cond2: +// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* @a, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @b, align 4 +// CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]] +// CHECK-NEXT: br i1 [[CMP]], label [[DO_BODY1]], label [[DO_END3:%.*]], !llvm.loop [[LOOP8:!.*]] +// CHECK: do.end3: +// CHECK-NEXT: ret void +// +void D() { + do { + } while (1); + do { + } while (a == b); +} + +// CHECK: [[LOOP2]] = distinct !{[[LOOP2]], [[GEN3:!.*]]} +// CHECK: [[GEN3]] = !{!"llvm.loop.mustprogress"} +// CHECK: [[LOOP4]] = distinct !{[[LOOP4]], [[GEN3]]} +// CHECK: [[LOOP5]] = distinct !{[[LOOP5]], [[GEN3]]} +// CHECK: [[LOOP6]] = distinct !{[[LOOP6]], [[GEN3]]} +// CHECK: [[LOOP7]] = distinct !{[[LOOP7]], [[GEN3]]} +// CHECK: [[LOOP8]] = distinct !{[[LOOP8]], [[GEN3]]} diff --git a/clang/test/CodeGen/attr-noprogress.cpp b/clang/test/CodeGen/attr-noprogress.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/attr-noprogress.cpp @@ -0,0 +1,183 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes +// RUN: %clang_cc1 -S -emit-llvm %s -o - | FileCheck %s + +int a = 0; +int b = 0; + +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @_Z2f1v( +// CHECK-NEXT: entry: +// CHECK-NEXT: br label [[FOR_COND:%.*]] +// CHECK: for.cond: +// CHECK: br i1 true, label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] +// CHECK: for.body: +// CHECK: br label [[FOR_COND]] +// CHECK: for.end: +// CHECK: ret void +// +void f1() { + for (; 1;) { + } +} + +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @_Z2f2v( +// CHECK-NEXT: entry: +// CHECK-NEXT: br label [[FOR_COND:%.*]] +// CHECK: for.cond: +// CHECK: [[TMP0:%.*]] = load i32, i32* @a, align 4 +// CHECK: [[TMP1:%.*]] = load i32, i32* @b, align 4 +// CHECK: [[CMP:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]] +// CHECK: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] +// CHECK: for.body: +// CHECK: br label [[FOR_COND]] +// CHECK: for.end: +// CHECK: ret void +// +void f2() { + for (; a == b;) { + } +} + +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @_Z1Fv( +// CHECK-NEXT: entry: +// CHECK-NEXT: br label [[FOR_COND:%.*]] +// CHECK: for.cond: +// CHECK: br i1 true, label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] +// CHECK: for.body: +// CHECK: br label [[FOR_COND]] +// CHECK: for.end: +// CHECK: br label [[FOR_COND1:%.*]] +// CHECK: for.cond1: +// CHECK: [[TMP0:%.*]] = load i32, i32* @a, align 4 +// CHECK: [[TMP1:%.*]] = load i32, i32* @b, align 4 +// CHECK: [[CMP:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]] +// CHECK: br i1 [[CMP]], label [[FOR_BODY2:%.*]], label [[FOR_END3:%.*]] +// CHECK: for.body2: +// CHECK: br label [[FOR_COND1]] +// CHECK: for.end3: +// CHECK: ret void +// +void F() { + for (; 1;) { + } + for (; a == b;) { + } +} + +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @_Z2w1v( +// CHECK-NEXT: entry: +// CHECK-NEXT: br label [[WHILE_BODY:%.*]] +// CHECK: while.body: +// CHECK: br label [[WHILE_BODY]] +// +void w1() { + while (1) { + } +} + +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @_Z2w2v( +// CHECK-NEXT: entry: +// CHECK-NEXT: br label [[WHILE_COND:%.*]] +// CHECK: while.cond: +// CHECK: [[TMP0:%.*]] = load i32, i32* @a, align 4 +// CHECK: [[TMP1:%.*]] = load i32, i32* @b, align 4 +// CHECK: [[CMP:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]] +// CHECK: br i1 [[CMP]], label [[WHILE_BODY:%.*]], label [[WHILE_END:%.*]] +// CHECK: while.body: +// CHECK: br label [[WHILE_COND]] +// CHECK: while.end: +// CHECK: ret void +// +void w2() { + while (a == b) { + } +} + +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @_Z1Wv( +// CHECK-NEXT: entry: +// CHECK-NEXT: br label [[WHILE_COND:%.*]] +// CHECK: while.cond: +// CHECK: [[TMP0:%.*]] = load i32, i32* @a, align 4 +// CHECK: [[TMP1:%.*]] = load i32, i32* @b, align 4 +// CHECK: [[CMP:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]] +// CHECK: br i1 [[CMP]], label [[WHILE_BODY:%.*]], label [[WHILE_END:%.*]] +// CHECK: while.body: +// CHECK: br label [[WHILE_COND]] +// CHECK: while.end: +// CHECK: br label [[WHILE_BODY2:%.*]] +// CHECK: while.body2: +// CHECK: br label [[WHILE_BODY2]] +// +void W() { + while (a == b) { + } + while (1) { + } +} + +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @_Z2d1v( +// CHECK-NEXT: entry: +// CHECK-NEXT: br label [[DO_BODY:%.*]] +// CHECK: do.body: +// CHECK: br label [[DO_COND:%.*]] +// CHECK: do.cond: +// CHECK: br i1 true, label [[DO_BODY]], label [[DO_END:%.*]] +// CHECK: do.end: +// CHECK: ret void +// +void d1() { + do { + } while (1); +} + +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @_Z2d2v( +// CHECK-NEXT: entry: +// CHECK-NEXT: br label [[DO_BODY:%.*]] +// CHECK: do.body: +// CHECK: br label [[DO_COND:%.*]] +// CHECK: do.cond: +// CHECK: [[TMP0:%.*]] = load i32, i32* @a, align 4 +// CHECK: [[TMP1:%.*]] = load i32, i32* @b, align 4 +// CHECK: [[CMP:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]] +// CHECK: br i1 [[CMP]], label [[DO_BODY]], label [[DO_END:%.*]] +// CHECK: do.end: +// CHECK: ret void +// +void d2() { + do { + } while (a == b); +} + +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @_Z1Dv( +// CHECK-NEXT: entry: +// CHECK-NEXT: br label [[DO_BODY:%.*]] +// CHECK: do.body: +// CHECK: br label [[DO_COND:%.*]] +// CHECK: do.cond: +// CHECK: br i1 true, label [[DO_BODY]], label [[DO_END:%.*]] +// CHECK: do.end: +// CHECK: br label [[DO_BODY1:%.*]] +// CHECK: do.body1: +// CHECK: br label [[DO_COND2:%.*]] +// CHECK: do.cond2: +// CHECK: [[TMP0:%.*]] = load i32, i32* @a, align 4 +// CHECK: [[TMP1:%.*]] = load i32, i32* @b, align 4 +// CHECK: [[CMP:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]] +// CHECK: br i1 [[CMP]], label [[DO_BODY1]], label [[DO_END3:%.*]] +// CHECK: do.end3: +// CHECK: ret void +// +void D() { + do { + } while (1); + do { + } while (a == b); +} diff --git a/clang/test/CodeGen/unwind-attr.c b/clang/test/CodeGen/unwind-attr.c --- a/clang/test/CodeGen/unwind-attr.c +++ b/clang/test/CodeGen/unwind-attr.c @@ -23,7 +23,7 @@ return 0; } -// CHECK: attributes [[TF]] = { noinline optnone "{{.*}} } +// CHECK: attributes [[TF]] = { noinline optnone maynotprogress "{{.*}} } // CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} } // CHECK-NOEXC: attributes [[NUW]] = { noinline nounwind{{.*}} } diff --git a/clang/test/CodeGenCXX/fno-unroll-loops-metadata.cpp b/clang/test/CodeGenCXX/fno-unroll-loops-metadata.cpp --- a/clang/test/CodeGenCXX/fno-unroll-loops-metadata.cpp +++ b/clang/test/CodeGenCXX/fno-unroll-loops-metadata.cpp @@ -4,7 +4,7 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -emit-llvm -o - %s -O3 -disable-llvm-optzns -fno-unroll-loops | FileCheck --check-prefix=UNROLL_DISABLED_MD %s // RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -emit-llvm -o - %s -O3 -disable-llvm-optzns | FileCheck --check-prefix=NO_UNROLL_MD %s -// NO_UNROLL_MD-NOT: llvm.loop +// NO_UNROLL_MD-NOT: llvm.loop.unroll.disable // Verify unroll.disable metadata is added to while loop with -fno-unroll-loops // and optlevel > 0. diff --git a/clang/test/CodeGenObjC/class-stubs.m b/clang/test/CodeGenObjC/class-stubs.m --- a/clang/test/CodeGenObjC/class-stubs.m +++ b/clang/test/CodeGenObjC/class-stubs.m @@ -55,7 +55,7 @@ + (void) anotherClassMethod { [super classMethod]; } -// CHECK-LABEL: define internal void @"\01+[Derived(MyCategory) anotherClassMethod]"(i8* %self, i8* %_cmd) #0 { +// CHECK-LABEL: define internal void @"\01+[Derived(MyCategory) anotherClassMethod]"(i8* %self, i8* %_cmd) #3 { // CHECK-NEXT: entry: // CHECK: [[SUPER:%.*]] = alloca %struct._objc_super, align 8 // CHECK: [[METACLASS_REF:%.*]] = load %struct._class_t*, %struct._class_t** @"OBJC_CLASSLIST_SUP_REFS_$_", align 8 @@ -68,7 +68,7 @@ - (void) anotherInstanceMethod { [super instanceMethod]; } -// CHECK-LABEL: define internal void @"\01-[Derived(MyCategory) anotherInstanceMethod]"(%0* %self, i8* %_cmd) #0 { +// CHECK-LABEL: define internal void @"\01-[Derived(MyCategory) anotherInstanceMethod]"(%0* %self, i8* %_cmd) #3 { // CHECK-NEXT: entry: // CHECK: [[SUPER:%.*]] = alloca %struct._objc_super, align 8 // CHECK: [[CLASS_REF:%.*]] = call %struct._class_t* @objc_loadClassref(i8** @"OBJC_CLASSLIST_SUP_REFS_$_.1") diff --git a/clang/test/CodeGenObjC/gnu-exceptions.m b/clang/test/CodeGenObjC/gnu-exceptions.m --- a/clang/test/CodeGenObjC/gnu-exceptions.m +++ b/clang/test/CodeGenObjC/gnu-exceptions.m @@ -32,4 +32,4 @@ log(1); } -// CHECK: attributes [[TF]] = { noinline optnone "{{.*}} } +// CHECK: attributes [[TF]] = { noinline optnone maynotprogress "{{.*}} } diff --git a/clang/test/OpenMP/simd_metadata.c b/clang/test/OpenMP/simd_metadata.c --- a/clang/test/OpenMP/simd_metadata.c +++ b/clang/test/OpenMP/simd_metadata.c @@ -137,7 +137,8 @@ } // CHECK: store float {{.+}}, float* {{.+}}, align {{.+}}, !llvm.access.group ![[ACCESS_GROUP_13:[0-9]+]] } -// CHECK: br label %{{.+}}, !llvm.loop [[LOOP_H3_HEADER:![0-9]+]] + // CHECK: br label %{{.+}}, !llvm.loop [[LOOP_H3_HEADER_INNER:![0-9]+]] + // CHECK: br label %{{.+}}, !llvm.loop [[LOOP_H3_HEADER:![0-9]+]] } // Metadata for h1: diff --git a/clang/test/Profile/c-unprofiled-blocks.c b/clang/test/Profile/c-unprofiled-blocks.c --- a/clang/test/Profile/c-unprofiled-blocks.c +++ b/clang/test/Profile/c-unprofiled-blocks.c @@ -16,7 +16,7 @@ // PGOUSE: br i1 %{{[^,]*}}, label %{{[^,]*}}, label %{{[^,]*}}{{$}} while (--i) {} - // PGOUSE: br i1 %{{[^,]*}}, label %{{[^,]*}}, label %{{[^,]*}}{{$}} + // PGOUSE: br i1 %{{[^,]*}}, label %{{[^,]*}}, label %{{[^,]*}}, !llvm.loop [[LOOP1:!.*]] do {} while (i++ < 75); // PGOUSE: switch {{.*}} [ @@ -46,7 +46,7 @@ // PGOUSE: br i1 %{{[^,]*}}, label %{{[^,]*}}, label %{{[^,]*}}{{$}} while (--i) {} - // PGOUSE: br i1 %{{[^,]*}}, label %{{[^,]*}}, label %{{[^,]*}}{{$}} + // PGOUSE: br i1 %{{[^,]*}}, label %{{[^,]*}}, label %{{[^,]*}}, !llvm.loop [[LOOP2:!.*]] do {} while (i++ < 75); // PGOUSE: switch {{.*}} [