OSDN Git Service

[clang] Add -ffinite-loops & -fno-finite-loops options.
authorFlorian Hahn <flo@fhahn.com>
Sat, 20 Feb 2021 05:48:46 +0000 (21:48 -0800)
committerTom Stellard <tstellar@redhat.com>
Sat, 20 Feb 2021 05:48:47 +0000 (21:48 -0800)
This cherry-picks the following patches on the release branch:

6280bb4cd80e [clang] Remove redundant condition (NFC).
51bf4c0e6d4c [clang] Add -ffinite-loops & -fno-finite-loops options.
fb4d8fe80701 [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.

Differential Revision: https://reviews.llvm.org/D96850

12 files changed:
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 [deleted file]
clang/test/CodeGen/attr-mustprogress-0.cpp [deleted file]
clang/test/CodeGen/attr-mustprogress-1.c [deleted file]
clang/test/CodeGen/attr-mustprogress-1.cpp [deleted file]
clang/test/CodeGen/attr-mustprogress.c [new file with mode: 0644]
clang/test/CodeGenCXX/attr-mustprogress.cpp [new file with mode: 0644]

index 5c8af65..9d53b5b 100644 (file)
@@ -266,6 +266,9 @@ CODEGENOPT(VectorizeLoop     , 1, 0) ///< Run loop vectorizer.
 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)
index 73d41e3..c550817 100644 (file)
@@ -140,6 +140,12 @@ public:
     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 1f6c13d..8177989 100644 (file)
@@ -2410,6 +2410,11 @@ def fno_unroll_loops : Flag<["-"], "fno-unroll-loops">, Group<f_Group>,
 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 8eb7adb..95c0b7b 100644 (file)
@@ -507,12 +507,23 @@ public:
 
   /// 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 f8e6379..1976b48 100644 (file)
@@ -5620,6 +5620,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
     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 036388e..5c5cf46 100644 (file)
@@ -1037,7 +1037,6 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
   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 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
 
   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;
 }
 
diff --git a/clang/test/CodeGen/attr-mustprogress-0.c b/clang/test/CodeGen/attr-mustprogress-0.c
deleted file mode 100644 (file)
index 2af24e8..0000000
+++ /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);
-}
diff --git a/clang/test/CodeGen/attr-mustprogress-0.cpp b/clang/test/CodeGen/attr-mustprogress-0.cpp
deleted file mode 100644 (file)
index 3a180cc..0000000
+++ /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);
-}
diff --git a/clang/test/CodeGen/attr-mustprogress-1.c b/clang/test/CodeGen/attr-mustprogress-1.c
deleted file mode 100644 (file)
index 2ff068b..0000000
+++ /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);
-}
diff --git a/clang/test/CodeGen/attr-mustprogress-1.cpp b/clang/test/CodeGen/attr-mustprogress-1.cpp
deleted file mode 100644 (file)
index 945d746..0000000
+++ /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);
-}
-
diff --git a/clang/test/CodeGen/attr-mustprogress.c b/clang/test/CodeGen/attr-mustprogress.c
new file mode 100644 (file)
index 0000000..1f83cd4
--- /dev/null
@@ -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]]}
diff --git a/clang/test/CodeGenCXX/attr-mustprogress.cpp b/clang/test/CodeGenCXX/attr-mustprogress.cpp
new file mode 100644 (file)
index 0000000..48ac7ad
--- /dev/null
@@ -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]]}