|
49 | 49 | #include "clang/Frontend/FrontendDiagnostic.h"
|
50 | 50 | #include "llvm/ADT/StringSwitch.h"
|
51 | 51 | #include "llvm/ADT/Triple.h"
|
| 52 | +#include "llvm/Analysis/LoopInfo.h" |
52 | 53 | #include "llvm/Analysis/TargetLibraryInfo.h"
|
53 | 54 | #include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
|
54 | 55 | #include "llvm/IR/CallingConv.h"
|
55 | 56 | #include "llvm/IR/DataLayout.h"
|
| 57 | +#include "llvm/IR/Dominators.h" |
56 | 58 | #include "llvm/IR/Intrinsics.h"
|
57 | 59 | #include "llvm/IR/LLVMContext.h"
|
58 | 60 | #include "llvm/IR/Module.h"
|
@@ -2049,10 +2051,41 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
|
2049 | 2051 | }
|
2050 | 2052 |
|
2051 | 2053 | if (D->hasAttr<YkOutlineAttr>()) {
|
2052 |
| - // Prevent the Yk trace compiler from inlining the call. |
2053 |
| - B.addAttribute("yk_outline"); |
2054 |
| - // Prevent LLVM from inlining the call when optimising the trace. |
2055 | 2054 | B.addAttribute(llvm::Attribute::NoInline);
|
| 2055 | + B.addAttribute("yk_outline"); |
| 2056 | + } |
| 2057 | + |
| 2058 | + // Mark all functions containing loops with `yk_outline` unless the function |
| 2059 | + // was annotated `yk_unroll_safe`. |
| 2060 | + // |
| 2061 | + // This needs to be gated so that we don't impact the normal clang and LLVM |
| 2062 | + // tests. |
| 2063 | + // |
| 2064 | + // If `F->empty()` then this is merely a function declaration for which we |
| 2065 | + // have no IR. In this case the JIT will be unable to inline calls to this |
| 2066 | + // function anyway, so there's no need to conservatively add `yk_outline`. |
| 2067 | + if (CodeGenOpts.YkNoinlineFuncsWithLoops && !F->empty()) { |
| 2068 | + llvm::DominatorTree DT(*F); |
| 2069 | + llvm::LoopInfo LI(DT); |
| 2070 | + if (!LI.empty()) { |
| 2071 | + if (!D->hasAttr<YkUnrollSafeAttr>()) |
| 2072 | + B.addAttribute("yk_outline"); |
| 2073 | + |
| 2074 | + // Note that we still mark the loopy function `F` with `noinline` (to |
| 2075 | + // block it being inlined during AOT compilation) regardless of if it can |
| 2076 | + // be inlined into the trace or not, because: |
| 2077 | + // |
| 2078 | + // * if `F` is to be inlined into a trace and we don't block AOT inlining |
| 2079 | + // then `F` may get AOT inlined into a parent function which contains |
| 2080 | + // loops but isn't marked `yk_unroll_safe`. The trace would have to call |
| 2081 | + // the parent, meaning that `F` would not be inlined into the trace! |
| 2082 | + // |
| 2083 | + // * if `F` is to be outlined in a trace and we don't block AOT inlining, |
| 2084 | + // then `F` may be inlined into a parent function and tracing the parent |
| 2085 | + // function would give a trace where `F` was actually inlined instead of |
| 2086 | + // outlined. |
| 2087 | + B.addAttribute(llvm::Attribute::NoInline); |
| 2088 | + } |
2056 | 2089 | }
|
2057 | 2090 |
|
2058 | 2091 | F->addFnAttrs(B);
|
|
0 commit comments