diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index ab68640005bba..4a1373d3ef881 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4255,6 +4255,13 @@ def YkUnrollSafe : InheritableAttr { let SimpleHandler = 1; } +def YkIndirectInline : InheritableAttr { + let Spellings = [GCC<"yk_indirect_inline">, Declspec<"yk_indirect_inline">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [YkIndirectInlineDocs]; + let SimpleHandler = 1; +} + def WebAssemblyFuncref : TypeAttr, TargetSpecificAttr { let Spellings = [CustomKeyword<"__funcref">]; let Documentation = [WebAssemblyExportNameDocs]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 8e6d202e8e2bf..d947d92d7b710 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -7205,6 +7205,14 @@ def YkUnrollSafeDocs : Documentation { }]; } +def YkIndirectInlineDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ + This attribute prevents functions only called indirectly from being + marked yk_outline. + }]; +} + def ReadOnlyPlacementDocs : Documentation { let Category = DocCatType; let Content = [{This attribute is attached to a structure, class or union declaration. diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index ae2587aa4e766..bc26c75e184fe 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2423,6 +2423,10 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, B.addAttribute(YK_IDEMPOTENT_FNATTR); } + if (D->hasAttr()) { + B.addAttribute(YK_INDIRECT_INLINE_FNATTR); + } + // Mark all functions containing loops with `yk_outline` unless the function // was annotated `yk_unroll_safe`. // diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index 8da7028df6070..7f535a6922d3c 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -205,6 +205,7 @@ // CHECK-NEXT: XRayInstrument (SubjectMatchRule_function, SubjectMatchRule_objc_method) // CHECK-NEXT: XRayLogArgs (SubjectMatchRule_function, SubjectMatchRule_objc_method) // CHECK-NEXT: YkIdempotent (SubjectMatchRule_function) +// CHECK-NEXT: YkIndirectInline (SubjectMatchRule_function) // CHECK-NEXT: YkOutline (SubjectMatchRule_function) // CHECK-NEXT: YkUnrollSafe (SubjectMatchRule_function) // CHECK-NEXT: ZeroCallUsedRegs (SubjectMatchRule_function) diff --git a/llvm/include/llvm/YkIR/YkIRWriter.h b/llvm/include/llvm/YkIR/YkIRWriter.h index 6435ccbc948e5..77a071019d4ef 100644 --- a/llvm/include/llvm/YkIR/YkIRWriter.h +++ b/llvm/include/llvm/YkIR/YkIRWriter.h @@ -6,6 +6,7 @@ #include "llvm/MC/MCStreamer.h" #define YK_OUTLINE_FNATTR "yk_outline" +#define YK_INDIRECT_INLINE_FNATTR "yk_indirect_inline" #define YK_PROMOTE_PREFIX "__yk_promote" #define YK_DEBUG_STR "yk_debug_str" diff --git a/llvm/lib/Transforms/Yk/OutlineUntraceable.cpp b/llvm/lib/Transforms/Yk/OutlineUntraceable.cpp index fed683700f8b5..57f7ce5cc69cd 100644 --- a/llvm/lib/Transforms/Yk/OutlineUntraceable.cpp +++ b/llvm/lib/Transforms/Yk/OutlineUntraceable.cpp @@ -1,8 +1,8 @@ //===- OutlineUntraceable.cpp - Add yk_outline to untraceable functions -=== //// // -// This pass searches for functions which can never be traced and marks them -// `yk_outline`. This has two effects: +// This pass searches for functions which are unlikely to be traced and marks +// them `yk_outline`. This has two effects: // // - It causes instrumentation passes that run after this to ignore the // untraceable functions. This means that we don't have to pay a runtime @@ -94,7 +94,19 @@ class OutlineUntraceable : public ModulePass { bool Changed = false; for (Function &F : M) { - if ((!F.isDeclaration()) && (!couldBeTraced(&IG, &F))) { + // Note that the inverted call graph doesn't take into account indirect + // calls. This means that we will sometimes consider functions that could + // be traceable (via indirect calls) untraceable. + // + // An earlier attempt to consider functions called from functions with + // their address taken, as potentially traceable, lead to much worse + // performance overall. We may need to revisit this. + // + // To prevent this pass from `yk_outline`ing a function only called + // indirectly, the interpreter author can annotate it with the + // `yk_indirect_inline` function attribute. + if ((!F.isDeclaration()) && (!couldBeTraced(&IG, &F)) && + (!F.hasFnAttribute(YK_INDIRECT_INLINE_FNATTR))) { F.addFnAttr(YK_OUTLINE_FNATTR); Changed = true; } diff --git a/llvm/lib/YkIR/YkIRWriter.cpp b/llvm/lib/YkIR/YkIRWriter.cpp index 5175afde43a14..375836b0b936e 100644 --- a/llvm/lib/YkIR/YkIRWriter.cpp +++ b/llvm/lib/YkIR/YkIRWriter.cpp @@ -39,6 +39,7 @@ const int PPArgIdxNumTargetArgs = 3; // Function flags. const uint8_t YkFuncFlagOutline = 1; const uint8_t YkFuncFlagIdempotent = 2; +const uint8_t YkFuncFlagInlineIndirect = 4; #include @@ -1714,6 +1715,9 @@ class YkIRWriter { if (F.hasFnAttribute(YK_IDEMPOTENT_FNATTR)) { Flags |= YkFuncFlagIdempotent; } + if (F.hasFnAttribute(YK_INDIRECT_INLINE_FNATTR)) { + Flags |= YkFuncFlagInlineIndirect; + } OutStreamer.emitInt8(Flags); }