atmnpatel updated this revision to Diff 289849.
atmnpatel added a comment.

In Summary:

- I changed the llvm loop metadata name to `mustprogress`, to indicate that 
loops with this attribute are required to have side-effects.
- The `mayprogress` function attribute is applied to functions where an 
infinite loop is found with a constant conditional.
- The `mustprogress` attribute is applied to loops within a `mayprogress` 
function that do not have a constant conditional.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86841/new/

https://reviews.llvm.org/D86841

Files:
  clang/lib/CodeGen/CGLoopInfo.cpp
  clang/lib/CodeGen/CGLoopInfo.h
  clang/lib/CodeGen/CGStmt.cpp
  clang/lib/CodeGen/CodeGenFunction.cpp
  clang/lib/CodeGen/CodeGenFunction.h
  clang/test/CodeGen/attr-noprogress.c
  clang/test/CodeGen/attr-noprogress.cpp
  clang/test/CodeGenCXX/fno-unroll-loops-metadata.cpp

Index: clang/test/CodeGenCXX/fno-unroll-loops-metadata.cpp
===================================================================
--- clang/test/CodeGenCXX/fno-unroll-loops-metadata.cpp
+++ 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.
Index: clang/test/CodeGen/attr-noprogress.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/attr-noprogress.cpp
@@ -0,0 +1,188 @@
+// 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 mayprogress
+// 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 mayprogress
+// 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]], !llvm.loop [[LOOP2:!.*]]
+// CHECK:       for.end3:
+// CHECK:         ret void
+//
+void F() {
+  for (; 1;) {
+  }
+  for (; a == b;) {
+  }
+}
+
+// CHECK: Function Attrs: noinline nounwind optnone mayprogress
+// 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 mayprogress
+// 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]], !llvm.loop [[LOOP4:!.*]]
+// 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 mayprogress
+// 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 mayprogress
+// 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:%.*]], !llvm.loop [[LOOP5:!.*]]
+// CHECK:       do.end3:
+// CHECK:         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]]}
Index: clang/test/CodeGen/attr-noprogress.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/attr-noprogress.c
@@ -0,0 +1,188 @@
+// 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 mayprogress
+// CHECK-LABEL: @f1(
+// 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: @f2(
+// 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 mayprogress
+// CHECK-LABEL: @F(
+// 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]], !llvm.loop [[LOOP2:!.*]]
+// CHECK:       for.end3:
+// CHECK:         ret void
+//
+void F() {
+  for (; 1;) {
+  }
+  for (; a == b;) {
+  }
+}
+
+// CHECK: Function Attrs: noinline nounwind optnone mayprogress
+// CHECK-LABEL: @w1(
+// 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: @w2(
+// 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 mayprogress
+// CHECK-LABEL: @W(
+// 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]], !llvm.loop [[LOOP4:!.*]]
+// 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 mayprogress
+// CHECK-LABEL: @d1(
+// 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: @d2(
+// 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 mayprogress
+// CHECK-LABEL: @D(
+// 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:%.*]], !llvm.loop [[LOOP5:!.*]]
+// CHECK:       do.end3:
+// CHECK:         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]]}
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -2071,6 +2071,9 @@
 
   static bool IsConstructorDelegationValid(const CXXConstructorDecl *Ctor);
 
+  void StmtIsMayProgressLoop(const Stmt *S);
+  void CompoundStmtContainsMayProgressLoop(const Stmt *S);
+
   void EmitConstructorBody(FunctionArgList &Args);
   void EmitDestructorBody(FunctionArgList &Args);
   void emitImplicitAssignmentOperatorBody(FunctionArgList &Args);
Index: clang/lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.cpp
+++ clang/lib/CodeGen/CodeGenFunction.cpp
@@ -1141,8 +1141,60 @@
       LargestVectorWidth = VecWidth->getVectorWidth();
 }
 
