Skip to content

Commit c3553a7

Browse files
authored
Merge pull request #68327 from eeckstein/fix-compiletime-bug
[5.9] AliasAnalysis: add complexity limits to some basic utility functions
2 parents f42cd3b + fd26ef1 commit c3553a7

File tree

6 files changed

+552
-25
lines changed

6 files changed

+552
-25
lines changed

SwiftCompilerSources/Sources/Optimizer/Analysis/AliasAnalysis.swift

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ struct AliasAnalysis {
6363
static func register() {
6464
BridgedAliasAnalysis.registerAnalysis(
6565
// getMemEffectsFn
66-
{ (bridgedCtxt: BridgedPassContext, bridgedVal: BridgedValue, bridgedInst: BridgedInstruction) -> swift.MemoryBehavior in
66+
{ (bridgedCtxt: BridgedPassContext, bridgedVal: BridgedValue, bridgedInst: BridgedInstruction, complexityBudget: Int) -> swift.MemoryBehavior in
6767
let context = FunctionPassContext(_bridged: bridgedCtxt)
6868
let inst = bridgedInst.instruction
6969
let val = bridgedVal.value
@@ -77,23 +77,28 @@ struct AliasAnalysis {
7777
case (true, true): return .MayReadWrite
7878
}
7979
}
80-
if val.at(path).isEscaping(using: EscapesToInstructionVisitor(target: inst, isAddress: true), context) {
80+
if val.at(path).isEscaping(using: EscapesToInstructionVisitor(target: inst, isAddress: true),
81+
complexityBudget: complexityBudget, context) {
8182
return .MayReadWrite
8283
}
8384
return .None
8485
},
8586

8687
// isObjReleasedFn
87-
{ (bridgedCtxt: BridgedPassContext, bridgedObj: BridgedValue, bridgedInst: BridgedInstruction) -> Bool in
88+
{ (bridgedCtxt: BridgedPassContext, bridgedObj: BridgedValue, bridgedInst: BridgedInstruction, complexityBudget: Int) -> Bool in
8889
let context = FunctionPassContext(_bridged: bridgedCtxt)
8990
let inst = bridgedInst.instruction
9091
let obj = bridgedObj.value
9192
let path = SmallProjectionPath(.anyValueFields)
9293
if let apply = inst as? ApplySite {
93-
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)
9498
return effect.destroy
9599
}
96-
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)
97102
},
98103

99104
// isAddrVisibleFromObj
@@ -144,9 +149,10 @@ private func getMemoryEffect(of apply: ApplySite, for address: Value, path: Smal
144149
return memoryEffects
145150
}
146151

147-
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 {
148154
let visitor = SideEffectsVisitor(apply: apply, calleeAnalysis: context.calleeAnalysis, isAddress: false)
149-
if let result = value.at(path).visit(using: visitor, context) {
155+
if let result = value.at(path).visit(using: visitor, complexityBudget: complexityBudget, context) {
150156
// The resulting effects are the argument effects to which `value` escapes to.
151157
return result.ownership
152158
} 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/Analysis/AliasAnalysis.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ class AliasAnalysis {
206206
/// Returns true if the address(es of) `addr` can escape to `toInst`.
207207
MemoryBehavior getMemoryBehaviorOfInst(SILValue addr, SILInstruction *toInst);
208208

209+
int getComplexityBudget(SILValue valueInFunction);
210+
209211
/// Returns true if the object(s of) `obj` can escape to `toInst`.
210212
bool isObjectReleasedByInst(SILValue obj, SILInstruction *toInst);
211213

include/swift/SILOptimizer/OptimizerBridging.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ struct BridgedAliasAnalysis {
3232
}
3333

3434
typedef swift::MemoryBehavior (* _Nonnull GetMemEffectFn)(
35-
BridgedPassContext context, BridgedValue, BridgedInstruction);
35+
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: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -715,30 +715,24 @@ MemoryBehavior AliasAnalysis::getMemoryBehaviorOfInst(
715715
SILValue addr, SILInstruction *toInst) {
716716
if (getMemEffectsFunction) {
717717
return (MemoryBehavior)getMemEffectsFunction({PM->getSwiftPassInvocation()}, {addr},
718-
{toInst->asSILNode()});
718+
{toInst->asSILNode()},
719+
getComplexityBudget(addr));
719720
}
720721
return MemoryBehavior::MayHaveSideEffects;
721722
}
722723

723724
bool AliasAnalysis::isObjectReleasedByInst(SILValue obj, SILInstruction *inst) {
724725
if (isObjReleasedFunction) {
725-
return isObjReleasedFunction({PM->getSwiftPassInvocation()}, {obj}, {inst->asSILNode()}) != 0;
726+
return isObjReleasedFunction({PM->getSwiftPassInvocation()}, {obj}, {inst->asSILNode()},
727+
getComplexityBudget(obj)) != 0;
726728
}
727729
return true;
728730
}
729731

730732
bool AliasAnalysis::isAddrVisibleFromObject(SILValue addr, SILValue obj) {
731733
if (isAddrVisibleFromObjFunction) {
732-
// This function is called a lot from ARCSequenceOpt and ReleaseHoisting.
733-
// To avoid quadratic complexity for large functions, we limit the amount
734-
// of work what the EscapeUtils are allowed to to.
735-
// This keeps the complexity linear.
736-
//
737-
// This arbitrary limit is good enough for almost all functions. It lets
738-
// the EscapeUtils do several hundred up/down walks which is much more than
739-
// needed in most cases.
740-
SwiftInt complexityLimit = 1000000 / getEstimatedFunctionSize(addr);
741-
return isAddrVisibleFromObjFunction({PM->getSwiftPassInvocation()}, {addr}, {obj}, complexityLimit) != 0;
734+
return isAddrVisibleFromObjFunction({PM->getSwiftPassInvocation()}, {addr}, {obj},
735+
getComplexityBudget(addr)) != 0;
742736
}
743737
return true;
744738
}
@@ -750,7 +744,14 @@ bool AliasAnalysis::canReferenceSameField(SILValue lhs, SILValue rhs) {
750744
return true;
751745
}
752746

753-
int AliasAnalysis::getEstimatedFunctionSize(SILValue valueInFunction) {
747+
// To avoid quadratic complexity for large functions, we limit the amount
748+
// of work what the EscapeUtils are allowed to to.
749+
// This keeps the complexity linear.
750+
//
751+
// This arbitrary limit is good enough for almost all functions. It lets
752+
// the EscapeUtils do several hundred up/down walks which is much more than
753+
// needed in most cases.
754+
int AliasAnalysis::getComplexityBudget(SILValue valueInFunction) {
754755
if (estimatedFunctionSize < 0) {
755756
int numInsts = 0;
756757
SILFunction *f = valueInFunction->getFunction();
@@ -759,5 +760,5 @@ int AliasAnalysis::getEstimatedFunctionSize(SILValue valueInFunction) {
759760
}
760761
estimatedFunctionSize = numInsts;
761762
}
762-
return estimatedFunctionSize;
763+
return 1000000 / estimatedFunctionSize;
763764
}

0 commit comments

Comments
 (0)