Skip to content

Commit 4a5d7ae

Browse files
committed
[move-function] Break blocks right after the non-undef debug info associated with move only values.
The reason why I am doing this is that right now SelectionDAG seems to sink certain llvm.dbg.addr to the end of block. By breaking the block, we ensure that we initialize the debug value of values early enough. NOTE: We are relying on code at -Onone not eliminating control flow which it does not today. A few additional notes: 1. I also fixed a small issue where I was not setting the proper debug scope for reinit debug_values. This came up when I was writing test cases for this commit. So I just fixed it at the same time. 2. Since I am splitting blocks and I don't want to invalidate dominators/etc at this point in the pipeline, I took advantage of the APIs ability to update dominators/loopinfo at the same time. 3. I also expanded the tests in tree further by adding debug info tests for the reinit copyable/addressonly cases in the multi-block case.
1 parent 30d318a commit 4a5d7ae

File tree

6 files changed

+345
-27
lines changed

6 files changed

+345
-27
lines changed

include/swift/SILOptimizer/Utils/CFGOptUtils.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,22 @@ SILBasicBlock *splitBasicBlockAndBranch(SILBuilder &builder,
144144
DominanceInfo *domInfo,
145145
SILLoopInfo *loopInfo);
146146

147+
/// A version of splitBasicBlockAndBranch that takes a SILBuilderContext instead
148+
/// of a SILBuilder. We generally are trying to eliminate APIs that take in
149+
/// SILBuilder directly since that can cause weird downstream mistakes around
150+
/// debug info scopes. So this provides a better choice for engineers.
151+
///
152+
/// TODO: Migrate all callers of splitBasicBlockAndBranch to use this entry
153+
/// point.
154+
inline SILBasicBlock *splitBasicBlockAndBranch(SILBuilderContext &builderCtx,
155+
SILInstruction *splitBeforeInst,
156+
DominanceInfo *domInfo,
157+
SILLoopInfo *loopInfo) {
158+
// Make sure we have the right debug scope from split before inst.
159+
SILBuilderWithScope builder(splitBeforeInst, builderCtx);
160+
return splitBasicBlockAndBranch(builder, splitBeforeInst, domInfo, loopInfo);
161+
}
162+
147163
/// Return true if the function has a critical edge, false otherwise.
148164
bool hasCriticalEdges(SILFunction &f, bool onlyNonCondBr);
149165

lib/SILOptimizer/Mandatory/MoveKillsCopyableAddressesChecker.cpp

