Skip to content

Commit 51bf4c0

Browse files
committed
[clang] Add -ffinite-loops & -fno-finite-loops options.
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. Reviewed By: jdoerfert Differential Revision: https://reviews.llvm.org/D96419
1 parent 4fc2557 commit 51bf4c0

File tree

8 files changed

+102
-39
lines changed

8 files changed

+102
-39
lines changed

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,9 @@ CODEGENOPT(VectorizeLoop , 1, 0) ///< Run loop vectorizer.
266266
CODEGENOPT(VectorizeSLP , 1, 0) ///< Run SLP vectorizer.
267267
CODEGENOPT(ProfileSampleAccurate, 1, 0) ///< Sample profile is accurate.
268268

269+
/// Treat loops as finite: language, always, never.
270+
ENUM_CODEGENOPT(FiniteLoops, FiniteLoopsKind, 2, FiniteLoopsKind::Language)
271+
269272
/// Attempt to use register sized accesses to bit-fields in structures, when
270273
/// possible.
271274
CODEGENOPT(UseRegisterSizedBitfieldAccess , 1, 0)

clang/include/clang/Basic/CodeGenOptions.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ class CodeGenOptions : public CodeGenOptionsBase {
140140
All, // Keep all frame pointers.
141141
};
142142

143+
enum FiniteLoopsKind {
144+
Language, // Not specified, use language standard.
145+
Always, // All loops are assumed to be finite.
146+
Never, // No loop is assumed to be finite.
147+
};
148+
143149
/// The code model to use (-mcmodel).
144150
std::string CodeModel;
145151

clang/include/clang/Driver/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2469,6 +2469,11 @@ def fno_unroll_loops : Flag<["-"], "fno-unroll-loops">, Group<f_Group>,
24692469
defm reroll_loops : BoolFOption<"reroll-loops",
24702470
CodeGenOpts<"RerollLoops">, DefaultFalse,
24712471
PosFlag<SetTrue, [CC1Option], "Turn on loop reroller">, NegFlag<SetFalse>>;
2472+
def ffinite_loops: Flag<["-"], "ffinite-loops">, Group<f_Group>,
2473+
HelpText<"Assume all loops are finite.">, Flags<[CC1Option]>;
2474+
def fno_finite_loops: Flag<["-"], "fno-finite-loops">, Group<f_Group>,
2475+
HelpText<"Do not assume that any loop is finite.">, Flags<[CC1Option]>;
2476+
24722477
def ftrigraphs : Flag<["-"], "ftrigraphs">, Group<f_Group>,
24732478
HelpText<"Process trigraph sequences">, Flags<[CC1Option]>;
24742479
def fno_trigraphs : Flag<["-"], "fno-trigraphs">, Group<f_Group>,

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,12 +507,26 @@ class CodeGenFunction : public CodeGenTypeCache {
507507

508508
/// True if the C++ Standard Requires Progress.
509509
bool CPlusPlusWithProgress() {
510+
if (CGM.getCodeGenOpts().getFiniteLoops() ==
511+
CodeGenOptions::FiniteLoopsKind::Never)
512+
return false;
513+
if (CGM.getCodeGenOpts().getFiniteLoops() ==
514+
CodeGenOptions::FiniteLoopsKind::Never)
515+
return false;
516+
510517
return getLangOpts().CPlusPlus11 || getLangOpts().CPlusPlus14 ||
511518
getLangOpts().CPlusPlus17 || getLangOpts().CPlusPlus20;
512519
}
513520

514521
/// True if the C Standard Requires Progress.
515522
bool CWithProgress() {
523+
if (CGM.getCodeGenOpts().getFiniteLoops() ==
524+
CodeGenOptions::FiniteLoopsKind::Always)
525+
return true;
526+
if (CGM.getCodeGenOpts().getFiniteLoops() ==
527+
CodeGenOptions::FiniteLoopsKind::Never)
528+
return false;
529+
516530
return getLangOpts().C11 || getLangOpts().C17 || getLangOpts().C2x;
517531
}
518532

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5640,6 +5640,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
56405640
if (A->getOption().matches(options::OPT_freroll_loops))
56415641
CmdArgs.push_back("-freroll-loops");
56425642

5643+
Args.AddLastArg(CmdArgs, options::OPT_ffinite_loops,
5644+
options::OPT_fno_finite_loops);
5645+
56435646
Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings);
56445647
Args.AddLastArg(CmdArgs, options::OPT_funroll_loops,
56455648
options::OPT_fno_unroll_loops);

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1633,7 +1633,6 @@ bool CompilerInvocation::ParseCodeGenArgsImpl(CodeGenOptions &Opts,
16331633
Opts.UnrollLoops =
16341634
Args.hasFlag(OPT_funroll_loops, OPT_fno_unroll_loops,
16351635
(Opts.OptimizationLevel > 1));
1636-
16371636
Opts.BinutilsVersion =
16381637
std::string(Args.getLastArgValue(OPT_fbinutils_version_EQ));
16391638

@@ -1921,6 +1920,11 @@ bool CompilerInvocation::ParseCodeGenArgsImpl(CodeGenOptions &Opts,
19211920

19221921
Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true);
19231922

1923+
if (Args.hasArg(options::OPT_ffinite_loops))
1924+
Opts.FiniteLoops = CodeGenOptions::FiniteLoopsKind::Always;
1925+
else if (Args.hasArg(options::OPT_fno_finite_loops))
1926+
Opts.FiniteLoops = CodeGenOptions::FiniteLoopsKind::Never;
1927+
19241928
return Success && Diags.getNumErrors() == NumErrorsBefore;
19251929
}
19261930

