Skip to content

Commit e66a142

Browse files
committed
Add the yk_unroll_safe attribute.
This function attribute tells the Yk JIT that it is OK to inline the decorated function into the trace, even if it contains loops. By default functions containing loops will not be inlined into traces by default any more. These new behaviours are enabled by passing -fyk-noinline-funcs-with-loops to clang.
1 parent 78e5e93 commit e66a142

File tree

8 files changed

+79
-3
lines changed

8 files changed

+79
-3
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4072,3 +4072,10 @@ def YkOutline : InheritableAttr {
40724072
let Documentation = [YkOutlineDocs];
40734073
let SimpleHandler = 1;
40744074
}
4075+
4076+
def YkUnrollSafe : InheritableAttr {
4077+
let Spellings = [GCC<"yk_unroll_safe">, Declspec<"yk_unroll_safe">];
4078+
let Subjects = SubjectList<[Function]>;
4079+
let Documentation = [YkUnrollSafeDocs];
4080+
let SimpleHandler = 1;
4081+
}

clang/include/clang/Basic/AttrDocs.td

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6667,3 +6667,12 @@ def YkOutlineDocs : Documentation {
66676667
to the annotated function.
66686668
}];
66696669
}
6670+
6671+
def YkUnrollSafeDocs : Documentation {
6672+
let Category = DocCatFunction;
6673+
let Content = [{
6674+
The ``yk_unroll_safe`` attribute tells the Yk JIT that during tracing, calls
6675+
to the annotated function can be inlined, even if it contains loops. By
6676+
default only calls to functions that contain no loops are inlined.
6677+
}];
6678+
}

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,8 @@ CODEGENOPT(DebugColumnInfo, 1, 0) ///< Whether or not to use column information
333333
CODEGENOPT(DebugTypeExtRefs, 1, 0) ///< Whether or not debug info should contain
334334
///< external references to a PCH or module.
335335

336+
CODEGENOPT(YkNoinlineFuncsWithLoops, 1, 0) ///< Yk JIT: by default don't inline functions
337+
///< containing loops.
336338
CODEGENOPT(DebugExplicitImport, 1, 0) ///< Whether or not debug info should
337339
///< contain explicit imports for
338340
///< anonymous namespaces

clang/include/clang/Driver/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4739,6 +4739,11 @@ def finline_limit_EQ : Joined<["-"], "finline-limit=">, Group<clang_ignored_gcc_
47394739
defm finline_limit : BooleanFFlag<"inline-limit">, Group<clang_ignored_gcc_optimization_f_Group>;
47404740
defm inline_small_functions : BooleanFFlag<"inline-small-functions">,
47414741
Group<clang_ignored_gcc_optimization_f_Group>;
4742+
defm yk_noinline_funcs_with_loops : BoolOption<"f", "yk-noinline-funcs-with-loops",
4743+
CodeGenOpts<"YkNoinlineFuncsWithLoops">, DefaultFalse,
4744+
NegFlag<SetFalse, []>,
4745+
PosFlag<SetTrue, [], "Don't inline functions containing loops by default (used for the Yk JIT).">,
4746+
BothFlags<[CC1Option, CoreOption]>>;
47424747
defm ipa_cp : BooleanFFlag<"ipa-cp">,
47434748
Group<clang_ignored_gcc_optimization_f_Group>;
47444749
defm ivopts : BooleanFFlag<"ivopts">, Group<clang_ignored_gcc_optimization_f_Group>;

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,12 @@
4949
#include "clang/Frontend/FrontendDiagnostic.h"
5050
#include "llvm/ADT/StringSwitch.h"
5151
#include "llvm/ADT/Triple.h"
52+
#include "llvm/Analysis/LoopInfo.h"
5253
#include "llvm/Analysis/TargetLibraryInfo.h"
5354
#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
5455
#include "llvm/IR/CallingConv.h"
5556
#include "llvm/IR/DataLayout.h"
57+
#include "llvm/IR/Dominators.h"
5658
#include "llvm/IR/Intrinsics.h"
5759
#include "llvm/IR/LLVMContext.h"
5860
#include "llvm/IR/Module.h"
@@ -2049,10 +2051,41 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
20492051
}
20502052

20512053
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.
20552054
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+
}
20562089
}
20572090

20582091
F->addFnAttrs(B);

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5399,6 +5399,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
53995399
else if (UnwindTables)
54005400
CmdArgs.push_back("-funwind-tables=1");
54015401

5402+
if (Args.hasFlag(options::OPT_fyk_noinline_funcs_with_loops,
5403+
options::OPT_fno_yk_noinline_funcs_with_loops, false))
5404+
CmdArgs.push_back("-fyk-noinline-funcs-with-loops");
5405+
54025406
// Prepare `-aux-target-cpu` and `-aux-target-feature` unless
54035407
// `--gpu-use-aux-triple-only` is specified.
54045408
if (!Args.getLastArg(options::OPT_gpu_use_aux_triple_only) &&

clang/test/Misc/pragma-attribute-supported-attributes-list.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,5 +197,6 @@
197197
// CHECK-NEXT: XRayInstrument (SubjectMatchRule_function, SubjectMatchRule_objc_method)
198198
// CHECK-NEXT: XRayLogArgs (SubjectMatchRule_function, SubjectMatchRule_objc_method)
199199
// CHECK-NEXT: YkOutline (SubjectMatchRule_function)
200+
// CHECK-NEXT: YkUnrollSafe (SubjectMatchRule_function)
200201
// CHECK-NEXT: ZeroCallUsedRegs (SubjectMatchRule_function)
201202
// CHECK-NEXT: End of supported attributes.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %clang -emit-llvm -fyk-noinline-funcs-with-loops -c -O0 -o - %s | llvm-dis | grep "call .*@never_aot_inline("
2+
// RUN: %clang -emit-llvm -fyk-noinline-funcs-with-loops -c -O1 -o - %s | llvm-dis | grep "call .*@never_aot_inline("
3+
// RUN: %clang -emit-llvm -fyk-noinline-funcs-with-loops -c -O2 -o - %s | llvm-dis | grep "call .*@never_aot_inline("
4+
// RUN: %clang -emit-llvm -fyk-noinline-funcs-with-loops -c -O3 -o - %s | llvm-dis | grep "call .*@never_aot_inline("
5+
6+
#include <stdio.h>
7+
8+
static void never_aot_inline(int i) {
9+
while (i--)
10+
putchar('.');
11+
}
12+
13+
int main(int argc, char **argv) {
14+
never_aot_inline(argc);
15+
}

0 commit comments

Comments
 (0)