Lines changed: 100 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,9 @@
158158
#include "swift/SIL/SILVisitor.h"
159159
#include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h"
160160
#include "swift/SILOptimizer/Analysis/ClosureScope.h"
161+
#include "swift/SILOptimizer/Analysis/LoopAnalysis.h"
161162
#include "swift/SILOptimizer/PassManager/Transforms.h"
163+
#include "swift/SILOptimizer/Utils/CFGOptUtils.h"
162164
#include "swift/SILOptimizer/Utils/CanonicalOSSALifetime.h"
163165
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
164166
#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h"
@@ -1396,17 +1398,19 @@ struct DataflowState {
13961398
applySiteToPromotedArgIndices(applySiteToPromotedArgIndices),
13971399
closureConsumes(closureConsumes) {}
13981400
void init();
1399-
bool process(
1400-
SILValue address,
1401-
SmallBlotSetVector<SILInstruction *, 8> &postDominatingConsumingUsers);
1401+
bool
1402+
process(SILValue address,
1403+
SmallBlotSetVector<SILInstruction *, 8> &postDominatingConsumingUsers,
1404+
SmallSetVector<SILInstruction *, 8> &debugInfoBlockSplitPoints);
14021405
bool handleSingleBlockClosure(SILArgument *address,
14031406
ClosureOperandState &state);
14041407
bool cleanupAllDestroyAddr(
14051408
SILValue address, SILFunction *fn, SmallBitVector &destroyIndices,
14061409
SmallBitVector &reinitIndices, SmallBitVector &consumingClosureIndices,
14071410
BasicBlockSet &blocksVisitedWhenProcessingNewTakes,
14081411
BasicBlockSet &blocksWithMovesThatAreNowTakes,
1409-
SmallBlotSetVector<SILInstruction *, 8> &postDominatingConsumingUsers);
1412+
SmallBlotSetVector<SILInstruction *, 8> &postDominatingConsumingUsers,
1413+
SmallSetVector<SILInstruction *, 8> &debugInfoBlockSplitPoints);
14101414
void clear() {
14111415
useBlocks.clear();
14121416
initBlocks.clear();
@@ -1425,7 +1429,8 @@ bool DataflowState::cleanupAllDestroyAddr(
14251429
SmallBitVector &reinitIndices, SmallBitVector &consumingClosureIndices,
14261430
BasicBlockSet &blocksVisitedWhenProcessingNewTakes,
14271431
BasicBlockSet &blocksWithMovesThatAreNowTakes,
1428-
SmallBlotSetVector<SILInstruction *, 8> &postDominatingConsumingUsers) {
1432+
SmallBlotSetVector<SILInstruction *, 8> &postDominatingConsumingUsers,
1433+
SmallSetVector<SILInstruction *, 8> &debugInfoBlockSplitPoints) {
14291434
bool madeChange = false;
14301435
BasicBlockWorklist worklist(fn);
14311436

@@ -1538,8 +1543,13 @@ bool DataflowState::cleanupAllDestroyAddr(
15381543
if (debugVarInst) {
15391544
if (auto varInfo = debugVarInst.getVarInfo()) {
15401545
SILBuilderWithScope reinitBuilder(*reinit);
1541-
reinitBuilder.createDebugValue(debugVarInst.inst->getLoc(), address,
1542-
*varInfo, false, /*was moved*/ true);
1546+
reinitBuilder.setCurrentDebugScope(debugVarInst->getDebugScope());
1547+
auto *dvi =
1548+
reinitBuilder.createDebugValue(debugVarInst.inst->getLoc(), address,
1549+
*varInfo, false, /*was moved*/ true);
1550+
// After we are done processing, we are going to split at the reinit
1551+
// point.
1552+
debugInfoBlockSplitPoints.insert(dvi);
15431553
}
15441554
}
15451555
madeChange = true;
@@ -1581,7 +1591,8 @@ bool DataflowState::cleanupAllDestroyAddr(
15811591

15821592
bool DataflowState::process(
15831593
SILValue address,
1584-
SmallBlotSetVector<SILInstruction *, 8> &postDominatingConsumingUsers) {
1594+
SmallBlotSetVector<SILInstruction *, 8> &postDominatingConsumingUsers,
1595+
SmallSetVector<SILInstruction *, 8> &debugInfoBlockSplitPoints) {
15851596
SILFunction *fn = address->getFunction();
15861597
assert(fn);
15871598

@@ -1778,9 +1789,9 @@ bool DataflowState::process(
17781789
debug.markAsMoved();
17791790
if (auto varInfo = debug.getVarInfo()) {
17801791
SILBuilderWithScope undefBuilder(builder);
1781-
undefBuilder.setCurrentDebugScope(debug.inst->getDebugScope());
1792+
undefBuilder.setCurrentDebugScope(debug->getDebugScope());
17821793
undefBuilder.createDebugValue(
1783-
debug.inst->getLoc(),
1794+
debug->getLoc(),
17841795
SILUndef::get(address->getType(), builder.getModule()), *varInfo,
17851796
false /*poison*/, true /*was moved*/);
17861797
}
@@ -1800,13 +1811,25 @@ bool DataflowState::process(
18001811
if (!convertedMarkMoveToTake)
18011812
return madeChange;
18021813

1814+
// Now if we had a debug var carrying inst for our address, add the debug var
1815+
// carrying inst to debugInfoBlockSplitPoints so when we are done processing
1816+
// we can break blocks at those locations. This is done to ensure that we
1817+
// don't have to worry about the CFG changing while we are processing. The
1818+
// reason why we do this is that we are working around a bug in SelectionDAG
1819+
// that results in llvm.dbg.addr being sunk to the end of blocks. This can
1820+
// cause the value to appear to not be available after it is initialized. By
1821+
// breaking the block here, we guarantee that SelectionDAG's sinking has no
1822+
// effect since we are the end of the block.
1823+
if (auto debug = DebugVarCarryingInst::getFromValue(address))
1824+
debugInfoBlockSplitPoints.insert(*debug);
1825+
18031826
// Now that we have processed all of our mark_moves, eliminate all of the
18041827
// destroy_addr.
18051828
madeChange |= cleanupAllDestroyAddr(
18061829
address, fn, getIndicesOfPairedDestroys(), getIndicesOfPairedReinits(),
18071830
getIndicesOfPairedConsumingClosureUses(),
18081831
blocksVisitedWhenProcessingNewTakes, blocksWithMovesThatAreNowTakes,
1809-
postDominatingConsumingUsers);
1832+
postDominatingConsumingUsers, debugInfoBlockSplitPoints);
18101833

18111834
return madeChange;
18121835
}
@@ -1895,9 +1918,10 @@ void DataflowState::init() {
18951918
// Returns true if we emitted a diagnostic and handled the single block
18961919
// case. Returns false if we visited all of the uses and seeded the UseState
18971920
// struct with the information needed to perform our interprocedural dataflow.
1898-
static bool performSingleBasicBlockAnalysis(DataflowState &dataflowState,
1899-
SILValue address,
1900-
MarkUnresolvedMoveAddrInst *mvi) {
1921+
static bool performSingleBasicBlockAnalysis(
1922+
DataflowState &dataflowState,
1923+
SmallSetVector<SILInstruction *, 8> &debugInfoBlockSplitPoints,
1924+
SILValue address, MarkUnresolvedMoveAddrInst *mvi) {
19011925
// First scan downwards to make sure we are move out of this block.
19021926
auto &useState = dataflowState.useState;
19031927
auto &applySiteToPromotedArgIndices =
@@ -1926,6 +1950,7 @@ static bool performSingleBasicBlockAnalysis(DataflowState &dataflowState,
19261950
if (auto debug = DebugVarCarryingInst::getFromValue(address)) {
19271951
if (auto varInfo = debug.getVarInfo()) {
19281952
SILBuilderWithScope undefBuilder(builder);
1953+
debugInfoBlockSplitPoints.insert(*debug);
19291954
undefBuilder.setCurrentDebugScope(debug.inst->getDebugScope());
19301955
undefBuilder.createDebugValue(
19311956
debug.inst->getLoc(),
@@ -2036,6 +2061,7 @@ static bool performSingleBasicBlockAnalysis(DataflowState &dataflowState,
20362061
if (auto debug = DebugVarCarryingInst::getFromValue(address)) {
20372062
if (auto varInfo = debug.getVarInfo()) {
20382063
{
2064+
debugInfoBlockSplitPoints.insert(*debug);
20392065
SILBuilderWithScope undefBuilder(builder);
20402066
undefBuilder.setCurrentDebugScope(debug.inst->getDebugScope());
20412067
undefBuilder.createDebugValue(
@@ -2049,8 +2075,11 @@ static bool performSingleBasicBlockAnalysis(DataflowState &dataflowState,
20492075
// reinit instruction so we reshow the variable.
20502076
auto *next = interestingUser->getNextInstruction();
20512077
SILBuilderWithScope reinitBuilder(next);
2052-
reinitBuilder.createDebugValue(debug.inst->getLoc(), address,
2053-
*varInfo, false, /*was moved*/ true);
2078+
reinitBuilder.setCurrentDebugScope(debug->getDebugScope());
2079+
auto *dvi = reinitBuilder.createDebugValue(debug.inst->getLoc(),
2080+
address, *varInfo, false,
2081+
/*was moved*/ true);
2082+
debugInfoBlockSplitPoints.insert(dvi);
20542083
}
20552084
}
20562085
debug.markAsMoved();
@@ -2086,6 +2115,7 @@ static bool performSingleBasicBlockAnalysis(DataflowState &dataflowState,
20862115
dumpBitVector(llvm::dbgs(), bitVector); llvm::dbgs() << '\n');
20872116
if (auto debug = DebugVarCarryingInst::getFromValue(address)) {
20882117
if (auto varInfo = debug.getVarInfo()) {
2118+
debugInfoBlockSplitPoints.insert(*debug);
20892119
SILBuilderWithScope undefBuilder(builder);
20902120
undefBuilder.setCurrentDebugScope(debug.inst->getDebugScope());
20912121
undefBuilder.createDebugValue(
@@ -2137,6 +2167,19 @@ struct MoveKillsCopyableAddressesChecker {
21372167
applySiteToPromotedArgIndices;
21382168
SmallBlotSetVector<SILInstruction *, 8> closureConsumes;
21392169

2170+
/// A list of instructions where to work around the behavior of SelectionDAG,
2171+
/// we break the block. These are debug var carrying insts or debug_value
2172+
/// associated with reinits. This is initialized when we process all of the
2173+
/// addresses. Then as a final step after wards we use this as a worklist and
2174+
/// break blocks at each of these instructions. We update DebugInfo, LoopInfo
2175+
/// if we found that they already exist.
2176+
///
2177+
/// We on purpose use a set vector to ensure that we only ever split a block
2178+
/// once.
2179+
SmallSetVector<SILInstruction *, 8> debugInfoBlockSplitPoints;
2180+
DominanceInfo *dominanceToUpdate = nullptr;
2181+
SILLoopInfo *loopInfoToUpdate = nullptr;
2182+
21402183
MoveKillsCopyableAddressesChecker(SILFunction *fn,
21412184
SILOptFunctionBuilder &funcBuilder)
21422185
: fn(fn), useState(),
@@ -2145,6 +2188,12 @@ struct MoveKillsCopyableAddressesChecker {
21452188
closureUseState(), closureUseDataflowState(closureUseState),
21462189
funcBuilder(funcBuilder) {}
21472190

2191+
void setDominanceToUpdate(DominanceInfo *newInfo) {
2192+
dominanceToUpdate = newInfo;
2193+
}
2194+
2195+
void setLoopInfoToUpdate(SILLoopInfo *newInfo) { loopInfoToUpdate = newInfo; }
2196+
21482197
void cloneDeferCalleeAndRewriteUses(
21492198
SmallVectorImpl<SILValue> &temporaryStorage,
21502199
const SmallBitVector &bitVector, FullApplySite oldApplySite,
@@ -2156,6 +2205,19 @@ struct MoveKillsCopyableAddressesChecker {
21562205

21572206
void emitDiagnosticForMove(SILValue borrowedValue,
21582207
StringRef borrowedValueName, MoveValueInst *mvi);
2208+
bool splitBlocksAfterDebugInfoCarryingInst(SILModule &mod) {
2209+
if (debugInfoBlockSplitPoints.empty())
2210+
return false;
2211+
2212+
SILBuilderContext ctx(mod);
2213+
do {
2214+
auto *next = debugInfoBlockSplitPoints.pop_back_val();
2215+
splitBasicBlockAndBranch(ctx, next->getNextInstruction(),
2216+
dominanceToUpdate, loopInfoToUpdate);
2217+
} while (!debugInfoBlockSplitPoints.empty());
2218+
2219+
return true;
2220+
}
21592221

21602222
ASTContext &getASTContext() const { return fn->getASTContext(); }
21612223
};
@@ -2332,8 +2394,8 @@ bool MoveKillsCopyableAddressesChecker::check(SILValue address) {
23322394
// diagnostic.
23332395
bool emittedSingleBBDiagnostic = false;
23342396
for (auto *mvi : useState.markMoves) {
2335-
emittedSingleBBDiagnostic |=
2336-
performSingleBasicBlockAnalysis(dataflowState, address, mvi);
2397+
emittedSingleBBDiagnostic |= performSingleBasicBlockAnalysis(
2398+
dataflowState, debugInfoBlockSplitPoints, address, mvi);
23372399
}
23382400

23392401
if (emittedSingleBBDiagnostic) {
@@ -2353,7 +2415,8 @@ bool MoveKillsCopyableAddressesChecker::check(SILValue address) {
23532415
// Ok, we need to perform global dataflow for one of our moves. Initialize our
23542416
// dataflow state engine and then run the dataflow itself.
23552417
dataflowState.init();
2356-
bool result = dataflowState.process(address, closureConsumes);
2418+
bool result = dataflowState.process(address, closureConsumes,
2419+
debugInfoBlockSplitPoints);
23572420
return result;
23582421
}
23592422

@@ -2405,9 +2468,19 @@ class MoveKillsCopyableAddressesCheckerPass : public SILFunctionTransform {
24052468
llvm::makeArrayRef(addressesToCheck.begin(), addressesToCheck.end());
24062469

24072470
SILOptFunctionBuilder funcBuilder(*this);
2471+
24082472
MoveKillsCopyableAddressesChecker checker(getFunction(), funcBuilder);
2409-
bool madeChange = false;
24102473

2474+
// If we already had dominance or loop info generated, update them when
2475+
// splitting blocks.
2476+
auto *dominanceAnalysis = getAnalysis<DominanceAnalysis>();
2477+
if (dominanceAnalysis->hasFunctionInfo(fn))
2478+
checker.setDominanceToUpdate(dominanceAnalysis->get(fn));
2479+
auto *loopAnalysis = getAnalysis<SILLoopAnalysis>();
2480+
if (loopAnalysis->hasFunctionInfo(fn))
2481+
checker.setLoopInfoToUpdate(loopAnalysis->get(fn));
2482+
2483+
bool madeChange = false;
24112484
while (!addressToProcess.empty()) {
24122485
auto address = addressToProcess.front();
24132486
addressToProcess = addressToProcess.drop_front(1);
@@ -2419,6 +2492,13 @@ class MoveKillsCopyableAddressesCheckerPass : public SILFunctionTransform {
24192492
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
24202493
}
24212494

2495+
// We update debug info/loop info here, so we just invalidate instructions.
2496+
if (checker.splitBlocksAfterDebugInfoCarryingInst(fn->getModule())) {
2497+
AnalysisPreserver preserveDominance(dominanceAnalysis);
2498+
AnalysisPreserver preserveLoop(loopAnalysis);
2499+
invalidateAnalysis(SILAnalysis::InvalidationKind::BranchesAndInstructions);
2500+
}
2501+
24222502
// Now go through and clone any apply sites that we need to clone.
24232503
SmallVector<SILValue, 8> newArgs;
24242504
bool rewroteCallee = false;

0 commit comments

Comments
 (0)