]> granicus.if.org Git - clang/commitdiff
Implement the flatten attribute.
authorPeter Collingbourne <peter@pcc.me.uk>
Tue, 20 May 2014 17:12:51 +0000 (17:12 +0000)
committerPeter Collingbourne <peter@pcc.me.uk>
Tue, 20 May 2014 17:12:51 +0000 (17:12 +0000)
This is a GNU attribute that causes calls within the attributed function
to be inlined where possible. It is implemented by giving such calls the
alwaysinline attribute.

Differential Revision: http://reviews.llvm.org/D3816

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@209217 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/Attr.td
include/clang/Basic/AttrDocs.td
lib/CodeGen/CGCall.cpp
lib/Sema/SemaDeclAttr.cpp
test/CodeGen/flatten.c [new file with mode: 0644]
test/CodeGenCXX/flatten.cpp [new file with mode: 0644]
test/SemaCXX/attr-flatten.cpp [new file with mode: 0644]

index e054d6a8fb9391a9d003ea1a0302ec8b2149aba3..1b011b06868eba2b058afd64f513f5b3890ba44a 100644 (file)
@@ -668,6 +668,12 @@ def MinSize : InheritableAttr {
   let Documentation = [Undocumented];
 }
 
+def Flatten : InheritableAttr {
+  let Spellings = [GCC<"flatten">];
+  let Subjects = SubjectList<[Function], ErrorDiag>;
+  let Documentation = [FlattenDocs];
+}
+
 def Format : InheritableAttr {
   let Spellings = [GCC<"format">];
   let Args = [IdentifierArgument<"Type">, IntArgument<"FormatIdx">,
index a0c2028512a3d53d6340ff38e761bec50e19a86f..9694e210909e6dd20a969fc5a5c5d1675a558d57 100644 (file)
@@ -877,6 +877,14 @@ expression is compared to the type tag.  There are two supported flags:
   }];
 }
 
+def FlattenDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+The ``flatten`` attribute causes calls within the attributed function to be
+inlined if possible.
+  }];
+}
+
 def FormatDocs : Documentation {
   let Category = DocCatFunction;
   let Content = [{
index e477a54c67efeb3dd402551f9e5774fb56c3c889..31665f8851ad1c3c9235d7e102b5f9a0bbf74b87 100644 (file)
@@ -2935,6 +2935,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
   if (callOrInvoke)
     *callOrInvoke = CS.getInstruction();
 
+  if (CurCodeDecl && CurCodeDecl->hasAttr<FlattenAttr>() &&
+      !CS.hasFnAttr(llvm::Attribute::NoInline))
+    Attrs =
+        Attrs.addAttribute(getLLVMContext(), llvm::AttributeSet::FunctionIndex,
+                           llvm::Attribute::AlwaysInline);
+
   CS.setAttributes(Attrs);
   CS.setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
 
index b7c1d5d15b76d46c2e37dcbbced4e4dd7fbfd44d..9775c58639c20eb8b4b04f61c6f03f13bf8d1cf7 100644 (file)
@@ -4147,6 +4147,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
   case AttributeList::AT_OptimizeNone:
     handleOptimizeNoneAttr(S, D, Attr);
     break;
+  case AttributeList::AT_Flatten:
+    handleSimpleAttribute<FlattenAttr>(S, D, Attr);
+    break;
   case AttributeList::AT_Format:
     handleFormatAttr(S, D, Attr);
     break;
diff --git a/test/CodeGen/flatten.c b/test/CodeGen/flatten.c
new file mode 100644 (file)
index 0000000..d766d54
--- /dev/null
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple=x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s
+
+void f(void) {}
+
+__attribute__((noinline)) void ni(void) {}
+
+__attribute__((flatten))
+// CHECK: define void @g()
+void g(void) {
+  // CHECK-NOT: call {{.*}} @f
+  f();
+  // CHECK: call {{.*}} @ni
+  ni();
+}
+
+void h(void) {
+  // CHECK: call {{.*}} @f
+  f();
+}
diff --git a/test/CodeGenCXX/flatten.cpp b/test/CodeGenCXX/flatten.cpp
new file mode 100644 (file)
index 0000000..9e0f67f
--- /dev/null
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple=x86_64-linux-gnu -std=c++11 %s -emit-llvm -o - | FileCheck %s
+
+void f(void) {}
+
+[[gnu::flatten]]
+// CHECK: define void @_Z1gv()
+void g(void) {
+  // CHECK-NOT: call {{.*}} @_Z1fv
+  f();
+}
diff --git a/test/SemaCXX/attr-flatten.cpp b/test/SemaCXX/attr-flatten.cpp
new file mode 100644 (file)
index 0000000..afcba72
--- /dev/null
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+int i __attribute__((flatten)); // expected-error {{'flatten' attribute only applies to functions}}
+
+void f1() __attribute__((flatten));
+void f2() __attribute__((flatten(1))); // expected-error {{'flatten' attribute takes no arguments}}
+
+template <typename T>
+void tf1() __attribute__((flatten));
+
+int f3(int __attribute__((flatten)), int); // expected-error{{'flatten' attribute only applies to functions}}
+
+struct A {
+  int f __attribute__((flatten));  // expected-error{{'flatten' attribute only applies to functions}}
+  void mf1() __attribute__((flatten));
+  static void mf2() __attribute__((flatten));
+};
+
+int ci [[gnu::flatten]]; // expected-error {{'flatten' attribute only applies to functions}}
+
+[[gnu::flatten]] void cf1();
+[[gnu::flatten(1)]] void cf2(); // expected-error {{'flatten' attribute takes no arguments}}
+
+template <typename T>
+[[gnu::flatten]]
+void ctf1();
+
+int cf3(int c[[gnu::flatten]], int); // expected-error{{'flatten' attribute only applies to functions}}
+
+struct CA {
+  int f [[gnu::flatten]];  // expected-error{{'flatten' attribute only applies to functions}}
+  [[gnu::flatten]] void mf1();
+  [[gnu::flatten]] static void mf2();
+};