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
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to