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

Following D94366 <https://reviews.llvm.org/D94366>, clang will strictly adheres 
to the language standard
when deciding whether or not to emit `mustprogress` attributes for
loops. This patch adds two flags: `-ffinite-loops` and
`-fno-finite-loops` that override the language standard into either
never emitting `mustprogress` attributes or emitting `mustprogress`
attributes for all loops/functions.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D94367

Files:
  clang/docs/ClangCommandLineReference.rst
  clang/include/clang/Basic/CodeGenOptions.def
  clang/include/clang/Basic/CodeGenOptions.h
  clang/include/clang/Driver/Options.td
  clang/lib/CodeGen/CGStmt.cpp
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Frontend/CompilerInvocation.cpp
  clang/test/CodeGen/finite-loops.c
  clang/test/CodeGenCXX/finite-loops.cpp
  clang/test/Driver/clang_f_opts.c

Index: clang/test/Driver/clang_f_opts.c
===================================================================
--- clang/test/Driver/clang_f_opts.c
+++ clang/test/Driver/clang_f_opts.c
@@ -52,6 +52,15 @@
 // CHECK-REROLL-LOOPS: "-freroll-loops"
 // CHECK-NO-REROLL-LOOPS-NOT: "-freroll-loops"
 
+// RUN: %clang -### -S -ffinite-loops %s 2>&1 | FileCheck -check-prefix=CHECK-FINITE-LOOPS %s
+// RUN: %clang -### -S -fno-finite-loops %s 2>&1 | FileCheck -check-prefix=CHECK-NO-FINITE-LOOPS %s
+// RUN: %clang -### -S -fno-finite-loops -ffinite-loops %s 2>&1 | FileCheck -check-prefix=CHECK-FINITE-LOOPS %s
+// RUN: %clang -### -S -ffinite-loops -fno-finite-loops %s 2>&1 | FileCheck -check-prefix=CHECK-NO-FINITE-LOOPS %s
+// CHECK-FINITE-LOOPS: "-ffinite-loops"
+// CHECK-FINITE-LOOPS-NOT: "-fno-finite-loops"
+// CHECK-NO-FINITE-LOOPS: "-fno-finite-loops"
+// CHECK-NO-FINITE-LOOPS-NOT: "-ffinite-loops"
+
 // RUN: %clang -### -S -fprofile-sample-accurate %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-SAMPLE-ACCURATE %s
 // CHECK-PROFILE-SAMPLE-ACCURATE: "-fprofile-sample-accurate"
 
@@ -292,6 +301,7 @@
 // RUN:     -malign-functions=100                                             \
 // RUN:     -malign-loops=100                                                 \
 // RUN:     -malign-jumps=100                                                 \
+// RUN:     -ffinite-loops -fno-finite-loops                                  \
 // RUN:     %s 2>&1 | FileCheck --check-prefix=IGNORE %s
 // IGNORE-NOT: error: unknown argument
 
