This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG003c0b9307bc: [Clang] always_inline statement  attribute 
(authored by xbolva00).
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D120717

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/CodeGen/CGCall.cpp
  clang/lib/CodeGen/CGStmt.cpp
  clang/lib/CodeGen/CodeGenFunction.h
  clang/lib/Sema/SemaStmtAttr.cpp
  clang/test/CodeGen/attr-alwaysinline.cpp
  clang/test/Parser/objc-implementation-attrs.m
  clang/test/Sema/attr-alwaysinline.cpp

Index: clang/test/Sema/attr-alwaysinline.cpp
===================================================================
--- /dev/null
+++ clang/test/Sema/attr-alwaysinline.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -verify -fsyntax-only %s
+
+int bar();
+
+[[gnu::always_inline]] void always_inline_fn(void) {}
+[[gnu::flatten]] void flatten_fn(void) {}
+
+[[gnu::noinline]] void noinline_fn(void) {}
+
+void foo() {
+  [[clang::always_inline]] bar();
+  [[clang::always_inline(0)]] bar(); // expected-error {{'always_inline' attribute takes no arguments}}
+  int x;
+  [[clang::always_inline]] int i = bar();  // expected-warning {{'always_inline' attribute only applies to functions and statements}}
+  [[clang::always_inline]] x = 0;          // expected-warning {{'always_inline' attribute is ignored because there exists no call expression inside the statement}}
+  [[clang::always_inline]] { asm("nop"); } // expected-warning {{'always_inline' attribute is ignored because there exists no call expression inside the statement}}
+  [[clang::always_inline]] label : x = 1;  // expected-warning {{'always_inline' attribute only applies to functions and statements}}
+
+  [[clang::always_inline]] always_inline_fn();
+  [[clang::always_inline]] noinline_fn(); // expected-warning {{statement attribute 'always_inline' has higher precedence than function attribute 'noinline'}}
+  [[clang::always_inline]] flatten_fn();  // expected-warning {{statement attribute 'always_inline' has higher precedence than function attribute 'flatten'}}
+
+  [[gnu::always_inline]] bar();         // expected-warning {{attribute is ignored on this statement as it only applies to functions; use '[[clang::always_inline]]' on statements}}
+  __attribute__((always_inline)) bar(); // expected-warning {{attribute is ignored on this statement as it only applies to functions; use '[[clang::always_inline]]' on statements}}
+}
+
+[[clang::always_inline]] static int i = bar(); // expected-warning {{'always_inline' attribute only applies to functions and statements}}
Index: clang/test/Parser/objc-implementation-attrs.m
===================================================================
--- clang/test/Parser/objc-implementation-attrs.m
+++ clang/test/Parser/objc-implementation-attrs.m
@@ -2,15 +2,15 @@
 
 @interface I1 @end
 
-// expected-warning@+1 {{'always_inline' attribute only applies to functions}}
+// expected-warning@+1 {{'always_inline' attribute only applies to functions and statements}}
 __attribute__((always_inline))
 @implementation I1 @end
 
-// expected-warning@+1 {{'always_inline' attribute only applies to functions}}
+// expected-warning@+1 {{'always_inline' attribute only applies to functions and statements}}
 __attribute__((always_inline))
 @implementation I1 (MyCat) @end
 
-// expected-warning@+1 {{'always_inline' attribute only applies to functions}}
+// expected-warning@+1 {{'always_inline' attribute only applies to functions and statements}}
 __attribute__((always_inline))
 // expected-warning@+1 {{cannot find interface declaration for 'I2'}}
 @implementation I2 @end
