[clang] Add mustprogress and llvm.loop.mustprogress attribute deduction
Since C++11, the C++ standard has a forward progress guarantee
[intro.progress], so all such functions must have the `mustprogress`
requirement. In addition, from C11 and onwards, loops without a non-zero
constant conditional or no conditional are also required to make
progress (C11 6.8.5p6). This patch implements these attribute deductions
so they can be used by the optimization passes.
Differential Revision: https://reviews.llvm.org/D86841
diff --git a/clang/test/CodeGen/attr-mustprogress-1.cpp b/clang/test/CodeGen/attr-mustprogress-1.cpp
new file mode 100644
index 0000000..6d53d2d
--- /dev/null
+++ b/clang/test/CodeGen/attr-mustprogress-1.cpp
@@ -0,0 +1,261 @@
+// 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: @_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);
+}
+