[opt-remark] Print out the type when we retain/release.

This can be useful if we can't recognize a retain/release and one needs to
reason about what is being retained/released.
This commit is contained in:
Michael Gottesman
2020-07-28 16:10:12 -07:00
parent 73f07a6f0f
commit ce298e94de
5 changed files with 133 additions and 120 deletions

View File

@@ -70,7 +70,8 @@ Argument::Argument(ArgumentKey key, SILFunction *f) : key(key) {
Argument::Argument(StringRef key, SILType ty)
: key(ArgumentKeyKind::Default, key) {
llvm::raw_string_ostream stream(val);
ty.print(stream);
PrintOptions subPrinter = PrintOptions::printSIL();
ty.getASTType().print(stream, subPrinter);
}
Argument::Argument(StringRef key, CanType ty)

View File

@@ -249,7 +249,8 @@ void OptRemarkGeneratorInstructionVisitor::visitStrongRetainInst(
// Retains begin a lifetime scope so we infer scan forward.
auto remark = RemarkMissed("memory", *sri,
SourceLocInferenceBehavior::ForwardScanOnly)
<< "retain";
<< "retain of type '"
<< NV("ValueType", sri->getOperand()->getType()) << "'";
for (auto arg : inferredArgs) {
remark << arg;
}
@@ -269,7 +270,8 @@ void OptRemarkGeneratorInstructionVisitor::visitStrongReleaseInst(
auto remark = RemarkMissed("memory", *sri,
SourceLocInferenceBehavior::BackwardScanOnly)
<< "release";
<< "release of type '"
<< NV("ValueType", sri->getOperand()->getType()) << "'";
for (auto arg : inferredArgs) {
remark << arg;
}
@@ -288,7 +290,8 @@ void OptRemarkGeneratorInstructionVisitor::visitRetainValueInst(
// Retains begin a lifetime scope, so we infer scan forwards.
auto remark = RemarkMissed("memory", *rvi,
SourceLocInferenceBehavior::ForwardScanOnly)
<< "retain";
<< "retain of type '"
<< NV("ValueType", rvi->getOperand()->getType()) << "'";
for (auto arg : inferredArgs) {
remark << arg;
}
@@ -308,7 +311,8 @@ void OptRemarkGeneratorInstructionVisitor::visitReleaseValueInst(
// Releases end a lifetime scope so we infer scan backward.
auto remark = RemarkMissed("memory", *rvi,
SourceLocInferenceBehavior::BackwardScanOnly)
<< "release";
<< "release of type '"
<< NV("ValueType", rvi->getOperand()->getType()) << "'";
for (auto arg : inferredArgs) {
remark << arg;
}

View File

@@ -7,70 +7,78 @@
// works without burdening opt-remark-generator-yaml.swift with having to update all
// of the yaml test cases everytime new code is added.
// CHECK: --- !Missed
// CHECK-NEXT: Pass: sil-opt-remark-gen
// CHECK-NEXT: Name: sil.memory
// CHECK-NEXT: DebugLoc: { File: '{{.*}}opt-remark-generator-yaml.swift',
// CHECK-NEXT: Line: 63, Column: 5 }
// CHECK-NEXT: Function: 'getGlobal()'
// CHECK-NEXT: Args:
// CHECK-NEXT: - String: retain
// CHECK-NEXT: - InferredValue: 'of ''global'''
// CHECK-NEXT: DebugLoc: { File: '{{.*}}opt-remark-generator-yaml.swift',
// CHECK-NEXT: Line: 59, Column: 12 }
// CHECK-NEXT: ...
// CHECK-NEXT: --- !Missed
// CHECK-NEXT: Pass: sil-opt-remark-gen
// CHECK-NEXT: Name: sil.memory
// CHECK-NEXT: DebugLoc: { File: '{{.*}}opt-remark-generator-yaml.swift',
// CHECK-NEXT: Line: 71, Column: 5 }
// CHECK-NEXT: Function: 'useGlobal()'
// CHECK-NEXT: Args:
// CHECK-NEXT: - String: retain
// CHECK-NEXT: - InferredValue: 'of ''x'''
// CHECK-NEXT: DebugLoc: { File: '{{.*}}opt-remark-generator-yaml.swift',
// CHECK-NEXT: Line: 68, Column: 9 }
// CHECK-NEXT: ...
// CHECK-NEXT: --- !Missed
// CHECK-NEXT: Pass: sil-opt-remark-gen
// CHECK-NEXT: Name: sil.memory
// CHECK-NEXT: DebugLoc: { File: '{{.*}}opt-remark-generator-yaml.swift',
// CHECK-NEXT: Line: 71, Column: 12 }
// CHECK-NEXT: Function: 'useGlobal()'
// CHECK-NEXT: Args:
// CHECK-NEXT: - String: release
// CHECK-NEXT: ...
// CHECK-NEXT: --- !Missed
// CHECK-NEXT: Pass: sil-opt-remark-gen
// CHECK-NEXT: Name: sil.memory
// CHECK-NEXT: DebugLoc: { File: '{{.*}}opt-remark-generator-yaml.swift',
// CHECK-NEXT: Line: 71, Column: 12 }
// CHECK-NEXT: Function: 'useGlobal()'
// CHECK-NEXT: Args:
// CHECK-NEXT: - String: release
// CHECK-NEXT: - InferredValue: 'of ''x'''
// CHECK-NEXT: DebugLoc: { File: '{{.*}}opt-remark-generator-yaml.swift',
// CHECK-NEXT: Line: 68, Column: 9 }
// CHECK-NEXT: ...
public class Klass {}
public var global = Klass()
// CHECK: --- !Missed
// CHECK-NEXT: Pass: sil-opt-remark-gen
// CHECK-NEXT: Name: sil.memory
// CHECK-NEXT: DebugLoc: { File: '{{.*}}opt-remark-generator-yaml.swift',
// CHECK-NEXT: Line: [[# @LINE + 12]], Column: 5 }
// CHECK-NEXT: Function: 'getGlobal()'
// CHECK-NEXT: Args:
// CHECK-NEXT: - String: 'retain of type '''
// CHECK-NEXT: - ValueType: Klass
// CHECK-NEXT: - String: ''''
// CHECK-NEXT: - InferredValue: 'of ''global'''
// CHECK-NEXT: DebugLoc: { File: '{{.*}}opt-remark-generator-yaml.swift',
// CHECK-NEXT: Line: [[# @LINE - 14]], Column: 12 }
// CHECK-NEXT: ...
@inline(never)
public func getGlobal() -> Klass {
return global // expected-remark @:5 {{retain}}
// expected-note @-5:12 {{of 'global'}}
return global // expected-remark @:5 {{retain of type 'Klass'}}
// expected-note @-19:12 {{of 'global'}}
}
// CHECK-NEXT: --- !Missed
// CHECK-NEXT: Pass: sil-opt-remark-gen
// CHECK-NEXT: Name: sil.memory
// CHECK-NEXT: DebugLoc: { File: '{{.*}}opt-remark-generator-yaml.swift',
// CHECK-NEXT: Line: [[# @LINE + 40]], Column: 5 }
// CHECK-NEXT: Function: 'useGlobal()'
// CHECK-NEXT: Args:
// CHECK-NEXT: - String: 'retain of type '''
// CHECK-NEXT: - ValueType: Klass
// CHECK-NEXT: - String: ''''
// CHECK-NEXT: - InferredValue: 'of ''x'''
// CHECK-NEXT: DebugLoc: { File: '{{.*}}opt-remark-generator-yaml.swift',
// CHECK-NEXT: Line: [[# @LINE + 29]], Column: 9 }
// CHECK-NEXT: ...
// CHECK-NEXT: --- !Missed
// CHECK-NEXT: Pass: sil-opt-remark-gen
// CHECK-NEXT: Name: sil.memory
// CHECK-NEXT: DebugLoc: { File: '{{.*}}opt-remark-generator-yaml.swift',
// CHECK-NEXT: Line: [[# @LINE + 26]], Column: 12 }
// CHECK-NEXT: Function: 'useGlobal()'
// CHECK-NEXT: Args:
// CHECK-NEXT: - String: 'release of type '''
// CHECK-NEXT: - ValueType: {{'Array<Any>'|__ContiguousArrayStorageBase}}
// CHECK-NEXT: - String: ''''
// CHECK-NEXT: ...
// CHECK-NEXT: --- !Missed
// CHECK-NEXT: Pass: sil-opt-remark-gen
// CHECK-NEXT: Name: sil.memory
// CHECK-NEXT: DebugLoc: { File: '{{.*}}opt-remark-generator-yaml.swift',
// CHECK-NEXT: Line: [[# @LINE + 15]], Column: 12 }
// CHECK-NEXT: Function: 'useGlobal()'
// CHECK-NEXT: Args:
// CHECK-NEXT: - String: 'release of type '''
// CHECK-NEXT: - ValueType: Klass
// CHECK-NEXT: - String: ''''
// CHECK-NEXT: - InferredValue: 'of ''x'''
// CHECK-NEXT: DebugLoc: { File: '{{.*}}opt-remark-generator-yaml.swift',
// CHECK-NEXT: Line: [[# @LINE + 4]], Column: 9 }
// CHECK-NEXT: ...
public func useGlobal() {
let x = getGlobal()
// Make sure that the retain msg is at the beginning of the print and the
// releases are the end of the print.
print(x) // expected-remark @:5 {{retain}}
print(x) // expected-remark @:5 {{retain of type 'Klass'}}
// expected-note @-4:9 {{of 'x'}}
// expected-remark @-2:12 {{release}}
// expected-remark @-3:12 {{release}}
// expected-note @-7:9 {{of 'x'}}
// We test the type emission above since FileCheck can handle regex.
// expected-remark @-3:12 {{release of type}}
// expected-remark @-4:12 {{release of type 'Klass'}}
// expected-note @-8:9 {{of 'x'}}
}

View File

@@ -6,10 +6,10 @@ import Builtin
sil @foo : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
bb0(%0 : $Builtin.NativeObject):
strong_retain %0 : $Builtin.NativeObject // expected-remark {{retain}}
retain_value %0 : $Builtin.NativeObject // expected-remark {{retain}}
strong_release %0 : $Builtin.NativeObject // expected-remark {{release}}
release_value %0 : $Builtin.NativeObject // expected-remark {{release}}
strong_retain %0 : $Builtin.NativeObject // expected-remark {{retain of type 'Builtin.NativeObject'}}
retain_value %0 : $Builtin.NativeObject // expected-remark {{retain of type 'Builtin.NativeObject'}}
strong_release %0 : $Builtin.NativeObject // expected-remark {{release of type 'Builtin.NativeObject'}}
release_value %0 : $Builtin.NativeObject // expected-remark {{release of type 'Builtin.NativeObject'}}
%9999 = tuple()
return %9999 : $()
}

View File

@@ -6,7 +6,7 @@ public var global = Klass()
@inline(never)
public func getGlobal() -> Klass {
return global // expected-remark @:5 {{retain}}
return global // expected-remark @:5 {{retain of type 'Klass'}}
// expected-note @-5:12 {{of 'global'}}
}
@@ -14,10 +14,10 @@ public func useGlobal() {
let x = getGlobal()
// Make sure that the retain msg is at the beginning of the print and the
// releases are the end of the print.
print(x) // expected-remark @:5 {{retain}}
print(x) // expected-remark @:5 {{retain of type 'Klass'}}
// expected-note @-4:9 {{of 'x'}}
// expected-remark @-2:12 {{release}}
// expected-remark @-3:12 {{release}}
// expected-remark @-2:12 {{release of type}}
// expected-remark @-3:12 {{release of type 'Klass'}}
// expected-note @-7:9 {{of 'x'}}
}
@@ -31,107 +31,107 @@ struct StructWithOwner {
// This retain is from the initializers of owner.
//
// TODO: Should we emit this?
var owner = Klass() // expected-remark {{retain}}
var owner = Klass() // expected-remark {{retain of type 'Klass'}}
// expected-note @-1 {{of 'self.owner'}}
// expected-remark @-2 {{release}}
// expected-remark @-2 {{release of type 'Klass'}}
// expected-note @-3 {{of 'self.owner'}}
var state = TrivialState.first
}
func printStructWithOwner(x : StructWithOwner) {
print(x) // expected-remark {{retain}}
print(x) // expected-remark {{retain of type 'Klass'}}
// expected-note @-2:27 {{of 'x.owner'}}
// We should be able to infer the arg here.
// expected-remark @-3:12 {{release}}
// expected-remark @-3:12 {{release of type}}
}
func printStructWithOwnerOwner(x : StructWithOwner) {
print(x.owner) // expected-remark {{retain}}
print(x.owner) // expected-remark {{retain of type 'Klass'}}
// expected-note @-2:32 {{of 'x.owner'}}
// We should be able to infer the arg here.
// expected-remark @-3:18 {{release}}
// expected-remark @-3:18 {{release of type}}
}
func returnStructWithOwnerOwner(x: StructWithOwner) -> Klass {
return x.owner // expected-remark {{retain}}
return x.owner // expected-remark {{retain of type 'Klass'}}
// expected-note @-2:33 {{of 'x.owner'}}
}
func callingAnInitializerStructWithOwner(x: Klass) -> StructWithOwner {
return StructWithOwner(owner: x) // expected-remark {{retain}}
return StructWithOwner(owner: x) // expected-remark {{retain of type 'Klass'}}
// expected-note @-2:42 {{of 'x'}}
}
struct KlassPair {
var lhs: Klass // expected-remark {{retain}}
var lhs: Klass // expected-remark {{retain of type 'Klass'}}
// expected-note @-1 {{of 'self.lhs'}}
// expected-remark @-2 {{release}}
// expected-remark @-2 {{release of type 'Klass'}}
// expected-note @-3 {{of 'self.lhs'}}
var rhs: Klass // expected-remark {{retain}}
var rhs: Klass // expected-remark {{retain of type 'Klass'}}
// expected-note @-1 {{of 'self.rhs'}}
// expected-remark @-2 {{release}}
// expected-remark @-2 {{release of type 'Klass'}}
// expected-note @-3 {{of 'self.rhs'}}
}
func printKlassPair(x : KlassPair) {
// We pattern match columns to ensure we get retain on the p and release on
// the end ')'
print(x) // expected-remark @:5 {{retain}}
print(x) // expected-remark @:5 {{retain of type 'Klass'}}
// expected-note @-4:21 {{of 'x.lhs'}}
// expected-remark @-2:5 {{retain}}
// expected-remark @-2:5 {{retain of type 'Klass'}}
// expected-note @-6:21 {{of 'x.rhs'}}
// This is a release for Array<Any> for print.
// expected-remark @-5:12 {{release}}
// expected-remark @-5:12 {{release of type}}
}
func printKlassPairLHS(x : KlassPair) {
// We print the remarks at the 'p' and at the ending ')'.
print(x.lhs) // expected-remark @:5 {{retain}}
print(x.lhs) // expected-remark @:5 {{retain of type 'Klass'}}
// expected-note @-3:24 {{of 'x.lhs'}}
// Release for Array<Any> needed for print.
// expected-remark @-3:16 {{release}}
// expected-remark @-3:16 {{release of type}}
}
func returnKlassPairLHS(x: KlassPair) -> Klass {
return x.lhs // expected-remark @:14 {{retain}}
return x.lhs // expected-remark @:14 {{retain of type 'Klass'}}
// expected-note @-2:25 {{of 'x.lhs'}}
}
func callingAnInitializerKlassPair(x: Klass, y: Klass) -> KlassPair {
return KlassPair(lhs: x, rhs: y) // expected-remark {{retain}}
return KlassPair(lhs: x, rhs: y) // expected-remark {{retain of type 'Klass'}}
// expected-note @-2:36 {{of 'x'}}
// expected-remark @-2:5 {{retain}}
// expected-remark @-2:5 {{retain of type 'Klass'}}
// expected-note @-4:46 {{of 'y'}}
}
func printKlassTuplePair(x : (Klass, Klass)) {
// We pattern match columns to ensure we get retain on the p and release on
// the end ')'
print(x) // expected-remark @:5 {{retain}}
print(x) // expected-remark @:5 {{retain of type 'Klass'}}
// expected-note @-4:26 {{of 'x'}}
// expected-remark @-2:5 {{retain}}
// expected-remark @-2:5 {{retain of type 'Klass'}}
// expected-note @-6:26 {{of 'x'}}
// Release on temp array for print(...).
// expected-remark @-5:12 {{release}}
// expected-remark @-5:12 {{release of type}}
}
func printKlassTupleLHS(x : (Klass, Klass)) {
// We print the remarks at the 'p' and at the ending ')'.
print(x.0) // expected-remark @:5 {{retain}}
print(x.0) // expected-remark @:5 {{retain of type 'Klass'}}
// expected-note @-3:25 {{of 'x'}}
// Release on Array<Any> for print.
// expected-remark @-3:14 {{release}}
// expected-remark @-3:14 {{release of type}}
}
func returnKlassTupleLHS(x: (Klass, Klass)) -> Klass {
return x.0 // expected-remark @:12 {{retain}}
return x.0 // expected-remark @:12 {{retain of type 'Klass'}}
// expected-note @-2:26 {{of 'x'}}
}
func callingAnInitializerKlassTuplePair(x: Klass, y: Klass) -> (Klass, Klass) {
return (x, y) // expected-remark {{retain}}
return (x, y) // expected-remark {{retain of type 'Klass'}}
// expected-note @-2:41 {{of 'x'}}
// expected-remark @-2:5 {{retain}}
// expected-remark @-2:5 {{retain of type 'Klass'}}
// expected-note @-4:51 {{of 'y'}}
}
@@ -141,22 +141,22 @@ public class SubKlass : Klass {
}
func lookThroughCast(x: SubKlass) -> Klass {
return x as Klass // expected-remark {{retain}}
return x as Klass // expected-remark {{retain of type 'SubKlass'}}
// expected-note @-2:22 {{of 'x'}}
}
func lookThroughRefCast(x: Klass) -> SubKlass {
return x as! SubKlass // expected-remark {{retain}}
return x as! SubKlass // expected-remark {{retain of type 'Klass'}}
// expected-note @-2:25 {{of 'x'}}
}
func lookThroughEnum(x: Klass?) -> Klass {
return x! // expected-remark {{retain}}
return x! // expected-remark {{retain of type 'Klass'}}
// expected-note @-2:22 {{of 'x.some'}}
}
func castAsQuestion(x: Klass) -> SubKlass? {
x as? SubKlass // expected-remark {{retain}}
x as? SubKlass // expected-remark {{retain of type 'Klass'}}
// expected-note @-2:21 {{of 'x'}}
}
@@ -166,7 +166,7 @@ func castAsQuestionDiamond(x: Klass) -> SubKlass? {
}
y.doSomething()
return y // expected-remark {{retain}}
return y // expected-remark {{retain of type 'Klass'}}
// expected-note @-7:28 {{of 'x'}}
}
@@ -177,66 +177,66 @@ func castAsQuestionDiamondGEP(x: KlassPair) -> SubKlass? {
y.doSomething()
// We eliminate the rhs retain/release.
return y // expected-remark {{retain}}
return y // expected-remark {{retain of type 'Klass'}}
// expected-note @-8:31 {{of 'x.lhs'}}
}
// We don't handle this test case as well.
func castAsQuestionDiamondGEP2(x: KlassPair) {
switch (x.lhs as? SubKlass, x.rhs as? SubKlass) { // expected-remark @:19 {{retain}}
switch (x.lhs as? SubKlass, x.rhs as? SubKlass) { // expected-remark @:19 {{retain of type 'Klass'}}
// expected-note @-2 {{of 'x.lhs'}}
// expected-remark @-2:39 {{retain}}
// expected-remark @-2:39 {{retain of type 'Klass'}}
// expected-note @-4 {{of 'x.rhs'}}
case let (.some(x1), .some(x2)):
print(x1, x2) // expected-remark {{retain}}
// expected-remark @-1 {{retain}}
// expected-remark @-2 {{release}}
// expected-remark @-3 {{release}}
// expected-remark @-4 {{release}}
print(x1, x2) // expected-remark {{retain of type 'Optional<SubKlass>'}}
// expected-remark @-1 {{retain of type 'Optional<SubKlass>'}}
// expected-remark @-2 {{release of type}}
// expected-remark @-3 {{release of type 'Optional<SubKlass>'}}
// expected-remark @-4 {{release of type 'Optional<SubKlass>'}}
case let (.some(x1), nil):
print(x1) // expected-remark {{retain}}
// expected-remark @-1 {{release}}
// expected-remark @-2 {{release}}
print(x1) // expected-remark {{retain of type 'SubKlass'}}
// expected-remark @-1 {{release of type}}
// expected-remark @-2 {{release of type 'Optional<SubKlass>'}}
case let (nil, .some(x2)):
print(x2) // expected-remark {{retain}}
// expected-remark @-1 {{release}}
// expected-remark @-2 {{release}}
print(x2) // expected-remark {{retain of type 'SubKlass'}}
// expected-remark @-1 {{release of type}}
// expected-remark @-2 {{release of type 'Optional<SubKlass>'}}
case (nil, nil):
break
}
}
func inoutKlassPairArgument(x: inout KlassPair) -> Klass {
return x.lhs // expected-remark {{retain}}
return x.lhs // expected-remark {{retain of type 'Klass'}}
// expected-note @-2 {{of 'x.lhs'}}
}
func inoutKlassTuplePairArgument(x: inout (Klass, Klass)) -> Klass {
return x.0 // expected-remark {{retain}}
return x.0 // expected-remark {{retain of type 'Klass'}}
// expected-note @-2 {{of 'x.0'}}
}
func inoutKlassOptionalArgument(x: inout Klass?) -> Klass {
return x! // expected-remark {{retain}}
return x! // expected-remark {{retain of type 'Klass'}}
// expected-note @-2 {{of 'x.some'}}
}
func inoutKlassBangCastArgument(x: inout Klass) -> SubKlass {
return x as! SubKlass // expected-remark {{retain}}
return x as! SubKlass // expected-remark {{retain of type 'Klass'}}
// expected-note @-2 {{of 'x'}}
}
func inoutKlassQuestionCastArgument(x: inout Klass) -> SubKlass? {
return x as? SubKlass // expected-remark {{retain}}
return x as? SubKlass // expected-remark {{retain of type 'Klass'}}
// expected-note @-2 {{of 'x'}}
}
func inoutKlassBangCastArgument2(x: inout Klass?) -> SubKlass {
return x as! SubKlass // expected-remark {{retain}}
return x as! SubKlass // expected-remark {{retain of type 'Klass'}}
// expected-note @-2 {{of 'x.some'}}
}
func inoutKlassQuestionCastArgument2(x: inout Klass?) -> SubKlass? {
return x as? SubKlass // expected-remark {{retain}}
return x as? SubKlass // expected-remark {{retain of type 'Klass'}}
// expected-note @-2 {{of 'x.some'}}
}