fhahn created this revision.
Herald added subscribers: jansvoboda11, dexonsmith, dang.
fhahn requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

This cherry-picks the following patches on the release branch:

6280bb4cd80e 
<https://reviews.llvm.org/rG6280bb4cd80e39b0e54b1c8dd091f2b7175381eb> [clang] 
Remove redundant condition (NFC).
51bf4c0e6d4c 
<https://reviews.llvm.org/rG51bf4c0e6d4cbc6dfa57857fc78003413cbeb17f> [clang] 
Add -ffinite-loops & -fno-finite-loops options.
fb4d8fe80701 
<https://reviews.llvm.org/rGfb4d8fe807016fed221263d9a406e3856c8dfa4c> [clang] 
Update mustprogress tests

This patch adds 2 new options to control when Clang adds `mustprogress`:

1. -ffinite-loops: assume all loops are finite; mustprogress is added to all 
loops, regardless of the selected language standard.
2. -fno-finite-loops: assume no loop is finite; mustprogress is not added to 
any loop or function. We could add mustprogress to functions without loops, but 
we would have to detect that in Clang, which is probably not worth it.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D96850

Files:
  clang/include/clang/Basic/CodeGenOptions.def
  clang/include/clang/Basic/CodeGenOptions.h
  clang/include/clang/Driver/Options.td
  clang/lib/CodeGen/CodeGenFunction.h
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Frontend/CompilerInvocation.cpp
  clang/test/CodeGen/attr-mustprogress-0.c
  clang/test/CodeGen/attr-mustprogress-0.cpp
  clang/test/CodeGen/attr-mustprogress-1.c
  clang/test/CodeGen/attr-mustprogress-1.cpp
  clang/test/CodeGen/attr-mustprogress.c
  clang/test/CodeGenCXX/attr-mustprogress.cpp

Index: clang/test/CodeGenCXX/attr-mustprogress.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/attr-mustprogress.cpp
@@ -0,0 +1,330 @@
+// RUN: %clang_cc1 -std=c++98 -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=CXX98 %s
+// RUN: %clang_cc1 -std=c++11 -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=CXX11 %s
+// RUN: %clang_cc1 -std=c++14 -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=CXX11 %s
+// RUN: %clang_cc1 -std=c++17 -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=CXX11 %s
+// RUN: %clang_cc1 -std=c++20 -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=CXX11 %s
+
+// Make sure -ffinite-loops overrides -std=c++98 for loops.
+// RUN: %clang_cc1 -std=c++98 -ffinite-loops -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=FINITE %s
+
+// Make sure -fno-finite-loops overrides -std=c++11
+// RUN: %clang_cc1 -std=c++11 -fno-finite-loops -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=CXX98 %s
+
+int a = 0;
+int b = 0;
+
+// CHECK: datalayout
+
+// CXX98-NOT: mustprogress
+// CXX11-NOT: mustprogress
+// FINITE-NOT:     mustprogress
+// CHECK-LABEL: @_Z2f0v(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    br label %for.cond
+// CHECK:       for.cond:
+// CHECK-NOT:    br {{.*}} llvm.loop
+void f0() {
+  for (; ;) ;
+}
+
+// CXX98-NOT: mustprogress
+// CXX11-NOT: mustprogress
+// FINITE-NOT: mustprogress
+// CHECK-LABEL: @_Z2f1v(
+// 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-NOT:    br {{.*}}, !llvm.loop
+// CHECK:       for.end:
+// CHECK-NEXT:    ret void
+//
+void f1() {
+  for (; 1;)
+    ;
+}
+
+// CXX98-NOT: mustprogress
+// CXX11:     mustprogress
+// FINITE-NOT: mustprogress
+// CHECK-LABEL: @_Z2f2v(
+// 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:
+// CXX98-NOT:    br {{.*}}, !llvm.loop
+// CXX11:        br label %for.cond, !llvm.loop [[LOOP1:!.*]]
+// FINITE-NEXT:   br label %for.cond, !llvm.loop [[LOOP1:!.*]]
+// CHECK:       for.end:
+// CHECK-NEXT:    ret void
+//
+void f2() {
+  for (; a == b;)
+    ;
+}
+
+// CXX98-NOT: mustprogress
+// CXX11-NOT: mustprogress
+// FINITE-NOT: mustprogress
+// CHECK-LABEL: @_Z1Fv(
+// 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-NOT:     br {{.*}}, !llvm.loop
+// 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:
+// CXX98-NOT:     br {{.*}}, !llvm.loop
+// CXX11-NEXT:    br label %for.cond1, !llvm.loop [[LOOP2:!.*]]
+// FINITE-NEXT:   br label %for.cond1, !llvm.loop [[LOOP2:!.*]]
+// CHECK:       for.end3:
+// CHECK-NEXT:    ret void
+//
+void F() {
+  for (; 1;)
+    ;
+  for (; a == b;)
+    ;
+}
+
+// CXX98-NOT: mustprogress
+// CXX11-NOT: mustprogress
+// FINITE-NOT: mustprogress
+// CHECK-LABEL: @_Z2F2v(
+// 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:
+// CXX98_NOT:     br {{.*}} !llvm.loop
+// CXX11-NEXT:    br label %for.cond, !llvm.loop [[LOOP3:!.*]]
+// FINITE-NEXT:    br label %for.cond, !llvm.loop [[LOOP3:!.*]]
+// 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
+// CHECK:       for.end3:
+// CHECK-NEXT:    ret void
+//
+void F2() {
+  for (; a == b;)
+    ;
+  for (; 1;)
+    ;
+}
+
+// CXX98-NOT: mustprogress
+// CXX11-NOT: mustprogress
+// FINITE-NOT:     mustprogress
+// CHECK-LABEL: @_Z2w1v(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    br label %while.body
+// CHECK:       while.body:
+// CHECK-NOT:     br {{.*}}, !llvm.loop
+//
+void w1() {
+  while (1)
+    ;
+}
+
+// CXX98-NOT: mustprogress
+// CXX11:     mustprogress
+// FINITE-NOT: mustprogress
+// CHECK-LABEL: @_Z2w2v(
+// 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:
+// CXX98-NOT:     br {{.*}}, !llvm.loop
+// CXX11-NEXT:    br label %while.cond, !llvm.loop [[LOOP4:!.*]]
+// FINITE-NEXT:   br label %while.cond, !llvm.loop [[LOOP4:!.*]]
+// CHECK:       while.end:
+// CHECK-NEXT:    ret void
+//
+void w2() {
+  while (a == b)
+    ;
+}
+
+// CXX98-NOT: mustprogress
+// CXX11-NOT: mustprogress
+// FINITE-NOT: mustprogress
+// CHECK-LABEL: @_Z1Wv(
+// 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:
+// CXX98-NOT:     br {{.*}}, !llvm.loop
+// CXX11-NEXT:    br label %while.cond, !llvm.loop [[LOOP5:!.*]]
+// FINITE-NEXT:   br label %while.cond, !llvm.loop [[LOOP5:!.*]]
+// CHECK:       while.end:
+// CHECK-NEXT:    br label %while.body2
+// CHECK:       while.body2:
+// CHECK-NOT:     br {{.*}}, !llvm.loop
+//
+void W() {
+  while (a == b)
+    ;
+  while (1)
+    ;
+}
+
+// CXX98-NOT: mustprogress
+// CXX11-NOT: mustprogress
+// FINITE-NOT: mustprogress
+// CHECK-LABEL: @_Z2W2v(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    br label %while.body
+// CHECK:       while.body:
+// CHECK-NOT:     br {{.*}}, !llvm.loop
+//
+void W2() {
+  while (1)
+    ;
+  while (a == b)
+    ;
+}
+
+// CXX98-NOT: mustprogress
+// CXX11-NOT: mustprogress
+// FINITE-NOT: mustprogress
+// CHECK-LABEL: @_Z2d1v(
+// 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
+// CHECK:       do.end:
+// CHECK-NEXT:    ret void
+//
+void d1() {
+  do
+    ;
+  while (1);
+}
+
+// CXX98-NOT: mustprogress
+// CXX11:     mustprogress
+// FINITE-NOT:  mustprogress
+// CHECK-LABEL: @_Z2d2v(
+// 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]]
+// 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:!.*]]
+// CHECK:       do.end:
+// CHECK-NEXT:    ret void
+//
+void d2() {
+  do
+    ;
+  while (a == b);
+}
+
+// CXX98-NOT: mustprogress
+// CXX11-NOT: 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
+// 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]]
+// 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:!.*]]
+// CHECK:       do.end3:
+// CHECK-NEXT:    ret void
+//
+void D() {
+  do
+    ;
+  while (1);
+  do
+    ;
+  while (a == b);
+}
+
+// CXX98-NOT: mustprogress
+// CXX11-NOT: mustprogress
+// FINITE-NOT:     mustprogress
+// CHECK-LABEL: @_Z2D2v(
+// 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]]
+// 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:!.*]]
+// 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
+// CHECK:       do.end3:
+// CHECK-NEXT:    ret void
+//
+void D2() {
+  do
+    ;
+  while (a == b);
+  do
+    ;
+  while (1);
+}
+
+// CXX11: [[LOOP1]] = distinct !{[[LOOP1]], [[MP:!.*]]}
+// CXX11: [[MP]] = !{!"llvm.loop.mustprogress"}
+// CXX11: [[LOOP2]] = distinct !{[[LOOP2]], [[MP]]}
+// CXX11: [[LOOP3]] = distinct !{[[LOOP3]], [[MP]]}
+// CXX11: [[LOOP4]] = distinct !{[[LOOP4]], [[MP]]}
+// CXX11: [[LOOP5]] = distinct !{[[LOOP5]], [[MP]]}
+// CXX11: [[LOOP6]] = distinct !{[[LOOP6]], [[MP]]}
+// CXX11: [[LOOP7]] = distinct !{[[LOOP7]], [[MP]]}
+// CXX11: [[LOOP8]] = distinct !{[[LOOP8]], [[MP]]}
Index: clang/test/CodeGen/attr-mustprogress.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/attr-mustprogress.c
@@ -0,0 +1,221 @@
+// 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
+//
+// 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=c11 -fno-finite-loops -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=C99 %s
+
+int a = 0;
+int b = 0;
+
+// CHECK: datalayout
+//
+// CHECK-NOT: mustprogress
+// CHECK-LABEL: @f0(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    br label %for.cond
+// CHECK:       for.cond:
+// CHECK-NOT:     br {{.*}}!llvm.loop
+//
+void f0() {
+  for (; ;) ;
+}
+
+// CHECK-NOT: mustprogress
+// 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-NOT:     br {{.*}}, !llvm.loop
+// CHECK:       for.end:
+// CHECK-NEXT:    ret void
+//
+void f1() {
+  for (; 1;) {
+  }
+}
+
+// CHECK-NOT: mustprogress
+// 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:
+// C99-NOT:       br {{.*}} !llvm.loop
+// C11:           br label %for.cond, !llvm.loop [[LOOP1:!.*]]
+// FINITE:        br label %for.cond, !llvm.loop [[LOOP1:!.*]]
+// CHECK:       for.end:
+// CHECK-NEXT:    ret void
+//
+void f2() {
+  for (; a == b;) {
+  }
+}
+
+// CHECK-NOT: mustprogress
+// 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-NOT:     br {{.*}}, !llvm.loop
+// 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:
+// C99-NOT:       br {{.*}}, !llvm.loop
+// C11:           br label %for.cond1, !llvm.loop [[LOOP2:!.*]]
+// FINITE:        br label %for.cond1, !llvm.loop [[LOOP2:!.*]]
+// CHECK:       for.end3:
+// CHECK-NEXT:    ret void
+//
+void F() {
+  for (; 1;) {
+  }
+  for (; a == b;) {
+  }
+}
+
+// CHECK-NOT: mustprogress
+// CHECK-LABEL: @w1(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    br label %while.body
+// CHECK:       while.body:
+// CHECK-NOT:     br {{.*}}, !llvm.loop
+//
+void w1() {
+  while (1) {
+  }
+}
+
+// CHECK-NOT: mustprogress
+// 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:
+// C99-NOT:       br {{.*}}, !llvm.loop
+// C11:           br label %while.cond, !llvm.loop [[LOOP3:!.*]]
+// FINITE:        br label %while.cond, !llvm.loop [[LOOP3:!.*]]
+// CHECK:       while.end:
+// CHECK-NEXT:    ret void
+//
+void w2() {
+  while (a == b) {
+  }
+}
+
+// CHECK-NOT: mustprogress
+// 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:
+// C99-NOT:       br {{.*}} !llvm.loop
+// C11:           br label %while.cond, !llvm.loop [[LOOP4:!.*]]
+// FINITE:        br label %while.cond, !llvm.loop [[LOOP4:!.*]]
+// CHECK:       while.end:
+// CHECK-NEXT:    br label %while.body2
+// CHECK:       while.body2:
+// CHECK-NOT:     br {{.*}} !llvm.loop
+//
+void W() {
+  while (a == b) {
+  }
+  while (1) {
+  }
+}
+
+// CHECK-NOT: mustprogress
+// 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-NOT:     br {{.*}}, !llvm.loop
+// CHECK:       do.end:
+// CHECK-NEXT:    ret void
+//
+void d1() {
+  do {
+  } while (1);
+}
+
+// CHECK-NOT: mustprogress
+// 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]]
+// C99-NOT:       br {{.*}}, !llvm.loop
+// C11:           br i1 [[CMP]], label %do.body, label %do.end, !llvm.loop [[LOOP5:!.*]]
+// FINITE:        br i1 [[CMP]], label %do.body, label %do.end, !llvm.loop [[LOOP5:!.*]]
+// CHECK:       do.end:
+// CHECK-NEXT:    ret void
+//
+void d2() {
+  do {
+  } while (a == b);
+}
+
+// CHECK-NOT: mustprogress
+// 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-NOT:     br label {{.*}}, !llvm.loop
+// 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]]
+// C99-NOT:       br {{.*}}, !llvm.loop
+// C11:           br i1 [[CMP]], label %do.body1, label %do.end3, !llvm.loop [[LOOP6:!.*]]
+// FINITE:        br i1 [[CMP]], label %do.body1, label %do.end3, !llvm.loop [[LOOP6:!.*]]
+// CHECK:       do.end3:
+// CHECK-NEXT:    ret void
+//
+void D() {
+  do {
+  } while (1);
+  do {
+  } while (a == b);
+}
+
+// C11: [[LOOP1]] = distinct !{[[LOOP1]], [[MP:!.*]]}
+// C11: [[MP]] = !{!"llvm.loop.mustprogress"}
+// C11: [[LOOP2]] = distinct !{[[LOOP2]], [[MP]]}
+// C11: [[LOOP3]] = distinct !{[[LOOP3]], [[MP]]}
+// C11: [[LOOP4]] = distinct !{[[LOOP4]], [[MP]]}
+// C11: [[LOOP5]] = distinct !{[[LOOP5]], [[MP]]}
+// C11: [[LOOP6]] = distinct !{[[LOOP6]], [[MP]]}
Index: clang/test/CodeGen/attr-mustprogress-1.cpp
===================================================================
--- clang/test/CodeGen/attr-mustprogress-1.cpp
+++ /dev/null
@@ -1,271 +0,0 @@
-// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes
-// RUN: %clang_cc1 -std=c++11 -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -std=c++14 -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -std=c++17 -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -std=c++20 -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck %s
-
-int a = 0;
-int b = 0;
-
-// CHECK: Function Attrs: noinline nounwind optnone
-// CHECK-LABEL: @_Z2f0v(
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    br label [[FOR_COND:%.*]]
-// CHECK:       for.cond:
-// CHECK-NOT:    br label [[FOR_COND]], !llvm.loop !{{.*}}
-void f0() {
-  for (; ;) ;
-}
-
-// CHECK: Function Attrs: noinline nounwind optnone
-// CHECK-LABEL: @_Z2f1v(
-// 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 mustprogress
-// CHECK-LABEL: @_Z2f2v(
-// 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]], [[LOOP2:!llvm.loop !.*]]
-// CHECK:       for.end:
-// CHECK-NEXT:    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-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]], [[LOOP4:!llvm.loop !.*]]
-// CHECK:       for.end3:
-// CHECK-NEXT:    ret void
-//
-void F() {
-  for (; 1;)
-    ;
-  for (; a == b;)
-    ;
-}
-
-// CHECK: Function Attrs: noinline nounwind optnone
-// CHECK-LABEL: @_Z2F2v(
-// 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]], [[LOOP5:!llvm.loop !.*]]
-// 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-NEXT:    br label [[FOR_COND1]]
-// CHECK:       for.end3:
-// CHECK-NEXT:    ret void
-//
-void F2() {
-  for (; a == b;)
-    ;
-  for (; 1;)
-    ;
-}
-
-// CHECK: Function Attrs: noinline nounwind optnone
-// CHECK-LABEL: @_Z2w1v(
-// 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 mustprogress
-// CHECK-LABEL: @_Z2w2v(
-// 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]], [[LOOP6:!llvm.loop !.*]]
-// CHECK:       while.end:
-// CHECK-NEXT:    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-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]], [[LOOP7:!llvm.loop !.*]]
-// 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
-// CHECK-LABEL: @_Z2W2v(
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    br label [[WHILE_BODY:%.*]]
-// CHECK:       while.body:
-// CHECK-NEXT:    br label [[WHILE_BODY]]
-//
-void W2() {
-  while (1)
-    ;
-  while (a == b)
-    ;
-}
-
-// CHECK: Function Attrs: noinline nounwind optnone
-// CHECK-LABEL: @_Z2d1v(
-// 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 mustprogress
-// CHECK-LABEL: @_Z2d2v(
-// 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:%.*]], [[LOOP8:!llvm.loop !.*]]
-// CHECK:       do.end:
-// CHECK-NEXT:    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-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:%.*]], [[LOOP9:!llvm.loop !.*]]
-// CHECK:       do.end3:
-// CHECK-NEXT:    ret void
-//
-void D() {
-  do
-    ;
-  while (1);
-  do
-    ;
-  while (a == b);
-}
-
-// CHECK: Function Attrs: noinline nounwind optnone
-// CHECK-LABEL: @_Z2D2v(
-// 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:%.*]], [[LOOP10:!llvm.loop !.*]]
-// CHECK:       do.end:
-// CHECK-NEXT:    br label [[DO_BODY1:%.*]]
-// CHECK:       do.body1:
-// CHECK-NEXT:    br label [[DO_COND2:%.*]]
-// CHECK:       do.cond2:
-// CHECK-NEXT:    br i1 true, label [[DO_BODY1]], label [[DO_END3:%.*]]
-// CHECK:       do.end3:
-// CHECK-NEXT:    ret void
-//
-void D2() {
-  do
-    ;
-  while (a == b);
-  do
-    ;
-  while (1);
-}
-
Index: clang/test/CodeGen/attr-mustprogress-1.c
===================================================================
--- clang/test/CodeGen/attr-mustprogress-1.c
+++ /dev/null
@@ -1,197 +0,0 @@
-// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes
-// RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -std=c11 -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -std=c18 -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -std=c2x -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck %s
-
-int a = 0;
-int b = 0;
-
-// CHECK: Function Attrs: noinline nounwind optnone
-// CHECK-LABEL: @f0(
-// CHECK-NEXT:  entry:
-// CHECK-NEXT:    br label [[FOR_COND:%.*]]
-// CHECK:       for.cond:
-// CHECK-NOT:    br label [[FOR_COND]], !llvm.loop !{{.*}}
-//
-void f0() {
-  for (; ;) ;
-}
-
-// CHECK: Function Attrs: noinline nounwind optnone
-// 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
-// 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]], [[LOOP2:!llvm.loop !.*]]
-// CHECK:       for.end:
-// CHECK-NEXT:    ret void
-//
-void f2() {
-  for (; a == b;) {
-  }
-}
-
-// CHECK: Function Attrs: noinline nounwind optnone
-// 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]], [[LOOP4:!llvm.loop !.*]]
-// CHECK:       for.end3:
-// CHECK-NEXT:    ret void
-//
-void F() {
-  for (; 1;) {
-  }
-  for (; a == b;) {
-  }
-}
-
-// CHECK: Function Attrs: noinline nounwind optnone
-// 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
-// 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]], [[LOOP5:!llvm.loop !.*]]
-// CHECK:       while.end:
-// CHECK-NEXT:    ret void
-//
-void w2() {
-  while (a == b) {
-  }
-}
-
-// CHECK: Function Attrs: noinline nounwind optnone
-// 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]], [[LOOP6:!llvm.loop !.*]]
-// 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
-// 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
-// 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:%.*]], [[LOOP7:!llvm.loop !.*]]
-// CHECK:       do.end:
-// CHECK-NEXT:    ret void
-//
-void d2() {
-  do {
-  } while (a == b);
-}
-
-// CHECK: Function Attrs: noinline nounwind optnone
-// 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:%.*]], [[LOOP8:!llvm.loop !.*]]
-// CHECK:       do.end3:
-// CHECK-NEXT:    ret void
-//
-void D() {
-  do {
-  } while (1);
-  do {
-  } while (a == b);
-}
Index: clang/test/CodeGen/attr-mustprogress-0.cpp
===================================================================
--- clang/test/CodeGen/attr-mustprogress-0.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes
-// RUN: %clang_cc1 -std=c++98 -triple=x86_64-unknown-linux-gnu -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-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
-// CHECK-LABEL: @_Z2f2v(
-// 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]]
-// CHECK:       for.end:
-// CHECK-NEXT:    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-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]]
-// CHECK:       for.end3:
-// CHECK-NEXT:    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-NEXT:    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-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]]
-// CHECK:       while.end:
-// CHECK-NEXT:    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-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]]
-// 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
-// CHECK-LABEL: @_Z2d1v(
-// 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
-// CHECK-LABEL: @_Z2d2v(
-// 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:%.*]]
-// CHECK:       do.end:
-// CHECK-NEXT:    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-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:%.*]]
-// CHECK:       do.end3:
-// CHECK-NEXT:    ret void
-//
-void D() {
-  do {
-  } while (1);
-  do {
-  } while (a == b);
-}
Index: clang/test/CodeGen/attr-mustprogress-0.c
===================================================================
--- clang/test/CodeGen/attr-mustprogress-0.c
+++ /dev/null
@@ -1,184 +0,0 @@
-// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes
-// RUN: %clang_cc1 -std=c89 -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -std=c99 -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck %s
-
-int a = 0;
-int b = 0;
-
-// CHECK: Function Attrs: noinline nounwind optnone
-// 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
-// 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]]
-// CHECK:       for.end:
-// CHECK-NEXT:    ret void
-//
-void f2() {
-  for (; a == b;) {
-  }
-}
-
-// CHECK: Function Attrs: noinline nounwind optnone
-// 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]]
-// CHECK:       for.end3:
-// CHECK-NEXT:    ret void
-//
-void F() {
-  for (; 1;) {
-  }
-  for (; a == b;) {
-  }
-}
-
-// CHECK: Function Attrs: noinline nounwind optnone
-// 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
-// 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]]
-// CHECK:       while.end:
-// CHECK-NEXT:    ret void
-//
-void w2() {
-  while (a == b) {
-  }
-}
-
-// CHECK: Function Attrs: noinline nounwind optnone
-// 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]]
-// 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
-// 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
-// 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:%.*]]
-// CHECK:       do.end:
-// CHECK-NEXT:    ret void
-//
-void d2() {
-  do {
-  } while (a == b);
-}
-
-// CHECK: Function Attrs: noinline nounwind optnone
-// 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:%.*]]
-// CHECK:       do.end3:
-// CHECK-NEXT:    ret void
-//
-void D() {
-  do {
-  } while (1);
-  do {
-  } while (a == b);
-}
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -1037,7 +1037,6 @@
   Opts.UnrollLoops =
       Args.hasFlag(OPT_funroll_loops, OPT_fno_unroll_loops,
                    (Opts.OptimizationLevel > 1));
