Skip to content

Commit 61e93c5

Browse files
authored
Merge pull request swiftlang#33599 from gottesmm/pr-0a5fe73f7591074eb2e48781ce406f7df53c9c63
[opt-remark] Add remarks for alloc_box, alloc_ref, alloc_stack
2 parents 8094bd9 + ac64ad6 commit 61e93c5

File tree

5 files changed

+262
-88
lines changed

5 files changed

+262
-88
lines changed

lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp

Lines changed: 120 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,10 @@ struct ValueToDeclInferrer {
7171

7272
void ValueToDeclInferrer::printNote(llvm::raw_string_ostream &stream,
7373
const ValueDecl *decl) {
74+
assert(decl &&
75+
"We assume for now that this is always called with a non-null decl");
7476
stream << "of '" << decl->getBaseName();
77+
7578
for (auto &pair : accessPath) {
7679
auto baseType = pair.first;
7780
auto &proj = pair.second;
@@ -133,6 +136,12 @@ static SingleValueInstruction *isSupportedProjection(Projection p, SILValue v) {
133136
llvm_unreachable("Covered switch is not covered?!");
134137
}
135138

139+
static bool hasNonInlinedDebugScope(SILInstruction *i) {
140+
if (auto *scope = i->getDebugScope())
141+
return !scope->InlinedCallSite;
142+
return false;
143+
}
144+
136145
bool ValueToDeclInferrer::infer(
137146
ArgumentKeyKind keyKind, SILValue value,
138147
SmallVectorImpl<Argument> &resultingInferredDecls) {
@@ -167,6 +176,46 @@ bool ValueToDeclInferrer::infer(
167176
return true;
168177
}
169178

179+
if (auto *ari = dyn_cast<AllocRefInst>(value)) {
180+
if (auto *decl = ari->getDecl()) {
181+
std::string msg;
182+
{
183+
llvm::raw_string_ostream stream(msg);
184+
printNote(stream, decl);
185+
}
186+
resultingInferredDecls.push_back(
187+
Argument({keyKind, "InferredValue"}, std::move(msg), decl));
188+
return true;
189+
}
190+
}
191+
192+
if (auto *abi = dyn_cast<AllocBoxInst>(value)) {
193+
if (auto *decl = abi->getDecl()) {
194+
std::string msg;
195+
{
196+
llvm::raw_string_ostream stream(msg);
197+
printNote(stream, decl);
198+
}
199+
200+
resultingInferredDecls.push_back(
201+
Argument({keyKind, "InferredValue"}, std::move(msg), decl));
202+
return true;
203+
}
204+
}
205+
206+
if (auto *asi = dyn_cast<AllocStackInst>(value)) {
207+
if (auto *decl = asi->getDecl()) {
208+
std::string msg;
209+
{
210+
llvm::raw_string_ostream stream(msg);
211+
printNote(stream, decl);
212+
}
213+
resultingInferredDecls.push_back(
214+
Argument({keyKind, "InferredValue"}, std::move(msg), decl));
215+
return true;
216+
}
217+
}
218+
170219
// Then visit our users and see if we can find a debug_value that provides
171220
// us with a decl we can use to construct an argument.
172221
bool foundDeclFromUse = false;
@@ -178,18 +227,16 @@ bool ValueToDeclInferrer::infer(
178227
if (auto *dvi = dyn_cast<DebugValueInst>(use->getUser())) {
179228
// Check if our debug_value has a decl and was not inlined into the
180229
// current function.
181-
if (auto *scope = dvi->getDebugScope()) {
182-
if (!scope->InlinedCallSite) {
183-
if (auto *decl = dvi->getDecl()) {
184-
std::string msg;
185-
{
186-
llvm::raw_string_ostream stream(msg);
187-
printNote(stream, decl);
188-
}
189-
resultingInferredDecls.push_back(
190-
Argument({keyKind, "InferredValue"}, std::move(msg), decl));
191-
foundDeclFromUse = true;
230+
if (hasNonInlinedDebugScope(dvi)) {
231+
if (auto *decl = dvi->getDecl()) {
232+
std::string msg;
233+
{
234+
llvm::raw_string_ostream stream(msg);
235+
printNote(stream, decl);
192236
}
237+
resultingInferredDecls.push_back(
238+
Argument({keyKind, "InferredValue"}, std::move(msg), decl));
239+
foundDeclFromUse = true;
193240
}
194241
}
195242
}
@@ -216,6 +263,8 @@ bool ValueToDeclInferrer::infer(
216263
}
217264
}
218265

266+
// TODO: We could emit at this point a msg for temporary allocations.
267+
219268
// If we reached this point, we finished falling through the loop and return
220269
// true.
221270
return true;
@@ -245,6 +294,8 @@ struct OptRemarkGeneratorInstructionVisitor
245294
void visitStrongReleaseInst(StrongReleaseInst *sri);
246295
void visitRetainValueInst(RetainValueInst *rvi);
247296
void visitReleaseValueInst(ReleaseValueInst *rvi);
297+
void visitAllocRefInst(AllocRefInst *ari);
298+
void visitAllocBoxInst(AllocBoxInst *abi);
248299
void visitSILInstruction(SILInstruction *) {}
249300
};
250301

@@ -333,6 +384,64 @@ void OptRemarkGeneratorInstructionVisitor::visitReleaseValueInst(
333384
});
334385
}
335386

387+
void OptRemarkGeneratorInstructionVisitor::visitAllocRefInst(
388+
AllocRefInst *ari) {
389+
if (ari->canAllocOnStack()) {
390+
return ORE.emit([&]() {
391+
using namespace OptRemark;
392+
SmallVector<Argument, 8> inferredArgs;
393+
bool foundArgs =
394+
valueToDeclInferrer.infer(ArgumentKeyKind::Note, ari, inferredArgs);
395+
(void)foundArgs;
396+
auto resultRemark =
397+
RemarkPassed("memory", *ari,
398+
SourceLocInferenceBehavior::ForwardScanOnly)
399+
<< "stack allocated ref of type '" << NV("ValueType", ari->getType())
400+
<< "'";
401+
for (auto &arg : inferredArgs)
402+
resultRemark << arg;
403+
return resultRemark;
404+
});
405+
}
406+
407+
return ORE.emit([&]() {
408+
using namespace OptRemark;
409+
SmallVector<Argument, 8> inferredArgs;
410+
bool foundArgs =
411+
valueToDeclInferrer.infer(ArgumentKeyKind::Note, ari, inferredArgs);
412+
(void)foundArgs;
413+
414+
auto resultRemark =
415+
RemarkMissed("memory", *ari,
416+
SourceLocInferenceBehavior::ForwardScanOnly)
417+
<< "heap allocated ref of type '" << NV("ValueType", ari->getType())
418+
<< "'";
419+
for (auto &arg : inferredArgs)
420+
resultRemark << arg;
421+
return resultRemark;
422+
});
423+
}
424+
425+
void OptRemarkGeneratorInstructionVisitor::visitAllocBoxInst(
426+
AllocBoxInst *abi) {
427+
return ORE.emit([&]() {
428+
using namespace OptRemark;
429+
SmallVector<Argument, 8> inferredArgs;
430+
bool foundArgs =
431+
valueToDeclInferrer.infer(ArgumentKeyKind::Note, abi, inferredArgs);
432+
(void)foundArgs;
433+
434+
auto resultRemark =
435+
RemarkMissed("memory", *abi,
436+
SourceLocInferenceBehavior::ForwardScanOnly)
437+
<< "heap allocated box of type '" << NV("ValueType", abi->getType())
438+
<< "'";
439+
for (auto &arg : inferredArgs)
440+
resultRemark << arg;
441+
return resultRemark;
442+
});
443+
}
444+
336445
//===----------------------------------------------------------------------===//
337446
// Top Level Entrypoint
338447
//===----------------------------------------------------------------------===//

test/SILOptimizer/opt-remark-generator-force-emit-implicit-autogen.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// RUN: %target-swiftc_driver -O -Rpass-missed=sil-opt-remark-gen -Xllvm -sil-disable-pass=FunctionSignatureOpts -emit-sil %s -o /dev/null -Xfrontend -verify -Xllvm -optremarkgen-visit-implicit-autogen-funcs=1
22

3-
class Klass {}
3+
// From the constructor.
4+
class Klass {} // expected-remark {{heap allocated ref of type 'Klass'}}
45

56
struct KlassPair {
67
var lhs: Klass // expected-remark {{retain of type 'Klass'}}
Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -emit-sil %s -verify -Osize
1+
// RUN: %target-swift-frontend -emit-sil %s -verify -Osize -o /dev/null -module-name main
22
//
33
// NOTE: We only emit opt-remarks with -Osize,-O today! -O does drop way more
44
// stuff though, so we test with -Osize.
@@ -7,29 +7,41 @@ public class Klass {}
77

88
public var mySingleton = Klass()
99

10+
@inline(never)
11+
func getGlobal() -> Klass {
12+
return mySingleton
13+
}
14+
15+
@inline(never)
16+
func useKlass(_ k: Klass) {}
17+
1018
@_semantics("optremark")
1119
@inline(never)
12-
public func forceOptRemark() -> Klass {
13-
return mySingleton // expected-remark {{retain}}
14-
// expected-note @-6 {{of 'mySingleton'}}
20+
public func forceOptRemark() {
21+
let x = getGlobal()
22+
useKlass(x) // expected-remark {{release of type 'Klass'}}
23+
// expected-note @-2 {{of 'x'}}
1524
}
1625

1726
@_semantics("optremark.sil-opt-remark-gen")
1827
@inline(never)
19-
public func forceOptRemark2() -> Klass {
20-
return mySingleton // expected-remark {{retain}}
21-
// expected-note @-13 {{of 'mySingleton'}}
28+
public func forceOptRemark2() {
29+
let x = getGlobal()
30+
useKlass(x) // expected-remark {{release of type 'Klass'}}
31+
// expected-note @-2 {{of 'x'}}
2232
}
2333

2434
@_semantics("optremark.fail")
2535
@inline(never)
26-
public func failMatch() -> Klass {
27-
return mySingleton
36+
public func failMatch() {
37+
let x = getGlobal()
38+
useKlass(x)
2839
}
2940

3041
@_semantics("optremark")
3142
public func allocateInlineCallee() -> Klass {
3243
return Klass() // expected-remark {{Pure call. Always profitable to inline "main.Klass.__allocating_init()"}}
44+
// expected-remark @-1 {{heap allocated ref of type 'Klass'}}
3345
}
3446

3547
@_semantics("optremark.sil-inliner")
@@ -45,29 +57,31 @@ public func allocateInlineCallee3() -> Klass {
4557
@_semantics("optremark.sil-inliner")
4658
@_semantics("optremark.sil-opt-remark-gen")
4759
public func mix1() -> (Klass, Klass) {
48-
return (mySingleton, Klass()) // expected-remark {{Pure call. Always profitable to inline "main.Klass.__allocating_init()"}}
49-
// expected-remark @-1:5 {{retain}}
50-
// expected-note @-42:12 {{of 'mySingleton'}}
60+
let x = getGlobal()
61+
return (x, Klass()) // expected-remark {{Pure call. Always profitable to inline "main.Klass.__allocating_init()"}}
62+
// expected-remark @-1:16 {{heap allocated ref of type 'Klass'}}
5163
}
5264

5365
@_semantics("optremark.sil-inliner")
5466
public func mix2() -> (Klass, Klass) {
55-
return (mySingleton, Klass()) // expected-remark {{Pure call. Always profitable to inline "main.Klass.__allocating_init()"}}
67+
let x = getGlobal()
68+
return (x, Klass()) // expected-remark {{Pure call. Always profitable to inline "main.Klass.__allocating_init()"}}
5669
}
5770

5871
@_semantics("optremark.sil-opt-remark-gen")
5972
public func mix3() -> (Klass, Klass) {
60-
return (mySingleton, Klass()) // expected-remark @:5 {{retain}}
61-
// expected-note @-53:12 {{of 'mySingleton'}}
73+
let x = getGlobal()
74+
return (x, Klass()) // expected-remark {{heap allocated ref of type 'Klass'}}
6275
}
6376

6477
@_semantics("optremark")
6578
public func mix4() -> (Klass, Klass) {
66-
return (mySingleton, Klass()) // expected-remark {{Pure call. Always profitable to inline "main.Klass.__allocating_init()"}}
67-
// expected-remark @-1:5 {{retain}}
68-
// expected-note @-60:12 {{of 'mySingleton'}}
79+
let x = getGlobal()
80+
return (x, Klass()) // expected-remark {{Pure call. Always profitable to inline "main.Klass.__allocating_init()"}}
81+
// expected-remark @-1 {{heap allocated ref of type 'Klass'}}
6982
}
7083

7184
public func mix5() -> (Klass, Klass) {
72-
return (mySingleton, Klass())
85+
let x = getGlobal()
86+
return (x, Klass())
7387
}

test/SILOptimizer/opt-remark-generator-yaml.swift

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,18 @@
99

1010
public class Klass {}
1111

12-
public var global = Klass()
12+
// CHECK: --- !Missed
13+
// CHECK-NEXT: Pass: sil-opt-remark-gen
14+
// CHECK-NEXT: Name: sil.memory
15+
// CHECK-NEXT: DebugLoc: { File: '{{.*}}opt-remark-generator-yaml.swift',
16+
// CHECK-NEXT: Line: [[# @LINE + 7 ]], Column: 21 }
17+
// CHECK-NEXT: Function: main
18+
// CHECK-NEXT: Args:
19+
// CHECK-NEXT: - String: 'heap allocated ref of type '''
20+
// CHECK-NEXT: - ValueType: Klass
21+
// CHECK-NEXT: - String: ''''
22+
// CHECK-NEXT: ...
23+
public var global = Klass() // expected-remark {{heap allocated ref of type 'Klass'}}
1324

1425
// CHECK: --- !Missed
1526
// CHECK-NEXT: Pass: sil-opt-remark-gen
@@ -31,6 +42,17 @@ public func getGlobal() -> Klass {
3142
// expected-note @-19:12 {{of 'global'}}
3243
}
3344

45+
// CHECK: --- !Missed
46+
// CHECK-NEXT: Pass: sil-opt-remark-gen
47+
// CHECK-NEXT: Name: sil.memory
48+
// CHECK-NEXT: DebugLoc: { File: '{{.*}}opt-remark-generator-yaml.swift',
49+
// CHECK-NEXT: Line: [[# @LINE + 51]], Column: 11 }
50+
// CHECK-NEXT: Function: 'useGlobal()'
51+
// CHECK-NEXT: Args:
52+
// CHECK-NEXT: - String: 'heap allocated ref of type '''
53+
// CHECK-NEXT: - ValueType:
54+
// CHECK-NEXT: - String: ''''
55+
// CHECK-NEXT: ...
3456
// CHECK-NEXT: --- !Missed
3557
// CHECK-NEXT: Pass: sil-opt-remark-gen
3658
// CHECK-NEXT: Name: sil.memory
@@ -75,10 +97,11 @@ public func useGlobal() {
7597
let x = getGlobal()
7698
// Make sure that the retain msg is at the beginning of the print and the
7799
// releases are the end of the print.
78-
print(x) // expected-remark @:5 {{retain of type 'Klass'}}
79-
// expected-note @-4:9 {{of 'x'}}
100+
print(x) // expected-remark @:11 {{heap allocated ref of type}}
101+
// expected-remark @-1:5 {{retain of type 'Klass'}}
102+
// expected-note @-5:9 {{of 'x'}}
80103
// We test the type emission above since FileCheck can handle regex.
81-
// expected-remark @-3:12 {{release of type}}
82-
// expected-remark @-4:12 {{release of type 'Klass'}}
83-
// expected-note @-8:9 {{of 'x'}}
104+
// expected-remark @-4:12 {{release of type}}
105+
// expected-remark @-5:12 {{release of type 'Klass'}}
106+
// expected-note @-9:9 {{of 'x'}}
84107
}

0 commit comments

Comments
 (0)