Skip to content

Commit 69eb6ce

Browse files
committed
[opt-remark] Add a new SIL testing option that works around not having decls in SIL for debug_value.
Instead, in such a case, we use the name on the debug_value instead and just use as the loc the debug_value itself. This will let me write SIL test cases for opt-remark-gen. I am going to add SIL test cases for future changes (as well as swift ones) using this technique. I am going to in forthcoming commits fill in some tests for the current opt-remark-generation here. I just want to get in this part.
1 parent 6f9df09 commit 69eb6ce

File tree

3 files changed

+97
-13
lines changed

3 files changed

+97
-13
lines changed

include/swift/SIL/OptimizationRemark.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,12 @@ struct Argument {
119119
: Argument(ArgumentKey(ArgumentKeyKind::Default, key), msg, decl) {}
120120
Argument(ArgumentKey key, StringRef msg, const ValueDecl *decl)
121121
: key(key), val(msg), loc(decl->getLoc()) {}
122+
123+
Argument(StringRef key, llvm::Twine &&msg, SILLocation loc)
124+
: Argument(ArgumentKey(ArgumentKeyKind::Default, key), std::move(msg),
125+
loc) {}
126+
Argument(ArgumentKey key, llvm::Twine &&msg, SILLocation loc)
127+
: key(key), val(msg.str()), loc(loc.getSourceLoc()) {}
122128
};
123129

124130
/// Shorthand to insert named-value pairs.

lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ static llvm::cl::opt<bool> ForceVisitImplicitAutogeneratedFunctions(
4141
"Emit opt remarks even on implicit and autogenerated functions"),
4242
llvm::cl::init(false));
4343

44+
static llvm::cl::opt<bool> DecllessDebugValueUseSILDebugInfo(
45+
"optremarkgen-declless-debugvalue-use-sildebugvar-info", llvm::cl::Hidden,
46+
llvm::cl::desc(
47+
"If a debug_value does not have a decl, infer a value with a name from "
48+
"that info that has a loc set to the loc of the debug_value "
49+
"instruction itself. This is for testing purposes so it is easier to "
50+
"write SIL test cases for this pass"),
51+
llvm::cl::init(false));
52+
4453
//===----------------------------------------------------------------------===//
4554
// Value To Decl Inferrer
4655
//===----------------------------------------------------------------------===//
@@ -65,16 +74,13 @@ struct ValueToDeclInferrer {
6574
/// accessPath we computed for decl producing a segmented access path, e.x.:
6675
/// "of 'x.lhs.ivar'".
6776
void printNote(llvm::raw_string_ostream &stream, const ValueDecl *decl);
77+
78+
void printProjectionPath(llvm::raw_string_ostream &stream);
6879
};
6980

7081
} // anonymous namespace
7182

72-
void ValueToDeclInferrer::printNote(llvm::raw_string_ostream &stream,
73-
const ValueDecl *decl) {
74-
assert(decl &&
75-
"We assume for now that this is always called with a non-null decl");
76-
stream << "of '" << decl->getBaseName();
77-
83+
void ValueToDeclInferrer::printProjectionPath(llvm::raw_string_ostream &stream) {
7884
for (auto &pair : accessPath) {
7985
auto baseType = pair.first;
8086
auto &proj = pair.second;
@@ -111,8 +117,14 @@ void ValueToDeclInferrer::printNote(llvm::raw_string_ostream &stream,
111117

112118
llvm_unreachable("Covered switch is not covered?!");
113119
}
120+
}
114121

115-
accessPath.clear();
122+
void ValueToDeclInferrer::printNote(llvm::raw_string_ostream &stream,
123+
const ValueDecl *decl) {
124+
assert(decl &&
125+
"We assume for now that this is always called with a non-null decl");
126+
stream << "of '" << decl->getBaseName();
127+
printProjectionPath(stream);
116128
stream << "'";
117129
}
118130

@@ -145,6 +157,11 @@ static bool hasNonInlinedDebugScope(SILInstruction *i) {
145157
bool ValueToDeclInferrer::infer(
146158
ArgumentKeyKind keyKind, SILValue value,
147159
SmallVectorImpl<Argument> &resultingInferredDecls) {
160+
// Clear the stored access path at end of scope.
161+
SWIFT_DEFER {
162+
accessPath.clear();
163+
};
164+
148165
// This is a linear IR traversal using a 'falling while loop'. That means
149166
// every time through the loop we are trying to handle a case before we hit
150167
// the bottom of the while loop where we always return true (since we did not
@@ -234,15 +251,37 @@ bool ValueToDeclInferrer::infer(
234251
llvm::raw_string_ostream stream(msg);
235252
printNote(stream, decl);
236253
}
237-
resultingInferredDecls.push_back(
238-
Argument({keyKind, "InferredValue"}, std::move(msg), decl));
254+
resultingInferredDecls.emplace_back(
255+
OptRemark::ArgumentKey{keyKind, "InferredValue"},
256+
std::move(msg), decl);
239257
foundDeclFromUse = true;
258+
} else {
259+
// If we did not have a decl, see if we were asked for testing
260+
// purposes to use SILDebugInfo to create a placeholder inferred
261+
// value.
262+
if (DecllessDebugValueUseSILDebugInfo) {
263+
if (auto varInfo = dvi->getVarInfo()) {
264+
auto name = varInfo->Name;
265+
if (!name.empty()) {
266+
std::string msg;
267+
{
268+
llvm::raw_string_ostream stream(msg);
269+
stream << "of '" << name;
270+
printProjectionPath(stream);
271+
stream << "'";
272+
}
273+
resultingInferredDecls.push_back(
274+
Argument({keyKind, "InferredValue"},
275+
std::move(msg),
276+
dvi->getLoc()));
277+
foundDeclFromUse = true;
278+
}
279+
}
280+
}
240281
}
241282
}
242283
}
243284
}
244-
if (foundDeclFromUse)
245-
return true;
246285

