Author: Florian Hahn Date: 2021-02-19T21:48:47-08:00 New Revision: b5b31112bf63debaa905e42785317a947e696252
URL: https://github.com/llvm/llvm-project/commit/b5b31112bf63debaa905e42785317a947e696252 DIFF: https://github.com/llvm/llvm-project/commit/b5b31112bf63debaa905e42785317a947e696252.diff LOG: [clang] Add -ffinite-loops & -fno-finite-loops options. 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 Added: clang/test/CodeGen/attr-mustprogress.c clang/test/CodeGenCXX/attr-mustprogress.cpp Modified: 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 Removed: clang/test/CodeGen/attr-mustprogress-0.c clang/test/CodeGen/attr-mustprogress-0.cpp clang/test/CodeGen/attr-mustprogress-1.c clang/test/CodeGen/attr-mustprogress-1.cpp ################################################################################ diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 5c8af65326ed..9d53b5b923bb 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -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) diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index 73d41e3293c6..c550817f0f69 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -140,6 +140,12 @@ class CodeGenOptions : public CodeGenOptionsBase { 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/Driver/Options.td b/clang/include/clang/Driver/Options.td index 1f6c13d5cc96..817798926650 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -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>, diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 8eb7adbc8fcb..95c0b7b4d7c0 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -507,12 +507,23 @@ class CodeGenFunction : public CodeGenTypeCache { /// 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; } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index f8e637974662..1976b48e0f6a 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -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); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 036388ebd355..5c5cf46150e2 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -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 index 2af24e88ceef..000000000000 --- a/clang/test/CodeGen/attr-mustprogress-0.c +++ /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 index 3a180cc6b5ad..000000000000 --- a/clang/test/CodeGen/attr-mustprogress-0.cpp +++ /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 index 2ff068b8b90a..000000000000 --- a/clang/test/CodeGen/attr-mustprogress-1.c +++ /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 index 945d74663c6d..000000000000 --- a/clang/test/CodeGen/attr-mustprogress-1.cpp +++ /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 index 000000000000..1f83cd44b308 --- /dev/null +++ b/clang/test/CodeGen/attr-mustprogress.c @@ -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 index 000000000000..48ac7ad938ba --- /dev/null +++ b/clang/test/CodeGenCXX/attr-mustprogress.cpp @@ -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]]} _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits