Skip to content

Commit a569160

Browse files
committed
[sil] Refactor out the variable name inferer from MoveOnlyDiagnostics.cpp -> VariableNameUtils.
I am going to reuse this for TransferNonSendable. In the process I made a few changes to make it more amenable to both use cases and used the current set of tests that we have for noncopyable types to validate that I didn't break anything.
1 parent c9fcab1 commit a569160

File tree

5 files changed

+323
-173
lines changed

5 files changed

+323
-173
lines changed

include/swift/SIL/DebugUtils.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,19 @@ struct DebugVarCarryingInst : VarDeclCarryingInst {
531531
return varName;
532532
}
533533

534+
std::optional<StringRef> maybeGetName() const {
535+
assert(getKind() != Kind::Invalid);
536+
if (auto varInfo = getVarInfo()) {
537+
return varInfo->Name;
538+
}
539+
540+
if (auto *decl = getDecl()) {
541+
return decl->getBaseName().userFacingName();
542+
}
543+
544+
return {};
545+
}
546+
534547
/// Take in \p inst, a potentially invalid DebugVarCarryingInst, and returns a
535548
/// name for it. If we have an invalid value or don't find var info or a decl,
536549
/// return "unknown".
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
//===--- VariableNameUtils.h ----------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
///
13+
/// Utilities for inferring the name of a value.
14+
///
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_SILOPTIMIZER_UTILS_VARIABLENAMEUTILS_H
18+
#define SWIFT_SILOPTIMIZER_UTILS_VARIABLENAMEUTILS_H
19+
20+
#include "swift/SIL/ApplySite.h"
21+
#include "swift/SIL/DebugUtils.h"
22+
#include "swift/SIL/MemAccessUtils.h"
23+
#include "swift/SIL/SILInstruction.h"
24+
#include "swift/SIL/StackList.h"
25+
26+
namespace swift {
27+
28+
class VariableNameInferrer {
29+
/// The stacklist that we use to process from use->
30+
StackList<PointerUnion<SILInstruction *, SILValue>> variableNamePath;
31+
32+
/// The root value of our string.
33+
///
34+
/// If set, a diagnostic should do a 'root' is defined here error.
35+
SILValue rootValue;
36+
37+
/// The final string we computed.
38+
SmallString<64> &resultingString;
39+
40+
public:
41+
VariableNameInferrer(SILFunction *fn, SmallString<64> &resultingString)
42+
: variableNamePath(fn), resultingString(resultingString) {}
43+
44+
/// Attempts to infer a name from just uses of \p searchValue.
45+
///
46+
/// Returns true if we found a name.
47+
bool tryInferNameFromUses(SILValue searchValue) {
48+
auto *use = getAnyDebugUse(searchValue);
49+
if (!use)
50+
return false;
51+
52+
auto debugVar = DebugVarCarryingInst(use->getUser());
53+
if (!debugVar)
54+
return false;
55+
56+
assert(debugVar.getKind() == DebugVarCarryingInst::Kind::DebugValue);
57+
resultingString += debugVar.getName();
58+
return true;
59+
}
60+
61+
/// See if \p searchValue or one of its defs (walking use->def) has a name
62+
/// that we can use.
63+
///
64+
/// \p failInsteadOfEmittingUnknown set to true if we should return false
65+
/// rather than emitting unknown (and always succeeding).
66+
///
67+
/// \returns true if we inferred anything. Returns false otherwise.
68+
bool inferByWalkingUsesToDefs(SILValue searchValue) {
69+
// Look up our root value while adding to the variable name path list.
70+
auto rootValue = findDebugInfoProvidingValue(searchValue);
71+
if (!rootValue) {
72+
// If we do not pattern match successfully, just set resulting string to
73+
// unknown and return early.
74+
resultingString += "unknown";
75+
return true;
76+
}
77+
78+
drainVariableNamePath();
79+
return true;
80+
}
81+
82+
/// Infers the value that provides the debug info. This can be something like
83+
/// an alloc_stack that provides the information directly or a value that has
84+
/// a debug_value as a user.
85+
///
86+
/// \returns SILValue() if we did not find anything.
87+
SILValue inferByWalkingUsesToDefsReturningRoot(SILValue searchValue) {
88+
// Look up our root value while adding to the variable name path list.
89+
auto rootValue = findDebugInfoProvidingValue(searchValue);
90+
if (!rootValue) {
91+
// If we do not pattern match successfully, return SILValue() early.
92+
return SILValue();
93+
}
94+
95+
drainVariableNamePath();
96+
return rootValue;
97+
}
98+
99+
StringRef getName() const { return resultingString; }
100+
101+
private:
102+
void drainVariableNamePath();
103+
104+
/// Finds the SILValue that either provides the direct debug information or
105+
/// that has a debug_value user that provides the name of the value.
106+
SILValue findDebugInfoProvidingValue(SILValue searchValue);
107+
};
108+
109+
} // namespace swift
110+
111+
#endif

