Izaron created this revision.
Izaron added reviewers: clang-language-wg, aaron.ballman, rsmith, nikic.
Herald added a subscriber: StephenFan.
Herald added a project: All.
Izaron requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
Clang already supports assumes for optimizing. Now it is standardized
in C++2b via a new attribute - https://wg21.link/p1774r8.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D144334
Files:
clang/docs/ReleaseNotes.rst
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/AttrDocs.td
clang/include/clang/Basic/DiagnosticGroups.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/CodeGen/CGStmt.cpp
clang/lib/Sema/SemaStmtAttr.cpp
clang/test/AST/ast-dump-attr.cpp
clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.assume/p1.cpp
clang/test/CodeGenCXX/cxx2b-assume.cpp
clang/www/cxx_status.html
Index: clang/www/cxx_status.html
===================================================================
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -1501,7 +1501,7 @@
<tr>
<td>Portable assumptions</td>
<td><a href="https://wg21.link/P1774R8">P1774R8</a></td>
- <td class="none" align="center">No</td>
+ <td class="unreleased" align="center">Clang 17</td>
</tr>
<tr>
<td>Support for UTF-8 as a portable source file encoding</td>
Index: clang/test/CodeGenCXX/cxx2b-assume.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/cxx2b-assume.cpp
@@ -0,0 +1,62 @@
+// RUN: %clang_cc1 -std=c++2b %s -emit-llvm -o - -triple x86_64-linux-gnu -disable-llvm-passes -DUSE_ASSUME | FileCheck %s
+// RUN: %clang_cc1 -std=c++2b %s -emit-llvm -o - -triple x86_64-linux-gnu -O3 | FileCheck --check-prefixes=CHECK-OPT-NOASSUME %s
+// RUN: %clang_cc1 -std=c++2b %s -emit-llvm -o - -triple x86_64-linux-gnu -O3 -DUSE_ASSUME | FileCheck --check-prefixes=CHECK-OPT %s
+
+// CHECK-LABEL: @_Z12divide_by_32i
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %[[VAR:.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 %x, ptr %[[VAR]], align 4
+// CHECK-NEXT: %0 = load i32, ptr %[[VAR]], align 4
+// CHECK-NEXT: %[[CMP:.*]] = icmp sge i32 %0, 0
+// CHECK-NEXT: call void @llvm.assume(i1 %[[CMP]])
+// CHECK-NEXT: %1 = load i32, ptr %[[VAR]], align 4
+// CHECK-NEXT: %[[DIV:.*]] = sdiv i32 %1, 32
+// CHECK-NEXT: ret i32 %[[DIV]]
+//
+// CHECK-OPT-NOASSUME-LABEL: @_Z12divide_by_32i
+// CHECK-OPT-NOASSUME-NEXT: entry:
+// CHECK-OPT-NOASSUME-NEXT: %[[DIV:.*]] = sdiv i32 %x, 32
+// CHECK-OPT-NOASSUME-NEXT: ret i32 %[[DIV]]
+//
+// CHECK-OPT-LABEL: @_Z12divide_by_32i
+// CHECK-OPT-NEXT: entry:
+// CHECK-OPT-NEXT: %[[CMP:.*]] = icmp sgt i32 %x, -1
+// CHECK-OPT-NEXT: tail call void @llvm.assume(i1 %[[CMP]])
+// CHECK-OPT-NEXT: %[[DIV:.*]] = lshr i32 %x, 5
+// CHECK-OPT-NEXT: ret i32 %[[DIV]]
+//
+int divide_by_32(int x) {
+#ifdef USE_ASSUME
+ [[assume(x >= 0)]];
+#endif
+ return x/32;
+}
+
+// CHECK-LABEL: @_Z9incrementi
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %[[VAR:.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 %y, ptr %[[VAR]], align 4
+// CHECK-NEXT: %0 = load i32, ptr %[[VAR]], align 4
+// CHECK-NEXT: %[[VARP1:.*]] = add nsw i32 %0, 1
+// CHECK-NEXT: store i32 %[[VARP1]], ptr %[[VAR]], align 4
+// CHECK-NEXT: %[[CMP:.*]] = icmp eq i32 %[[VARP1]], 43
+// CHECK-NEXT: call void @llvm.assume(i1 %[[CMP]])
+// CHECK-NEXT: %1 = load i32, ptr %[[VAR]], align 4
+// CHECK-NEXT: ret i32 %1
+//
+// CHECK-OPT-NOASSUME-LABEL: @_Z9incrementi
+// CHECK-OPT-NOASSUME-NEXT: entry:
+// CHECK-OPT-NOASSUME-NEXT: ret i32 %y
+//
+// CHECK-OPT-LABEL: @_Z9incrementi
+// CHECK-OPT-NEXT: entry:
+// CHECK-OPT-NEXT: %[[CMP:.*]] = icmp eq i32 %y, 42
+// CHECK-OPT-NEXT: tail call void @llvm.assume(i1 %[[CMP]])
+// CHECK-OPT-NEXT: ret i32 43
+//
+int increment(int y) {
+#ifdef USE_ASSUME
+ [[assume(++y == 43)]];
+#endif
+ return y;
+}
Index: clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.assume/p1.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.assume/p1.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunused -std=c++2b -verify %s
+
+int divide_by_32(int x) {
+ [[assume(x >= 0)]];
+ return x/32;
+}
+
+int increment(int y) {
+ [[assume(++y == 43)]];
+ return y;
+}
+
+[[assume(true)]] int incorrects(int y) { // expected-error {{'assume' attribute cannot be applied to a declaration}}
+ [[assume(++y == 43)]] int x = 0; // expected-error {{'assume' attribute cannot be applied to a declaration}}
+ [[assume(++y == 43)]] x = 0; // expected-error {{'assume' attribute only applies to empty statements}}
+ [[assume(++y == 43 && ++y == 44)]];
+ [[assume(++y == 43, ++y == 43)]]; // expected-error {{'assume' attribute takes one argument}}
+ [[assume]]; // expected-error {{'assume' attribute takes one argument}}
+ return y;
+}
Index: clang/test/AST/ast-dump-attr.cpp
===================================================================
--- clang/test/AST/ast-dump-attr.cpp
+++ clang/test/AST/ast-dump-attr.cpp
@@ -259,3 +259,14 @@
// CHECK-NEXT: AnnotateAttr{{.*}} Inherited
// CHECK-NEXT: UnusedAttr
// CHECK-NEXT: NoThreadSafetyAnalysisAttr
+
+namespace TestAssume {
+ int DivideBy32(int x) {
+ [[assume(x >= 0)]];
+ return x/32;
+ }
+ // CHECK: FunctionDecl{{.*}}DivideBy32
+ // CHECK: AttributedStmt
+ // CHECK-NEXT: AssumeAttr
+ // CHECK: NullStmt
+} // namespace TestAssume
Index: clang/lib/Sema/SemaStmtAttr.cpp
===================================================================
--- clang/lib/Sema/SemaStmtAttr.cpp
+++ clang/lib/Sema/SemaStmtAttr.cpp
@@ -291,6 +291,15 @@
return ::new (S.Context) UnlikelyAttr(S.Context, A);
}
+static Attr *handleAssume(Sema &S, Stmt *St, const ParsedAttr &A,
+ SourceRange Range) {
+
+ if (!S.getLangOpts().CPlusPlus2b)
+ S.Diag(A.getLoc(), diag::ext_cxx2b_attr) << A << Range;
+
+ return ::new (S.Context) AssumeAttr(S.Context, A, A.getArgAsExpr(0));
+}
+
#define WANT_STMT_MERGE_LOGIC
#include "clang/Sema/AttrParsedAttrImpl.inc"
#undef WANT_STMT_MERGE_LOGIC
@@ -490,6 +499,8 @@
return handleLikely(S, St, A, Range);
case ParsedAttr::AT_Unlikely:
return handleUnlikely(S, St, A, Range);
+ case ParsedAttr::AT_Assume:
+ return handleAssume(S, St, A, Range);
default:
// N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a
// declaration attribute is not written on a statement, but this code is
Index: clang/lib/CodeGen/CGStmt.cpp
===================================================================
--- clang/lib/CodeGen/CGStmt.cpp
+++ clang/lib/CodeGen/CGStmt.cpp
@@ -714,12 +714,19 @@
case attr::AlwaysInline:
alwaysinline = true;
break;
- case attr::MustTail:
+ case attr::MustTail: {
const Stmt *Sub = S.getSubStmt();
const ReturnStmt *R = cast<ReturnStmt>(Sub);
musttail = cast<CallExpr>(R->getRetValue()->IgnoreParens());
break;
}
+ case attr::Assume: {
+ llvm::Value *ArgValue = EmitScalarExpr(cast<AssumeAttr>(A)->getCond());
+ llvm::Function *FnAssume = CGM.getIntrinsic(llvm::Intrinsic::assume);
+ Builder.CreateCall(FnAssume, ArgValue);
+ break;
+ }
+ }
}
SaveAndRestore save_nomerge(InNoMergeAttributedStmt, nomerge);
SaveAndRestore save_noinline(InNoInlineAttributedStmt, noinline);
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8796,6 +8796,8 @@
"use of the %0 attribute is a C++17 extension">, InGroup<CXX17Attrs>;
def ext_cxx20_attr : Extension<
"use of the %0 attribute is a C++20 extension">, InGroup<CXX20Attrs>;
+def ext_cxx2b_attr : Extension<
+ "use of the %0 attribute is a C++2b extension">, InGroup<CXX2bAttrs>;
def warn_unused_comparison : Warning<
"%select{equality|inequality|relational|three-way}0 comparison result unused">,
Index: clang/include/clang/Basic/DiagnosticGroups.td
===================================================================
--- clang/include/clang/Basic/DiagnosticGroups.td
+++ clang/include/clang/Basic/DiagnosticGroups.td
@@ -1087,6 +1087,7 @@
def CXX14Attrs : DiagGroup<"c++14-attribute-extensions">;
def CXX17Attrs : DiagGroup<"c++17-attribute-extensions">;
def CXX20Attrs : DiagGroup<"c++20-attribute-extensions">;
+def CXX2bAttrs : DiagGroup<"c++2b-attribute-extensions">;
def FutureAttrs : DiagGroup<"future-attribute-extensions", [CXX14Attrs,
CXX17Attrs,
CXX20Attrs]>;
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -2100,6 +2100,36 @@
}];
}
+def AssumeDocs : Documentation {
+ let Category = DocCatStmt;
+ let Heading = "assume";
+ let Content = [{
+The ``assume`` attribute used to provide the optimizer with an expression that
+is defined to evaluate to ``true`` at the place the assumption occurs. The
+optimizer may analyze the form of the expression provided as the argument and
+deduce from that information used to optimize the program. If the condition is
+violated during execution, the behavior is undefined. The argument itself is
+never evaluated, so any side effects of the expression will be discarded.
+
+Example usage:
+
+.. code-block:: c++
+
+ int divide_by_32(int x) {
+ [[assume(x >= 0)]];
+ return x/32; // is equivalent to `return x>>5;`
+ }
+
+ int increment(int y) {
+ [[assume(++y == 43)]];
+ return y; // is equivalent to `return 42;`
+ }
+
+``[[assume(expression)]]`` is a standard C++23 attribute. Clang supports its
+use in C++11 onwards.
+ }];
+}
+
def ARMInterruptDocs : Documentation {
let Category = DocCatFunction;
let Heading = "interrupt (ARM)";
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -1444,6 +1444,13 @@
}
def : MutualExclusions<[Likely, Unlikely]>;
+def Assume : StmtAttr {
+ let Spellings = [CXX11<"", "assume", 202302>];
+ let Documentation = [AssumeDocs];
+ let Subjects = SubjectList<[NullStmt], ErrorDiag, "empty statements">;
+ let Args = [ExprArgument<"Cond">];
+}
+
def NoMerge : DeclOrStmtAttr {
let Spellings = [Clang<"nomerge">];
let Documentation = [NoMergeDocs];
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -133,6 +133,8 @@
C++2b Feature Support
^^^^^^^^^^^^^^^^^^^^^
+- Support the ``[[assume(expression)]]`` attribute (`P1774R8 <https://wg21.link/p1774r8>`_).
+
CUDA/HIP Language Changes in Clang
----------------------------------
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits