r252369 - Add support for function attribute 'not_tail_called'.
Akira Hatanaka via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 6 15:56:16 PST 2015
Author: ahatanak
Date: Fri Nov 6 17:56:15 2015
New Revision: 252369
URL: http://llvm.org/viewvc/llvm-project?rev=252369&view=rev
Log:
Add support for function attribute 'not_tail_called'.
This attribute is used to prevent tail-call optimizations to the marked
function. For example, in the following piece of code, foo1 will not be
tail-call optimized:
int __attribute__((not_tail_called)) foo1(int);
int foo2(int a) {
return foo1(a); // Tail-call optimization is not performed.
}
The attribute has effect only on statically bound calls. It has no
effect on indirect calls. Also, virtual functions and objective-c
methods cannot be marked as 'not_tail_called'.
rdar://problem/22667622
Differential Revision: http://reviews.llvm.org/D12922
Added:
cfe/trunk/test/CodeGen/attr-no-tail.c
cfe/trunk/test/CodeGenCXX/attr-notail.cpp
cfe/trunk/test/Sema/attr-notail.c
cfe/trunk/test/SemaCXX/attr-notail.cpp
Modified:
cfe/trunk/include/clang/Basic/Attr.td
cfe/trunk/include/clang/Basic/AttrDocs.td
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/CodeGen/CGCall.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=252369&r1=252368&r2=252369&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Fri Nov 6 17:56:15 2015
@@ -1029,6 +1029,12 @@ def NoInstrumentFunction : InheritableAt
let Documentation = [Undocumented];
}
+def NotTailCalled : InheritableAttr {
+ let Spellings = [GNU<"not_tail_called">, CXX11<"clang", "not_tail_called">];
+ let Subjects = SubjectList<[Function]>;
+ let Documentation = [NotTailCalledDocs];
+}
+
def NoThrow : InheritableAttr {
let Spellings = [GCC<"nothrow">, Declspec<"nothrow">];
let Documentation = [Undocumented];
Modified: cfe/trunk/include/clang/Basic/AttrDocs.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AttrDocs.td?rev=252369&r1=252368&r2=252369&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/AttrDocs.td (original)
+++ cfe/trunk/include/clang/Basic/AttrDocs.td Fri Nov 6 17:56:15 2015
@@ -1620,3 +1620,52 @@ function are loads and stores from objec
arguments, with arbitrary offsets.
}];
}
+
+def NotTailCalledDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+The ``not_tail_called`` attribute prevents tail-call optimization on statically bound calls. It has no effect on indirect calls. Virtual functions, objective-c methods, and functions marked as ``always_inline`` cannot be marked as ``not_tail_called``.
+
+For example, it prevents tail-call optimization in the following case:
+ .. code-block: c
+ int __attribute__((not_tail_called)) foo1(int);
+
+ int foo2(int a) {
+ return foo1(a); // No tail-call optimization on direct calls.
+ }
+
+However, it doesn't prevent tail-call optimization in this case:
+ .. code-block: c
+ int __attribute__((not_tail_called)) foo1(int);
+
+ int foo2(int a) {
+ int (*fn)(int) = &foo1;
+
+ // not_tail_called has no effect on an indirect call even if the call can be
+ // resolved at compile time.
+ return (*fn)(a);
+ }
+
+Marking virtual functions as ``not_tail_called`` is an error:
+ .. code-block: c++
+ class Base {
+ public:
+ // not_tail_called on a virtual function is an error.
+ [[clang::not_tail_called]] virtual int foo1();
+
+ virtual int foo2();
+
+ // Non-virtual functions can be marked ``not_tail_called``.
+ [[clang::not_tail_called]] int foo3();
+ };
+
+ class Derived1 : public Base {
+ public:
+ int foo1() override;
+
+ // not_tail_called on a virtual function is an error.
+ [[clang::not_tail_called]] int foo2() override;
+ };
+
+ }];
+}
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=252369&r1=252368&r2=252369&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Nov 6 17:56:15 2015
@@ -2409,6 +2409,8 @@ def warn_attribute_not_on_decl : Warning
"%0 attribute ignored when parsing type">, InGroup<IgnoredAttributes>;
def err_base_specifier_attribute : Error<
"%0 attribute cannot be applied to a base specifier">;
+def err_invalid_attribute_on_virtual_function : Error<
+ "%0 attribute cannot be applied to virtual functions">;
// Availability attribute
def warn_availability_unknown_platform : Warning<
Modified: cfe/trunk/lib/CodeGen/CGCall.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=252369&r1=252368&r2=252369&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCall.cpp Fri Nov 6 17:56:15 2015
@@ -3493,6 +3493,10 @@ RValue CodeGenFunction::EmitCall(const C
// lexical order, so deactivate it and run it manually here.
CallArgs.freeArgumentMemory(*this);
+ if (llvm::CallInst *Call = dyn_cast<llvm::CallInst>(CI))
+ if (TargetDecl && TargetDecl->hasAttr<NotTailCalledAttr>())
+ Call->setTailCallKind(llvm::CallInst::TCK_NoTail);
+
RValue Ret = [&] {
switch (RetAI.getKind()) {
case ABIArgInfo::InAlloca:
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=252369&r1=252368&r2=252369&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Nov 6 17:56:15 2015
@@ -5373,6 +5373,16 @@ static void checkAttributesAfterMerging(
ND.setInvalidDecl();
}
}
+
+ // Virtual functions cannot be marked as 'notail'.
+ if (auto *Attr = ND.getAttr<NotTailCalledAttr>())
+ if (auto *MD = dyn_cast<CXXMethodDecl>(&ND))
+ if (MD->isVirtual()) {
+ S.Diag(ND.getLocation(),
+ diag::err_invalid_attribute_on_virtual_function)
+ << Attr;
+ ND.dropAttr<NotTailCalledAttr>();
+ }
}
static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=252369&r1=252368&r2=252369&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Fri Nov 6 17:56:15 2015
@@ -1701,6 +1701,15 @@ static void handleDependencyAttr(Sema &S
Attr.getAttributeSpellingListIndex()));
}
+static void handleNotTailCalledAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (checkAttrMutualExclusion<AlwaysInlineAttr>(S, D, Attr))
+ return;
+
+ D->addAttr(::new (S.Context) NotTailCalledAttr(
+ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
+}
+
static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (VD->hasLocalStorage()) {
@@ -3419,6 +3428,9 @@ OptimizeNoneAttr *Sema::mergeOptimizeNon
static void handleAlwaysInlineAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
+ if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, Attr))
+ return;
+
if (AlwaysInlineAttr *Inline = S.mergeAlwaysInlineAttr(
D, Attr.getRange(), Attr.getName(),
Attr.getAttributeSpellingListIndex()))
@@ -4991,6 +5003,9 @@ static void ProcessDeclAttribute(Sema &S
case AttributeList::AT_ReturnsTwice:
handleSimpleAttribute<ReturnsTwiceAttr>(S, D, Attr);
break;
+ case AttributeList::AT_NotTailCalled:
+ handleNotTailCalledAttr(S, D, Attr);
+ break;
case AttributeList::AT_Used:
handleUsedAttr(S, D, Attr);
break;
Added: cfe/trunk/test/CodeGen/attr-no-tail.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/attr-no-tail.c?rev=252369&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/attr-no-tail.c (added)
+++ cfe/trunk/test/CodeGen/attr-no-tail.c Fri Nov 6 17:56:15 2015
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.7.0 %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: %{{[a-z0-9]+}} = notail call i32 @callee0(i32 %
+// CHECK: %{{[a-z0-9]+}} = notail call i32 @callee1(i32 %
+
+// Check that indirect calls do not have the notail marker.
+// CHECK: store i32 (i32)* @callee1, i32 (i32)** [[ALLOCA1:%[A-Za-z0-9]+]], align 8
+// CHECK: [[INDIRFUNC:%[0-9]+]] = load i32 (i32)*, i32 (i32)** [[ALLOCA1]], align 8
+// CHECK: %{{[a-z0-9]+}} = call i32 [[INDIRFUNC]](i32 %6)
+
+// CHECK: %{{[a-z0-9]+}} = call i32 @callee2(i32 %
+
+int callee0(int a) __attribute__((not_tail_called)) {
+ return a + 1;
+}
+
+int callee1(int) __attribute__((not_tail_called));
+
+int callee2(int);
+
+typedef int (*FuncTy)(int);
+
+int foo0(int a) {
+ if (a > 1)
+ return callee0(a);
+ if (a == 1)
+ return callee1(a);
+ if (a < 0) {
+ FuncTy F = callee1;
+ return (*F)(a);
+ }
+ return callee2(a);
+}
Added: cfe/trunk/test/CodeGenCXX/attr-notail.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/attr-notail.cpp?rev=252369&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/attr-notail.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/attr-notail.cpp Fri Nov 6 17:56:15 2015
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -triple=x86_64-apple-darwin -std=c++11 -emit-llvm -o - %s | FileCheck %s
+
+class Class1 {
+public:
+ [[clang::not_tail_called]] int m1();
+ int m2();
+};
+
+int foo1(int a, Class1 *c1) {
+ if (a)
+ return c1->m1();
+ return c1->m2();
+}
+
+// CHECK-LABEL: define i32 @_Z4foo1iP6Class1(
+// CHECK: %{{[a-z0-9]+}} = notail call i32 @_ZN6Class12m1Ev(%class.Class1*
+// CHECK: %{{[a-z0-9]+}} = call i32 @_ZN6Class12m2Ev(%class.Class1*
Added: cfe/trunk/test/Sema/attr-notail.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-notail.c?rev=252369&view=auto
==============================================================================
--- cfe/trunk/test/Sema/attr-notail.c (added)
+++ cfe/trunk/test/Sema/attr-notail.c Fri Nov 6 17:56:15 2015
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int callee0() __attribute__((not_tail_called,always_inline)); // expected-error{{'not_tail_called' and 'always_inline' attributes are not compatible}}
+int callee1() __attribute__((always_inline,not_tail_called)); // expected-error{{'always_inline' and 'not_tail_called' attributes are not compatible}}
+
+int foo(int a) {
+ return a ? callee0() : callee1();
+}
+
+int g0 __attribute__((not_tail_called)); // expected-warning {{'not_tail_called' attribute only applies to functions}}
+
+int foo2(int a) __attribute__((not_tail_called("abc"))); // expected-error {{'not_tail_called' attribute takes no arguments}}
Added: cfe/trunk/test/SemaCXX/attr-notail.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-notail.cpp?rev=252369&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/attr-notail.cpp (added)
+++ cfe/trunk/test/SemaCXX/attr-notail.cpp Fri Nov 6 17:56:15 2015
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+class Base {
+public:
+ [[clang::not_tail_called]] virtual int foo1(); // expected-error {{'not_tail_called' attribute cannot be applied to virtual functions}}
+ virtual int foo2();
+ [[clang::not_tail_called]] int foo3();
+ virtual ~Base() {}
+};
+
+class Derived1 : public Base {
+public:
+ int foo1() override;
+ [[clang::not_tail_called]] int foo2() override; // expected-error {{'not_tail_called' attribute cannot be applied to virtual functions}}
+ [[clang::not_tail_called]] int foo4();
+};
More information about the cfe-commits
mailing list