Skip to content

Commit 356bfee

Browse files
authored
Merge pull request swiftlang#33023 from gottesmm/pr-c7a2ff52b8850a874dcf6dc84616594e4cbcfaf4
[opt-remark] Teach opt-remark how to emit back notes to retain/released variables in simple cases.
2 parents 4b6641f + 2c9a34f commit 356bfee

File tree

7 files changed

+279
-59
lines changed

7 files changed

+279
-59
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,7 @@ ERROR(non_borrowed_indirect_addressof,none,
536536

537537
REMARK(opt_remark_passed, none, "%0", (StringRef))
538538
REMARK(opt_remark_missed, none, "%0", (StringRef))
539+
NOTE(opt_remark_note, none, "%0", (StringRef))
539540

540541
// Float-point to integer conversions
541542
ERROR(float_to_int_overflow, none,

include/swift/SIL/OptimizationRemark.h

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include "swift/Basic/SourceLoc.h"
2323
#include "swift/Demangling/Demangler.h"
24+
#include "swift/SIL/SILArgument.h"
2425
#include "swift/SIL/SILBasicBlock.h"
2526
#include "swift/SIL/SILInstruction.h"
2627
#include "swift/SIL/SILModule.h"
@@ -32,27 +33,105 @@ class SILFunction;
3233

3334
namespace OptRemark {
3435

36+
struct ArgumentKeyKind {
37+
enum InnerTy {
38+
// Just assume this is a normal msg that we are emitting.
39+
Default,
40+
41+
// Assume this is a note that should be emitted as a separate
42+
// diagnostic when emitting diagnostics. Do nothing special
43+
// along the backend path.
44+
Note,
45+
46+
// Assume that this is a note that should be emitted as a separate
47+
// diagnostic but that doesn't have its own source loc: we should reuse the
48+
// one for the original remark.
49+
//
50+
// This is intended to be used in situations where one needs to emit a
51+
// "note" warning due to us not being able to infer a part of our
52+
// opt-remark.
53+
ParentLocNote,
54+
};
55+
56+
InnerTy innerValue;
57+
58+
ArgumentKeyKind(InnerTy value) : innerValue(value) {}
59+
ArgumentKeyKind(const ArgumentKeyKind &kind) : innerValue(kind.innerValue) {}
60+
61+
operator InnerTy() const { return innerValue; }
62+
63+
/// Return true if this argument is meant to be a separate diagnostic when we
64+
/// emit diagnostics but when we emit to the remark streamer (due to not
65+
/// having support for this), we just emit the remark inline.
66+
///
67+
/// TODO: Unfortunate that this needs to be done.
68+
bool isSeparateDiagnostic() const {
69+
switch (innerValue) {
70+
case InnerTy::Default:
71+
return false;
72+
case InnerTy::Note:
73+
case InnerTy::ParentLocNote:
74+
return true;
75+
}
76+
77+
llvm_unreachable("Covered switch isn't covered?!");
78+
}
79+
};
80+
81+
struct ArgumentKey {
82+
ArgumentKeyKind kind;
83+
std::string data;
84+
85+
ArgumentKey(ArgumentKeyKind kind, StringRef data) : kind(kind), data(data) {}
86+
ArgumentKey(ArgumentKeyKind::InnerTy kind, StringRef data)
87+
: kind(kind), data(data) {}
88+
ArgumentKey(ArgumentKey kind, StringRef data) : kind(kind.kind), data(data) {}
89+
};
90+
3591
/// Used in the streaming interface as the general argument type. It
3692
/// internally converts everything into a key-value pair.
3793
struct Argument {
38-
std::string key;
94+
ArgumentKey key;
3995
std::string val;
4096
/// If set, the debug location corresponding to the value.
4197
SourceLoc loc;
4298

43-
explicit Argument(StringRef Str = "") : key("String"), val(Str) {}
44-
Argument(StringRef key, StringRef val) : key(key), val(val) {}
99+
explicit Argument(StringRef str = "")
100+
: Argument({ArgumentKeyKind::Default, "String"}, str) {}
45101

102+
Argument(StringRef key, StringRef val)
103+
: Argument({ArgumentKeyKind::Default, key}, val) {}
104+
Argument(ArgumentKey key, StringRef val) : key(key), val(val) {}
46105
Argument(StringRef key, int n);
47106
Argument(StringRef key, long n);
48107
Argument(StringRef key, long long n);
49108
Argument(StringRef key, unsigned n);
50109
Argument(StringRef key, unsigned long n);
51110
Argument(StringRef key, unsigned long long n);
52111

53-
Argument(StringRef key, SILFunction *f);
112+
Argument(StringRef key, SILFunction *f)
113+
: Argument(ArgumentKey(ArgumentKeyKind::Default, key), f) {}
114+
Argument(ArgumentKey key, SILFunction *f);
54115
Argument(StringRef key, SILType ty);
55116
Argument(StringRef key, CanType ty);
117+
118+
Argument(StringRef key, StringRef msg, const ValueDecl *decl)
119+
: Argument(ArgumentKey(ArgumentKeyKind::Default, key), msg, decl) {}
120+
Argument(ArgumentKey key, StringRef msg, const ValueDecl *decl)
121+
: key(key), val(msg), loc(decl->getLoc()) {}
122+
123+
/// Given a value, call \p funcPassedInferredArgs for each associated
124+
/// ValueDecl that is associated with \p value. All created Arguments are
125+
/// passed the same StringRef. To stop iteration, return false in \p
126+
/// funcPassedInferedArgs.
127+
///
128+
/// NOTE: the function may be called multiple times if the optimizer joined
129+
/// two live ranges and thus when iterating over value's users we see multiple
130+
/// debug_value operations.
131+
static bool
132+
inferArgumentsForValue(ArgumentKeyKind keyKind, StringRef message,
133+
SILValue value,
134+
function_ref<bool(Argument)> funcPassedInferedArgs);
56135
};
57136

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

include/swift/SIL/SILRemarkStreamer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ llvm::remarks::Remark SILRemarkStreamer::toLLVMRemark(
111111

112112
for (const OptRemark::Argument &arg : optRemark.getArgs()) {
113113
llvmRemark.Args.emplace_back();
114-
llvmRemark.Args.back().Key = arg.key;
114+
llvmRemark.Args.back().Key = arg.key.data;
115115
llvmRemark.Args.back().Val = arg.val;
116116
llvmRemark.Args.back().Loc =
117117
toRemarkLocation(arg.loc, getASTContext().SourceMgr);

lib/SIL/Utils/OptimizationRemark.cpp

Lines changed: 70 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
#include "swift/AST/DiagnosticEngine.h"
2121
#include "swift/AST/DiagnosticsSIL.h"
2222
#include "swift/Demangling/Demangler.h"
23+
#include "swift/SIL/DebugUtils.h"
24+
#include "swift/SIL/SILArgument.h"
25+
#include "swift/SIL/SILInstruction.h"
2326
#include "swift/SIL/SILRemarkStreamer.h"
2427
#include "llvm/ADT/StringExtras.h"
2528
#include "llvm/Support/CommandLine.h"
@@ -28,23 +31,25 @@
2831
using namespace swift;
2932
using namespace OptRemark;
3033

31-
Argument::Argument(StringRef key, int n) : key(key), val(llvm::itostr(n)) {}
34+
Argument::Argument(StringRef key, int n)
35+
: key(ArgumentKeyKind::Default, key), val(llvm::itostr(n)) {}
3236

33-
Argument::Argument(StringRef key, long n) : key(key), val(llvm::itostr(n)) {}
37+
Argument::Argument(StringRef key, long n)
38+
: key(ArgumentKeyKind::Default, key), val(llvm::itostr(n)) {}
3439

3540
Argument::Argument(StringRef key, long long n)
36-
: key(key), val(llvm::itostr(n)) {}
41+
: key(ArgumentKeyKind::Default, key), val(llvm::itostr(n)) {}
3742

3843
Argument::Argument(StringRef key, unsigned n)
39-
: key(key), val(llvm::utostr(n)) {}
44+
: key(ArgumentKeyKind::Default, key), val(llvm::utostr(n)) {}
4045

4146
Argument::Argument(StringRef key, unsigned long n)
42-
: key(key), val(llvm::utostr(n)) {}
47+
: key(ArgumentKeyKind::Default, key), val(llvm::utostr(n)) {}
4348

4449
Argument::Argument(StringRef key, unsigned long long n)
45-
: key(key), val(llvm::utostr(n)) {}
50+
: key(ArgumentKeyKind::Default, key), val(llvm::utostr(n)) {}
4651

47-
Argument::Argument(StringRef key, SILFunction *f) : key(key) {
52+
Argument::Argument(ArgumentKey key, SILFunction *f) : key(key) {
4853
auto options = Demangle::DemangleOptions::SimplifiedUIDemangleOptions();
4954
// Enable module names so that we have a way of filtering out
5055
// stdlib-related remarks.
@@ -58,22 +63,53 @@ Argument::Argument(StringRef key, SILFunction *f) : key(key) {
5863
loc = f->getLocation().getSourceLoc();
5964
}
6065

61-
Argument::Argument(StringRef key, SILType ty) : key(key) {
66+
Argument::Argument(StringRef key, SILType ty)
67+
: key(ArgumentKeyKind::Default, key) {
6268
llvm::raw_string_ostream stream(val);
6369
ty.print(stream);
6470
}
6571

66-
Argument::Argument(StringRef key, CanType ty) : key(key) {
72+
Argument::Argument(StringRef key, CanType ty)
73+
: key(ArgumentKeyKind::Default, key) {
6774
llvm::raw_string_ostream stream(val);
6875
ty.print(stream);
6976
}
7077

78+
bool Argument::inferArgumentsForValue(
79+
ArgumentKeyKind keyKind, StringRef msg, SILValue value,
80+
function_ref<bool(Argument)> funcPassedInferedArgs) {
81+
// If we have an argument, just use that.
82+
if (auto *arg = dyn_cast<SILArgument>(value))
83+
if (auto *decl = arg->getDecl())
84+
return funcPassedInferedArgs(
85+
Argument({keyKind, "InferredValue"}, msg, decl));
86+
87+
// TODO: Look for loads from globals and addresses.
88+
89+
// Otherwise, look for debug_values.
90+
for (auto *use : getDebugUses(value))
91+
if (auto *dvi = dyn_cast<DebugValueInst>(use->getUser()))
92+
if (auto *decl = dvi->getDecl())
93+
if (!funcPassedInferedArgs(
94+
Argument({keyKind, "InferredValue"}, msg, decl)))
95+
return false;
96+
97+
return true;
98+
}
99+
71100
template <typename DerivedT>
72101
std::string Remark<DerivedT>::getMsg() const {
73102
std::string str;
74103
llvm::raw_string_ostream stream(str);
75-
for (const Argument &arg : args)
104+
// Go through our args and if we are not emitting for diagnostics *OR* we are
105+
// emitting for diagnostics and this argument is not intended to be emitted as
106+
// a diagnostic separate from our main remark, emit the arg value here.
107+
for (const Argument &arg : args) {
108+
if (arg.key.kind.isSeparateDiagnostic())
109+
continue;
76110
stream << arg.val;
111+
}
112+
77113
return stream.str();
78114
}
79115

@@ -194,9 +230,30 @@ static void emitRemark(SILModule &module, const Remark<RemarkT> &remark,
194230
return;
195231
if (auto *remarkStreamer = module.getSILRemarkStreamer())
196232
remarkStreamer->emit(remark);
197-
if (diagEnabled)
198-
module.getASTContext().Diags.diagnose(remark.getLocation(), id,
199-
remark.getMsg());
233+
234+
// If diagnostics are enabled, first emit the main diagnostic and then loop
235+
// through our arguments and allow the arguments to add additional diagnostics
236+
// if they want.
237+
if (!diagEnabled)
238+
return;
239+
240+
auto &de = module.getASTContext().Diags;
241+
de.diagnoseWithNotes(
242+
de.diagnose(remark.getLocation(), id, remark.getMsg()), [&]() {
243+
for (auto &arg : remark.getArgs()) {
244+
switch (arg.key.kind) {
245+
case ArgumentKeyKind::Default:
246+
continue;
247+
case ArgumentKeyKind::Note:
248+
de.diagnose(arg.loc, diag::opt_remark_note, arg.val);
249+
continue;
250+
case ArgumentKeyKind::ParentLocNote:
251+
de.diagnose(remark.getLocation(), diag::opt_remark_note, arg.val);
252+
continue;
253+
}
254+
llvm_unreachable("Unhandled case?!");
255+
}
256+
});
200257
}
201258

202259
void Emitter::emit(const RemarkPassed &remark) {

0 commit comments

Comments
 (0)