forked from ldc-developers/ldc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfunction-inlining.cpp
193 lines (163 loc) · 6.06 KB
/
function-inlining.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
//===-- function-inlining.cpp ---------------------------------------------===//
//
// LDC – the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
#include "gen/function-inlining.h"
#include "dmd/declaration.h"
#include "dmd/errors.h"
#include "dmd/expression.h"
#include "dmd/globals.h"
#include "dmd/id.h"
#include "dmd/module.h"
#include "dmd/statement.h"
#include "dmd/template.h"
#include "gen/irstate.h"
#include "gen/logger.h"
#include "gen/optimizer.h"
#include "gen/recursivevisitor.h"
#include "gen/uda.h"
namespace {
/// An ASTVisitor that checks whether the number of statements is larger than a
/// certain number.
struct MoreThanXStatements : public StoppableVisitor {
/// Are there more or fewer statements than `threshold`?.
unsigned threshold;
/// The statement count.
unsigned count;
explicit MoreThanXStatements(unsigned X) : threshold(X), count(0) {}
using StoppableVisitor::visit;
void visit(Statement *stmt) override {
count++;
if (count > threshold)
stop = true;
}
void visit(Expression *exp) override {}
void visit(Declaration *decl) override {}
void visit(Initializer *init) override {}
void visit(Dsymbol *) override {}
};
// Use a heuristic to determine if it could make sense to inline this fdecl.
// Note: isInlineCandidate is called _before_ semantic3 analysis of fdecl.
bool isInlineCandidate(FuncDeclaration &fdecl) {
// Giving maximum inlining potential to LLVM should be possible, but we
// restrict it to save some compile time.
// return true;
// TODO: make the heuristic more sophisticated?
// In the end, LLVM will make the decision whether to _actually_ inline.
// The statement count threshold is completely arbitrary. Also, all
// statements are weighed the same.
unsigned statementThreshold = 10;
MoreThanXStatements statementCounter(statementThreshold);
RecursiveWalker walker(&statementCounter, false);
fdecl.fbody->accept(&walker);
IF_LOG Logger::println("Contains %u statements or more (threshold = %u).",
statementCounter.count, statementThreshold);
return statementCounter.count <= statementThreshold;
}
} // end anonymous namespace
bool skipCodegen(FuncDeclaration &fdecl) {
if (fdecl.isFuncLiteralDeclaration()) // emitted into each referencing CU
return false;
for (FuncDeclaration *f = &fdecl; f;) {
if (f->inNonRoot()) { // false if instantiated
return true;
}
if (f->isNested()) {
f = f->toParent2()->isFuncDeclaration();
} else {
break;
}
}
return false;
}
bool defineAsExternallyAvailable(FuncDeclaration &fdecl) {
IF_LOG Logger::println("Enter defineAsExternallyAvailable");
LOG_SCOPE
// Implementation note: try to do cheap checks first.
if (fdecl.neverInline || fdecl.inlining == PINLINE::never) {
IF_LOG Logger::println("pragma(inline, false) specified");
return false;
}
// pragma(inline, true) functions will be inlined even at -O0
if (fdecl.inlining == PINLINE::always) {
IF_LOG Logger::println(
"pragma(inline, true) specified, overrides cmdline flags");
} else if (!willCrossModuleInline()) {
IF_LOG Logger::println("Commandline flags indicate no inlining");
return false;
}
if (fdecl.isFuncLiteralDeclaration()) {
// defined as discardable linkonce_odr in each referencing CU
IF_LOG Logger::println("isFuncLiteralDeclaration() == true");
return false;
}
if (fdecl.isUnitTestDeclaration()) {
IF_LOG Logger::println("isUnitTestDeclaration() == true");
return false;
}
if (fdecl.isFuncAliasDeclaration()) {
IF_LOG Logger::println("isFuncAliasDeclaration() == true");
return false;
}
if (!fdecl.fbody) {
IF_LOG Logger::println("No function body available for inlining");
return false;
}
// Because the frontend names `__invariant*` functions differently depending
// on the compilation order, we cannot emit the `__invariant` wrapper that
// calls the `__invariant*` functions.
// This is a workaround, the frontend needs to be changed such that the
// __invariant* names no longer depend on semantic analysis order.
// See https://github.com/ldc-developers/ldc/issues/1678
if (fdecl.isInvariantDeclaration()) {
IF_LOG Logger::println("__invariant cannot be emitted.");
return false;
}
Module *module = fdecl.getModule();
if (module == gIR->dmodule || (module->isRoot() && global.params.oneobj)) {
IF_LOG Logger::println(
"Function will be regularly defined later in this compilation unit.");
return false;
}
// Weak-linkage functions can not be inlined.
if (hasWeakUDA(&fdecl)) {
IF_LOG Logger::println("@weak functions cannot be inlined.");
return false;
}
if (fdecl.inlining != PINLINE::always && !isInlineCandidate(fdecl))
return false;
IF_LOG Logger::println("Potential inlining candidate");
if (fdecl.semanticRun < PASSsemantic3) {
IF_LOG Logger::println("Do semantic analysis");
LOG_SCOPE
// The inlining is aggressive and may give semantic errors that are
// forward referencing errors. Simply avoid those cases for inlining.
unsigned errors = global.startGagging();
global.gaggedForInlining = true;
bool semantic_error = false;
if (fdecl.functionSemantic3()) {
Module::runDeferredSemantic3();
} else {
IF_LOG Logger::println("Failed functionSemantic3.");
semantic_error = true;
}
global.gaggedForInlining = false;
if (global.endGagging(errors) || semantic_error) {
IF_LOG Logger::println("Errors occured during semantic analysis.");
return false;
}
assert(fdecl.semanticRun >= PASSsemantic3done);
}
// FuncDeclaration::naked is set by the AsmParser during semantic3 analysis,
// and so this check can only be done at this late point.
if (fdecl.naked) {
IF_LOG Logger::println("Naked asm functions cannot be inlined.");
return false;
}
IF_LOG Logger::println("defineAsExternallyAvailable? Yes.");
return true;
}