fhahn created this revision. fhahn added reviewers: jdoerfert, rjmccall, xbolva00, atmnpatel, aaron.ballman, rsmith. Herald added subscribers: dexonsmith, dang. Herald added a reviewer: jansvoboda11. fhahn requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
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/D96419 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.c clang/test/CodeGenCXX/attr-mustprogress.cpp
Index: clang/test/CodeGenCXX/attr-mustprogress.cpp =================================================================== --- clang/test/CodeGenCXX/attr-mustprogress.cpp +++ 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 // Index: clang/test/CodeGen/attr-mustprogress.c =================================================================== --- clang/test/CodeGen/attr-mustprogress.c +++ 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 // Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ 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,17 @@ Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true); + if (Arg *A = Args.getLastArg(OPT_save_temps_EQ)) + Opts.SaveTempsFilePrefix = + llvm::StringSwitch<std::string>(A->getValue()) + .Case("obj", OutputFile) + .Default(llvm::sys::path::filename(OutputFile).str()); + + if (Args.hasArg(options::OPT_ffinite_loops)) + Opts.FiniteLoops = CodeGenOptions::FiniteLoopsKind::Yes; + else if (Args.hasArg(options::OPT_fno_finite_loops)) + Opts.FiniteLoops = CodeGenOptions::FiniteLoopsKind::No; + return Success && Diags.getNumErrors() == NumErrorsBefore; } Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -4757,6 +4757,11 @@ assert(FPKeepKindStr && "unknown FramePointerKind"); CmdArgs.push_back(FPKeepKindStr); + if (Args.hasArg(options::OPT_ffinite_loops)) + CmdArgs.push_back("-ffinite-loops"); + else if (Args.hasArg(options::OPT_fno_finite_loops)) + CmdArgs.push_back("-fno-finite-loops"); + if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss, options::OPT_fno_zero_initialized_in_bss, true)) CmdArgs.push_back("-fno-zero-initialized-in-bss"); Index: clang/lib/CodeGen/CodeGenFunction.h =================================================================== --- clang/lib/CodeGen/CodeGenFunction.h +++ clang/lib/CodeGen/CodeGenFunction.h @@ -507,6 +507,10 @@ /// Returns true if the function must make progress. bool functionMustProgress() { + if (CGM.getCodeGenOpts().getFiniteLoops() == + CodeGenOptions::FiniteLoopsKind::No) + return false; + return getLangOpts().CPlusPlus11 || getLangOpts().CPlusPlus14 || getLangOpts().CPlusPlus17 || getLangOpts().CPlusPlus20; } @@ -515,6 +519,13 @@ /// Otherwise return false if the loop condition is a known constant and true /// if the language standard is C11+. bool loopMustProgress(bool HasConstantCond) { + if (CGM.getCodeGenOpts().getFiniteLoops() == + CodeGenOptions::FiniteLoopsKind::Yes) + return true; + if (CGM.getCodeGenOpts().getFiniteLoops() == + CodeGenOptions::FiniteLoopsKind::No) + return false; + if (functionMustProgress()) return true; if (HasConstantCond) Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -2467,6 +2467,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<"Process trigraph sequences">, Flags<[CC1Option]>; +def fno_finite_loops: Flag<["-"], "fno-finite-loops">, Group<f_Group>, + HelpText<"Process trigraph sequences">, 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 { + None = 0, // Not specified, use language standard. + Yes = 1, // All loops are assumed to be finite. + No = 2, // 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,8 @@ CODEGENOPT(VectorizeSLP , 1, 0) ///< Run SLP vectorizer. CODEGENOPT(ProfileSampleAccurate, 1, 0) ///< Sample profile is accurate. +ENUM_CODEGENOPT(FiniteLoops, FiniteLoopsKind, 2, FiniteLoopsKind::None) /// finite-loops: none, yes, no + /// 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