Skip to content

Commit a553b87

Browse files
committed
[move-function] Rather than breaking block at the SIL level after moved dbg_value, do it late as an LLVM pass on llvm.dbg.addr
This has a few nice benefits: 1. The splitting happens after LLVM optimizations have run. This ensures that LLVM will not join these blocks no matter what! The author of this commit has found that in certain cases LLVM does this even at -Onone. By running this late, we get the benefit we are looking for: working around the bad SelectionDAG behavior. 2. This block splitting is just a workaround for the above mentioned unfortunate SelectionDAG behavior. By doing this when we remove the workaround, we will not have to update SIL level tests... instead we will just remove a small LLVM pass. Some additional notes: 1. Only moved values will ever have llvm.dbg.addr emitted today, so we do not have to worry about this impacting the rest of the language. 2. The pass's behavior is tested at the IR level by move_function_dbginfo.swift.
1 parent 7d9d798 commit a553b87

File tree

11 files changed

+118
-130
lines changed

11 files changed

+118
-130
lines changed

include/swift/LLVMPasses/Passes.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ namespace swift {
102102
static char ID;
103103
InlineTreePrinter() : llvm::ModulePass(ID) {}
104104
};
105-
106105
} // end namespace swift
107106

108107
#endif

include/swift/LLVMPasses/PassesFwd.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ namespace llvm {
2525
void initializeSwiftARCContractPass(PassRegistry &);
2626
void initializeInlineTreePrinterPass(PassRegistry &);
2727
void initializeSwiftMergeFunctionsPass(PassRegistry &);
28+
void initializeSwiftDbgAddrBlockSplitterPass(PassRegistry &);
2829
}
2930

3031
namespace swift {
@@ -33,6 +34,7 @@ namespace swift {
3334
llvm::ModulePass *createInlineTreePrinterPass();
3435
llvm::ModulePass *createSwiftMergeFunctionsPass(bool ptrAuthEnabled,
3536
unsigned ptrAuthKey);
37+
llvm::FunctionPass *createSwiftDbgAddrBlockSplitter();
3638
llvm::ImmutablePass *createSwiftAAWrapperPass();
3739
llvm::ImmutablePass *createSwiftRCIdentityPass();
3840
} // end namespace swift

lib/IRGen/IRGen.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,11 @@ static void addThreadSanitizerPass(const PassManagerBuilder &Builder,
146146
PM.add(createThreadSanitizerLegacyPassPass());
147147
}
148148

149+
static void addSwiftDbgAddrBlockSplitterPass(const PassManagerBuilder &Builder,
150+
legacy::PassManagerBase &PM) {
151+
PM.add(createSwiftDbgAddrBlockSplitter());
152+
}
153+
149154
static void addSanitizerCoveragePass(const PassManagerBuilder &Builder,
150155
legacy::PassManagerBase &PM) {
151156
const PassManagerBuilderWrapper &BuilderWrapper =
@@ -289,6 +294,13 @@ void swift::performLLVMOptimizations(const IRGenOptions &Opts,
289294
});
290295
}
291296

