@@ -217,6 +217,87 @@ static bool hasNonInlinedDebugScope(SILInstruction *i) {
217217 return false ;
218218}
219219
220+ namespace {
221+
222+ // / A helper struct that attempts to infer the decl associated with a value from
223+ // / one of its uses. It does this by searching the def-use graph locally for
224+ // / debug_value and debug_value_addr instructions.
225+ struct ValueUseToDeclInferrer {
226+ using Argument = ValueToDeclInferrer::Argument;
227+ using ArgumentKeyKind = ValueToDeclInferrer::ArgumentKeyKind;
228+
229+ SmallPtrSet<swift::SILInstruction *, 8 > visitedDebugValueInsts;
230+ ValueToDeclInferrer &object;
231+ ArgumentKeyKind keyKind;
232+ SmallVectorImpl<Argument> &resultingInferredDecls;
233+
234+ bool findDecls (Operand *use, SILValue value);
235+ };
236+
237+ } // anonymous namespace
238+
239+ bool ValueUseToDeclInferrer::findDecls (Operand *use, SILValue value) {
240+ // Skip type dependent operands.
241+ if (use->isTypeDependent ())
242+ return false ;
243+
244+ // Then see if we have a debug_value that is associated with a non-inlined
245+ // debug scope. Such an instruction is an instruction that is from the
246+ // current function.
247+ auto *dvi = dyn_cast<DebugValueInst>(use->getUser ());
248+ if (!dvi)
249+ return false ;
250+
251+ if (!hasNonInlinedDebugScope (dvi))
252+ return false ;
253+
254+ // See if we have already inferred this debug_value as a potential source
255+ // for this instruction. In such a case, just return.
256+ if (!visitedDebugValueInsts.insert (dvi).second )
257+ return false ;
258+
259+ if (auto *decl = dvi->getDecl ()) {
260+ std::string msg;
261+ {
262+ llvm::raw_string_ostream stream (msg);
263+ // If we are not a top level use, we must be a rc-identical transitive
264+ // use. In such a case, we just print out the rc identical value
265+ // without a projection path. This is because we now have a better
266+ // name and the name is rc-identical to whatever was at the end of the
267+ // projection path but is not at the end of that projection path.
268+ object.printNote (stream, decl,
269+ use->get () == value /* print projection path*/ );
270+ }
271+ resultingInferredDecls.emplace_back (
272+ OptRemark::ArgumentKey{keyKind, " InferredValue" }, std::move (msg), decl);
273+ return true ;
274+ }
275+
276+ // If we did not have a decl, see if we were asked for testing
277+ // purposes to use SILDebugInfo to create a placeholder inferred
278+ // value.
279+ if (!DecllessDebugValueUseSILDebugInfo)
280+ return false ;
281+
282+ auto varInfo = dvi->getVarInfo ();
283+ if (!varInfo)
284+ return false ;
285+
286+ auto name = varInfo->Name ;
287+ if (name.empty ())
288+ return false ;
289+
290+ std::string msg;
291+ {
292+ llvm::raw_string_ostream stream (msg);
293+ object.printNote (stream, name,
294+ use->get () == value /* print projection path*/ );
295+ }
296+ resultingInferredDecls.push_back (
297+ Argument ({keyKind, " InferredValue" }, std::move (msg), dvi->getLoc ()));
298+ return true ;
299+ }
300+
220301bool ValueToDeclInferrer::infer (
221302 ArgumentKeyKind keyKind, SILValue value,
222303 SmallVectorImpl<Argument> &resultingInferredDecls,
@@ -225,7 +306,8 @@ bool ValueToDeclInferrer::infer(
225306 SWIFT_DEFER {
226307 accessPath.clear ();
227308 };
228- SmallPtrSet<SILInstruction *, 8 > visitedDebugValueInsts;
309+ ValueUseToDeclInferrer valueUseInferrer{
310+ {}, *this , keyKind, resultingInferredDecls};
229311 bool foundSingleRefElementAddr = false ;
230312
231313 // This is a linear IR traversal using a 'falling while loop'. That means
@@ -308,66 +390,7 @@ bool ValueToDeclInferrer::infer(
308390 // instance, if we FSOed.
309391 bool foundDeclFromUse = false ;
310392 rcfi.visitRCUses (value, [&](Operand *use) {
311- // Skip type dependent uses.
312- if (use->isTypeDependent ())
313- return ;
314-
315- // Then see if we have a debug_value that is associated with a non-inlined
316- // debug scope. Such an instruction is an instruction that is from the
317- // current function.
318- auto *dvi = dyn_cast<DebugValueInst>(use->getUser ());
319- if (!dvi)
320- return ;
321-
322- if (!hasNonInlinedDebugScope (dvi))
323- return ;
324-
325- // See if we have already inferred this debug_value as a potential source
326- // for this instruction. In such a case, just return.
327- if (!visitedDebugValueInsts.insert (dvi).second )
328- return ;
329-
330- if (auto *decl = dvi->getDecl ()) {
331- std::string msg;
332- {
333- llvm::raw_string_ostream stream (msg);
334- // If we are not a top level use, we must be a rc-identical transitive
335- // use. In such a case, we just print out the rc identical value
336- // without a projection path. This is because we now have a better
337- // name and the name is rc-identical to whatever was at the end of the
338- // projection path but is not at the end of that projection path.
339- printNote (stream, decl,
340- use->get () == value /* print projection path*/ );
341- }
342- resultingInferredDecls.emplace_back (
343- OptRemark::ArgumentKey{keyKind, " InferredValue" }, std::move (msg),
344- decl);
345- foundDeclFromUse = true ;
346- return ;
347- }
348-
349- // If we did not have a decl, see if we were asked for testing
350- // purposes to use SILDebugInfo to create a placeholder inferred
351- // value.
352- if (!DecllessDebugValueUseSILDebugInfo)
353- return ;
354-
355- auto varInfo = dvi->getVarInfo ();
356- if (!varInfo)
357- return ;
358-
359- auto name = varInfo->Name ;
360- if (name.empty ())
361- return ;
362-
363- std::string msg;
364- {
365- llvm::raw_string_ostream stream (msg);
366- printNote (stream, name, use->get () == value /* print projection path*/ );
367- }
368- resultingInferredDecls.push_back (
369- Argument ({keyKind, " InferredValue" }, std::move (msg), dvi->getLoc ()));
370- foundDeclFromUse = true ;
393+ foundDeclFromUse |= valueUseInferrer.findDecls (use, value);
371394 });
372395
373396 // At this point, we could not infer any argument. See if we can look up the
0 commit comments