Skip to content

Commit 0c860f8

Browse files
authored
Merge pull request #78136 from eeckstein/fix-ssa-updater-2
LoopRotate: remove redundant phis after ssa-update
2 parents 8553f99 + 8439d0b commit 0c860f8

File tree

12 files changed

+271
-199
lines changed

12 files changed

+271
-199
lines changed

SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,5 +140,5 @@ private func registerSwiftAnalyses() {
140140

141141
private func registerUtilities() {
142142
registerVerifier()
143-
registerGuaranteedPhiUpdater()
143+
registerPhiUpdater()
144144
}

SwiftCompilerSources/Sources/Optimizer/Utilities/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
swift_compiler_sources(Optimizer
1010
AccessUtilsTest.swift
1111
AddressUtils.swift
12-
GuaranteedPhiUpdater.swift
1312
BorrowUtils.swift
1413
SpecializationCloner.swift
1514
DiagnosticEngine.swift
@@ -22,6 +21,7 @@ swift_compiler_sources(Optimizer
2221
LocalVariableUtils.swift
2322
OptUtils.swift
2423
OwnershipLiveness.swift
24+
PhiUpdater.swift
2525
SSAUpdater.swift
2626
StaticInitCloner.swift
2727
Test.swift

SwiftCompilerSources/Sources/Optimizer/Utilities/GuaranteedPhiUpdater.swift renamed to SwiftCompilerSources/Sources/Optimizer/Utilities/PhiUpdater.swift

Lines changed: 99 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===--- GuaranteedPhiUpdater.swift ---------------------------------------===//
1+
//===--- PhiUpdater.swift -------------------------------------------------===//
22
//
33
// This source file is part of the Swift.org open source project
44
//
@@ -152,13 +152,100 @@ private func addEnclosingValues(
152152
return true
153153
}
154154

155-
func registerGuaranteedPhiUpdater() {
156-
BridgedUtilities.registerGuaranteedPhiUpdater(
155+
/// Replaces a phi with the unique incoming value if all incoming values are the same:
156+
/// ```
157+
/// bb1:
158+
/// br bb3(%1)
159+
/// bb2:
160+
/// br bb3(%1)
161+
/// bb3(%2 : $T): // Predecessors: bb1, bb2
162+
/// use(%2)
163+
/// ```
164+
/// ->
165+
/// ```
166+
/// bb1:
167+
/// br bb3
168+
/// bb2:
169+
/// br bb3
170+
/// bb3:
171+
/// use(%1)
172+
/// ```
173+
///
174+
func replacePhiWithIncomingValue(phi: Phi, _ context: some MutatingContext) -> Bool {
175+
if phi.predecessors.isEmpty {
176+
return false
177+
}
178+
let uniqueIncomingValue = phi.incomingValues.first!
179+
if !uniqueIncomingValue.parentFunction.hasOwnership {
180+
// For the SSAUpdater it's only required to simplify phis in OSSA.
181+
// This avoids that we need to handle cond_br instructions below.
182+
return false
183+
}
184+
if phi.incomingValues.contains(where: { $0 != uniqueIncomingValue }) {
185+
return false
186+
}
187+
if let borrowedFrom = phi.borrowedFrom {
188+
borrowedFrom.uses.replaceAll(with: uniqueIncomingValue, context)
189+
context.erase(instruction: borrowedFrom)
190+
} else {
191+
phi.value.uses.replaceAll(with: uniqueIncomingValue, context)
192+
}
193+
194+
let block = phi.value.parentBlock
195+
for incomingOp in phi.incomingOperands {
196+
let existingBranch = incomingOp.instruction as! BranchInst
197+
let argsWithRemovedPhiOp = existingBranch.operands.filter{ $0 != incomingOp }.map{ $0.value }
198+
Builder(before: existingBranch, context).createBranch(to: block, arguments: argsWithRemovedPhiOp)
199+
context.erase(instruction: existingBranch)
200+
}
201+
block.eraseArgument(at: phi.value.index, context)
202+
return true
203+
}
204+
205+
/// Replaces phis with the unique incoming values if all incoming values are the same.
206+
/// This is needed after running the SSAUpdater for an existing OSSA value, because the updater can
207+
/// insert unnecessary phis in the middle of the original liverange which breaks up the original
208+
/// liverange into smaller ones:
209+
/// ```
210+
/// %1 = def_of_owned_value
211+
/// %2 = begin_borrow %1
212+
/// ...
213+
/// br bb2(%1)
214+
/// bb2(%3 : @owned $T): // inserted by SSAUpdater
215+
/// ...
216+
/// end_borrow %2 // use after end-of-lifetime!
217+
/// destroy_value %3
218+
/// ```
219+
///
220+
/// It's not needed to run this utility if SSAUpdater is used to create a _new_ OSSA liverange.
221+
///
222+
func replacePhisWithIncomingValues(phis: [Phi], _ context: some MutatingContext) {
223+
var currentPhis = phis
224+
// Do this in a loop because replacing one phi might open up the opportunity for another phi
225+
// and the order of phis in the array can be arbitrary.
226+
while true {
227+
var newPhis = [Phi]()
228+
for phi in currentPhis {
229+
if !replacePhiWithIncomingValue(phi: phi, context) {
230+
newPhis.append(phi)
231+
}
232+
}
233+
if newPhis.count == currentPhis.count {
234+
return
235+
}
236+
currentPhis = newPhis
237+
}
238+
}
239+
240+
func registerPhiUpdater() {
241+
BridgedUtilities.registerPhiUpdater(
242+
// updateAllGuaranteedPhis
157243
{ (bridgedCtxt: BridgedPassContext, bridgedFunction: BridgedFunction) in
158244
let context = FunctionPassContext(_bridged: bridgedCtxt)
159245
let function = bridgedFunction.function;
160246
updateGuaranteedPhis(in: function, context)
161247
},
248+
// updateGuaranteedPhis
162249
{ (bridgedCtxt: BridgedPassContext, bridgedPhiArray: BridgedArrayRef) in
163250
let context = FunctionPassContext(_bridged: bridgedCtxt)
164251
var guaranteedPhis = Stack<Phi>(context)
@@ -172,6 +259,15 @@ func registerGuaranteedPhiUpdater() {
172259
}
173260
}
174261
updateGuaranteedPhis(phis: guaranteedPhis, context)
262+
},
263+
// replacePhisWithIncomingValues
264+
{ (bridgedCtxt: BridgedPassContext, bridgedPhiArray: BridgedArrayRef) in
265+
let context = FunctionPassContext(_bridged: bridgedCtxt)
266+
var phis = [Phi]()
267+
bridgedPhiArray.withElements(ofType: BridgedValue.self) {
268+
phis = $0.map { Phi($0.value)! }
269+
}
270+
replacePhisWithIncomingValues(phis: phis, context)
175271
}
176272
)
177273
}

SwiftCompilerSources/Sources/SIL/Operand.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import SILBridging
1414

1515
/// An operand of an instruction.
16-
public struct Operand : CustomStringConvertible, NoReflectionChildren {
16+
public struct Operand : CustomStringConvertible, NoReflectionChildren, Equatable {
1717
public let bridged: BridgedOperand
1818

1919
public init(bridged: BridgedOperand) {

include/swift/SILOptimizer/OptimizerBridging.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,9 @@ struct BridgedUtilities {
134134
typedef void (* _Nonnull UpdatePhisFn)(BridgedPassContext, BridgedArrayRef);
135135

136136
static void registerVerifier(VerifyFunctionFn verifyFunctionFn);
137-
static void registerGuaranteedPhiUpdater(UpdateFunctionFn updateBorrowedFromFn,
138-
UpdatePhisFn updateBorrowedFromPhisFn);
137+
static void registerPhiUpdater(UpdateFunctionFn updateBorrowedFromFn,
138+
UpdatePhisFn updateBorrowedFromPhisFn,
139+
UpdatePhisFn replacePhisWithIncomingValuesFn);
139140
};
140141

141142
struct BridgedBasicBlockSet {

include/swift/SILOptimizer/Utils/OwnershipOptUtils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,9 @@ void updateAllGuaranteedPhis(SILPassManager *pm, SILFunction *f);
364364
/// Updates the reborrow flags and the borrowed-from instructions for all `phis`.
365365
void updateGuaranteedPhis(SILPassManager *pm, ArrayRef<SILPhiArgument *> phis);
366366

367+
/// Replaces phis with the unique incoming values if all incoming values are the same.
368+
void replacePhisWithIncomingValues(SILPassManager *pm, ArrayRef<SILPhiArgument *> phis);
369+
367370
} // namespace swift
368371

369372
#endif

include/swift/SILOptimizer/Utils/SILSSAUpdater.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,6 @@ class SILBasicBlock;
3535
class SILType;
3636
class SILUndef;
3737

38-
/// Independent utility that canonicalizes BB arguments by reusing structurally
39-
/// equivalent arguments and replacing the original arguments with casts.
40-
SILValue replaceBBArgWithCast(SILPhiArgument *arg);
41-
4238
/// This class updates SSA for a set of SIL instructions defined in multiple
4339
/// blocks.
4440
class SILSSAUpdater {

lib/SILOptimizer/LoopTransforms/LoopRotate.cpp

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ static llvm::cl::opt<bool> RotateSingleBlockLoop("looprotate-single-block-loop",
4646

4747
static bool rotateLoop(SILLoop *loop, DominanceInfo *domInfo,
4848
SILLoopInfo *loopInfo, bool rotateSingleBlockLoops,
49-
SILBasicBlock *upToBB);
49+
SILBasicBlock *upToBB, SILPassManager *pm);
5050

5151
/// Check whether all operands are loop invariant.
5252
static bool
@@ -151,7 +151,8 @@ static void mapOperands(SILInstruction *inst,
151151
static void updateSSAForUseOfValue(
152152
SILSSAUpdater &updater, SmallVectorImpl<SILPhiArgument *> &insertedPhis,
153153
const llvm::DenseMap<ValueBase *, SILValue> &valueMap,
154-
SILBasicBlock *Header, SILBasicBlock *EntryCheckBlock, SILValue Res) {
154+
SILBasicBlock *Header, SILBasicBlock *EntryCheckBlock, SILValue Res,
155+
SILPassManager *pm) {
155156
// Find the mapped instruction.
156157
assert(valueMap.count(Res) && "Expected to find value in map!");
157158
SILValue MappedValue = valueMap.find(Res)->second;
@@ -187,34 +188,25 @@ static void updateSSAForUseOfValue(
187188
updater.rewriteUse(*use);
188189
}
189190

190-
// Canonicalize inserted phis to avoid extra BB Args and if we find an address
191-
// phi, stash it so we can handle it after we are done rewriting.
192-
for (SILPhiArgument *arg : insertedPhis) {
193-
if (SILValue inst = replaceBBArgWithCast(arg)) {
194-
arg->replaceAllUsesWith(inst);
195-
// DCE+SimplifyCFG runs as a post-pass cleanup.
196-
// DCE replaces dead arg values with undef.
197-
// SimplifyCFG deletes the dead BB arg.
198-
continue;
199-
}
200-
}
191+
replacePhisWithIncomingValues(pm, insertedPhis);
201192
}
202193

203194
static void
204195
updateSSAForUseOfInst(SILSSAUpdater &updater,
205196
SmallVectorImpl<SILPhiArgument *> &insertedPhis,
206197
const llvm::DenseMap<ValueBase *, SILValue> &valueMap,
207198
SILBasicBlock *header, SILBasicBlock *entryCheckBlock,
208-
SILInstruction *inst) {
199+
SILInstruction *inst, SILPassManager *pm) {
209200
for (auto result : inst->getResults())
210201
updateSSAForUseOfValue(updater, insertedPhis, valueMap, header,
211-
entryCheckBlock, result);
202+
entryCheckBlock, result, pm);
212203
}
213204

214205
/// Rewrite the code we just created in the preheader and update SSA form.
215206
static void rewriteNewLoopEntryCheckBlock(
216207
SILBasicBlock *header, SILBasicBlock *entryCheckBlock,
217-
const llvm::DenseMap<ValueBase *, SILValue> &valueMap) {
208+
const llvm::DenseMap<ValueBase *, SILValue> &valueMap,
209+
SILPassManager *pm) {
218210
SmallVector<SILPhiArgument *, 8> insertedPhis;
219211
SILSSAUpdater updater(&insertedPhis);
220212

@@ -223,7 +215,7 @@ static void rewriteNewLoopEntryCheckBlock(
223215
for (unsigned i : range(header->getNumArguments())) {
224216
auto *arg = header->getArguments()[i];
225217
updateSSAForUseOfValue(updater, insertedPhis, valueMap, header,
226-
entryCheckBlock, arg);
218+
entryCheckBlock, arg, pm);
227219
}
228220

229221
auto instIter = header->begin();
@@ -232,7 +224,7 @@ static void rewriteNewLoopEntryCheckBlock(
232224
while (instIter != header->end()) {
233225
auto &inst = *instIter;
234226
updateSSAForUseOfInst(updater, insertedPhis, valueMap, header,
235-
entryCheckBlock, &inst);
227+
entryCheckBlock, &inst, pm);
236228
++instIter;
237229
}
238230
}
@@ -254,7 +246,7 @@ static void updateDomTree(DominanceInfo *domInfo, SILBasicBlock *preheader,
254246
}
255247

256248
static bool rotateLoopAtMostUpToLatch(SILLoop *loop, DominanceInfo *domInfo,
257-
SILLoopInfo *loopInfo) {
249+
SILLoopInfo *loopInfo, SILPassManager *pm) {
258250
auto *latch = loop->getLoopLatch();
259251
if (!latch) {
260252
LLVM_DEBUG(llvm::dbgs()
@@ -264,11 +256,11 @@ static bool rotateLoopAtMostUpToLatch(SILLoop *loop, DominanceInfo *domInfo,
264256

265257
bool didRotate = rotateLoop(
266258
loop, domInfo, loopInfo,
267-
RotateSingleBlockLoop /* rotateSingleBlockLoops */, latch);
259+
RotateSingleBlockLoop /* rotateSingleBlockLoops */, latch, pm);
268260

269261
// Keep rotating at most until we hit the original latch.
270262
if (didRotate)
271-
while (rotateLoop(loop, domInfo, loopInfo, false, latch)) {
263+
while (rotateLoop(loop, domInfo, loopInfo, false, latch, pm)) {
272264
}
273265

274266
return didRotate;
@@ -317,7 +309,7 @@ static bool isSingleBlockLoop(SILLoop *L) {
317309
/// loop for termination.
318310
static bool rotateLoop(SILLoop *loop, DominanceInfo *domInfo,
319311
SILLoopInfo *loopInfo, bool rotateSingleBlockLoops,
320-
SILBasicBlock *upToBB) {
312+
SILBasicBlock *upToBB, SILPassManager *pm) {
321313
assert(loop != nullptr && domInfo != nullptr && loopInfo != nullptr
322314
&& "Missing loop information");
323315

@@ -443,7 +435,7 @@ static bool rotateLoop(SILLoop *loop, DominanceInfo *domInfo,
443435

444436
// If there were any uses of instructions in the duplicated loop entry check
445437
// block rewrite them using the ssa updater.
446-
rewriteNewLoopEntryCheckBlock(header, preheader, valueMap);
438+
rewriteNewLoopEntryCheckBlock(header, preheader, valueMap, pm);
447439

448440
loop->moveToHeader(newHeader);
449441

@@ -509,7 +501,7 @@ class LoopRotation : public SILFunctionTransform {
509501
SILLoop *loop = worklist.pop_back_val();
510502
changed |= canonicalizeLoop(loop, domInfo, loopInfo);
511503
changed |=
512-
rotateLoopAtMostUpToLatch(loop, domInfo, loopInfo);
504+
rotateLoopAtMostUpToLatch(loop, domInfo, loopInfo, getPassManager());
513505
}
514506
}
515507

lib/SILOptimizer/Utils/OwnershipOptUtils.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1915,11 +1915,14 @@ bool swift::extendStoreBorrow(StoreBorrowInst *sbi,
19151915

19161916
static BridgedUtilities::UpdateFunctionFn updateAllGuaranteedPhisFunction;
19171917
static BridgedUtilities::UpdatePhisFn updateGuaranteedPhisFunction;
1918+
static BridgedUtilities::UpdatePhisFn replacePhisWithIncomingValuesFunction;
19181919

1919-
void BridgedUtilities::registerGuaranteedPhiUpdater(UpdateFunctionFn updateAllGuaranteedPhisFn,
1920-
UpdatePhisFn updateGuaranteedPhisFn) {
1920+
void BridgedUtilities::registerPhiUpdater(UpdateFunctionFn updateAllGuaranteedPhisFn,
1921+
UpdatePhisFn updateGuaranteedPhisFn,
1922+
UpdatePhisFn replacePhisWithIncomingValuesFn) {
19211923
updateAllGuaranteedPhisFunction = updateAllGuaranteedPhisFn;
19221924
updateGuaranteedPhisFunction = updateGuaranteedPhisFn;
1925+
replacePhisWithIncomingValuesFunction = replacePhisWithIncomingValuesFn;
19231926
}
19241927

19251928
void swift::updateAllGuaranteedPhis(SILPassManager *pm, SILFunction *f) {
@@ -1937,3 +1940,14 @@ void swift::updateGuaranteedPhis(SILPassManager *pm, ArrayRef<SILPhiArgument *>
19371940
}
19381941
updateGuaranteedPhisFunction({pm->getSwiftPassInvocation()}, ArrayRef(bridgedPhis));
19391942
}
1943+
1944+
void swift::replacePhisWithIncomingValues(SILPassManager *pm, ArrayRef<SILPhiArgument *> phis) {
1945+
if (!replacePhisWithIncomingValuesFunction)
1946+
return;
1947+
1948+
llvm::SmallVector<BridgedValue, 8> bridgedPhis;
1949+
for (SILPhiArgument *phi : phis) {
1950+
bridgedPhis.push_back({phi});
1951+
}
1952+
replacePhisWithIncomingValuesFunction({pm->getSwiftPassInvocation()}, ArrayRef(bridgedPhis));
1953+
}

0 commit comments

Comments
 (0)