Skip to content

Commit 13518c5

Browse files
committed
[move-function-addr] Make Single Basic Block analysis a method on the checker instead of a free function.
This lets me simplify the code by eliminating 2 arguments we were already passing in from the checker. NFC.
1 parent 67e0b43 commit 13518c5

File tree

1 file changed

+185
-185
lines changed

1 file changed

+185
-185
lines changed

lib/SILOptimizer/Mandatory/MoveKillsCopyableAddressesChecker.cpp

Lines changed: 185 additions & 185 deletions
Original file line numberDiff line numberDiff line change
@@ -1915,12 +1915,193 @@ void DataflowState::init() {
19151915
}
19161916
}
19171917

1918+
//===----------------------------------------------------------------------===//
1919+
// Address Checker
1920+
//===----------------------------------------------------------------------===//
1921+
1922+
namespace {
1923+
1924+
struct MoveKillsCopyableAddressesChecker {
1925+
SILFunction *fn;
1926+
UseState useState;
1927+
DataflowState dataflowState;
1928+
UseState closureUseState;
1929+
ClosureArgDataflowState closureUseDataflowState;
1930+
SILOptFunctionBuilder &funcBuilder;
1931+
llvm::SmallMapVector<FullApplySite, SmallBitVector, 8>
1932+
applySiteToPromotedArgIndices;
1933+
SmallBlotSetVector<SILInstruction *, 8> closureConsumes;
1934+
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+
1948+
MoveKillsCopyableAddressesChecker(SILFunction *fn,
1949+
SILOptFunctionBuilder &funcBuilder)
1950+
: fn(fn), useState(),
1951+
dataflowState(funcBuilder, useState, applySiteToPromotedArgIndices,
1952+
closureConsumes),
1953+
closureUseState(), closureUseDataflowState(closureUseState),
1954+
funcBuilder(funcBuilder) {}
1955+
1956+
void setDominanceToUpdate(DominanceInfo *newInfo) {
1957+
dominanceToUpdate = newInfo;
1958+
}
1959+
1960+
void setLoopInfoToUpdate(SILLoopInfo *newInfo) { loopInfoToUpdate = newInfo; }
1961+
1962+
void cloneDeferCalleeAndRewriteUses(
1963+
SmallVectorImpl<SILValue> &temporaryStorage,
1964+
const SmallBitVector &bitVector, FullApplySite oldApplySite,
1965+
SmallBlotSetVector<SILInstruction *, 8> &postDominatingConsumingUsers);
1966+
1967+
bool check(SILValue address);
1968+
bool performClosureDataflow(Operand *callerOperand,
1969+
ClosureOperandState &calleeOperandState);
1970+
1971+
void emitDiagnosticForMove(SILValue borrowedValue,
1972+
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+
1987+
bool performSingleBasicBlockAnalysis(SILValue address,
1988+
MarkUnresolvedMoveAddrInst *mvi);
1989+
1990+
ASTContext &getASTContext() const { return fn->getASTContext(); }
1991+
};
1992+
1993+
} // namespace
1994+
1995+
void MoveKillsCopyableAddressesChecker::cloneDeferCalleeAndRewriteUses(
1996+
SmallVectorImpl<SILValue> &newArgs, const SmallBitVector &bitVector,
1997+
FullApplySite oldApplySite,
1998+
SmallBlotSetVector<SILInstruction *, 8> &postDominatingConsumingUsers) {
1999+
auto *origCallee = oldApplySite.getReferencedFunctionOrNull();
2000+
assert(origCallee);
2001+
2002+
auto name = getClonedName(origCallee, origCallee->isSerialized(), bitVector);
2003+
2004+
SILFunction *newCallee = nullptr;
2005+
if (auto *fn = origCallee->getModule().lookUpFunction(name)) {
2006+
newCallee = fn;
2007+
} else {
2008+
ClosureArgumentInOutToOutCloner cloner(
2009+
funcBuilder, origCallee, origCallee->isSerialized(),
2010+
postDominatingConsumingUsers, bitVector, name);
2011+
cloner.populateCloned();
2012+
newCallee = cloner.getCloned();
2013+
}
2014+
assert(newCallee);
2015+
2016+
// Ok, we now have populated our new callee. We need to create a new full
2017+
// apply site that calls the new function appropriately.
2018+
SWIFT_DEFER { newArgs.clear(); };
2019+
2020+
// First add all of our old results to newArgs.
2021+
auto oldConv = oldApplySite.getSubstCalleeConv();
2022+
for (unsigned i : range(oldConv.getSILArgIndexOfFirstIndirectResult(),
2023+
oldConv.getSILArgIndexOfFirstParam())) {
2024+
newArgs.push_back(oldApplySite->getOperand(i));
2025+
}
2026+
2027+
// Now add all of our new out params.
2028+
for (int i = bitVector.find_first(); i != -1; i = bitVector.find_next(i)) {
2029+
unsigned appliedArgIndex =
2030+
oldApplySite.getOperandIndexOfFirstArgument() + i;
2031+
newArgs.push_back(oldApplySite->getOperand(appliedArgIndex));
2032+
}
2033+
2034+
// Finally, add all of the rest of our arguments, skipping our new out
2035+
// parameters.
2036+
for (unsigned i : range(oldConv.getSILArgIndexOfFirstParam(),
2037+
oldConv.getNumSILArguments())) {
2038+
if (bitVector.test(i))
2039+
continue;
2040+
unsigned appliedArgIndex =
2041+
oldApplySite.getOperandIndexOfFirstArgument() + i;
2042+
newArgs.push_back(oldApplySite->getOperand(appliedArgIndex));
2043+
}
2044+
2045+
// Then create our new apply.
2046+
SILBuilderWithScope builder(*oldApplySite);
2047+
auto *newCalleeRef =
2048+
builder.createFunctionRef(oldApplySite->getLoc(), newCallee);
2049+
auto *newApply =
2050+
builder.createApply(oldApplySite->getLoc(), newCalleeRef,
2051+
oldApplySite.getSubstitutionMap(), newArgs);
2052+
oldApplySite->replaceAllUsesPairwiseWith(newApply);
2053+
oldApplySite->eraseFromParent();
2054+
}
2055+
2056+
bool MoveKillsCopyableAddressesChecker::performClosureDataflow(
2057+
Operand *callerOperand, ClosureOperandState &calleeOperandState) {
2058+
auto fas = FullApplySite::isa(callerOperand->getUser());
2059+
auto *func = fas.getCalleeFunction();
2060+
auto *address =
2061+
func->begin()->getArgument(fas.getCalleeArgIndex(*callerOperand));
2062+
2063+
LLVM_DEBUG(llvm::dbgs() << "Performing closure dataflow on caller use: "
2064+
<< *callerOperand->getUser());
2065+
LLVM_DEBUG(llvm::dbgs() << " Callee: " << func->getName() << '\n');
2066+
LLVM_DEBUG(llvm::dbgs() << " Callee Argument: " << *address);
2067+
// We emit an end closure dataflow to make it easier when reading debug output
2068+
// to make it easy to see when we have returned to analyzing the caller.
2069+
SWIFT_DEFER {
2070+
LLVM_DEBUG(llvm::dbgs()
2071+
<< "Finished performing closure dataflow on Callee: "
2072+
<< func->getName() << '\n';);
2073+
};
2074+
auto accessPathWithBase = AccessPathWithBase::compute(address);
2075+
auto accessPath = accessPathWithBase.accessPath;
2076+
2077+
// Bail on an invalid AccessPath.
2078+
//
2079+
// AccessPath completeness is verified independently--it may be invalid in
2080+
// extraordinary situations. When AccessPath is valid, we know all its uses
2081+
// are recognizable.
2082+
//
2083+
// NOTE: If due to an invalid access path we fail here, we will just error
2084+
// on the _move since the _move would not have been handled.
2085+
if (!accessPath.isValid())
2086+
return false;
2087+
2088+
// TODO: Hoist this useState into an ivar that we can reuse in between closure
2089+
// operands?
2090+
GatherClosureUseVisitor visitor(closureUseState);
2091+
SWIFT_DEFER { visitor.clear(); };
2092+
visitor.reset(address);
2093+
if (!visitAccessPathUses(visitor, accessPath, fn))
2094+
return false;
2095+
2096+
SWIFT_DEFER { closureUseDataflowState.clear(); };
2097+
return closureUseDataflowState.process(address, calleeOperandState,
2098+
closureConsumes);
2099+
}
2100+
19182101
// Returns true if we emitted a diagnostic and handled the single block
19192102
// case. Returns false if we visited all of the uses and seeded the UseState
19202103
// struct with the information needed to perform our interprocedural dataflow.
1921-
static bool performSingleBasicBlockAnalysis(
1922-
DataflowState &dataflowState,
1923-
SmallSetVector<SILInstruction *, 8> &debugInfoBlockSplitPoints,
2104+
bool MoveKillsCopyableAddressesChecker::performSingleBasicBlockAnalysis(
19242105
SILValue address, MarkUnresolvedMoveAddrInst *mvi) {
19252106
// First scan downwards to make sure we are move out of this block.
19262107
auto &useState = dataflowState.useState;
@@ -2150,186 +2331,6 @@ static bool performSingleBasicBlockAnalysis(
21502331
return false;
21512332
}
21522333

2153-
//===----------------------------------------------------------------------===//
2154-
// Address Checker
2155-
//===----------------------------------------------------------------------===//
2156-
2157-
namespace {
2158-
2159-
struct MoveKillsCopyableAddressesChecker {
2160-
SILFunction *fn;
2161-
UseState useState;
2162-
DataflowState dataflowState;
2163-
UseState closureUseState;
2164-
ClosureArgDataflowState closureUseDataflowState;
2165-
SILOptFunctionBuilder &funcBuilder;
2166-
llvm::SmallMapVector<FullApplySite, SmallBitVector, 8>
2167-
applySiteToPromotedArgIndices;
2168-
SmallBlotSetVector<SILInstruction *, 8> closureConsumes;
2169-
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-
2183-
MoveKillsCopyableAddressesChecker(SILFunction *fn,
2184-
SILOptFunctionBuilder &funcBuilder)
2185-
: fn(fn), useState(),
2186-
dataflowState(funcBuilder, useState, applySiteToPromotedArgIndices,
2187-
closureConsumes),
2188-
closureUseState(), closureUseDataflowState(closureUseState),
2189-
funcBuilder(funcBuilder) {}
2190-
2191-
void setDominanceToUpdate(DominanceInfo *newInfo) {
2192-
dominanceToUpdate = newInfo;
2193-
}
2194-
2195-
void setLoopInfoToUpdate(SILLoopInfo *newInfo) { loopInfoToUpdate = newInfo; }
2196-
2197-
void cloneDeferCalleeAndRewriteUses(
2198-
SmallVectorImpl<SILValue> &temporaryStorage,
2199-
const SmallBitVector &bitVector, FullApplySite oldApplySite,
2200-
SmallBlotSetVector<SILInstruction *, 8> &postDominatingConsumingUsers);
2201-
2202-
bool check(SILValue address);
2203-
bool performClosureDataflow(Operand *callerOperand,
2204-
ClosureOperandState &calleeOperandState);
2205-
2206-
void emitDiagnosticForMove(SILValue borrowedValue,
2207-
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-
}
2221-
2222-
ASTContext &getASTContext() const { return fn->getASTContext(); }
2223-
};
2224-
2225-
} // namespace
2226-
2227-
void MoveKillsCopyableAddressesChecker::cloneDeferCalleeAndRewriteUses(
2228-
SmallVectorImpl<SILValue> &newArgs, const SmallBitVector &bitVector,
2229-
FullApplySite oldApplySite,
2230-
SmallBlotSetVector<SILInstruction *, 8> &postDominatingConsumingUsers) {
2231-
auto *origCallee = oldApplySite.getReferencedFunctionOrNull();
2232-
assert(origCallee);
2233-
2234-
auto name = getClonedName(origCallee, origCallee->isSerialized(), bitVector);
2235-
2236-
SILFunction *newCallee = nullptr;
2237-
if (auto *fn = origCallee->getModule().lookUpFunction(name)) {
2238-
newCallee = fn;
2239-
} else {
2240-
ClosureArgumentInOutToOutCloner cloner(
2241-
funcBuilder, origCallee, origCallee->isSerialized(),
2242-
postDominatingConsumingUsers, bitVector, name);
2243-
cloner.populateCloned();
2244-
newCallee = cloner.getCloned();
2245-
}
2246-
assert(newCallee);
2247-
2248-
// Ok, we now have populated our new callee. We need to create a new full
2249-
// apply site that calls the new function appropriately.
2250-
SWIFT_DEFER { newArgs.clear(); };
2251-
2252-
// First add all of our old results to newArgs.
2253-
auto oldConv = oldApplySite.getSubstCalleeConv();
2254-
for (unsigned i : range(oldConv.getSILArgIndexOfFirstIndirectResult(),
2255-
oldConv.getSILArgIndexOfFirstParam())) {
2256-
newArgs.push_back(oldApplySite->getOperand(i));
2257-
}
2258-
2259-
// Now add all of our new out params.
2260-
for (int i = bitVector.find_first(); i != -1; i = bitVector.find_next(i)) {
2261-
unsigned appliedArgIndex =
2262-
oldApplySite.getOperandIndexOfFirstArgument() + i;
2263-
newArgs.push_back(oldApplySite->getOperand(appliedArgIndex));
2264-
}
2265-
2266-
// Finally, add all of the rest of our arguments, skipping our new out
2267-
// parameters.
2268-
for (unsigned i : range(oldConv.getSILArgIndexOfFirstParam(),
2269-
oldConv.getNumSILArguments())) {
2270-
if (bitVector.test(i))
2271-
continue;
2272-
unsigned appliedArgIndex =
2273-
oldApplySite.getOperandIndexOfFirstArgument() + i;
2274-
newArgs.push_back(oldApplySite->getOperand(appliedArgIndex));
2275-
}
2276-
2277-
// Then create our new apply.
2278-
SILBuilderWithScope builder(*oldApplySite);
2279-
auto *newCalleeRef =
2280-
builder.createFunctionRef(oldApplySite->getLoc(), newCallee);
2281-
auto *newApply =
2282-
builder.createApply(oldApplySite->getLoc(), newCalleeRef,
2283-
oldApplySite.getSubstitutionMap(), newArgs);
2284-
oldApplySite->replaceAllUsesPairwiseWith(newApply);
2285-
oldApplySite->eraseFromParent();
2286-
}
2287-
2288-
bool MoveKillsCopyableAddressesChecker::performClosureDataflow(
2289-
Operand *callerOperand, ClosureOperandState &calleeOperandState) {
2290-
auto fas = FullApplySite::isa(callerOperand->getUser());
2291-
auto *func = fas.getCalleeFunction();
2292-
auto *address =
2293-
func->begin()->getArgument(fas.getCalleeArgIndex(*callerOperand));
2294-
2295-
LLVM_DEBUG(llvm::dbgs() << "Performing closure dataflow on caller use: "
2296-
<< *callerOperand->getUser());
2297-
LLVM_DEBUG(llvm::dbgs() << " Callee: " << func->getName() << '\n');
2298-
LLVM_DEBUG(llvm::dbgs() << " Callee Argument: " << *address);
2299-
// We emit an end closure dataflow to make it easier when reading debug output
2300-
// to make it easy to see when we have returned to analyzing the caller.
2301-
SWIFT_DEFER {
2302-
LLVM_DEBUG(llvm::dbgs()
2303-
<< "Finished performing closure dataflow on Callee: "
2304-
<< func->getName() << '\n';);
2305-
};
2306-
auto accessPathWithBase = AccessPathWithBase::compute(address);
2307-
auto accessPath = accessPathWithBase.accessPath;
2308-
2309-
// Bail on an invalid AccessPath.
2310-
//
2311-
// AccessPath completeness is verified independently--it may be invalid in
2312-
// extraordinary situations. When AccessPath is valid, we know all its uses
2313-
// are recognizable.
2314-
//
2315-
// NOTE: If due to an invalid access path we fail here, we will just error
2316-
// on the _move since the _move would not have been handled.
2317-
if (!accessPath.isValid())
2318-
return false;
2319-
2320-
// TODO: Hoist this useState into an ivar that we can reuse in between closure
2321-
// operands?
2322-
GatherClosureUseVisitor visitor(closureUseState);
2323-
SWIFT_DEFER { visitor.clear(); };
2324-
visitor.reset(address);
2325-
if (!visitAccessPathUses(visitor, accessPath, fn))
2326-
return false;
2327-
2328-
SWIFT_DEFER { closureUseDataflowState.clear(); };
2329-
return closureUseDataflowState.process(address, calleeOperandState,
2330-
closureConsumes);
2331-
}
2332-
23332334
bool MoveKillsCopyableAddressesChecker::check(SILValue address) {
23342335
auto accessPathWithBase = AccessPathWithBase::compute(address);
23352336
auto accessPath = accessPathWithBase.accessPath;
@@ -2394,8 +2395,7 @@ bool MoveKillsCopyableAddressesChecker::check(SILValue address) {
23942395
// diagnostic.
23952396
bool emittedSingleBBDiagnostic = false;
23962397
for (auto *mvi : useState.markMoves) {
2397-
emittedSingleBBDiagnostic |= performSingleBasicBlockAnalysis(
2398-
dataflowState, debugInfoBlockSplitPoints, address, mvi);
2398+
emittedSingleBBDiagnostic |= performSingleBasicBlockAnalysis(address, mvi);
23992399
}
24002400

24012401
if (emittedSingleBBDiagnostic) {

0 commit comments

Comments
 (0)