+void CodeGenFunction::StmtIsMayProgressLoop(const Stmt *S) {
+  Expr::EvalResult Result;
+  llvm::ConstantInt *C = nullptr;
+  switch (S->getStmtClass()) {
+  case Stmt::WhileStmtClass: {
+    const WhileStmt &W = cast<WhileStmt>(*S);
+    if (W.getCond()->isEvaluatable(getContext()) &&
+        W.getCond()->EvaluateAsInt(Result, getContext()))
+      C = llvm::ConstantInt::get(getLLVMContext(), Result.Val.getInt());
+    break;
+  }
+  case Stmt::DoStmtClass: {
+    const DoStmt &D = cast<DoStmt>(*S);
+    if (D.getCond()->isEvaluatable(getContext()) &&
+        D.getCond()->EvaluateAsInt(Result, getContext()))
+      C = llvm::ConstantInt::get(getLLVMContext(), Result.Val.getInt());
+    break;
+  }
+  case Stmt::ForStmtClass: {
+    const ForStmt &F = cast<ForStmt>(*S);
+    if (!F.getCond()) {
+      CurFn->addFnAttr(llvm::Attribute::MayProgress);
+      return;
+    } else {
+      if (F.getCond()->isEvaluatable(getContext()) &&
+          F.getCond()->EvaluateAsInt(Result, getContext()))
+        C = llvm::ConstantInt::get(getLLVMContext(), Result.Val.getInt());
+      break;
+    }
+    return;
+  }
+  default:
+    break;
+  }
+
+  if (C && C->isOne() && !CurFn->hasFnAttribute(llvm::Attribute::MayProgress)) {
+    CurFn->addFnAttr(llvm::Attribute::MayProgress);
+    return;
+  }
+}
+
+void CodeGenFunction::CompoundStmtContainsMayProgressLoop(const Stmt *Body) {
+  if (const CompoundStmt *C = dyn_cast<CompoundStmt>(Body)) {
+    for (auto *S : C->body()) {
+      CompoundStmtContainsMayProgressLoop(S);
+    }
+  } else {
+    StmtIsMayProgressLoop(Body);
+  }
+}
+
 void CodeGenFunction::EmitFunctionBody(const Stmt *Body) {
   incrementProfileCounter(Body);
+  CompoundStmtContainsMayProgressLoop(Body);
   if (const CompoundStmt *S = dyn_cast<CompoundStmt>(Body))
     EmitCompoundStmtWithoutScope(*S);
   else
Index: clang/lib/CodeGen/CGStmt.cpp
===================================================================
--- clang/lib/CodeGen/CGStmt.cpp
+++ 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<llvm::ConstantInt>(BoolCondVal))
+  bool MustProgress = false;
+  if (llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal)) {
     if (C->isOne())
       EmitBoolCondBranch = false;
+  } else if (CurFn->hasFnAttribute(llvm::Attribute::MayProgress))
+    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<llvm::ConstantInt>(BoolCondVal))
+  bool MustProgress = false;
+  if (llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal)) {
     if (C->isZero())
       EmitBoolCondBranch = false;
+  } else if (CurFn->hasFnAttribute(llvm::Attribute::MayProgress))
+    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,19 @@
   llvm::BasicBlock *CondBlock = Continue.getBlock();
   EmitBlock(CondBlock);
 
+  bool MustProgress = false;
+  if (S.getCond()) {
+    Expr::EvalResult Result;
+    if (!S.getCond()->EvaluateAsInt(Result, getContext()) &&
+        CurFn->hasFnAttribute(llvm::Attribute::MayProgress)) {
+      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
Index: clang/lib/CodeGen/CGLoopInfo.h
===================================================================
--- clang/lib/CodeGen/CGLoopInfo.h
+++ 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<const Attr *> 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(); }
Index: clang/lib/CodeGen/CGLoopInfo.cpp
===================================================================
--- clang/lib/CodeGen/CGLoopInfo.cpp
+++ 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<const clang::Attr *> 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<LoopHintAttr>(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.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to