Skip to content

Commit 5cb033d

Browse files
authored
Merge pull request #19027 from atrick/fix-phi-incoming-value
Fix the SIL incoming phi value API, verify critical edges, fix SIL passes that break verification.
2 parents 76aa3ed + 1e88e44 commit 5cb033d

28 files changed

+388
-266
lines changed

include/swift/SIL/SILArgument.h

Lines changed: 116 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -77,41 +77,51 @@ class SILArgument : public ValueBase {
7777
llvm_unreachable("SILArgument not argument of its parent BB");
7878
}
7979

80-
/// Returns the incoming SILValue from the \p BBIndex predecessor of this
81-
/// argument's parent BB. If the routine fails, it returns an empty SILValue.
82-
/// Note that for some predecessor terminators the incoming value is not
83-
/// exactly the argument value. E.g. the incoming value for a switch_enum
84-
/// payload argument is the enum itself (the operand of the switch_enum).
85-
SILValue getIncomingValue(unsigned BBIndex);
86-
87-
/// Returns the incoming SILValue for this argument from BB. If the routine
88-
/// fails, it returns an empty SILValue.
89-
/// Note that for some predecessor terminators the incoming value is not
90-
/// exactly the argument value. E.g. the incoming value for a switch_enum
91-
/// payload argument is the enum itself (the operand of the switch_enum).
92-
SILValue getIncomingValue(SILBasicBlock *BB);
93-
94-
/// Returns true if we were able to find incoming values for each predecessor
95-
/// of this arguments basic block. The found values are stored in OutArray.
96-
/// Note that for some predecessor terminators the incoming value is not
97-
/// exactly the argument value. E.g. the incoming value for a switch_enum
98-
/// payload argument is the enum itself (the operand of the switch_enum).
99-
bool getIncomingValues(llvm::SmallVectorImpl<SILValue> &OutArray);
100-
101-
/// Returns true if we were able to find incoming values for each predecessor
102-
/// of this arguments basic block. The found values are stored in OutArray.
103-
/// Note that for some predecessor terminators the incoming value is not
104-
/// exactly the argument value. E.g. the incoming value for a switch_enum
105-
/// payload argument is the enum itself (the operand of the switch_enum).
106-
bool getIncomingValues(
80+
/// Return true if this block argument is actually a phi argument as
81+
/// opposed to a cast or projection.
82+
bool isPhiArgument();
83+
84+
/// If this argument is a phi, return the incoming phi value for the given
85+
/// predecessor BB. If this argument is not a phi, return an invalid SILValue.
86+
SILValue getIncomingPhiValue(SILBasicBlock *predBB);
87+
88+
/// If this argument is a phi, populate `OutArray` with the incoming phi
89+
/// values for each predecessor BB. If this argument is not a phi, return
90+
/// false.
91+
bool getIncomingPhiValues(llvm::SmallVectorImpl<SILValue> &ReturnedPhiValues);
92+
93+
/// If this argument is a phi, populate `OutArray` with each predecessor block
94+
/// and its incoming phi value. If this argument is not a phi, return false.
95+
bool getIncomingPhiValues(
96+
llvm::SmallVectorImpl<std::pair<SILBasicBlock *, SILValue>>
97+
&ReturnedPredAndPhiValuePairs);
98+
99+
/// Returns true if we were able to find a single terminator operand value for
100+
/// each predecessor of this arguments basic block. The found values are
101+
/// stored in OutArray.
102+
///
103+
/// Note: this peeks through any projections or cast implied by the
104+
/// terminator. e.g. the incoming value for a switch_enum payload argument is
105+
/// the enum itself (the operand of the switch_enum).
106+
bool getSingleTerminatorOperands(llvm::SmallVectorImpl<SILValue> &OutArray);
107+
108+
/// Returns true if we were able to find single terminator operand values for
109+
/// each predecessor of this arguments basic block. The found values are
110+
/// stored in OutArray alongside their predecessor block.
111+
///
112+
/// Note: this peeks through any projections or cast implied by the
113+
/// terminator. e.g. the incoming value for a switch_enum payload argument is
114+
/// the enum itself (the operand of the switch_enum).
115+
bool getSingleTerminatorOperands(
107116
llvm::SmallVectorImpl<std::pair<SILBasicBlock *, SILValue>> &OutArray);
108117

109-
/// If this SILArgument's parent block has one predecessor, return the
110-
/// incoming value from that predecessor. Returns SILValue() otherwise.
111-
/// Note that for some predecessor terminators the incoming value is not
112-
/// exactly the argument value. E.g. the incoming value for a switch_enum
113-
/// payload argument is the enum itself (the operand of the switch_enum).
114-
SILValue getSingleIncomingValue() const;
118+
/// If this SILArgument's parent block has a single predecessor whose
119+
/// terminator has a single operand, return the incoming operand of the
120+
/// predecessor's terminator. Returns SILValue() otherwise. Note that for
121+
/// some predecessor terminators the incoming value is not exactly the
122+
/// argument value. E.g. the incoming value for a switch_enum payload argument
123+
/// is the enum itself (the operand of the switch_enum).
124+
SILValue getSingleTerminatorOperand() const;
115125

116126
protected:
117127
SILArgument(ValueKind SubClassKind, SILBasicBlock *ParentBB, SILType Ty,
@@ -138,41 +148,59 @@ class SILArgument : public ValueBase {
138148

139149
class SILPHIArgument : public SILArgument {
140150
public:
141-
/// Returns the incoming SILValue from the \p BBIndex predecessor of this
142-
/// argument's parent BB. If the routine fails, it returns an empty SILValue.
143-
/// Note that for some predecessor terminators the incoming value is not
144-
/// exactly the argument value. E.g. the incoming value for a switch_enum
145-
/// payload argument is the enum itself (the operand of the switch_enum).
146-
SILValue getIncomingValue(unsigned BBIndex);
147-
148-
/// Returns the incoming SILValue for this argument from BB. If the routine
149-
/// fails, it returns an empty SILValue.
150-
/// Note that for some predecessor terminators the incoming value is not
151-
/// exactly the argument value. E.g. the incoming value for a switch_enum
152-
/// payload argument is the enum itself (the operand of the switch_enum).
153-
SILValue getIncomingValue(SILBasicBlock *BB);
154-
155-
/// Returns true if we were able to find incoming values for each predecessor
156-
/// of this arguments basic block. The found values are stored in OutArray.
157-
/// Note that for some predecessor terminators the incoming value is not
158-
/// exactly the argument value. E.g. the incoming value for a switch_enum
159-
/// payload argument is the enum itself (the operand of the switch_enum).
160-
bool getIncomingValues(llvm::SmallVectorImpl<SILValue> &OutArray);
161-
162-
/// Returns true if we were able to find incoming values for each predecessor
163-
/// of this arguments basic block. The found values are stored in OutArray.
164-
/// Note that for some predecessor terminators the incoming value is not
165-
/// exactly the argument value. E.g. the incoming value for a switch_enum
166-
/// payload argument is the enum itself (the operand of the switch_enum).
167-
bool getIncomingValues(
151+
/// Return true if this is block argument is actually a phi argument as
152+
/// opposed to a cast or projection.
153+
bool isPhiArgument();
154+
155+
/// If this argument is a phi, return the incoming phi value for the given
156+
/// predecessor BB. If this argument is not a phi, return an invalid SILValue.
157+
///
158+
/// FIXME: Once SILPHIArgument actually implies that it is a phi argument,
159+
/// this will be guaranteed to return a valid SILValue.
160+
SILValue getIncomingPhiValue(SILBasicBlock *BB);
161+
162+
/// If this argument is a phi, populate `OutArray` with the incoming phi
163+
/// values for each predecessor BB. If this argument is not a phi, return
164+
/// false.
165+
///
166+
/// FIXME: Once SILPHIArgument actually implies that it is a phi argument,
167+
/// this will always succeed.
168+
bool getIncomingPhiValues(llvm::SmallVectorImpl<SILValue> &OutArray);
169+
170+
/// If this argument is a phi, populate `OutArray` with each predecessor block
171+
/// and its incoming phi value. If this argument is not a phi, return false.
172+
///
173+
/// FIXME: Once SILPHIArgument actually implies that it is a phi argument,
174+
/// this will always succeed.
175+
bool getIncomingPhiValues(
168176
llvm::SmallVectorImpl<std::pair<SILBasicBlock *, SILValue>> &OutArray);
169177

170-
/// If this SILArgument's parent block has one predecessor, return the
171-
/// incoming value from that predecessor. Returns SILValue() otherwise.
172-
/// Note that for some predecessor terminators the incoming value is not
173-
/// exactly the argument value. E.g. the incoming value for a switch_enum
174-
/// payload argument is the enum itself (the operand of the switch_enum).
175-
SILValue getSingleIncomingValue() const;
178+
/// Returns true if we were able to find a single terminator operand value for
179+
/// each predecessor of this arguments basic block. The found values are
180+
/// stored in OutArray.
181+
///
182+
/// Note: this peeks through any projections or cast implied by the
183+
/// terminator. e.g. the incoming value for a switch_enum payload argument is
184+
/// the enum itself (the operand of the switch_enum).
185+
bool getSingleTerminatorOperands(llvm::SmallVectorImpl<SILValue> &OutArray);
186+
187+
/// Returns true if we were able to find single terminator operand values for
188+
/// each predecessor of this arguments basic block. The found values are
189+
/// stored in OutArray alongside their predecessor block.
190+
///
191+
/// Note: this peeks through any projections or cast implied by the
192+
/// terminator. e.g. the incoming value for a switch_enum payload argument is
193+
/// the enum itself (the operand of the switch_enum).
194+
bool getSingleTerminatorOperands(
195+
llvm::SmallVectorImpl<std::pair<SILBasicBlock *, SILValue>> &OutArray);
196+
197+
/// If this SILArgument's parent block has a single predecessor whose
198+
/// terminator has a single operand, return the incoming operand of the
199+
/// predecessor's terminator. Returns SILValue() otherwise. Note that for
200+
/// some predecessor terminators the incoming value is not exactly the
201+
/// argument value. E.g. the incoming value for a switch_enum payload argument
202+
/// is the enum itself (the operand of the switch_enum).
203+
SILValue getSingleTerminatorOperand() const;
176204

177205
static bool classof(const SILInstruction *) = delete;
178206
static bool classof(const SILUndef *) = delete;
@@ -254,36 +282,45 @@ class SILFunctionArgument : public SILArgument {
254282
// Out of line Definitions for SILArgument to avoid Forward Decl issues
255283
//===----------------------------------------------------------------------===//
256284

257-
inline SILValue SILArgument::getIncomingValue(unsigned BBIndex) {
258-
if (isa<SILFunctionArgument>(this))
259-
return SILValue();
260-
return cast<SILPHIArgument>(this)->getIncomingValue(BBIndex);
285+
inline bool SILArgument::isPhiArgument() {
286+
if (auto *phiArg = dyn_cast<SILPHIArgument>(this))
287+
return phiArg->isPhiArgument();
288+
289+
return false;
261290
}
262291

263-
inline SILValue SILArgument::getIncomingValue(SILBasicBlock *BB) {
292+
inline SILValue SILArgument::getIncomingPhiValue(SILBasicBlock *BB) {
264293
if (isa<SILFunctionArgument>(this))
265294
return SILValue();
266-
return cast<SILPHIArgument>(this)->getIncomingValue(BB);
295+
return cast<SILPHIArgument>(this)->getIncomingPhiValue(BB);
267296
}
268297

269298
inline bool
270-
SILArgument::getIncomingValues(llvm::SmallVectorImpl<SILValue> &OutArray) {
299+
SILArgument::getIncomingPhiValues(llvm::SmallVectorImpl<SILValue> &OutArray) {
271300
if (isa<SILFunctionArgument>(this))
272301
return false;
273-
return cast<SILPHIArgument>(this)->getIncomingValues(OutArray);
302+
return cast<SILPHIArgument>(this)->getIncomingPhiValues(OutArray);
274303
}
275304

276-
inline bool SILArgument::getIncomingValues(
305+
inline bool SILArgument::getIncomingPhiValues(
277306
llvm::SmallVectorImpl<std::pair<SILBasicBlock *, SILValue>> &OutArray) {
278307
if (isa<SILFunctionArgument>(this))
279308
return false;
280-
return cast<SILPHIArgument>(this)->getIncomingValues(OutArray);
309+
return cast<SILPHIArgument>(this)->getIncomingPhiValues(OutArray);
281310
}
282311

283-
inline SILValue SILArgument::getSingleIncomingValue() const {
312+
inline bool SILArgument::getSingleTerminatorOperands(
313+
llvm::SmallVectorImpl<SILValue> &OutArray) {
284314
if (isa<SILFunctionArgument>(this))
285-
return SILValue();
286-
return cast<SILPHIArgument>(this)->getSingleIncomingValue();
315+
return false;
316+
return cast<SILPHIArgument>(this)->getSingleTerminatorOperands(OutArray);
317+
}
318+
319+
inline bool SILArgument::getSingleTerminatorOperands(
320+
llvm::SmallVectorImpl<std::pair<SILBasicBlock *, SILValue>> &OutArray) {
321+
if (isa<SILFunctionArgument>(this))
322+
return false;
323+
return cast<SILPHIArgument>(this)->getSingleTerminatorOperands(OutArray);
287324
}
288325

289326
} // end swift namespace

include/swift/SIL/SILFunction.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,11 @@ class SILFunction
883883
/// invariants.
884884
void verify(bool SingleFunction = true) const;
885885

886+
/// Verify that all non-cond-br critical edges have been split.
887+
///
888+
/// This is a fast subset of the checks performed in the SILVerifier.
889+
void verifyCriticalEdges() const;
890+
886891
/// Pretty-print the SILFunction.
887892
void dump(bool Verbose) const;
888893
void dump() const;

include/swift/SILOptimizer/Utils/CFG.h

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,11 @@ SILBasicBlock *splitBasicBlockAndBranch(SILBuilder &B,
118118
/// \brief Return true if the function has a critical edge, false otherwise.
119119
bool hasCriticalEdges(SILFunction &F, bool OnlyNonCondBr);
120120

121-
/// \brief Split all critical edges in the function updating the dominator tree
122-
/// and loop information (if they are not set to null). If \p OnlyNonCondBr is
123-
/// true this will not split cond_br edges (Only edges which can't carry
124-
/// arguments will be split).
125-
bool splitAllCriticalEdges(SILFunction &F, bool OnlyNonCondBr,
126-
DominanceInfo *DT, SILLoopInfo *LI);
121+
/// \brief Split all critical edges in the given function, updating the
122+
/// dominator tree and loop information if they are provided.
123+
///
124+
/// FIXME: This should never be called! Fix passes that create critical edges.
125+
bool splitAllCriticalEdges(SILFunction &F, DominanceInfo *DT, SILLoopInfo *LI);
127126

128127
/// \brief Split all cond_br critical edges with non-trivial arguments in the
129128
/// function updating the dominator tree and loop information (if they are not

include/swift/SILOptimizer/Utils/Local.h

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -343,37 +343,41 @@ class EdgeThreadingCloner : public BaseThreadingCloner {
343343
EdgeThreadingCloner(BranchInst *BI)
344344
: BaseThreadingCloner(*BI->getFunction(),
345345
BI->getDestBB(), nullptr) {
346-
DestBB = createEdgeBlockAndRedirectBranch(BI);
346+
createEdgeBlockAndRedirectBranch(BI);
347347
}
348348

349-
SILBasicBlock *createEdgeBlockAndRedirectBranch(BranchInst *BI) {
349+
void createEdgeBlockAndRedirectBranch(BranchInst *BI) {
350350
auto *Fn = BI->getFunction();
351351
auto *SrcBB = BI->getParent();
352-
auto *DestBB = BI->getDestBB();
353-
auto *EdgeBB = Fn->createBasicBlockAfter(SrcBB);
352+
auto *EdgeBB = BI->getDestBB();
353+
354+
this->DestBB = Fn->createBasicBlockAfter(SrcBB);
354355

355356
// Create block arguments.
356-
for (unsigned ArgIdx : range(DestBB->getNumArguments())) {
357-
auto *DestPHIArg = cast<SILPHIArgument>(DestBB->getArgument(ArgIdx));
357+
for (unsigned ArgIdx : range(EdgeBB->getNumArguments())) {
358+
auto *DestPHIArg = cast<SILPHIArgument>(EdgeBB->getArgument(ArgIdx));
358359
assert(BI->getArg(ArgIdx)->getType() == DestPHIArg->getType() &&
359360
"Types must match");
360-
auto *BlockArg = EdgeBB->createPHIArgument(
361+
auto *BlockArg = DestBB->createPHIArgument(
361362
DestPHIArg->getType(), DestPHIArg->getOwnershipKind());
362363
ValueMap[DestPHIArg] = SILValue(BlockArg);
363364
AvailVals.push_back(std::make_pair(DestPHIArg, BlockArg));
364365
}
365366

366367
// Redirect the branch.
367-
SILBuilderWithScope(BI).createBranch(BI->getLoc(), EdgeBB, BI->getArgs());
368+
SILBuilderWithScope(BI).createBranch(BI->getLoc(), DestBB, BI->getArgs());
368369
BI->eraseFromParent();
369-
return EdgeBB;
370370
}
371371

372372
SILBasicBlock *getEdgeBB() {
373373
// DestBB really is the edge basic block we created to clone instructions
374374
// to.
375375
return DestBB;
376376
}
377+
378+
/// Call this after processing all instructions to fix the control flow
379+
/// graph. The branch cloner may have left critical edges.
380+
bool splitCriticalEdges(DominanceInfo *DT, SILLoopInfo *LI);
377381
};
378382

379383
/// Helper class for cloning of basic blocks.
@@ -414,8 +418,7 @@ class BasicBlockCloner : public BaseThreadingCloner {
414418
/// 'NeedToSplitCriticalEdges' to false if all critical edges are split,
415419
/// otherwise this call will try to split all critical edges.
416420
void updateSSAAfterCloning(BaseThreadingCloner &Cloner, SILBasicBlock *SrcBB,
417-
SILBasicBlock *DestBB,
418-
bool NeedToSplitCriticalEdges = true);
421+
SILBasicBlock *DestBB);
419422

420423
// Helper class that provides a callback that can be used in
421424
// inliners/cloners for collecting new call sites.

lib/SIL/InstructionUtils.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ void swift::findClosuresForFunctionValue(
465465
// This should be done before calling findClosureStoredIntoBlock.
466466
if (auto *arg = dyn_cast<SILPHIArgument>(V)) {
467467
SmallVector<std::pair<SILBasicBlock *, SILValue>, 2> blockArgs;
468-
arg->getIncomingValues(blockArgs);
468+
arg->getIncomingPhiValues(blockArgs);
469469
for (auto &blockAndArg : blockArgs)
470470
worklistInsert(blockAndArg.second);
471471

0 commit comments

Comments
 (0)