Index: clang/test/CodeGen/attr-alwaysinline.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/attr-alwaysinline.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -S -emit-llvm %s -triple x86_64-unknown-linux-gnu -o - | FileCheck %s
+
+bool bar();
+void f(bool, bool);
+void g(bool);
+
+void foo(int i) {
+  [[clang::always_inline]] bar();
+// CHECK: call noundef zeroext i1 @_Z3barv() #[[ALWAYSINLINEATTR:[0-9]+]]
+  [[clang::always_inline]] (i = 4, bar());
+// CHECK: call noundef zeroext i1 @_Z3barv() #[[ALWAYSINLINEATTR]]
+  [[clang::always_inline]] (void)(bar());
+// CHECK: call noundef zeroext i1 @_Z3barv() #[[ALWAYSINLINEATTR]]
+  [[clang::always_inline]] f(bar(), bar());
+// CHECK: call noundef zeroext i1 @_Z3barv() #[[ALWAYSINLINEATTR]]
+// CHECK: call noundef zeroext i1 @_Z3barv() #[[ALWAYSINLINEATTR]]
+// CHECK: call void @_Z1fbb({{.*}}) #[[ALWAYSINLINEATTR]]
+  [[clang::always_inline]] for (bar(); bar(); bar()) {}
+// CHECK: call noundef zeroext i1 @_Z3barv() #[[ALWAYSINLINEATTR]]
+// CHECK: call noundef zeroext i1 @_Z3barv() #[[ALWAYSINLINEATTR]]
+// CHECK: call noundef zeroext i1 @_Z3barv() #[[ALWAYSINLINEATTR]]
+  bar();
+// CHECK: call noundef zeroext i1 @_Z3barv()
+  [[gnu::always_inline]] bar();
+// CHECK: call noundef zeroext i1 @_Z3barv()
+}
+
+struct S {
+  friend bool operator==(const S &LHS, const S &RHS);
+};
+
+void func(const S &s1, const S &s2) {
+  [[clang::always_inline]]g(s1 == s2);
+// CHECK: call noundef zeroext i1 @_ZeqRK1SS1_({{.*}}) #[[ALWAYSINLINEATTR]]
+// CHECK: call void @_Z1gb({{.*}}) #[[ALWAYSINLINEATTR]]
+  bool b;
+  [[clang::always_inline]] b = s1 == s2;
+// CHECK: call noundef zeroext i1 @_ZeqRK1SS1_({{.*}}) #[[ALWAYSINLINEATTR]]
+}
+
+// CHECK: attributes #[[ALWAYSINLINEATTR]] = { alwaysinline }
Index: clang/lib/Sema/SemaStmtAttr.cpp
===================================================================
--- clang/lib/Sema/SemaStmtAttr.cpp
+++ clang/lib/Sema/SemaStmtAttr.cpp
@@ -241,6 +241,32 @@
   return ::new (S.Context) NoInlineAttr(S.Context, A);
 }
 