247286
// At this point, we could not infer any argument. See if we can look
248287
// through loads.
@@ -267,7 +306,7 @@ bool ValueToDeclInferrer::infer(
267306

268307
// If we reached this point, we finished falling through the loop and return
269308
// true.
270-
return true;
309+
return foundDeclFromUse;
271310
}
272311
}
273312

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,54 @@
1-
// RUN: %target-sil-opt -sil-opt-remark-generator -sil-remarks-missed=sil-opt-remark-gen -verify %s -o /dev/null
1+
// RUN: %target-sil-opt -optremarkgen-declless-debugvalue-use-sildebugvar-info -sil-opt-remark-generator -sil-remarks-missed=sil-opt-remark-gen -verify %s -o /dev/null
22

33
sil_stage canonical
44

55
import Builtin
66

77
sil @foo : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
88
bb0(%0 : $Builtin.NativeObject):
9+
debug_value %0 : $Builtin.NativeObject, let, name "arg"
910
strong_retain %0 : $Builtin.NativeObject // expected-remark {{retain of type 'Builtin.NativeObject'}}
11+
// expected-note @-2 {{of 'arg'}}
1012
retain_value %0 : $Builtin.NativeObject // expected-remark {{retain of type 'Builtin.NativeObject'}}
13+
// expected-note @-4 {{of 'arg'}}
1114
strong_release %0 : $Builtin.NativeObject // expected-remark {{release of type 'Builtin.NativeObject'}}
15+
// expected-note @-6 {{of 'arg'}}
1216
release_value %0 : $Builtin.NativeObject // expected-remark {{release of type 'Builtin.NativeObject'}}
17+
// expected-note @-8 {{of 'arg'}}
1318
%9999 = tuple()
1419
return %9999 : $()
1520
}
21+
22+
public enum TrivialState {
23+
case first
24+
case second
25+
case third
26+
}
27+
28+
struct StructWithOwner {
29+
var owner: Builtin.NativeObject
30+
var state: TrivialState
31+
}
32+
33+
sil @extract_out_singleobj_struct_subfield_1 : $@convention(thin) (@guaranteed StructWithOwner) -> Builtin.NativeObject {
34+
bb0(%0 : $StructWithOwner):
35+
debug_value %0 : $StructWithOwner, let, name "x"
36+
%1 = struct_extract %0 : $StructWithOwner, #StructWithOwner.owner
37+
strong_retain %1 : $Builtin.NativeObject // expected-remark {{retain of type 'Builtin.NativeObject'}}
38+
// expected-note @-3 {{of 'x.owner'}}
39+
return %1 : $Builtin.NativeObject
40+
}
41+
42+
// This case should never actually happen like this, but we should handle it in
43+
// a sane way by printing both notes for y and x and also make sure that we do
44+
// not infer .owner on y since y is on owner itself.
45+
sil @extract_out_singleobj_struct_subfield_multiple_debugvalue : $@convention(thin) (@guaranteed StructWithOwner) -> Builtin.NativeObject {
46+
bb0(%0 : $StructWithOwner):
47+
debug_value %0 : $StructWithOwner, let, name "x"
48+
%1 = struct_extract %0 : $StructWithOwner, #StructWithOwner.owner
49+
debug_value %1 : $Builtin.NativeObject, let, name "y"
50+
strong_retain %1 : $Builtin.NativeObject // expected-remark {{retain of type 'Builtin.NativeObject'}}
51+
// expected-note @-4 {{of 'x.owner'}}
52+
// expected-note @-3 {{of 'y'}}
53+
return %1 : $Builtin.NativeObject
54+
}

0 commit comments

Comments
 (0)