9
9
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10
10
//
11
11
// ===----------------------------------------------------------------------===//
12
+ // /
13
+ // / \file
14
+ // /
15
+ // / In this pass, we define the opt-remark-generator, a simple SILVisitor that
16
+ // / attempts to infer opt-remarks for the user using heuristics.
17
+ // /
18
+ // ===----------------------------------------------------------------------===//
12
19
13
20
#define DEBUG_TYPE " sil-opt-remark-gen"
14
21
@@ -33,32 +40,95 @@ using namespace swift;
33
40
34
41
namespace {
35
42
36
- // / Given a value, call \p funcPassedInferredArgs for each associated
37
- // / ValueDecl that is associated with \p value. All created Arguments are
38
- // / passed the same StringRef. To stop iteration, return false in \p
39
- // / funcPassedInferedArgs.
40
- // /
41
- // / NOTE: the function may be called multiple times if the optimizer joined
42
- // / two live ranges and thus when iterating over value's users we see multiple
43
- // / debug_value operations.
44
43
struct ValueToDeclInferrer {
45
44
using Argument = OptRemark::Argument;
46
45
using ArgumentKeyKind = OptRemark::ArgumentKeyKind;
47
46
47
+ RCIdentityFunctionInfo &rcfi;
48
+ SmallVector<std::pair<SILType, Projection>, 32 > accessPath;
49
+
50
+ ValueToDeclInferrer (RCIdentityFunctionInfo &rcfi) : rcfi(rcfi) {}
51
+
52
+ // / Given a value, attempt to infer a conservative list of decls that the
53
+ // / passed in value could be referring to. This is done just using heuristics
48
54
bool infer (ArgumentKeyKind keyKind, SILValue value,
49
- function_ref<bool (Argument)> funcPassedInferedArgs);
55
+ SmallVectorImpl<Argument> &resultingInferredDecls);
56
+
57
+ // / Print out a note to \p stream that beings at decl and then consumes the
58
+ // / accessPath we computed for decl producing a segmented access path, e.x.:
59
+ // / "of 'x.lhs.ivar'".
60
+ void printNote (llvm::raw_string_ostream &stream, const ValueDecl *decl);
50
61
};
51
62
52
63
} // anonymous namespace
53
64
54
- static void printNote (llvm::raw_string_ostream &stream, const ValueDecl *decl) {
55
- stream << " of '" << decl->getBaseName () << " '" ;
65
+ void ValueToDeclInferrer::printNote (llvm::raw_string_ostream &stream,
66
+ const ValueDecl *decl) {
67
+ stream << " of '" << decl->getBaseName ();
68
+ for (auto &pair : accessPath) {
69
+ auto baseType = pair.first ;
70
+ auto &proj = pair.second ;
71
+ stream << " ." ;
72
+
73
+ // WARNING: This must be kept insync with isSupportedProjection!
74
+ switch (proj.getKind ()) {
75
+ case ProjectionKind::Upcast:
76
+ stream << " upcast<" << proj.getCastType (baseType) << " >" ;
77
+ continue ;
78
+ case ProjectionKind::RefCast:
79
+ stream << " refcast<" << proj.getCastType (baseType) << " >" ;
80
+ continue ;
81
+ case ProjectionKind::BitwiseCast:
82
+ stream << " bitwise_cast<" << proj.getCastType (baseType) << " >" ;
83
+ continue ;
84
+ case ProjectionKind::Struct:
85
+ stream << proj.getVarDecl (baseType)->getBaseName ();
86
+ continue ;
87
+ case ProjectionKind::Tuple:
88
+ stream << proj.getIndex ();
89
+ continue ;
90
+ case ProjectionKind::Enum:
91
+ stream << proj.getEnumElementDecl (baseType)->getBaseName ();
92
+ continue ;
93
+ // Object -> Address projections can never be looked through.
94
+ case ProjectionKind::Class:
95
+ case ProjectionKind::Box:
96
+ case ProjectionKind::Index:
97
+ case ProjectionKind::TailElems:
98
+ llvm_unreachable (
99
+ " Object -> Address projection should never be looked through!" );
100
+ }
101
+
102
+ llvm_unreachable (" Covered switch is not covered?!" );
103
+ }
104
+
105
+ accessPath.clear ();
106
+ stream << " '" ;
107
+ }
108
+
109
+ // WARNING: This must be kept insync with ValueToDeclInferrer::printNote(...).
110
+ static SingleValueInstruction *isSupportedProjection (Projection p, SILValue v) {
111
+ switch (p.getKind ()) {
112
+ case ProjectionKind::Upcast:
113
+ case ProjectionKind::RefCast:
114
+ case ProjectionKind::BitwiseCast:
115
+ case ProjectionKind::Struct:
116
+ case ProjectionKind::Tuple:
117
+ case ProjectionKind::Enum:
118
+ return cast<SingleValueInstruction>(v);
119
+ // Object -> Address projections can never be looked through.
120
+ case ProjectionKind::Class:
121
+ case ProjectionKind::Box:
122
+ case ProjectionKind::Index:
123
+ case ProjectionKind::TailElems:
124
+ return nullptr ;
125
+ }
126
+ llvm_unreachable (" Covered switch is not covered?!" );
56
127
}
57
128
58
129
bool ValueToDeclInferrer::infer (
59
130
ArgumentKeyKind keyKind, SILValue value,
60
- function_ref<bool (Argument)> funcPassedInferedArgs) {
61
-
131
+ SmallVectorImpl<Argument> &resultingInferredDecls) {
62
132
// This is a linear IR traversal using a 'falling while loop'. That means
63
133
// every time through the loop we are trying to handle a case before we hit
64
134
// the bottom of the while loop where we always return true (since we did not
@@ -73,8 +143,9 @@ bool ValueToDeclInferrer::infer(
73
143
llvm::raw_string_ostream stream (msg);
74
144
printNote (stream, decl);
75
145
}
76
- return funcPassedInferedArgs (
146
+ resultingInferredDecls. push_back (
77
147
Argument ({keyKind, " InferredValue" }, std::move (msg), decl));
148
+ return true ;
78
149
}
79
150
80
151
if (auto *ga = dyn_cast<GlobalAddrInst>(value))
@@ -84,13 +155,14 @@ bool ValueToDeclInferrer::infer(
84
155
llvm::raw_string_ostream stream (msg);
85
156
printNote (stream, decl);
86
157
}
87
- if (! funcPassedInferedArgs (
88
- Argument ({keyKind, " InferredValue" }, std::move (msg), decl)))
89
- return false ;
158
+ resultingInferredDecls. push_back (
159
+ Argument ({keyKind, " InferredValue" }, std::move (msg), decl));
160
+ return true ;
90
161
}
91
162
92
163
// Then visit our users and see if we can find a debug_value that provides
93
164
// us with a decl we can use to construct an argument.
165
+ bool foundDeclFromUse = false ;
94
166
for (auto *use : value->getUses ()) {
95
167
// Skip type dependent uses.
96
168
if (use->isTypeDependent ())
@@ -103,12 +175,14 @@ bool ValueToDeclInferrer::infer(
103
175
llvm::raw_string_ostream stream (msg);
104
176
printNote (stream, decl);
105
177
}
106
- if (! funcPassedInferedArgs (
107
- Argument ({keyKind, " InferredValue" }, std::move (msg), decl)))
108
- return false ;
178
+ resultingInferredDecls. push_back (
179
+ Argument ({keyKind, " InferredValue" }, std::move (msg), decl));
180
+ foundDeclFromUse = true ;
109
181
}
110
182
}
111
183
}
184
+ if (foundDeclFromUse)
185
+ return true ;
112
186
113
187
// At this point, we could not infer any argument. See if we can look
114
188
// through loads.
@@ -121,6 +195,14 @@ bool ValueToDeclInferrer::infer(
121
195
continue ;
122
196
}
123
197
198
+ if (auto proj = Projection (value)) {
199
+ if (auto *projInst = isSupportedProjection (proj, value)) {
200
+ value = projInst->getOperand (0 );
201
+ accessPath.emplace_back (value->getType (), proj);
202
+ continue ;
203
+ }
204
+ }
205
+
124
206
// If we reached this point, we finished falling through the loop and return
125
207
// true.
126
208
return true ;
@@ -136,7 +218,6 @@ namespace {
136
218
struct OptRemarkGeneratorInstructionVisitor
137
219
: public SILInstructionVisitor<OptRemarkGeneratorInstructionVisitor> {
138
220
SILModule &mod;
139
- RCIdentityFunctionInfo &rcfi;
140
221
OptRemark::Emitter ORE;
141
222
142
223
// / A class that we use to infer the decl that is associated with a
@@ -145,7 +226,7 @@ struct OptRemarkGeneratorInstructionVisitor
145
226
146
227
OptRemarkGeneratorInstructionVisitor (SILFunction &fn,
147
228
RCIdentityFunctionInfo &rcfi)
148
- : mod(fn.getModule()), rcfi(rcfi), ORE(DEBUG_TYPE, fn) {}
229
+ : mod(fn.getModule()), ORE(DEBUG_TYPE, fn), valueToDeclInferrer(rcfi ) {}
149
230
150
231
void visitStrongRetainInst (StrongRetainInst *sri);
151
232
void visitStrongReleaseInst (StrongReleaseInst *sri);
@@ -160,13 +241,9 @@ void OptRemarkGeneratorInstructionVisitor::visitStrongRetainInst(
160
241
StrongRetainInst *sri) {
161
242
ORE.emit ([&]() {
162
243
using namespace OptRemark ;
163
- SILValue root = rcfi.getRCIdentityRoot (sri->getOperand ());
164
244
SmallVector<Argument, 8 > inferredArgs;
165
- bool foundArgs = valueToDeclInferrer.infer (ArgumentKeyKind::Note, root,
166
- [&](Argument arg) {
167
- inferredArgs.push_back (arg);
168
- return true ;
169
- });
245
+ bool foundArgs = valueToDeclInferrer.infer (ArgumentKeyKind::Note,
246
+ sri->getOperand (), inferredArgs);
170
247
(void )foundArgs;
171
248
172
249
// Retains begin a lifetime scope so we infer scan forward.
@@ -185,13 +262,9 @@ void OptRemarkGeneratorInstructionVisitor::visitStrongReleaseInst(
185
262
ORE.emit ([&]() {
186
263
using namespace OptRemark ;
187
264
// Releases end a lifetime scope so we infer scan backward.
188
- SILValue root = rcfi.getRCIdentityRoot (sri->getOperand ());
189
265
SmallVector<Argument, 8 > inferredArgs;
190
- bool foundArgs = valueToDeclInferrer.infer (ArgumentKeyKind::Note, root,
191
- [&](Argument arg) {
192
- inferredArgs.push_back (arg);
193
- return true ;
194
- });
266
+ bool foundArgs = valueToDeclInferrer.infer (ArgumentKeyKind::Note,
267
+ sri->getOperand (), inferredArgs);
195
268
(void )foundArgs;
196
269
197
270
auto remark = RemarkMissed (" memory" , *sri,
@@ -208,15 +281,10 @@ void OptRemarkGeneratorInstructionVisitor::visitRetainValueInst(
208
281
RetainValueInst *rvi) {
209
282
ORE.emit ([&]() {
210
283
using namespace OptRemark ;
211
- SILValue root = rcfi.getRCIdentityRoot (rvi->getOperand ());
212
284
SmallVector<Argument, 8 > inferredArgs;
213
- bool foundArgs = valueToDeclInferrer.infer (ArgumentKeyKind::Note, root,
214
- [&](Argument arg) {
215
- inferredArgs.push_back (arg);
216
- return true ;
217
- });
285
+ bool foundArgs = valueToDeclInferrer.infer (ArgumentKeyKind::Note,
286
+ rvi->getOperand (), inferredArgs);
218
287
(void )foundArgs;
219
-
220
288
// Retains begin a lifetime scope, so we infer scan forwards.
221
289
auto remark = RemarkMissed (" memory" , *rvi,
222
290
SourceLocInferenceBehavior::ForwardScanOnly)
@@ -232,13 +300,9 @@ void OptRemarkGeneratorInstructionVisitor::visitReleaseValueInst(
232
300
ReleaseValueInst *rvi) {
233
301
ORE.emit ([&]() {
234
302
using namespace OptRemark ;
235
- SILValue root = rcfi.getRCIdentityRoot (rvi->getOperand ());
236
303
SmallVector<Argument, 8 > inferredArgs;
237
- bool foundArgs = valueToDeclInferrer.infer (ArgumentKeyKind::Note, root,
238
- [&](Argument arg) {
239
- inferredArgs.push_back (arg);
240
- return true ;
241
- });
304
+ bool foundArgs = valueToDeclInferrer.infer (ArgumentKeyKind::Note,
305
+ rvi->getOperand (), inferredArgs);
242
306
(void )foundArgs;
243
307
244
308
// Releases end a lifetime scope so we infer scan backward.
0 commit comments