Skip to content

Commit ca50c55

Browse files
authored
Merge pull request swiftlang#77806 from eeckstein/rle-of-array-elements
Optimizer: remove the ArrayElementPropagation optimization
2 parents 4b5a50b + 63f6a2f commit ca50c55

26 files changed

+221
-1437
lines changed

SwiftCompilerSources/Sources/Optimizer/Analysis/AliasAnalysis.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ struct AliasAnalysis {
134134
if let apply = inst as? FullApplySite {
135135
// Workaround for quadratic complexity in ARCSequenceOpts.
136136
// We need to use an ever lower budget to not get into noticeable compile time troubles.
137-
let effect = aa.getOwnershipEffect(of: apply, for: obj, path: path)
137+
let effect = aa.getOwnershipEffect(of: apply, for: obj, path: path, complexityBudget: budget / 10)
138138
return effect.destroy
139139
}
140140
return obj.at(path).isEscaping(using: EscapesToInstructionVisitor(target: inst, isAddress: false),
@@ -421,10 +421,10 @@ struct AliasAnalysis {
421421
}
422422

423423
private func getOwnershipEffect(of apply: FullApplySite, for value: Value,
424-
path: SmallProjectionPath) -> SideEffects.Ownership {
424+
path: SmallProjectionPath,
425+
complexityBudget: Int) -> SideEffects.Ownership {
425426
let visitor = FullApplyEffectsVisitor(apply: apply, calleeAnalysis: context.calleeAnalysis, isAddress: false)
426-
let budget = getComplexityBudget(for: apply.parentFunction)
427-
if let result = value.at(path).visit(using: visitor, complexityBudget: budget, context) {
427+
if let result = value.at(path).visit(using: visitor, complexityBudget: complexityBudget, context) {
428428
// The resulting effects are the argument effects to which `value` escapes to.
429429
return result.ownership
430430
} else {

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/AllocVectorLowering.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ private func createOutlinedGlobal(
227227
let elementType = allocVectorBuiltin.substitutionMap.replacementTypes[0]!
228228
let outlinedGlobal = context.createGlobalVariable(
229229
name: context.mangleOutlinedVariable(from: allocVectorBuiltin.parentFunction),
230-
type: elementType, isPrivate: true)
230+
type: elementType, linkage: .private, isLet: false)
231231

232232
let globalBuilder = Builder(staticInitializerOf: outlinedGlobal, context)
233233

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ObjectOutliner.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,10 @@ private func optimizeObjectAllocation(allocRef: AllocRefInstBase, _ context: Fun
106106

107107
let outlinedGlobal = context.createGlobalVariable(
108108
name: context.mangleOutlinedVariable(from: allocRef.parentFunction),
109-
type: allocRef.type, isPrivate: true)
109+
type: allocRef.type, linkage: .private,
110+
// Only if it's a COW object we can be sure that the object allocated in the global is not mutated.
111+
// If someone wants to mutate it, it has to be copied first.
112+
isLet: endOfInitInst is EndCOWMutationInst)
110113

111114
constructObject(of: allocRef, inInitializerOf: outlinedGlobal, storesToClassFields, storesToTailElements, context)
112115
context.erase(instructions: storesToClassFields)
@@ -562,7 +565,7 @@ private func replace(findStringCall: ApplyInst,
562565

563566
// Create an "opaque" global variable which is passed as inout to
564567
// _findStringSwitchCaseWithCache and into which the function stores the "cache".
565-
let cacheVar = context.createGlobalVariable(name: name, type: cacheType, isPrivate: true)
568+
let cacheVar = context.createGlobalVariable(name: name, type: cacheType, linkage: .private, isLet: false)
566569

567570
let varBuilder = Builder(staticInitializerOf: cacheVar, context)
568571
let zero = varBuilder.createIntegerLiteral(0, type: wordTy)

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyLoad.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,12 +234,34 @@ private func getGlobalInitValue(address: Value, _ context: SimplifyContext) -> V
234234
}
235235
case let bai as BeginAccessInst:
236236
return getGlobalInitValue(address: bai.address, context)
237+
case let rta as RefTailAddrInst:
238+
return getGlobalTailElement(of: rta, index: 0)
239+
case let ia as IndexAddrInst:
240+
if let rta = ia.base as? RefTailAddrInst,
241+
let literal = ia.index as? IntegerLiteralInst,
242+
let index = literal.value
243+
{
244+
return getGlobalTailElement(of: rta, index: index)
245+
}
246+
case let rea as RefElementAddrInst:
247+
if let object = rea.instance.immutableGlobalObjectRoot {
248+
return object.baseOperands[rea.fieldIndex].value
249+
}
237250
default:
238251
break
239252
}
240253
return nil
241254
}
242255

256+
private func getGlobalTailElement(of refTailAddr: RefTailAddrInst, index: Int) -> Value? {
257+
if let object = refTailAddr.instance.immutableGlobalObjectRoot,
258+
index >= 0 && index < object.tailOperands.count
259+
{
260+
return object.tailOperands[index].value
261+
}
262+
return nil
263+
}
264+
243265
private func getInitializerFromInitFunction(of globalAddr: GlobalAddrInst, _ context: SimplifyContext) -> Value? {
244266
guard let dependentOn = globalAddr.dependencyToken,
245267
let builtinOnce = dependentOn as? BuiltinInst,
@@ -321,6 +343,19 @@ private extension Value {
321343
}
322344
return (baseAddress: self, offset: 0)
323345
}
346+
347+
// If the reference-root of self references a global object, returns the `object` instruction of the
348+
// global's initializer. But only if the global is a let-global.
349+
var immutableGlobalObjectRoot: ObjectInst? {
350+
if let gv = self.referenceRoot as? GlobalValueInst,
351+
gv.global.isLet,
352+
let initval = gv.global.staticInitValue,
353+
let object = initval as? ObjectInst
354+
{
355+
return object
356+
}
357+
return nil
358+
}
324359
}
325360

326361
private extension Instruction {

SwiftCompilerSources/Sources/Optimizer/PassManager/Context.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,9 +391,9 @@ struct FunctionPassContext : MutatingContext {
391391
}
392392
}
393393

394-
func createGlobalVariable(name: String, type: Type, isPrivate: Bool) -> GlobalVariable {
394+
func createGlobalVariable(name: String, type: Type, linkage: Linkage, isLet: Bool) -> GlobalVariable {
395395
let gv = name._withBridgedStringRef {
396-
_bridged.createGlobalVariable($0, type.bridged, isPrivate)
396+
_bridged.createGlobalVariable($0, type.bridged, linkage.bridged, isLet)
397397
}
398398
return gv.globalVar
399399
}

SwiftCompilerSources/Sources/SIL/Utilities/WalkUtils.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -689,7 +689,7 @@ extension ValueUseDefWalker {
689689
return walkUp(value: oer.existential, path: path.push(.existential, index: 0))
690690
case is BeginBorrowInst, is CopyValueInst, is MoveValueInst,
691691
is UpcastInst, is EndCOWMutationInst, is EndInitLetRefInst,
692-
is BeginDeallocRefInst,
692+
is BeginDeallocRefInst, is MarkDependenceInst,
693693
is RefToBridgeObjectInst, is BridgeObjectToRefInst, is MarkUnresolvedNonCopyableValueInst:
694694
return walkUp(value: (def as! Instruction).operands[0].value, path: path)
695695
case let urc as UncheckedRefCastInst:

include/swift/SILOptimizer/OptimizerBridging.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ struct BridgedPassContext {
255255
BridgedFunction applySiteCallee) const;
256256

257257
SWIFT_IMPORT_UNSAFE BridgedGlobalVar createGlobalVariable(BridgedStringRef name, BridgedType type,
258-
bool isPrivate) const;
258+
BridgedLinkage linkage, bool isLet) const;
259259
void inlineFunction(BridgedInstruction apply, bool mandatoryInline) const;
260260
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedValue getSILUndef(BridgedType type) const;
261261
BRIDGED_INLINE bool optimizeMemoryAccesses(BridgedFunction f) const;

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,6 @@ IRGEN_PASS(AllocStackHoisting, "alloc-stack-hoisting",
120120
"SIL alloc_stack Hoisting")
121121
PASS(ArrayCountPropagation, "array-count-propagation",
122122
"Array Count Propagation")
123-
PASS(ArrayElementPropagation, "array-element-propagation",
124-
"Array Element Propagation")
125123
SWIFT_FUNCTION_PASS(AssumeSingleThreaded, "sil-assume-single-threaded",
126124
"Assume Single-Threaded Environment")
127125
SWIFT_MODULE_PASS(AsyncDemotion, "async-demotion",

lib/IRGen/GenDecl.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2755,8 +2755,11 @@ Address IRGenModule::getAddrOfSILGlobalVariable(SILGlobalVariable *var,
27552755
if (forDefinition && !gvar->hasInitializer()) {
27562756
if (initVal) {
27572757
gvar->setInitializer(initVal);
2758-
if (var->isLet() ||
2759-
(var->isInitializedObject() && canMakeStaticObjectReadOnly(var->getLoweredType()))) {
2758+
if (var->isLet() &&
2759+
// Even if it's a `let`, we cannot allocate an object as constant, because it's header
2760+
// (metadata, ref-count) is initialized at runtime.
2761+
// Exception: if it's an array for which we can initialize the header statically.
2762+
(!var->isInitializedObject() || canMakeStaticObjectReadOnly(var->getLoweredType()))) {
27602763
gvar->setConstant(true);
27612764
}
27622765
} else {

lib/SILOptimizer/PassManager/PassManager.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1879,11 +1879,14 @@ BridgedOwnedString BridgedPassContext::mangleWithClosureArgs(
18791879
return BridgedOwnedString(mangler.mangle());
18801880
}
18811881

1882-
BridgedGlobalVar BridgedPassContext::createGlobalVariable(BridgedStringRef name, BridgedType type, bool isPrivate) const {
1883-
return {SILGlobalVariable::create(
1882+
BridgedGlobalVar BridgedPassContext::createGlobalVariable(BridgedStringRef name, BridgedType type, BridgedLinkage linkage, bool isLet) const {
1883+
auto *global = SILGlobalVariable::create(
18841884
*invocation->getPassManager()->getModule(),
1885-
isPrivate ? SILLinkage::Private : SILLinkage::Public, IsNotSerialized,
1886-
name.unbridged(), type.unbridged())};
1885+
(swift::SILLinkage)linkage, IsNotSerialized,
1886+
name.unbridged(), type.unbridged());
1887+
if (isLet)
1888+
global->setLet(true);
1889+
return {global};
18871890
}
18881891

18891892
void BridgedPassContext::fixStackNesting(BridgedFunction function) const {

0 commit comments

Comments
 (0)