From ce298e94de0e6d4d3f68c4492de07cbc74d9a42e Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Tue, 28 Jul 2020 16:10:12 -0700 Subject: [PATCH] [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. --- lib/SIL/Utils/OptimizationRemark.cpp | 3 +- .../Transforms/OptRemarkGenerator.cpp | 12 +- .../opt-remark-generator-yaml.swift | 114 +++++++++-------- test/SILOptimizer/opt-remark-generator.sil | 8 +- test/SILOptimizer/opt-remark-generator.swift | 116 +++++++++--------- 5 files changed, 133 insertions(+), 120 deletions(-) diff --git a/lib/SIL/Utils/OptimizationRemark.cpp b/lib/SIL/Utils/OptimizationRemark.cpp index 66f1ab2fe6f..00da367598e 100644 --- a/lib/SIL/Utils/OptimizationRemark.cpp +++ b/lib/SIL/Utils/OptimizationRemark.cpp @@ -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) diff --git a/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp b/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp index 35f9732bb61..b20890a6b1c 100644 --- a/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp +++ b/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp @@ -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; } diff --git a/test/SILOptimizer/opt-remark-generator-yaml.swift b/test/SILOptimizer/opt-remark-generator-yaml.swift index 36881fee6aa..bcf38d19ec0 100644 --- a/test/SILOptimizer/opt-remark-generator-yaml.swift +++ b/test/SILOptimizer/opt-remark-generator-yaml.swift @@ -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'|__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'}} } diff --git a/test/SILOptimizer/opt-remark-generator.sil b/test/SILOptimizer/opt-remark-generator.sil index d678501ca04..b8ddadb6d1a 100644 --- a/test/SILOptimizer/opt-remark-generator.sil +++ b/test/SILOptimizer/opt-remark-generator.sil @@ -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 : $() } diff --git a/test/SILOptimizer/opt-remark-generator.swift b/test/SILOptimizer/opt-remark-generator.swift index 5ff61a1a474..dc7f3cf4d23 100644 --- a/test/SILOptimizer/opt-remark-generator.swift +++ b/test/SILOptimizer/opt-remark-generator.swift @@ -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 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 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 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'}} + // expected-remark @-1 {{retain of type 'Optional'}} + // expected-remark @-2 {{release of type}} + // expected-remark @-3 {{release of type 'Optional'}} + // expected-remark @-4 {{release of type 'Optional'}} 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'}} 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'}} 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'}} }