Index: clang/test/CodeGenCXX/finite-loops.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/finite-loops.cpp
@@ -0,0 +1,99 @@
+// RUN: %clang_cc1 -triple x86_64 -S -emit-llvm -std=c++03 -o - %s | FileCheck %s -check-prefix=CHECK-CPP03-LOOPS
+// RUN: %clang_cc1 -triple x86_64 -S -emit-llvm -std=c++03 -ffinite-loops -o - %s | FileCheck %s -check-prefix=CHECK-FINITE-LOOPS
+// RUN: %clang_cc1 -triple x86_64 -S -emit-llvm -std=c++03 -fno-finite-loops -o - %s | FileCheck %s -check-prefix=CHECK-INFINITE-LOOPS
+// RUN: %clang_cc1 -triple x86_64 -S -emit-llvm -std=c++11 -o - %s | FileCheck %s -check-prefix=CHECK-CPP11-LOOPS
+// RUN: %clang_cc1 -triple x86_64 -S -emit-llvm -std=c++11 -ffinite-loops -o - %s | FileCheck %s -check-prefix=CHECK-FINITE-LOOPS
+// RUN: %clang_cc1 -triple x86_64 -S -emit-llvm -std=c++11 -fno-finite-loops -o - %s | FileCheck %s -check-prefix=CHECK-INFINITE-LOOPS
+
+// CHECK-CPP03-LOOPS: Function Attrs: noinline nounwind optnone
+// CHECK-CPP03-LOOPS-LABEL: @_Z1fii(
+// CHECK-CPP03-LOOPS-NOT:    {{.*}} !llvm.loop !
+//
+// CHECK-FINITE-LOOPS: Function Attrs: noinline nounwind optnone mustprogress
+// CHECK-FINITE-LOOPS-LABEL: @_Z1fii(
+// CHECK-FINITE-LOOPS:    {{.*}} !llvm.loop !
+// CHECK-FINITE-LOOPS:    {{.*}} !llvm.loop !
+//
+// CHECK-INFINITE-LOOPS: Function Attrs: noinline nounwind optnone
+// CHECK-INFINITE-LOOPS-LABEL: @_Z1fii(
+// CHECK-INFINITE-LOOPS-NOT:    {{.*}} !llvm.loop !
+//
+// CHECK-CPP11-LOOPS: Function Attrs: noinline nounwind optnone
+// CHECK-CPP11-LOOPS-LABEL: @_Z1fii(
+// CHECK-CPP11-LOOPS:        {{.*}} !llvm.loop !
+// CHECK-CPP11-LOOPS:        {{.*}} !llvm.loop !
+//
+int f(int a, int b) {
+  for (; a != b; ) {
+    if (a == b)
+      return 1;
+  }
+
+  for (;;) {
+    if (a != b)
+      return 1;
+  }
+  return 0;
+}
+
+// CHECK-CPP03-LOOPS: Function Attrs: noinline nounwind optnone
+// CHECK-CPP03-LOOPS-LABEL: @_Z2dwii(
+// CHECK-CPP03-LOOPS-NOT:    {{.*}} !llvm.loop !
+//
+// CHECK-FINITE-LOOPS: Function Attrs: noinline nounwind optnone mustprogress
+// CHECK-FINITE-LOOPS-LABEL: @_Z2dwii(
+// CHECK-FINITE-LOOPS:    {{.*}} !llvm.loop !
+// CHECK-FINITE-LOOPS:    {{.*}} !llvm.loop !
+//
+// CHECK-INFINITE-LOOPS: Function Attrs: noinline nounwind optnone
+// CHECK-INFINITE-LOOPS-LABEL: @_Z2dwii(
+// CHECK-INFINITE-LOOPS-NOT:    {{.*}} !llvm.loop !
+//
+// CHECK-CPP11-LOOPS: Function Attrs: noinline nounwind optnone
+// CHECK-CPP11-LOOPS-LABEL: @_Z2dwii(
+// CHECK-CPP11-LOOPS:        {{.*}} !llvm.loop !
+// CHECK-CPP11-LOOPS:        {{.*}} !llvm.loop !
+//
+int dw(int a, int b) {
+  do {
+    if (a == b)
+      return 1;
+  } while (a != b);
+
+  do {
+    if (a != b)
+      return 1;
+  } while (1);
+  return 0;
+}
+
+// CHECK-CPP03-LOOPS: Function Attrs: noinline nounwind optnone
+// CHECK-CPP03-LOOPS-LABEL: @_Z1wii(
+// CHECK-CPP03-LOOPS-NOT:    {{.*}} !llvm.loop !
+//
+// CHECK-FINITE-LOOPS: Function Attrs: noinline nounwind optnone mustprogress
+// CHECK-FINITE-LOOPS-LABEL: @_Z1wii(
+// CHECK-FINITE-LOOPS:    {{.*}} !llvm.loop !
+// CHECK-FINITE-LOOPS:    {{.*}} !llvm.loop !
+//
+// CHECK-INFINITE-LOOPS: Function Attrs: noinline nounwind optnone
+// CHECK-INFINITE-LOOPS-LABEL: @_Z1wii(
+// CHECK-INFINITE-LOOPS-NOT:    {{.*}} !llvm.loop !
+//
+// CHECK-CPP11-LOOPS: Function Attrs: noinline nounwind optnone
+// CHECK-CPP11-LOOPS-LABEL: @_Z1wii(
+// CHECK-CPP11-LOOPS:        {{.*}} !llvm.loop !
+// CHECK-CPP11-LOOPS:        {{.*}} !llvm.loop !
+//
+int w(int a, int b) {
+  while(a != b) {
+    if (a == b) return 2;
+  }
+
+  while(1) {
+    if (a != b)
+      return 1;
+  }
+  return 0;
+}
+
Index: clang/test/CodeGen/finite-loops.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/finite-loops.c
@@ -0,0 +1,99 @@
+// RUN: %clang_cc1 -triple x86_64 -S -emit-llvm -std=c99 -o - %s | FileCheck %s -check-prefix=CHECK-C99-LOOPS
+// RUN: %clang_cc1 -triple x86_64 -S -emit-llvm -std=c99 -ffinite-loops -o - %s | FileCheck %s -check-prefix=CHECK-FINITE-LOOPS
+// RUN: %clang_cc1 -triple x86_64 -S -emit-llvm -std=c99 -fno-finite-loops -o - %s | FileCheck %s -check-prefix=CHECK-INFINITE-LOOPS
+// RUN: %clang_cc1 -triple x86_64 -S -emit-llvm -std=c11 -o - %s | FileCheck %s -check-prefix=CHECK-C11-LOOPS
+// RUN: %clang_cc1 -triple x86_64 -S -emit-llvm -std=c11 -ffinite-loops -o - %s | FileCheck %s -check-prefix=CHECK-FINITE-LOOPS
+// RUN: %clang_cc1 -triple x86_64 -S -emit-llvm -std=c11 -fno-finite-loops -o - %s | FileCheck %s -check-prefix=CHECK-INFINITE-LOOPS
+
+// CHECK-C99-LOOPS: Function Attrs: noinline nounwind optnone
+// CHECK-C99-LOOPS-LABEL: @f(
+// CHECK-C99-LOOPS-NOT:    {{.}} !llvm.loop !
+//
+// CHECK-FINITE-LOOPS: Function Attrs: noinline nounwind optnone mustprogress
+// CHECK-FINITE-LOOPS-LABEL: @f(
+// CHECK-FINITE-LOOPS:    {{.}} !llvm.loop !
+// CHECK-FINITE-LOOPS:    {{.}} !llvm.loop !
+//
+// CHECK-INFINITE-LOOPS: Function Attrs: noinline nounwind optnone
+// CHECK-INFINITE-LOOPS-LABEL: @f(
+// CHECK-INFINITE-LOOPS-NOT:    {{.}} !llvm.loop !
+//
+// CHECK-C11-LOOPS: Function Attrs: noinline nounwind optnone
+// CHECK-C11-LOOPS-LABEL: @f(
+// CHECK-C11-LOOPS:        {{.}} !llvm.loop !
+// CHECK-C11-LOOPS-NOT:    {{.}} !llvm.loop !
+//
+int f(int a, int b) {
+  for (; a != b; ) {
+    if (a == b)
+      return 1;
+  }
+
+  for (;;) {
+    if (a != b)
+      return 1;
+  }
+  return 0;
+}
+
+// CHECK-C99-LOOPS: Function Attrs: noinline nounwind optnone
+// CHECK-C99-LOOPS-LABEL: @dw(
+// CHECK-C99-LOOPS-NOT:    {{.}} !llvm.loop !
+//
+// CHECK-FINITE-LOOPS: Function Attrs: noinline nounwind optnone mustprogress
+// CHECK-FINITE-LOOPS-LABEL: @dw(
+// CHECK-FINITE-LOOPS:    {{.}} !llvm.loop !
+// CHECK-FINITE-LOOPS:    {{.}} !llvm.loop !
+//
+// CHECK-INFINITE-LOOPS: Function Attrs: noinline nounwind optnone
+// CHECK-INFINITE-LOOPS-LABEL: @dw(
+// CHECK-INFINITE-LOOPS-NOT:    {{.}} !llvm.loop !
+//
+// CHECK-C11-LOOPS: Function Attrs: noinline nounwind optnone
+// CHECK-C11-LOOPS-LABEL: @dw(
+// CHECK-C11-LOOPS:        {{.}} !llvm.loop !
+// CHECK-C11-LOOPS-NOT:    {{.}} !llvm.loop !
+//
+int dw(int a, int b) {
+  do {
+    if (a == b)
+      return 1;
+  } while (a != b);
+
+  do {
+    if (a != b)
+      return 1;
+  } while (1);
+  return 0;
+}
+
+// CHECK-C99-LOOPS: Function Attrs: noinline nounwind optnone
+// CHECK-C99-LOOPS-LABEL: @w(
+// CHECK-C99-LOOPS-NOT:    {{.}} !llvm.loop !
+//
+// CHECK-FINITE-LOOPS: Function Attrs: noinline nounwind optnone mustprogress
+// CHECK-FINITE-LOOPS-LABEL: @w(
+// CHECK-FINITE-LOOPS:    {{.}} !llvm.loop !
+// CHECK-FINITE-LOOPS:    {{.}} !llvm.loop !
+//
+// CHECK-INFINITE-LOOPS: Function Attrs: noinline nounwind optnone
+// CHECK-INFINITE-LOOPS-LABEL: @w(
+// CHECK-INFINITE-LOOPS-NOT:    {{.}} !llvm.loop !
+//
+// CHECK-C11-LOOPS: Function Attrs: noinline nounwind optnone
+// CHECK-C11-LOOPS-LABEL: @w(
+// CHECK-C11-LOOPS:        {{.}} !llvm.loop !
+// CHECK-C11-LOOPS-NOT:    {{.}} !llvm.loop !
+//
+int w(int a, int b) {
+  while(a != b) {
+    if (a == b) return 2;
+  }
+
+  while(1) {
+    if (a != b)
+      return 1;
+  }
+  return 0;
+}
+
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -981,6 +981,11 @@
   Opts.UnrollLoops =
       Args.hasFlag(OPT_funroll_loops, OPT_fno_unroll_loops,
                    (Opts.OptimizationLevel > 1));
+  Opts.FiniteLoops = Args.hasArg(OPT_ffinite_loops)
+                         ? CodeGenOptions::FiniteLoopsKind::Enforce
+                         : (Args.hasArg(OPT_fno_finite_loops)
+                                ? CodeGenOptions::FiniteLoopsKind::NeverEnforce
+                                : CodeGenOptions::FiniteLoopsKind::Default);
 
   Opts.DebugNameTable = static_cast<unsigned>(
       Args.hasArg(OPT_ggnu_pubnames)
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -5587,8 +5587,9 @@
   Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings);
   Args.AddLastArg(CmdArgs, options::OPT_funroll_loops,
                   options::OPT_fno_unroll_loops);
-
   Args.AddLastArg(CmdArgs, options::OPT_pthread);
+  Args.AddLastArg(CmdArgs, options::OPT_ffinite_loops,
+                  options::OPT_fno_finite_loops);
 
   if (Args.hasFlag(options::OPT_mspeculative_load_hardening,
                    options::OPT_mno_speculative_load_hardening, false))
Index: clang/lib/CodeGen/CGStmt.cpp
===================================================================
--- clang/lib/CodeGen/CGStmt.cpp
+++ clang/lib/CodeGen/CGStmt.cpp
@@ -804,6 +804,16 @@
   } else if (LanguageRequiresProgress())
     LoopMustProgress = true;
 
+  if (CGM.getCodeGenOpts().FiniteLoops ==
+      CodeGenOptions::FiniteLoopsKind::Enforce) {
+    FnIsMustProgress = true;
+    LoopMustProgress = true;
+  } else if (CGM.getCodeGenOpts().FiniteLoops ==
+             CodeGenOptions::FiniteLoopsKind::NeverEnforce) {
+    FnIsMustProgress = false;
+    LoopMustProgress = false;
+  }
+
   const SourceRange &R = S.getSourceRange();
   LoopStack.push(LoopHeader.getBlock(), CGM.getContext(), CGM.getCodeGenOpts(),
                  WhileAttrs, SourceLocToDebugLoc(R.getBegin()),
@@ -907,6 +917,16 @@
   } else if (LanguageRequiresProgress())
     LoopMustProgress = true;
 
+  if (CGM.getCodeGenOpts().FiniteLoops ==
+      CodeGenOptions::FiniteLoopsKind::Enforce) {
+    FnIsMustProgress = true;
+    LoopMustProgress = true;
+  } else if (CGM.getCodeGenOpts().FiniteLoops ==
+             CodeGenOptions::FiniteLoopsKind::NeverEnforce) {
+    FnIsMustProgress = false;
+    LoopMustProgress = false;
+  }
+
   const SourceRange &R = S.getSourceRange();
   LoopStack.push(LoopBody, CGM.getContext(), CGM.getCodeGenOpts(), DoAttrs,
                  SourceLocToDebugLoc(R.getBegin()),
@@ -959,6 +979,14 @@
       LoopMustProgress = true;
   }
 
+  if (CGM.getCodeGenOpts().FiniteLoops ==
+      CodeGenOptions::FiniteLoopsKind::Enforce) {
+    LoopMustProgress = true;
+  } else if (CGM.getCodeGenOpts().FiniteLoops ==
+             CodeGenOptions::FiniteLoopsKind::NeverEnforce) {
+    LoopMustProgress = false;
+  }
+
   const SourceRange &R = S.getSourceRange();
   LoopStack.push(CondBlock, CGM.getContext(), CGM.getCodeGenOpts(), ForAttrs,
                  SourceLocToDebugLoc(R.getBegin()),
@@ -1017,6 +1045,14 @@
   }
   incrementProfileCounter(&S);
 
+  if (CGM.getCodeGenOpts().FiniteLoops ==
+      CodeGenOptions::FiniteLoopsKind::Enforce) {
+    FnIsMustProgress = true;
+  } else if (CGM.getCodeGenOpts().FiniteLoops ==
+             CodeGenOptions::FiniteLoopsKind::NeverEnforce) {
+    FnIsMustProgress = false;
+  }
+
   {
     // Create a separate cleanup scope for the body, in case it is not
     // a compound statement.
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -2402,6 +2402,8 @@
 defm reroll_loops : BoolFOption<"reroll-loops",
   "CodeGenOpts.RerollLoops", DefaultsToFalse,
   ChangedBy<PosFlag, [], "Turn on loop reroller">, ResetBy<NegFlag>>;
+def ffinite_loops : Flag<["-"], "ffinite-loops">, Group<f_Group>, HelpText<"Assume that loops terminate">, Flags<[CC1Option]>;
+def fno_finite_loops : Flag<["-"], "fno-finite-loops">, Group<f_Group>, HelpText<"Don't assume that loops terminate">, 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
@@ -134,6 +134,12 @@
     All,         // Keep all frame pointers.
   };
 
+  enum FiniteLoopsKind {
+    Default,      // Follow the language standard
+    Enforce,      // Enforce finite loops
+    NeverEnforce, // Never enforce finite loops
+  };
+
   /// 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
@@ -260,6 +260,7 @@
                                                ///< traced by time profiler
 CODEGENOPT(UnrollLoops       , 1, 0) ///< Control whether loops are unrolled.
 CODEGENOPT(RerollLoops       , 1, 0) ///< Control whether loops are rerolled.
+CODEGENOPT(FiniteLoops       , 2, 0) ///< Control whether loops are assumed to terminate.
 CODEGENOPT(NoUseJumpTables   , 1, 0) ///< Set when -fno-jump-tables is enabled.
 CODEGENOPT(UnwindTables      , 1, 0) ///< Emit unwind tables.
 CODEGENOPT(VectorizeLoop     , 1, 0) ///< Run loop vectorizer.
Index: clang/docs/ClangCommandLineReference.rst
===================================================================
--- clang/docs/ClangCommandLineReference.rst
+++ clang/docs/ClangCommandLineReference.rst
@@ -2285,6 +2285,10 @@
 
 Turn on loop unroller
 
+.. option:: -ffinite-loops
+
+Assume that all loops must terminate. This takes precedence over the language standard.
+
 .. option:: -funsafe-math-optimizations, -fno-unsafe-math-optimizations
 
 .. option:: -funsigned-bitfields
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to