+static Attr *handleAlwaysInlineAttr(Sema &S, Stmt *St, const ParsedAttr &A,
+                                    SourceRange Range) {
+  AlwaysInlineAttr AIA(S.Context, A);
+  if (!AIA.isClangAlwaysInline()) {
+    S.Diag(St->getBeginLoc(), diag::warn_function_attribute_ignored_in_stmt)
+        << "[[clang::always_inline]]";
+    return nullptr;
+  }
+
+  CallExprFinder CEF(S, St);
+  if (!CEF.foundCallExpr()) {
+    S.Diag(St->getBeginLoc(), diag::warn_attribute_ignored_no_calls_in_stmt)
+        << A;
+    return nullptr;
+  }
+
+  for (const auto *CallExpr : CEF.getCallExprs()) {
+    const Decl *Decl = CallExpr->getCalleeDecl();
+    if (Decl->hasAttr<NoInlineAttr>() || Decl->hasAttr<FlattenAttr>())
+      S.Diag(St->getBeginLoc(), diag::warn_function_stmt_attribute_precedence)
+          << A << (Decl->hasAttr<NoInlineAttr>() ? 2 : 1);
+  }
+
+  return ::new (S.Context) AlwaysInlineAttr(S.Context, A);
+}
+
 static Attr *handleMustTailAttr(Sema &S, Stmt *St, const ParsedAttr &A,
                                 SourceRange Range) {
   // Validation is in Sema::ActOnAttributedStmt().
@@ -440,6 +466,8 @@
     return nullptr;
 
   switch (A.getKind()) {
+  case ParsedAttr::AT_AlwaysInline:
+    return handleAlwaysInlineAttr(S, St, A, Range);
   case ParsedAttr::AT_FallThrough:
     return handleFallThroughAttr(S, St, A, Range);
   case ParsedAttr::AT_LoopHint:
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -554,6 +554,9 @@
   /// True if the current statement has noinline attribute.
   bool InNoInlineAttributedStmt = false;
 
+  /// True if the current statement has always_inline attribute.
+  bool InAlwaysInlineAttributedStmt = false;
+
   // The CallExpr within the current statement that the musttail attribute
   // applies to.  nullptr if there is no 'musttail' on the current statement.
   const CallExpr *MustTailCall = nullptr;
Index: clang/lib/CodeGen/CGStmt.cpp
===================================================================
--- clang/lib/CodeGen/CGStmt.cpp
+++ clang/lib/CodeGen/CGStmt.cpp
@@ -667,23 +667,33 @@
 void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
   bool nomerge = false;
   bool noinline = false;
+  bool alwaysinline = false;
   const CallExpr *musttail = nullptr;
 
   for (const auto *A : S.getAttrs()) {
-    if (A->getKind() == attr::NoMerge) {
+    switch (A->getKind()) {
+    default:
+      break;
+    case attr::NoMerge:
       nomerge = true;
-    }
-    if (A->getKind() == attr::NoInline) {
+      break;
+    case attr::NoInline:
       noinline = true;
-    }
-    if (A->getKind() == attr::MustTail) {
+      break;
+    case attr::AlwaysInline:
+      alwaysinline = true;
+      break;
+    case attr::MustTail:
       const Stmt *Sub = S.getSubStmt();
       const ReturnStmt *R = cast<ReturnStmt>(Sub);
       musttail = cast<CallExpr>(R->getRetValue()->IgnoreParens());
+      break;
     }
   }
   SaveAndRestore<bool> save_nomerge(InNoMergeAttributedStmt, nomerge);
   SaveAndRestore<bool> save_noinline(InNoInlineAttributedStmt, noinline);
+  SaveAndRestore<bool> save_alwaysinline(InAlwaysInlineAttributedStmt,
+                                         alwaysinline);
   SaveAndRestore<const CallExpr *> save_musttail(MustTailCall, musttail);
   EmitStmt(S.getSubStmt(), S.getAttrs());
 }
Index: clang/lib/CodeGen/CGCall.cpp
===================================================================
--- clang/lib/CodeGen/CGCall.cpp
+++ clang/lib/CodeGen/CGCall.cpp
@@ -5248,6 +5248,11 @@
   if (InNoInlineAttributedStmt)
     Attrs = Attrs.addFnAttribute(getLLVMContext(), llvm::Attribute::NoInline);
 
+  // Add call-site always_inline attribute if exists.
+  if (InAlwaysInlineAttributedStmt)
+    Attrs =
+        Attrs.addFnAttribute(getLLVMContext(), llvm::Attribute::AlwaysInline);
+
   // Apply some call-site-specific attributes.
   // TODO: work this into building the attribute set.
 
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4052,7 +4052,7 @@
   InGroup<IgnoredAttributes>;
 def warn_function_stmt_attribute_precedence : Warning<
   "statement attribute %0 has higher precedence than function attribute "
-  "'%select{always_inline|flatten}1'">,
+  "'%select{always_inline|flatten|noinline}1'">,
   InGroup<IgnoredAttributes>;
 def note_declared_nonnull : Note<
   "declared %select{'returns_nonnull'|'nonnull'}0 here">;
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -6241,7 +6241,28 @@
 Inlining heuristics are disabled and inlining is always attempted regardless of
 optimization level.
 
-Does not guarantee that inline substitution actually occurs.
+``[[clang::always_inline]]`` spelling can be used as a statement attribute; other
+spellings of the attribute are not supported on statements. If a statement is
+marked ``[[clang::always_inline]]`` and contains calls, the compiler attempts
+to inline those calls.
+
+.. code-block:: c
+
+  int example(void) {
+    int i;
+    [[clang::always_inline]] foo(); // attempts to inline foo
+    [[clang::always_inline]] i = bar(); // attempts to inline bar
+    [[clang::always_inline]] return f(42, baz(bar())); // attempts to inline everything
+  }
+
+A declaration statement, which is a statement, is not a statement that can have an
+attribute associated with it (the attribute applies to the declaration, not the
+statement in that case). So this use case will not work:
+
+.. code-block:: c
+  [[clang::always_inline]] int i = bar();
+
+This attribute does not guarantee that inline substitution actually occurs.
 
 <ins>Note: applying this attribute to a coroutine at the `-O0` optimization level
 has no effect; other optimization levels may only partially inline and result in a
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -706,9 +706,13 @@
   let Documentation = [Undocumented];
 }
 
-def AlwaysInline : InheritableAttr {
-  let Spellings = [GCC<"always_inline">, Keyword<"__forceinline">];
-  let Subjects = SubjectList<[Function]>;
+def AlwaysInline : DeclOrStmtAttr {
+  let Spellings = [GCC<"always_inline">, CXX11<"clang", "always_inline">,
+                   C2x<"clang", "always_inline">, Keyword<"__forceinline">];
+  let Accessors = [Accessor<"isClangAlwaysInline", [CXX11<"clang", "always_inline">,
+                                                    C2x<"clang", "always_inline">]>];
+  let Subjects = SubjectList<[Function, Stmt], WarnDiag,
+                             "functions and statements">;
   let Documentation = [AlwaysInlineDocs];
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to