diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/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; diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/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) diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2467,6 +2467,11 @@ defm reroll_loops : BoolFOption<"reroll-loops", CodeGenOpts<"RerollLoops">, DefaultFalse, PosFlag, NegFlag>; +def ffinite_loops: Flag<["-"], "ffinite-loops">, Group, + HelpText<"Assume all loops are finite.">, Flags<[CC1Option]>; +def fno_finite_loops: Flag<["-"], "fno-finite-loops">, Group, + HelpText<"Do not assume that any loop is finite.">, Flags<[CC1Option]>; + def ftrigraphs : Flag<["-"], "ftrigraphs">, Group, HelpText<"Process trigraph sequences">, Flags<[CC1Option]>; def fno_trigraphs : Flag<["-"], "fno-trigraphs">, Group, diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -508,6 +508,10 @@ /// Returns true if a function must make progress, which means the /// mustprogress attribute can be added. bool functionMustProgress() { + if (CGM.getCodeGenOpts().getFiniteLoops() == + CodeGenOptions::FiniteLoopsKind::Never) + return false; + // C++11 and later guarantees that a thread eventually will do one of the // following: // - terminate, @@ -524,6 +528,13 @@ /// attribute can be added. \p HasConstantCond indicates whether the branch /// condition is a known constant. bool loopMustProgress(bool HasConstantCond) { + if (CGM.getCodeGenOpts().getFiniteLoops() == + CodeGenOptions::FiniteLoopsKind::Always) + return true; + if (CGM.getCodeGenOpts().getFiniteLoops() == + CodeGenOptions::FiniteLoopsKind::Never) + return false; + // If the containing function must make progress, loops also must make // progress (as in C++11 and later). if (functionMustProgress()) diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -5625,6 +5625,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); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1633,7 +1633,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)); @@ -1921,6 +1920,11 @@ 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 && Diags.getNumErrors() == NumErrorsBefore; } diff --git a/clang/test/CodeGen/attr-mustprogress.c b/clang/test/CodeGen/attr-mustprogress.c --- a/clang/test/CodeGen/attr-mustprogress.c +++ b/clang/test/CodeGen/attr-mustprogress.c @@ -2,6 +2,9 @@ // 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; @@ -13,7 +16,9 @@ // CHECK-NEXT: entry: // CHECK-NEXT: br label %for.cond // CHECK: for.cond: -// CHECK-NOT: br {{.*}}!llvm.loop +// C99-NOT: br {{.*}}!llvm.loop +// C11-NOT: br {{.*}}!llvm.loop +// FINITE: br label %for.cond, !llvm.loop // void f0() { for (; ;) ; @@ -26,7 +31,9 @@ // CHECK: for.cond: // CHECK-NEXT: br i1 true, label %for.body, label %for.end // CHECK: for.body: -// CHECK-NOT: br {{.*}}, !llvm.loop +// C99-NOT: br {{.*}}, !llvm.loop +// C11-NOT: br {{.*}}, !llvm.loop +// FINITE: br label %for.cond, !llvm.loop // CHECK: for.end: // CHECK-NEXT: ret void // @@ -45,8 +52,9 @@ // 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:!.*]] +// 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 // @@ -62,7 +70,9 @@ // CHECK: for.cond: // CHECK-NEXT: br i1 true, label %for.body, label %for.end // CHECK: for.body: -// CHECK-NOT: br {{.*}}, !llvm.loop +// C99-NOT: br {{.*}}, !llvm.loop +// C11-NOT: br {{.*}}, !llvm.loop +// FINITE: br label %for.cond, !llvm.loop // CHECK: for.end: // CHECK-NEXT: br label %for.cond1 // CHECK: for.cond1: @@ -88,7 +98,9 @@ // CHECK-NEXT: entry: // CHECK-NEXT: br label %while.body // CHECK: while.body: -// CHECK-NOT: br {{.*}}, !llvm.loop +// C99-NOT: br {{.*}}, !llvm.loop +// C11-NOT: br {{.*}}, !llvm.loop +// FINITE: br {{.*}}, !llvm.loop void w1() { while (1) { } @@ -127,7 +139,9 @@ // C99-NOT: br {{.*}} !llvm.loop // C11-NEXT: br label %while.cond, !llvm.loop [[LOOP4:!.*]] // CHECK: while.body2: -// CHECK-NOT: br {{.*}} !llvm.loop +// C99-NOT: br {{.*}} !llvm.loop +// C11-NOT: br {{.*}} !llvm.loop +// FINITE: br label %while.body2, !llvm.loop // void W() { while (a == b) { @@ -143,7 +157,9 @@ // CHECK: do.body: // CHECK-NEXT: br label %do.cond // CHECK: do.cond: -// CHECK-NOT: br {{.*}}, !llvm.loop +// C99-NOT: br {{.*}}, !llvm.loop +// C11-NOT: br {{.*}}, !llvm.loop +// FINITE: br i1 true, label %do.body, label %do.end, !llvm.loop // CHECK: do.end: // CHECK-NEXT: ret void // diff --git a/clang/test/CodeGenCXX/attr-mustprogress.cpp b/clang/test/CodeGenCXX/attr-mustprogress.cpp --- a/clang/test/CodeGenCXX/attr-mustprogress.cpp +++ b/clang/test/CodeGenCXX/attr-mustprogress.cpp @@ -4,6 +4,12 @@ // 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; @@ -11,18 +17,21 @@ // CXX98-NOT: mustprogress // CXX11: mustprogress +// FINITE-NOT: mustprogress // CHECK-LABEL: @_Z2f0v( // CHECK-NEXT: entry: // CHECK-NEXT: br label %for.cond // CHECK: for.cond: // CXX98-NOT: br {{.*}} llvm.loop // CXX11-NEXT: br label %for.cond, !llvm.loop [[LOOP1:!.*]] +// FINITE-NEXT: br label %for.cond, !llvm.loop [[LOOP1:!.*]] void f0() { for (; ;) ; } // CXX98-NOT: mustprogress // CXX11: mustprogress +// FINITE-NOT: mustprogress // CHECK-LABEL: @_Z2f1v( // CHECK-NEXT: entry: // CHECK-NEXT: br label %for.cond @@ -31,6 +40,7 @@ // CHECK: for.body: // CXX98-NOT: br {{.*}}, !llvm.loop // CXX11-NEXT: br label %for.cond, !llvm.loop [[LOOP2:!.*]] +// FINITE-NEXT: br label %for.cond, !llvm.loop [[LOOP2:!.*]] // CHECK: for.end: // CHECK-NEXT: ret void // @@ -41,6 +51,7 @@ // CXX98-NOT: mustprogress // CXX11: mustprogress +// FINITE-NOT: mustprogress // CHECK-LABEL: @_Z2f2v( // CHECK-NEXT: entry: // CHECK-NEXT: br label %for.cond @@ -52,6 +63,7 @@ // 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: ret void // @@ -62,6 +74,7 @@ // CXX98-NOT: mustprogress // CXX11: mustprogress +// FINITE-NOT: mustprogress // CHECK-LABEL: @_Z1Fv( // CHECK-NEXT: entry: // CHECK-NEXT: br label %for.cond @@ -70,6 +83,7 @@ // CHECK: for.body: // CXX98-NOT: br {{.*}}, !llvm.loop // CXX11-NEXT: br label %for.cond, !llvm.loop [[LOOP4:!.*]] +// FINITE-NEXT: br label %for.cond, !llvm.loop [[LOOP4:!.*]] // CHECK: for.end: // CHECK-NEXT: br label %for.cond1 // CHECK: for.cond1: @@ -80,6 +94,7 @@ // CHECK: for.body2: // CXX98-NOT: br {{.*}}, !llvm.loop // CXX11-NEXT: br label %for.cond1, !llvm.loop [[LOOP5:!.*]] +// FINITE-NEXT: br label %for.cond1, !llvm.loop [[LOOP5:!.*]] // CHECK: for.end3: // CHECK-NEXT: ret void // @@ -91,7 +106,8 @@ } // CXX98-NOT: mustprogress -// CXX11_NOT: mustprogress +// CXX11: mustprogress +// FINITE-NOT: mustprogress // CHECK-LABEL: @_Z2F2v( // CHECK-NEXT: entry: // CHECK-NEXT: br label %for.cond @@ -103,6 +119,7 @@ // CHECK: for.body: // CXX98_NOT: br {{.*}} !llvm.loop // CXX11-NEXT: br label %for.cond, !llvm.loop [[LOOP6:!.*]] +// FINITE-NEXT: br label %for.cond, !llvm.loop [[LOOP6:!.*]] // CHECK: for.end: // CHECK-NEXT: br label %for.cond1 // CHECK: for.cond1: @@ -110,6 +127,7 @@ // CHECK: for.body2: // CXX98-NOT: br {{.*}}, !llvm.loop // CXX11-NEXT: br label %for.cond1, !llvm.loop [[LOOP7:!.*]] +// FINITE-NEXT: br label %for.cond1, !llvm.loop [[LOOP7:!.*]] // CHECK: for.end3: // CHECK-NEXT: ret void // @@ -122,12 +140,14 @@ // CXX98-NOT: mustprogress // CXX11: mustprogress +// FINITE-NOT: mustprogress // CHECK-LABEL: @_Z2w1v( // CHECK-NEXT: entry: // CHECK-NEXT: br label %while.body // CHECK: while.body: // CXX98-NOT: br {{.*}}, !llvm.loop // CXX11-NEXT: br label %while.body, !llvm.loop [[LOOP8:!.*]] +// FINITE-NEXT: br label %while.body, !llvm.loop [[LOOP8:!.*]] // void w1() { while (1) @@ -136,6 +156,7 @@ // CXX98-NOT: mustprogress // CXX11: mustprogress +// FINITE-NOT: mustprogress // CHECK-LABEL: @_Z2w2v( // CHECK-NEXT: entry: // CHECK-NEXT: br label %while.cond @@ -147,6 +168,7 @@ // CHECK: while.body: // CXX98-NOT: br {{.*}}, !llvm.loop // CXX11-NEXT: br label %while.cond, !llvm.loop [[LOOP9:!.*]] +// FINITE-NEXT: br label %while.cond, !llvm.loop [[LOOP9:!.*]] // CHECK: while.end: // CHECK-NEXT: ret void // @@ -157,6 +179,7 @@ // CXX98-NOT: mustprogress // CXX11: mustprogress +// FINITE-NOT: mustprogress // CHECK-LABEL: @_Z1Wv( // CHECK-NEXT: entry: // CHECK-NEXT: br label %while.cond @@ -168,11 +191,13 @@ // CHECK: while.body: // CXX98-NOT: br {{.*}}, !llvm.loop // CXX11-NEXT: br label %while.cond, !llvm.loop [[LOOP10:!.*]] +// FINITE-NEXT: br label %while.cond, !llvm.loop [[LOOP10:!.*]] // CHECK: while.end: // CHECK-NEXT: br label %while.body2 // CHECK: while.body2: // CXX98-NOT: br {{.*}}, !llvm.loop // CXX11-NEXT: br label %while.body2, !llvm.loop [[LOOP11:!.*]] +// FINITE-NEXT: br label %while.body2, !llvm.loop [[LOOP11:!.*]] // void W() { while (a == b) @@ -183,12 +208,14 @@ // CXX98-NOT: mustprogress // CXX11: mustprogress +// FINITE-NOT: mustprogress // CHECK-LABEL: @_Z2W2v( // CHECK-NEXT: entry: // CHECK-NEXT: br label %while.body // CHECK: while.body: // CXX98-NOT: br {{.*}}, !llvm.loop // CXX11-NEXT: br label %while.body, !llvm.loop [[LOOP12:!.*]] +// FINITE-NEXT: br label %while.body, !llvm.loop [[LOOP12:!.*]] // void W2() { while (1) @@ -199,6 +226,7 @@ // CXX98-NOT: mustprogress // CXX11: mustprogress +// FINITE-NOT: mustprogress // CHECK-LABEL: @_Z2d1v( // CHECK-NEXT: entry: // CHECK-NEXT: br label %do.body @@ -207,6 +235,7 @@ // CHECK: do.cond: // CXX98-NOT: br {{.*}}, !llvm.loop // CXX11-NEXT: br i1 true, label %do.body, label %do.end, !llvm.loop [[LOOP13:!.*]] +// FINITE-NEXT: br i1 true, label %do.body, label %do.end, !llvm.loop [[LOOP13:!.*]] // CHECK: do.end: // CHECK-NEXT: ret void // @@ -218,6 +247,7 @@ // CXX98-NOT: mustprogress // CXX11: mustprogress +// FINITE-NOT: mustprogress // CHECK-LABEL: @_Z2d2v( // CHECK-NEXT: entry: // CHECK-NEXT: br label %do.body @@ -229,6 +259,7 @@ // 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 [[LOOP14:!.*]] +// FINITE-NEXT: br i1 [[CMP]], label %do.body, label %do.end, !llvm.loop [[LOOP14:!.*]] // CHECK: do.end: // CHECK-NEXT: ret void // @@ -240,6 +271,7 @@ // CXX98-NOT: mustprogress // CXX11: mustprogress +// FINITE-NOT: mustprogress // CHECK-LABEL: @_Z1Dv( // CHECK-NEXT: entry: // CHECK-NEXT: br label %do.body @@ -248,6 +280,7 @@ // CHECK: do.cond: // CXX98-NOT: br {{.*}}, !llvm.loop // CXX11-NEXT: br i1 true, label %do.body, label %do.end, !llvm.loop [[LOOP15:!.*]] +// FINITE-NEXT: br i1 true, label %do.body, label %do.end, !llvm.loop [[LOOP15:!.*]] // CHECK: do.end: // CHECK-NEXT: br label %do.body1 // CHECK: do.body1: @@ -258,6 +291,7 @@ // 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 [[LOOP16:!.*]] +// FINITE-NEXT: br i1 [[CMP]], label %do.body1, label %do.end3, !llvm.loop [[LOOP16:!.*]] // CHECK: do.end3: // CHECK-NEXT: ret void // @@ -272,6 +306,7 @@ // CXX98-NOT: mustprogress // CXX11: mustprogress +// FINITE-NOT: mustprogress // CHECK-LABEL: @_Z2D2v( // CHECK-NEXT: entry: // CHECK-NEXT: br label %do.body @@ -283,6 +318,7 @@ // 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 [[LOOP17:!.*]] +// FINITE-NEXT: br i1 [[CMP]], label %do.body, label %do.end, !llvm.loop [[LOOP17:!.*]] // CHECK: do.end: // CHECK-NEXT: br label %do.body1 // CHECK: do.body1: @@ -290,6 +326,7 @@ // CHECK: do.cond2: // CXX98-NOT: br {{.*}}, !llvm.loop // CXX11-NEXT: br i1 true, label %do.body1, label %do.end3, !llvm.loop [[LOOP18:!.*]] +// FINITE-NEXT: br i1 true, label %do.body1, label %do.end3, !llvm.loop [[LOOP18:!.*]] // CHECK: do.end3: // CHECK-NEXT: ret void //