Izaron updated this revision to Diff 498622.
Izaron added a comment.

A small fix for `def FutureAttrs`


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D144334/new/

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,9 +1087,11 @@
 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]>;
+                                                            CXX20Attrs,
+                                                            CXX2bAttrs]>;
 
 // A warning group for warnings about using C++11 features as extensions in
 // earlier C++ versions.
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
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to