-
   Opts.BinutilsVersion =
       std::string(Args.getLastArgValue(OPT_fbinutils_version_EQ));
 
@@ -1324,6 +1323,10 @@
 
   Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true);
 
+  if (Args.hasArg(options::OPT_ffinite_loops))
+    Opts.FiniteLoops = CodeGenOptions::FiniteLoopsKind::Always;
+  else if (Args.hasArg(options::OPT_fno_finite_loops))
+    Opts.FiniteLoops = CodeGenOptions::FiniteLoopsKind::Never;
   return Success;
 }
 
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -5620,6 +5620,9 @@
     if (A->getOption().matches(options::OPT_freroll_loops))
       CmdArgs.push_back("-freroll-loops");
 
+  Args.AddLastArg(CmdArgs, options::OPT_ffinite_loops,
+                  options::OPT_fno_finite_loops);
+
   Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings);
   Args.AddLastArg(CmdArgs, options::OPT_funroll_loops,
                   options::OPT_fno_unroll_loops);
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -507,12 +507,23 @@
 
   /// True if the C++ Standard Requires Progress.
   bool CPlusPlusWithProgress() {
+    if (CGM.getCodeGenOpts().getFiniteLoops() ==
+        CodeGenOptions::FiniteLoopsKind::Never)
+      return false;
+
     return getLangOpts().CPlusPlus11 || getLangOpts().CPlusPlus14 ||
            getLangOpts().CPlusPlus17 || getLangOpts().CPlusPlus20;
   }
 
   /// True if the C Standard Requires Progress.
   bool CWithProgress() {
+    if (CGM.getCodeGenOpts().getFiniteLoops() ==
+        CodeGenOptions::FiniteLoopsKind::Always)
+      return true;
+    if (CGM.getCodeGenOpts().getFiniteLoops() ==
+        CodeGenOptions::FiniteLoopsKind::Never)
+      return false;
+
     return getLangOpts().C11 || getLangOpts().C17 || getLangOpts().C2x;
   }
 
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -2410,6 +2410,11 @@
 defm reroll_loops : BoolFOption<"reroll-loops",
   CodeGenOpts<"RerollLoops">, DefaultFalse,
   PosFlag<SetTrue, [CC1Option], "Turn on loop reroller">, NegFlag<SetFalse>>;
