Skip to content

Commit fd26ef1

Browse files
committed
AliasAnalysis: use a complexity limit for the isObjReleased function
We already use a complexity limit for other functions in AliasAnalysis. This is a workaround for quadratic complexity in ARCSequenceOpts. Fixes a compile time problem rdar://114352817
1 parent 71d53b4 commit fd26ef1

File tree

5 files changed

+533
-9
lines changed

5 files changed

+533
-9
lines changed

SwiftCompilerSources/Sources/Optimizer/Analysis/AliasAnalysis.swift

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,16 +85,20 @@ struct AliasAnalysis {
8585
},
8686

8787
// isObjReleasedFn
88-
{ (bridgedCtxt: BridgedPassContext, bridgedObj: BridgedValue, bridgedInst: BridgedInstruction) -> Bool in
88+
{ (bridgedCtxt: BridgedPassContext, bridgedObj: BridgedValue, bridgedInst: BridgedInstruction, complexityBudget: Int) -> Bool in
8989
let context = FunctionPassContext(_bridged: bridgedCtxt)
9090
let inst = bridgedInst.instruction
9191
let obj = bridgedObj.value
9292
let path = SmallProjectionPath(.anyValueFields)
9393
if let apply = inst as? ApplySite {
94-
let effect = getOwnershipEffect(of: apply, for: obj, path: path, context)
94+
// Workaround for quadratic complexity in ARCSequenceOpts.
95+
// We need to use an ever lower budget to not get into noticable compile time troubles.
96+
let budget = complexityBudget / 10
97+
let effect = getOwnershipEffect(of: apply, for: obj, path: path, complexityBudget: budget, context)
9598
return effect.destroy
9699
}
97-
return obj.at(path).isEscaping(using: EscapesToInstructionVisitor(target: inst, isAddress: false), context)
100+
return obj.at(path).isEscaping(using: EscapesToInstructionVisitor(target: inst, isAddress: false),
101+
complexityBudget: complexityBudget, context)
98102
},
99103

100104
// isAddrVisibleFromObj
@@ -145,9 +149,10 @@ private func getMemoryEffect(of apply: ApplySite, for address: Value, path: Smal
145149
return memoryEffects
146150
}
147151

148-
private func getOwnershipEffect(of apply: ApplySite, for value: Value, path: SmallProjectionPath, _ context: FunctionPassContext) -> SideEffects.Ownership {
152+
private func getOwnershipEffect(of apply: ApplySite, for value: Value, path: SmallProjectionPath,
153+
complexityBudget: Int, _ context: FunctionPassContext) -> SideEffects.Ownership {
149154
let visitor = SideEffectsVisitor(apply: apply, calleeAnalysis: context.calleeAnalysis, isAddress: false)
150-
if let result = value.at(path).visit(using: visitor, context) {
155+
if let result = value.at(path).visit(using: visitor, complexityBudget: complexityBudget, context) {
151156
// The resulting effects are the argument effects to which `value` escapes to.
152157
return result.ownership
153158
} else {

SwiftCompilerSources/Sources/Optimizer/Utilities/EscapeUtils.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,10 @@ extension ProjectedValue {
9999
/// it returns the `result` of the `visitor`, if the projected value does not escape.
100100
/// Returns nil, if the projected value escapes.
101101
///
102-
func visit<V: EscapeVisitorWithResult>(using visitor: V, _ context: some Context) -> V.Result? {
103-
var walker = EscapeWalker(visitor: visitor, context)
102+
func visit<V: EscapeVisitorWithResult>(using visitor: V,
103+
complexityBudget: Int = Int.max,
104+
_ context: some Context) -> V.Result? {
105+
var walker = EscapeWalker(visitor: visitor, complexityBudget: complexityBudget, context)
104106
if walker.walkUp(addressOrValue: value, path: path.escapePath) == .abortWalk {
105107
return nil
106108
}

include/swift/SILOptimizer/OptimizerBridging.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ struct BridgedAliasAnalysis {
3434
typedef swift::MemoryBehavior (* _Nonnull GetMemEffectFn)(
3535
BridgedPassContext context, BridgedValue, BridgedInstruction, SwiftInt);
3636
typedef bool (* _Nonnull Escaping2InstFn)(
37-
BridgedPassContext context, BridgedValue, BridgedInstruction);
37+
BridgedPassContext context, BridgedValue, BridgedInstruction, SwiftInt);
3838
typedef bool (* _Nonnull Escaping2ValFn)(
3939
BridgedPassContext context, BridgedValue, BridgedValue);
4040
typedef bool (* _Nonnull Escaping2ValIntFn)(

lib/SILOptimizer/Analysis/AliasAnalysis.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,8 @@ MemoryBehavior AliasAnalysis::getMemoryBehaviorOfInst(
723723

724724
bool AliasAnalysis::isObjectReleasedByInst(SILValue obj, SILInstruction *inst) {
725725
if (isObjReleasedFunction) {
726-
return isObjReleasedFunction({PM->getSwiftPassInvocation()}, {obj}, {inst->asSILNode()}) != 0;
726+
return isObjReleasedFunction({PM->getSwiftPassInvocation()}, {obj}, {inst->asSILNode()},
727+
getComplexityBudget(obj)) != 0;
727728
}
728729
return true;
729730
}

0 commit comments

Comments
 (0)