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]; 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 calls to a function marked ``notail``. + }]; +} Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -1414,6 +1414,8 @@ FuncAttrs.addAttribute(llvm::Attribute::NoReturn); if (TargetDecl->hasAttr()) FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate); + if (TargetDecl->hasAttr()) + FuncAttrs.addAttribute(llvm::Attribute::NoTail); if (const FunctionDecl *Fn = dyn_cast(TargetDecl)) { const FunctionProtoType *FPT = Fn->getType()->getAs(); Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -4878,6 +4878,9 @@ case AttributeList::AT_ReturnsTwice: handleSimpleAttribute(S, D, Attr); break; + case AttributeList::AT_NoTail: + handleSimpleAttribute(S, D, Attr); + break; case AttributeList::AT_Used: handleUsedAttr(S, D, Attr); break; Index: test/CodeGen/attr-no-tail.c =================================================================== --- /dev/null +++ test/CodeGen/attr-no-tail.c @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.7.0 %s -emit-llvm -o - | FileCheck %s + +// CHECK: define i32 @callee0(i32 %a) [[ATTRNOTAIL0:#[0-9]+]] { +// CHECK: declare i32 @callee1(i32) [[ATTRNOTAIL1:#[0-9]+]] +// CHECK: declare i32 @callee2(i32) [[ATTRTAIL0:#[0-9]+]] + +int callee0(int a) __attribute__((notail)) { + return a + 1; +} + +int callee1(int) __attribute__((notail)); + +int callee2(int); + +int caller0(int a) { + if (a > 0) + return callee0(a); + if (a < 0) + return callee1(a); + return callee2(a); +} + +// CHECK: attributes [[ATTRNOTAIL0]] = { {{.*}}notail{{.*}} } +// CHECK: attributes [[ATTRNOTAIL1]] = { {{.*}}notail{{.*}} } +// CHECK-NOT: attributes [[ATTRTAIL0]] = { {{.*}}notail{{.*}} }