+def ffinite_loops: Flag<["-"],  "ffinite-loops">, Group<f_Group>,
+  HelpText<"Assume all loops are finite.">, Flags<[CC1Option]>;
+def fno_finite_loops: Flag<["-"], "fno-finite-loops">, Group<f_Group>,
+  HelpText<"Do not assume that any loop is finite.">, Flags<[CC1Option]>;
+
 def ftrigraphs : Flag<["-"], "ftrigraphs">, Group<f_Group>,
   HelpText<"Process trigraph sequences">, Flags<[CC1Option]>;
 def fno_trigraphs : Flag<["-"], "fno-trigraphs">, Group<f_Group>,
Index: clang/include/clang/Basic/CodeGenOptions.h
===================================================================
--- clang/include/clang/Basic/CodeGenOptions.h
+++ clang/include/clang/Basic/CodeGenOptions.h
@@ -140,6 +140,12 @@
     All,         // Keep all frame pointers.
   };
 
+  enum FiniteLoopsKind {
+    Language, // Not specified, use language standard.
+    Always,   // All loops are assumed to be finite.
+    Never,    // No loop is assumed to be finite.
+  };
+
   /// The code model to use (-mcmodel).
   std::string CodeModel;
 
Index: clang/include/clang/Basic/CodeGenOptions.def
===================================================================
--- clang/include/clang/Basic/CodeGenOptions.def
+++ clang/include/clang/Basic/CodeGenOptions.def
@@ -266,6 +266,9 @@
 CODEGENOPT(VectorizeSLP      , 1, 0) ///< Run SLP vectorizer.
 CODEGENOPT(ProfileSampleAccurate, 1, 0) ///< Sample profile is accurate.
 
+/// Treat loops as finite: language, always, never.
+ENUM_CODEGENOPT(FiniteLoops, FiniteLoopsKind, 2, FiniteLoopsKind::Language)
+
   /// Attempt to use register sized accesses to bit-fields in structures, when
   /// possible.
 CODEGENOPT(UseRegisterSizedBitfieldAccess , 1, 0)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to