clang/test/CodeGen/attr-mustprogress.c

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
// RUN: %clang_cc1 -std=c11 -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=C11 %s
33
// RUN: %clang_cc1 -std=c18 -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=C11 %s
44
// RUN: %clang_cc1 -std=c2x -triple=x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK --check-prefix=C11 %s
5+
//
6+
// 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
7+
// 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
58

69
int a = 0;
710
int b = 0;
@@ -13,7 +16,7 @@ int b = 0;
1316
// CHECK-NEXT: entry:
1417
// CHECK-NEXT: br label %for.cond
1518
// CHECK: for.cond:
16-
// CHECK-NOT: br {{.*}}!llvm.loop
19+
// CHECK-NOT: br {{.*}}!llvm.loop
1720
//
1821
void f0() {
1922
for (; ;) ;
@@ -45,8 +48,9 @@ void f1() {
4548
// CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]]
4649
// CHECK-NEXT: br i1 [[CMP]], label %for.body, label %for.end
4750
// CHECK: for.body:
48-
// C99-NOT: br {{.*}} !llvm.loop
49-
// C11: br label %for.cond, !llvm.loop [[LOOP1:!.*]]
51+
// C99-NOT: br {{.*}} !llvm.loop
52+
// C11: br label %for.cond, !llvm.loop [[LOOP1:!.*]]
53+
// FINITE: br label %for.cond, !llvm.loop [[LOOP1:!.*]]
5054
// CHECK: for.end:
5155
// CHECK-NEXT: ret void
5256
//
@@ -73,6 +77,7 @@ void f2() {
7377
// CHECK: for.body2:
7478
// C99-NOT: br {{.*}}, !llvm.loop
7579
// C11: br label %for.cond1, !llvm.loop [[LOOP2:!.*]]
80+
// FINITE: br label %for.cond1, !llvm.loop [[LOOP2:!.*]]
7681
// CHECK: for.end3:
7782
// CHECK-NEXT: ret void
7883
//
@@ -88,7 +93,8 @@ void F() {
8893
// CHECK-NEXT: entry:
8994
// CHECK-NEXT: br label %while.body
9095
// CHECK: while.body:
91-
// CHECK-NOT: br {{.*}}, !llvm.loop
96+
// CHECK-NOT: br {{.*}}, !llvm.loop
97+
//
9298
void w1() {
9399
while (1) {
94100
}
@@ -104,8 +110,9 @@ void w1() {
104110
// CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]]
105111
// CHECK-NEXT: br i1 [[CMP]], label %while.body, label %while.end
106112
// CHECK: while.body:
107-
// C11: br label %while.cond, [[LOOP5:!llvm.loop !.*]]
108113
// C99-NOT: br {{.*}}, !llvm.loop
114+
// C11: br label %while.cond, !llvm.loop [[LOOP3:!.*]]
115+
// FINITE: br label %while.cond, !llvm.loop [[LOOP3:!.*]]
109116
// CHECK: while.end:
110117
// CHECK-NEXT: ret void
111118
//
@@ -125,7 +132,8 @@ void w2() {
125132
// CHECK-NEXT: br i1 [[CMP]], label %while.body, label %while.end
126133
// CHECK: while.body:
127134
// C99-NOT: br {{.*}} !llvm.loop
128-
// C11: br label %while.cond, !llvm.loop [[LOOP3:!.*]]
135+
// C11: br label %while.cond, !llvm.loop [[LOOP4:!.*]]
136+
// FINITE: br label %while.cond, !llvm.loop [[LOOP4:!.*]]
129137
// CHECK: while.end:
130138
// CHECK-NEXT: br label %while.body2
131139
// CHECK: while.body2:
@@ -165,7 +173,8 @@ void d1() {
165173
// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @b, align 4
166174
// CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]]
167175
// C99-NOT: br {{.*}}, !llvm.loop
168-
// C11: br i1 [[CMP]], label %do.body, label %do.end, !llvm.loop [[LOOP4:!.*]]
176+
// C11: br i1 [[CMP]], label %do.body, label %do.end, !llvm.loop [[LOOP5:!.*]]
177+
// FINITE: br i1 [[CMP]], label %do.body, label %do.end, !llvm.loop [[LOOP5:!.*]]
169178
// CHECK: do.end:
170179
// CHECK-NEXT: ret void
171180
//
@@ -191,7 +200,8 @@ void d2() {
191200
// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @b, align 4
192201
// CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]]
193202
// C99-NOT: br {{.*}}, !llvm.loop
194-
// C11: br i1 [[CMP]], label %do.body1, label %do.end3, !llvm.loop [[LOOP5:!.*]]
203+
// C11: br i1 [[CMP]], label %do.body1, label %do.end3, !llvm.loop [[LOOP6:!.*]]
204+
// FINITE: br i1 [[CMP]], label %do.body1, label %do.end3, !llvm.loop [[LOOP6:!.*]]
195205
// CHECK: do.end3:
196206
// CHECK-NEXT: ret void
197207
//
@@ -208,3 +218,4 @@ void D() {
208218
// C11: [[LOOP3]] = distinct !{[[LOOP3]], [[MP]]}
209219
// C11: [[LOOP4]] = distinct !{[[LOOP4]], [[MP]]}
210220
// C11: [[LOOP5]] = distinct !{[[LOOP5]], [[MP]]}
221+
// C11: [[LOOP6]] = distinct !{[[LOOP6]], [[MP]]}

0 commit comments

Comments
 (0)