297+
if (RunSwiftSpecificLLVMOptzns) {
298+
PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
299+
addSwiftDbgAddrBlockSplitterPass);
300+
PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
301+
addSwiftDbgAddrBlockSplitterPass);
302+
}
303+
292304
// Configure the function passes.
293305
legacy::FunctionPassManager FunctionPasses(Module);
294306
FunctionPasses.add(createTargetTransformInfoWrapperPass(

lib/LLVMPasses/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ add_swift_host_library(swiftLLVMPasses STATIC
66
LLVMARCContract.cpp
77
LLVMInlineTree.cpp
88
LLVMMergeFunctions.cpp
9+
DbgAddrBlockSplitter.cpp
910

1011
LLVM_LINK_COMPONENTS
1112
analysis
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
//===--- DbgAddrBlockSplitter.cpp -----------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
///
13+
/// This simple pass runs late after all LLVM level optimization passes have
14+
/// completed and break blocks at llvm.dbg.addr when we are compiling at
15+
/// -Onone. This helps us avoid bad behavior in SelectionDAG where SelectionDAG
16+
/// in certain cases sink llvm.dbg.addr to the end of blocks.
17+
///
18+
//===----------------------------------------------------------------------===//
19+
20+
#include "swift/LLVMPasses/Passes.h"
21+
#include "swift/LLVMPasses/PassesFwd.h"
22+
#include "llvm/IR/IntrinsicInst.h"
23+
#include "llvm/Pass.h"
24+
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
25+
26+
using namespace llvm;
27+
28+
namespace {
29+
30+
struct SwiftDbgAddrBlockSplitter : FunctionPass {
31+
static char ID;
32+
SwiftDbgAddrBlockSplitter() : FunctionPass(ID) {}
33+
34+
bool runOnFunction(Function &fn) override;
35+
};
36+
37+
} // namespace
38+
39+
bool SwiftDbgAddrBlockSplitter::runOnFunction(Function &fn) {
40+
SmallVector<Instruction *, 32> breakBlockPoints;
41+
42+
for (auto &block : fn) {
43+
for (auto &inst : block) {
44+
if (isa<DbgAddrIntrinsic>(&inst)) {
45+
breakBlockPoints.push_back(&*std::next(inst.getIterator()));
46+
}
47+
}
48+
}
49+
50+
if (breakBlockPoints.empty())
51+
return false;
52+
53+
bool madeChange = false;
54+
55+
while (!breakBlockPoints.empty()) {
56+
auto *i = breakBlockPoints.pop_back_val();
57+
if (i->isTerminator())
58+
continue;
59+
SplitBlock(i->getParent(), i);
60+
madeChange = true;
61+
}
62+
63+
return madeChange;
64+
}
65+
66+
char SwiftDbgAddrBlockSplitter::ID = 0;
67+
INITIALIZE_PASS_BEGIN(SwiftDbgAddrBlockSplitter,
68+
"swift-dbg-addr-block-splitter",
69+
"Swift pass that splits blocks after llvm.dbg.addr",
70+
false, false)
71+
INITIALIZE_PASS_END(SwiftDbgAddrBlockSplitter, "swift-dbg-addr-block-splitter",
72+
"Swift pass that splits blocks after llvm.dbg.addr", false,
73+
false)
74+
75+
llvm::FunctionPass *swift::createSwiftDbgAddrBlockSplitter() {
76+
initializeSwiftDbgAddrBlockSplitterPass(
77+
*llvm::PassRegistry::getPassRegistry());
78+
return new SwiftDbgAddrBlockSplitter();
79+
}

lib/SILOptimizer/Mandatory/MoveKillsCopyableAddressesChecker.cpp

Lines changed: 13 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1398,19 +1398,17 @@ struct DataflowState {
13981398
applySiteToPromotedArgIndices(applySiteToPromotedArgIndices),
13991399
closureConsumes(closureConsumes) {}
14001400
void init();
1401-
bool
1402-
process(SILValue address,
1403-
SmallBlotSetVector<SILInstruction *, 8> &postDominatingConsumingUsers,
1404-
SmallSetVector<SILInstruction *, 8> &debugInfoBlockSplitPoints);
1401+
bool process(
1402+
SILValue address,
1403+
SmallBlotSetVector<SILInstruction *, 8> &postDominatingConsumingUsers);
14051404
bool handleSingleBlockClosure(SILArgument *address,
14061405
ClosureOperandState &state);
14071406
bool cleanupAllDestroyAddr(
14081407
SILValue address, SILFunction *fn, SmallBitVector &destroyIndices,
14091408
SmallBitVector &reinitIndices, SmallBitVector &consumingClosureIndices,
14101409
BasicBlockSet &blocksVisitedWhenProcessingNewTakes,
14111410
BasicBlockSet &blocksWithMovesThatAreNowTakes,
1412-
SmallBlotSetVector<SILInstruction *, 8> &postDominatingConsumingUsers,
1413-
SmallSetVector<SILInstruction *, 8> &debugInfoBlockSplitPoints);
1411+
SmallBlotSetVector<SILInstruction *, 8> &postDominatingConsumingUsers);
14141412
void clear() {
14151413
useBlocks.clear();
14161414
initBlocks.clear();
@@ -1429,8 +1427,7 @@ bool DataflowState::cleanupAllDestroyAddr(
14291427
SmallBitVector &reinitIndices, SmallBitVector &consumingClosureIndices,
14301428
BasicBlockSet &blocksVisitedWhenProcessingNewTakes,
14311429
BasicBlockSet &blocksWithMovesThatAreNowTakes,
1432-
SmallBlotSetVector<SILInstruction *, 8> &postDominatingConsumingUsers,
1433-
SmallSetVector<SILInstruction *, 8> &debugInfoBlockSplitPoints) {
1430+
SmallBlotSetVector<SILInstruction *, 8> &postDominatingConsumingUsers) {
14341431
bool madeChange = false;
14351432
BasicBlockWorklist worklist(fn);
14361433

@@ -1544,12 +1541,8 @@ bool DataflowState::cleanupAllDestroyAddr(
15441541
if (auto varInfo = debugVarInst.getVarInfo()) {
15451542
SILBuilderWithScope reinitBuilder(*reinit);
15461543
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);
1544+
reinitBuilder.createDebugValue(debugVarInst.inst->getLoc(), address,
1545+
*varInfo, false, /*was moved*/ true);
15531546
}
15541547
}
15551548
madeChange = true;
@@ -1591,8 +1584,7 @@ bool DataflowState::cleanupAllDestroyAddr(
15911584

15921585
bool DataflowState::process(
15931586
SILValue address,
1594-
SmallBlotSetVector<SILInstruction *, 8> &postDominatingConsumingUsers,
1595-
SmallSetVector<SILInstruction *, 8> &debugInfoBlockSplitPoints) {
1587+
SmallBlotSetVector<SILInstruction *, 8> &postDominatingConsumingUsers) {
15961588
SILFunction *fn = address->getFunction();
15971589
assert(fn);
15981590

@@ -1811,25 +1803,13 @@ bool DataflowState::process(
18111803
if (!convertedMarkMoveToTake)
18121804
return madeChange;
18131805

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-
18261806
// Now that we have processed all of our mark_moves, eliminate all of the
18271807
// destroy_addr.
18281808
madeChange |= cleanupAllDestroyAddr(
18291809
address, fn, getIndicesOfPairedDestroys(), getIndicesOfPairedReinits(),
18301810
getIndicesOfPairedConsumingClosureUses(),
18311811
blocksVisitedWhenProcessingNewTakes, blocksWithMovesThatAreNowTakes,
1832-
postDominatingConsumingUsers, debugInfoBlockSplitPoints);
1812+
postDominatingConsumingUsers);
18331813

18341814
return madeChange;
18351815
}
@@ -1932,19 +1912,6 @@ struct MoveKillsCopyableAddressesChecker {
19321912
applySiteToPromotedArgIndices;
19331913
SmallBlotSetVector<SILInstruction *, 8> closureConsumes;
19341914

1935-
/// A list of instructions where to work around the behavior of SelectionDAG,
1936-
/// we break the block. These are debug var carrying insts or debug_value
1937-
/// associated with reinits. This is initialized when we process all of the
1938-
/// addresses. Then as a final step after wards we use this as a worklist and
1939-
/// break blocks at each of these instructions. We update DebugInfo, LoopInfo
1940-
/// if we found that they already exist.
1941-
///
1942-
/// We on purpose use a set vector to ensure that we only ever split a block
1943-
/// once.
1944-
SmallSetVector<SILInstruction *, 8> debugInfoBlockSplitPoints;
1945-
DominanceInfo *dominanceToUpdate = nullptr;
1946-
SILLoopInfo *loopInfoToUpdate = nullptr;
1947-
19481915
MoveKillsCopyableAddressesChecker(SILFunction *fn,
19491916
SILOptFunctionBuilder &funcBuilder)
19501917
: fn(fn), useState(),
@@ -1953,12 +1920,6 @@ struct MoveKillsCopyableAddressesChecker {
19531920
closureUseState(), closureUseDataflowState(closureUseState),
19541921
funcBuilder(funcBuilder) {}
19551922

1956-
void setDominanceToUpdate(DominanceInfo *newInfo) {
1957-
dominanceToUpdate = newInfo;
1958-
}
1959-
1960-
void setLoopInfoToUpdate(SILLoopInfo *newInfo) { loopInfoToUpdate = newInfo; }
1961-
19621923
void cloneDeferCalleeAndRewriteUses(
19631924
SmallVectorImpl<SILValue> &temporaryStorage,
19641925
const SmallBitVector &bitVector, FullApplySite oldApplySite,
@@ -1970,20 +1931,6 @@ struct MoveKillsCopyableAddressesChecker {
19701931

19711932
void emitDiagnosticForMove(SILValue borrowedValue,
19721933
StringRef borrowedValueName, MoveValueInst *mvi);
1973-
bool splitBlocksAfterDebugInfoCarryingInst(SILModule &mod) {
1974-
if (debugInfoBlockSplitPoints.empty())
1975-
return false;
1976-
1977-
SILBuilderContext ctx(mod);
1978-
do {
1979-
auto *next = debugInfoBlockSplitPoints.pop_back_val();
1980-
splitBasicBlockAndBranch(ctx, next->getNextInstruction(),
1981-
dominanceToUpdate, loopInfoToUpdate);
1982-
} while (!debugInfoBlockSplitPoints.empty());
1983-
1984-
return true;
1985-
}
1986-
19871934
bool performSingleBasicBlockAnalysis(SILValue address,
19881935
MarkUnresolvedMoveAddrInst *mvi);
19891936

@@ -2131,7 +2078,6 @@ bool MoveKillsCopyableAddressesChecker::performSingleBasicBlockAnalysis(
21312078
if (auto debug = DebugVarCarryingInst::getFromValue(address)) {
21322079
if (auto varInfo = debug.getVarInfo()) {
21332080
SILBuilderWithScope undefBuilder(builder);
2134-
debugInfoBlockSplitPoints.insert(*debug);
21352081
undefBuilder.setCurrentDebugScope(debug->getDebugScope());
21362082
undefBuilder.createDebugValue(
21372083
debug->getLoc(),
@@ -2242,7 +2188,6 @@ bool MoveKillsCopyableAddressesChecker::performSingleBasicBlockAnalysis(
22422188
if (auto debug = DebugVarCarryingInst::getFromValue(address)) {
22432189
if (auto varInfo = debug.getVarInfo()) {
22442190
{
2245-
debugInfoBlockSplitPoints.insert(*debug);
22462191
SILBuilderWithScope undefBuilder(builder);
22472192
undefBuilder.setCurrentDebugScope(debug->getDebugScope());
22482193
undefBuilder.createDebugValue(
@@ -2257,10 +2202,9 @@ bool MoveKillsCopyableAddressesChecker::performSingleBasicBlockAnalysis(
22572202
auto *next = interestingUser->getNextInstruction();
22582203
SILBuilderWithScope reinitBuilder(next);
22592204
reinitBuilder.setCurrentDebugScope(debug->getDebugScope());
2260-
auto *dvi = reinitBuilder.createDebugValue(debug->getLoc(),
2261-
address, *varInfo, false,
2262-
/*was moved*/ true);
2263-
debugInfoBlockSplitPoints.insert(dvi);
2205+
reinitBuilder.createDebugValue(debug->getLoc(), address, *varInfo,
2206+
false,
2207+
/*was moved*/ true);
22642208
}
22652209
}
22662210
debug.markAsMoved();
@@ -2296,7 +2240,6 @@ bool MoveKillsCopyableAddressesChecker::performSingleBasicBlockAnalysis(
22962240
dumpBitVector(llvm::dbgs(), bitVector); llvm::dbgs() << '\n');
22972241
if (auto debug = DebugVarCarryingInst::getFromValue(address)) {
22982242
if (auto varInfo = debug.getVarInfo()) {
2299-
debugInfoBlockSplitPoints.insert(*debug);
23002243
SILBuilderWithScope undefBuilder(builder);
23012244
undefBuilder.setCurrentDebugScope(debug->getDebugScope());
23022245
undefBuilder.createDebugValue(
@@ -2415,8 +2358,7 @@ bool MoveKillsCopyableAddressesChecker::check(SILValue address) {
24152358
// Ok, we need to perform global dataflow for one of our moves. Initialize our
24162359
// dataflow state engine and then run the dataflow itself.
24172360
dataflowState.init();
2418-
bool result = dataflowState.process(address, closureConsumes,
2419-
debugInfoBlockSplitPoints);
2361+
bool result = dataflowState.process(address, closureConsumes);
24202362
return result;
24212363
}
24222364

@@ -2471,15 +2413,6 @@ class MoveKillsCopyableAddressesCheckerPass : public SILFunctionTransform {
24712413

24722414
MoveKillsCopyableAddressesChecker checker(getFunction(), funcBuilder);
24732415

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-
24832416
bool madeChange = false;
24842417
while (!addressToProcess.empty()) {
24852418
auto address = addressToProcess.front();
@@ -2492,13 +2425,6 @@ class MoveKillsCopyableAddressesCheckerPass : public SILFunctionTransform {
24922425
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
24932426
}
24942427

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-
25022428
// Now go through and clone any apply sites that we need to clone.
25032429
SmallVector<SILValue, 8> newArgs;
25042430
bool rewroteCallee = false;

lib/SILOptimizer/Mandatory/MoveKillsCopyableValuesChecker.cpp

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,6 @@ bool MoveKillsCopyableValuesChecker::check() {
380380
//
381381
// TODO: We should add llvm.dbg.addr support for fastisel and also teach
382382
// CodeGen how to handle llvm.dbg.addr better.
383-
SmallVector<SILInstruction *, 8> successMovesDbgInfoCarryingInsts;
384383
bool emittedDiagnostic = false;
385384
while (!valuesToProcess.empty()) {
386385
auto lexicalValue = valuesToProcess.front();
@@ -421,7 +420,6 @@ bool MoveKillsCopyableValuesChecker::check() {
421420
} else {
422421
LLVM_DEBUG(llvm::dbgs() << " WithinBoundary: No!\n");
423422
if (auto varInfo = dbgVarInst.getVarInfo()) {
424-
successMovesDbgInfoCarryingInsts.push_back(*dbgVarInst);
425423
auto *next = mvi->getNextInstruction();
426424
SILBuilderWithScope builder(next);
427425
// We need to make sure any undefs we put in are the same loc/debug
@@ -445,24 +443,6 @@ bool MoveKillsCopyableValuesChecker::check() {
445443
}
446444
}
447445

448-
// If we emitted any diagnostics, we are going to fail and thus don't need to
449-
// use any compile time to break blocks since a user will never debug such
450-
// programs.
451-
if (emittedDiagnostic)
452-
return false;
453-
454-
// Ok! Now break before the instruction after our debug info generating inst
455-
// so that the SelectionDAG behavior mentioned above on the declaration of
456-
// successMovesDbgInfoCarryingInst.
457-
if (!successMovesDbgInfoCarryingInsts.empty()) {
458-
SILBuilderContext ctx(mod);
459-
do {
460-
auto *next = successMovesDbgInfoCarryingInsts.pop_back_val();
461-
splitBasicBlockAndBranch(ctx, next->getNextInstruction(),
462-
dominanceToUpdate, loopInfoToUpdate);
463-
} while (!successMovesDbgInfoCarryingInsts.empty());
464-
}
465-
466446
return false;
467447
}
468448

0 commit comments

Comments
 (0)