ahatanak updated this revision to Diff 37437.
ahatanak added a comment.
Address some of the review comments:
- Added a c++ test which tests the c++ spelling of the attribute on member
functions and shows which virtual functions calls get marked as "notail" in the
IR.
- Added a check that was missing in always_inline attribute handler.
- Fixed test/Sema/attr-notail.c to test always_inline and notail are mutually
exclusive, regardless of the order in which they are added to the function.
http://reviews.llvm.org/D12922
Files:
include/clang/Basic/Attr.td
include/clang/Basic/AttrDocs.td
lib/CodeGen/CGCall.cpp
lib/Sema/SemaDeclAttr.cpp
test/CodeGen/attr-no-tail.c
test/CodeGenCXX/attr-notail.cpp
test/Sema/attr-notail.c
Index: test/Sema/attr-notail.c
===================================================================
--- /dev/null
+++ test/Sema/attr-notail.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int callee0() __attribute__((notail,always_inline)); // expected-error{{'notail' and 'always_inline' attributes are not compatible}}
+int callee1() __attribute__((always_inline,notail)); // expected-error{{'always_inline' and 'notail' attributes are not compatible}}
+
+int foo(int a) {
+ return a ? callee0() : callee1();
+}
Index: test/CodeGenCXX/attr-notail.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/attr-notail.cpp
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -triple=x86_64-apple-darwin -std=c++11 %s -emit-llvm -o - | FileCheck %s
+
+class Base {
+public:
+ [[clang::notail]] virtual int foo1() {
+ return 0;
+ }
+ virtual ~Base() {}
+};
+
+class Derived1 : public Base {
+public:
+ int foo1() override {
+ return 1;
+ }
+};
+
+class Derived2 : public Derived1 {
+public:
+ [[clang::notail]] int foo1() override {
+ return 2;
+ }
+};
+
+// CHECK-LABEL: define i32 @_Z4foo1iP4BaseP8Derived1
+// CHECK: [[BASEFUNC:%[a-z0-9]+]] = load i32 (%class.Base*)*, i32 (%class.Base*)** {{%[a-z0-9]+}}
+// CHECK: {{%[a-z0-9]+}} = notail call i32 [[BASEFUNC]](%class.Base* {{%[a-z0-9]+}})
+// CHECK: [[DERIVEDFUNC1_1:%[a-z0-9]+]] = load i32 (%class.Derived1*)*, i32 (%class.Derived1*)** {{%[a-z0-9]+}}
+// CHECK: {{%[a-z0-9]+}} = call i32 [[DERIVEDFUNC1_1]](%class.Derived1* {{%[a-z0-9]+}})
+// CHECK: [[DERIVEDFUNC1_2:%[a-z0-9]+]] = load i32 (%class.Derived1*)*, i32 (%class.Derived1*)** {{%[a-z0-9]+}}
+// CHECK: {{%[a-z0-9]+}} = call i32 [[DERIVEDFUNC1_2]](%class.Derived1* {{%[a-z0-9]+}})
+// CHECK: [[DERIVEDFUNC2:%[a-z0-9]+]] = load i32 (%class.Derived2*)*, i32 (%class.Derived2*)** {{%[a-z0-9]+}}
+// CHECK: {{%[a-z0-9]+}} = notail call i32 [[DERIVEDFUNC2]](%class.Derived2* {{%[a-z0-9]+}})
+
+int foo1(int a, Base *b, Derived1 *d) {
+ if (a > 1)
+ return b->foo1(); // Tail-call is prevented.
+ if (a < 0)
+ return d->foo1(); // Tail-call is not prevented.
+ if (a == 0) {
+ Derived1 *i = new Derived2(); // Tail-call is not prevented.
+ return i->foo1();
+ }
+ Derived2 *i = new Derived2(); // Tail-call is prevented.
+ return i->foo1();
+}
Index: test/CodeGen/attr-no-tail.c
===================================================================
--- /dev/null
+++ test/CodeGen/attr-no-tail.c
@@ -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__((notail)) {
+ return a + 1;
+}
+
+int callee1(int) __attribute__((notail));
+
+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);
+}
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -1701,6 +1701,14 @@
Attr.getAttributeSpellingListIndex()));
}
+static void handleNoTailAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (checkAttrMutualExclusion<AlwaysInlineAttr>(S, D, Attr))
+ return;
+
+ D->addAttr(::new (S.Context) NoTailAttr(
+ 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()) {
@@ -3335,6 +3343,9 @@
static void handleAlwaysInlineAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
+ if (checkAttrMutualExclusion<NoTailAttr>(S, D, Attr))
+ return;
+
if (AlwaysInlineAttr *Inline = S.mergeAlwaysInlineAttr(
D, Attr.getRange(), Attr.getName(),
Attr.getAttributeSpellingListIndex()))
@@ -4907,6 +4918,9 @@
case AttributeList::AT_ReturnsTwice:
handleSimpleAttribute<ReturnsTwiceAttr>(S, D, Attr);
break;
+ case AttributeList::AT_NoTail:
+ handleNoTailAttr(S, D, Attr);
+ break;
case AttributeList::AT_Used:
handleUsedAttr(S, D, Attr);
break;
Index: lib/CodeGen/CGCall.cpp
===================================================================
--- lib/CodeGen/CGCall.cpp
+++ lib/CodeGen/CGCall.cpp
@@ -3492,6 +3492,10 @@
// 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<NoTailAttr>())
+ Call->setTailCallKind(llvm::CallInst::TCK_NoTail);
+
RValue Ret = [&] {
switch (RetAI.getKind()) {
case ABIArgInfo::InAlloca:
Index: include/clang/Basic/AttrDocs.td
===================================================================
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -1612,3 +1612,10 @@
arguments, with arbitrary offsets.
}];
}
+
+def NoTailDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+Tail call optimization is not performed on direct calls to a function marked ``notail``.
+ }];
+}
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -1020,6 +1020,12 @@
let Documentation = [Undocumented];
}
+def NoTail : InheritableAttr {
+ let Spellings = [GNU<"notail">, CXX11<"clang", "notail">];
+ let Subjects = SubjectList<[Function, ObjCMethod]>;
+ let Documentation = [NoTailDocs];
+}
+
def NoThrow : InheritableAttr {
let Spellings = [GCC<"nothrow">, Declspec<"nothrow">];
let Documentation = [Undocumented];
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits