Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -1469,6 +1469,13 @@ let SimpleHandler = 1; } +def NoOutline : InheritableAttr { + let Spellings = [Clang<"nooutline">]; + let Subjects = SubjectList<[Function, ObjCMethod, Block]>; + let Documentation = [NoOutlineDocs]; + let SimpleHandler = 1; +} + def MustTail : StmtAttr { let Spellings = [Clang<"musttail">]; let Documentation = [MustTailDocs]; Index: clang/include/clang/Basic/AttrDocs.td =================================================================== --- clang/include/clang/Basic/AttrDocs.td +++ clang/include/clang/Basic/AttrDocs.td @@ -580,6 +580,26 @@ }]; } +def NoOutlineDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ + +Suppresses outlining from a function. Functions with this attribute will not +be considered for outlining. + +.. code-block:: c + + __attribute__((nooutline)) + int example(void) { + int r; + foo(); + bar(); + return r; + } + + }]; +} + def MustTailDocs : Documentation { let Category = DocCatStmt; let Content = [{ Index: clang/lib/CodeGen/CGCall.cpp =================================================================== --- clang/lib/CodeGen/CGCall.cpp +++ clang/lib/CodeGen/CGCall.cpp @@ -2344,6 +2344,8 @@ FuncAttrs.addAttribute(llvm::Attribute::NoCfCheck); if (TargetDecl->hasAttr()) FuncAttrs.addAttribute(llvm::Attribute::NoCallback); + if (TargetDecl->hasAttr()) + FuncAttrs.addAttribute("nooutline"); HasOptnone = TargetDecl->hasAttr(); if (auto *AllocSize = TargetDecl->getAttr()) { Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -2133,6 +2133,8 @@ if (D->hasAttr()) B.addAttribute(llvm::Attribute::MinSize); } + if (D->hasAttr()) + B.addAttribute("nooutline"); F->addFnAttrs(B); Index: clang/test/CodeGen/attr-nooutline-blocks.m =================================================================== --- /dev/null +++ clang/test/CodeGen/attr-nooutline-blocks.m @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 %s -S -emit-llvm -fblocks /tmp/test.m -o - | FileCheck %s + +// CHECK: define internal void @__block_param_block_invoke({{.*}}) [[HAS_ATTR:#[0-9]+]] +@interface ObjTy @end +ObjTy *global; +void escp(void (^)(ObjTy *)); +void block_param() { + escp(^(ObjTy *p) __attribute__((nooutline)) {}); +} + +// CHECK: attributes [[HAS_ATTR]] = { {{.*}}"nooutline"{{.*}} } Index: clang/test/CodeGen/attr-nooutline.c =================================================================== --- /dev/null +++ clang/test/CodeGen/attr-nooutline.c @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 %s -S -emit-llvm -o - | FileCheck %s + +// CHECK: define i32 @has_attr_2() [[HAS_ATTR_2:#[0-9]+]] +// CHECK: declare i32 @has_attr_1() [[HAS_ATTR_1:#[0-9]+]] + +__attribute__((nooutline)) int has_attr_1(void); +__attribute__((nooutline)) int has_attr_2(void) { return has_attr_1(); } + +// CHECK: attributes [[HAS_ATTR_2]] = { {{.*}}"nooutline"{{.*}} } +// CHECK: attributes [[HAS_ATTR_1]] = { {{.*}}"nooutline"{{.*}} }