ahatanak updated this revision to Diff 37172.
ahatanak added a comment.

I've made some changes following the discussion I had and the feedback I got on 
the llvm-side patch.

This is the link to the discussion thread:
http://thread.gmane.org/gmane.comp.compilers.llvm.cvs/271105/

The difference between the previous patch and this patch lies in the way 
indirect calls (at the source level) are handled. The approach taken in the 
previous patch attached the notail attribute to the declaration or definition 
of functions in the IR, which enabled blocking tail call optimization on an 
indirect call site if the compiler could statically determine it was calling a 
function marked notail. In this patch, clang marks a call instruction in the IR 
as notail only if it is a direct call to a function marked "notail". It does 
nothing to prevent tail call on indirect call sites.

I think there are a couple of things that have to be discussed:

1. Name of the attribute: Should it be "notail" or "notailcall"? Perhaps it 
should be named something like "nodirecttail" to indicate it is used to block 
direct calls, but not indirect calls?

2. Can we guarantee or promise that the attribute will *always* block direct 
calls (but do nothing for indirect calls)? Or should we say this attribute only 
prevents tail call (even for direct calls) on a best effort basis in case it 
turns out there are cases where it isn't possible to keep that promise?


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/Sema/attr-notail.c

Index: test/Sema/attr-notail.c
===================================================================
--- /dev/null
+++ test/Sema/attr-notail.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int callee() __attribute__((notail,always_inline)); // expected-error{{'notail' and 'always_inline' attributes are not compatible}}
+
+int foo() {
+  return callee();
+}
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()) {
@@ -4907,6 +4915,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