lib/SILOptimizer/Mandatory/MoveOnlyDiagnostics.cpp

Lines changed: 5 additions & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "swift/SIL/DebugUtils.h"
2424
#include "swift/SIL/FieldSensitivePrunedLiveness.h"
2525
#include "swift/SIL/SILArgument.h"
26+
#include "swift/SILOptimizer/Utils/VariableNameUtils.h"
2627
#include "llvm/Support/Debug.h"
2728

2829
#include "MoveOnlyTypeUtils.h"
@@ -73,181 +74,12 @@ static void diagnose(ASTContext &context, SourceLoc loc, Diag<T...> diag,
7374
context.Diags.diagnose(loc, diag, std::forward<U>(args)...);
7475
}
7576

76-
/// Helper function that actually implements getVariableNameForValue. Do not
77-
/// call it directly! Call the unary variants instead.
78-
static void getVariableNameForValue(SILValue value2,
79-
SILValue searchValue,
80-
SmallString<64> &resultingString) {
81-
// Before we do anything, lets see if we have an exact debug_value on our
82-
// mmci. In such a case, we can end early and are done.
83-
if (auto *use = getAnyDebugUse(value2)) {
84-
if (auto debugVar = DebugVarCarryingInst(use->getUser())) {
85-
assert(debugVar.getKind() == DebugVarCarryingInst::Kind::DebugValue);
86-
resultingString += debugVar.getName();
87-
return;
88-
}
89-
}
90-
91-
// Otherwise, we need to look at our mark_unresolved_non_copyable_value's
92-
// operand.
93-
StackList<llvm::PointerUnion<SILInstruction *, SILValue>> variableNamePath(
94-
value2->getFunction());
95-
while (searchValue) {
96-
if (auto *allocInst = dyn_cast<AllocationInst>(searchValue)) {
97-
// If the instruction itself doesn't carry any variable info, see whether
98-
// it's copied from another place that does.
99-
if (!allocInst->getDecl()) {
100-
if (auto copy = allocInst->getSingleUserOfType<CopyAddrInst>()) {
101-
if (copy->getDest() == allocInst
102-
&& !copy->isTakeOfSrc()
103-
&& copy->isInitializationOfDest()) {
104-
searchValue = copy->getSrc();
105-
continue;
106-
}
107-
}
108-
}
109-
110-
variableNamePath.push_back(allocInst);
111-
break;
112-
}
113-
114-
if (auto *globalAddrInst = dyn_cast<GlobalAddrInst>(searchValue)) {
115-
variableNamePath.push_back(globalAddrInst);
116-
break;
117-
}
118-
119-
if (auto *oeInst = dyn_cast<OpenExistentialAddrInst>(searchValue)) {
120-
searchValue = oeInst->getOperand();
121-
continue;
122-
}
123-
124-
if (auto *rei = dyn_cast<RefElementAddrInst>(searchValue)) {
125-
variableNamePath.push_back(rei);
126-
searchValue = rei->getOperand();
127-
continue;
128-
}
129-
130-
if (auto *fArg = dyn_cast<SILFunctionArgument>(searchValue)) {
131-
variableNamePath.push_back({fArg});
132-
break;
133-
}
134-
135-
auto getNamePathComponentFromCallee = [&](FullApplySite call) -> llvm::Optional<SILValue> {
136-
// Use the name of the property being accessed if we can get to it.
137-
if (isa<FunctionRefBaseInst>(call.getCallee())
138-
|| isa<MethodInst>(call.getCallee())) {
139-
variableNamePath.push_back(call.getCallee()->getDefiningInstruction());
140-
// Try to name the base of the property if this is a method.
141-
if (call.getSubstCalleeType()->hasSelfParam()) {
142-
return call.getSelfArgument();
143-
} else {
144-
return SILValue();
145-
}
146-
}
147-
return llvm::None;
148-
};
149-
150-
// Read or modify accessor.
151-
if (auto bai = dyn_cast_or_null<BeginApplyInst>(searchValue->getDefiningInstruction())) {
152-
if (auto selfParam = getNamePathComponentFromCallee(bai)) {
153-
searchValue = *selfParam;
154-
continue;
155-
}
156-
}
157-
158-
// Addressor accessor.
159-
if (auto ptrToAddr = dyn_cast<PointerToAddressInst>(stripAccessMarkers(searchValue))) {
160-
// The addressor can either produce the raw pointer itself or an `UnsafePointer` stdlib type wrapping it.
161-
ApplyInst *addressorInvocation;
162-
if (auto structExtract = dyn_cast<StructExtractInst>(ptrToAddr->getOperand())) {
163-
addressorInvocation = dyn_cast<ApplyInst>(structExtract->getOperand());
164-
} else {
165-
addressorInvocation = dyn_cast<ApplyInst>(ptrToAddr->getOperand());
166-
}
167-
168-
if (addressorInvocation) {
169-
if (auto selfParam = getNamePathComponentFromCallee(addressorInvocation)) {
170-
searchValue = *selfParam;
171-
continue;
172-
}
173-
}
174-
}
175-
176-
// If we do not do an exact match, see if we can find a debug_var inst. If
177-
// we do, we always break since we have a root value.
178-
if (auto *use = getAnyDebugUse(searchValue)) {
179-
if (auto debugVar = DebugVarCarryingInst(use->getUser())) {
180-
assert(debugVar.getKind() == DebugVarCarryingInst::Kind::DebugValue);
181-
variableNamePath.push_back(use->getUser());
182-
break;
183-
}
184-
}
185-
186-
// Otherwise, try to see if we have a single value instruction we can look
187-
// through.
188-
if (isa<BeginBorrowInst>(searchValue) || isa<LoadInst>(searchValue) ||
189-
isa<LoadBorrowInst>(searchValue) || isa<BeginAccessInst>(searchValue) ||
190-
isa<MarkUnresolvedNonCopyableValueInst>(searchValue) ||
191-
isa<ProjectBoxInst>(searchValue) || isa<CopyValueInst>(searchValue)) {
192-
searchValue = cast<SingleValueInstruction>(searchValue)->getOperand(0);
193-
continue;
194-
}
195-
196-
// If we do not pattern match successfully, just set resulting string to
197-
// unknown and return early.
198-
resultingString += "unknown";
199-
return;
200-
}
201-
202-
auto nameFromDecl = [&](Decl *d) -> StringRef {
203-
if (d) {
204-
if (auto accessor = dyn_cast<AccessorDecl>(d)) {
205-
return accessor->getStorage()->getBaseName().userFacingName();
206-
}
207-
if (auto vd = dyn_cast<ValueDecl>(d)) {
208-
return vd->getBaseName().userFacingName();
209-
}
210-
}
211-
212-
return "<unknown decl>";
213-
};
214-
215-
// Walk backwards, constructing our string.
216-
while (true) {
217-
auto next = variableNamePath.pop_back_val();
218-
219-
if (auto *inst = next.dyn_cast<SILInstruction *>()) {
220-
if (auto i = DebugVarCarryingInst(inst)) {
221-
resultingString += i.getName();
222-
} else if (auto i = VarDeclCarryingInst(inst)) {
223-
resultingString += i.getName();
224-
} else if (auto f = dyn_cast<FunctionRefBaseInst>(inst)) {
225-
if (auto dc = f->getInitiallyReferencedFunction()->getDeclContext()) {
226-
resultingString += nameFromDecl(dc->getAsDecl());
227-
} else {
228-
resultingString += "<unknown decl>";
229-
}
230-
} else if (auto m = dyn_cast<MethodInst>(inst)) {
231-
resultingString += nameFromDecl(m->getMember().getDecl());
232-
} else {
233-
resultingString += "<unknown decl>";
234-
}
235-
} else {
236-
auto value = next.get<SILValue>();
237-
if (auto *fArg = dyn_cast<SILFunctionArgument>(value))
238-
resultingString += fArg->getDecl()->getBaseName().userFacingName();
239-
}
240-
241-
if (variableNamePath.empty())
242-
return;
243-
244-
resultingString += '.';
245-
}
246-
}
247-
24877
static void getVariableNameForValue(MarkUnresolvedNonCopyableValueInst *mmci,
24978
SmallString<64> &resultingString) {
250-
return getVariableNameForValue(mmci, mmci->getOperand(), resultingString);
79+
VariableNameInferrer inferrer(mmci->getFunction(), resultingString);
80+
if (inferrer.tryInferNameFromUses(mmci))
81+
return;
82+
inferrer.inferByWalkingUsesToDefs(mmci->getOperand());
25183
}
25284

25385
//===----------------------------------------------------------------------===//

lib/SILOptimizer/Utils/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,5 @@ target_sources(swiftSILOptimizer PRIVATE
3131
SpecializationMangler.cpp
3232
StackNesting.cpp
3333
ValueLifetime.cpp
34+
VariableNameUtils.cpp
3435
OwnershipOptUtils.cpp)

0 commit comments

Comments
 (0)