31
31
#include " swift/SIL/SILFunction.h"
32
32
#include " swift/SIL/SILInstruction.h"
33
33
#include " swift/SIL/SILModule.h"
34
+ #include " swift/SIL/StackList.h"
34
35
#include " swift/SIL/TypeLowering.h"
36
+ #include " swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h"
35
37
#include " swift/SILOptimizer/Analysis/DominanceAnalysis.h"
36
38
#include " swift/SILOptimizer/PassManager/Passes.h"
37
39
#include " swift/SILOptimizer/PassManager/Transforms.h"
38
40
#include " swift/SILOptimizer/Utils/CFGOptUtils.h"
41
+ #include " swift/SILOptimizer/Utils/CanonicalizeBorrowScope.h"
42
+ #include " swift/SILOptimizer/Utils/CanonicalizeOSSALifetime.h"
39
43
#include " swift/SILOptimizer/Utils/InstOptUtils.h"
40
44
#include " swift/SILOptimizer/Utils/OwnershipOptUtils.h"
41
45
#include " swift/SILOptimizer/Utils/ScopeOptUtils.h"
@@ -56,6 +60,10 @@ STATISTIC(NumAllocStackFound, "Number of AllocStack found");
56
60
STATISTIC (NumAllocStackCaptured, " Number of AllocStack captured" );
57
61
STATISTIC (NumInstRemoved, " Number of Instructions removed" );
58
62
63
+ llvm::cl::opt<bool > Mem2RegDisableLifetimeCanonicalization (
64
+ " sil-mem2reg-disable-lifetime-canonicalization" , llvm::cl::init(false ),
65
+ llvm::cl::desc(" Don't canonicalize any lifetimes during Mem2Reg." ));
66
+
59
67
static bool lexicalLifetimeEnsured (AllocStackInst *asi);
60
68
static bool isGuaranteedLexicalValue (SILValue src);
61
69
@@ -1881,6 +1889,10 @@ class MemoryToRegisters {
1881
1889
// / Dominators.
1882
1890
DominanceInfo *domInfo;
1883
1891
1892
+ NonLocalAccessBlockAnalysis *accessBlockAnalysis;
1893
+
1894
+ BasicCalleeAnalysis *calleeAnalysis;
1895
+
1884
1896
// / The builder context used when creating new instructions during register
1885
1897
// / promotion.
1886
1898
SILBuilderContext ctx;
@@ -1929,10 +1941,23 @@ class MemoryToRegisters {
1929
1941
bool promoteAllocation (AllocStackInst *asi,
1930
1942
BasicBlockSetVector &livePhiBlocks);
1931
1943
1944
+ // / Record all the values stored and store_borrow'd into the address so that
1945
+ // / they can be canonicalized if promotion succeeds.
1946
+ void collectStoredValues (AllocStackInst *asi, StackList<SILValue> &owned,
1947
+ StackList<SILValue> &guaranteed);
1948
+
1949
+ // / Canonicalize the lifetimes of the specified owned and guaranteed values.
1950
+ void canonicalizeValueLifetimes (StackList<SILValue> &owned,
1951
+ StackList<SILValue> &guaranteed);
1952
+
1932
1953
public:
1933
1954
// / C'tor
1934
- MemoryToRegisters (SILFunction &inputFunc, DominanceInfo *inputDomInfo)
1935
- : f(inputFunc), domInfo(inputDomInfo), ctx(inputFunc.getModule()) {}
1955
+ MemoryToRegisters (SILFunction &inputFunc, DominanceInfo *inputDomInfo,
1956
+ NonLocalAccessBlockAnalysis *accessBlockAnalysis,
1957
+ BasicCalleeAnalysis *calleeAnalysis)
1958
+ : f(inputFunc), domInfo(inputDomInfo),
1959
+ accessBlockAnalysis (accessBlockAnalysis),
1960
+ calleeAnalysis(calleeAnalysis), ctx(inputFunc.getModule()) {}
1936
1961
1937
1962
// / Promote memory to registers. Return True on change.
1938
1963
bool run ();
@@ -2124,6 +2149,50 @@ void MemoryToRegisters::removeSingleBlockAllocation(AllocStackInst *asi) {
2124
2149
}
2125
2150
}
2126
2151
2152
+ void MemoryToRegisters::collectStoredValues (AllocStackInst *asi,
2153
+ StackList<SILValue> &owned,
2154
+ StackList<SILValue> &guaranteed) {
2155
+ for (auto *use : asi->getUses ()) {
2156
+ auto *user = use->getUser ();
2157
+ if (auto *si = dyn_cast<StoreInst>(user)) {
2158
+ owned.push_back (si->getSrc ());
2159
+ } else if (auto *sbi = dyn_cast<StoreBorrowInst>(user)) {
2160
+ guaranteed.push_back (sbi->getSrc ());
2161
+ }
2162
+ }
2163
+ }
2164
+
2165
+ void MemoryToRegisters::canonicalizeValueLifetimes (
2166
+ StackList<SILValue> &owned, StackList<SILValue> &guaranteed) {
2167
+ if (Mem2RegDisableLifetimeCanonicalization)
2168
+ return ;
2169
+
2170
+ CanonicalizeOSSALifetime canonicalizer (
2171
+ /* pruneDebug=*/ true , /* maximizeLifetime=*/ !f.shouldOptimize (), &f,
2172
+ accessBlockAnalysis, domInfo, calleeAnalysis, deleter);
2173
+ for (auto value : owned) {
2174
+ auto root = CanonicalizeOSSALifetime::getCanonicalCopiedDef (value);
2175
+ if (auto *copy = dyn_cast<CopyValueInst>(root)) {
2176
+ if (SILValue borrowDef = CanonicalizeBorrowScope::getCanonicalBorrowedDef (
2177
+ copy->getOperand ())) {
2178
+ guaranteed.push_back (copy);
2179
+ continue ;
2180
+ }
2181
+ }
2182
+ canonicalizer.canonicalizeValueLifetime (root);
2183
+ }
2184
+ CanonicalizeBorrowScope borrowCanonicalizer (&f, deleter);
2185
+ for (auto value : guaranteed) {
2186
+ auto borrowee = CanonicalizeBorrowScope::getCanonicalBorrowedDef (value);
2187
+ if (!borrowee)
2188
+ continue ;
2189
+ BorrowedValue borrow (borrowee);
2190
+ if (borrow.kind != BorrowedValueKind::SILFunctionArgument)
2191
+ continue ;
2192
+ borrowCanonicalizer.canonicalizeBorrowScope (borrow);
2193
+ }
2194
+ }
2195
+
2127
2196
// / Attempt to promote the specified stack allocation, returning true if so
2128
2197
// / or false if not. On success, this returns true and usually drops all of the
2129
2198
// / uses of the AllocStackInst, but never deletes the ASI itself. Callers
@@ -2192,6 +2261,13 @@ bool MemoryToRegisters::run() {
2192
2261
if (!asi)
2193
2262
continue ;
2194
2263
2264
+ // Record stored values because promoting a store eliminates a consuming
2265
+ // use of the stored value. If promotion succeeds, these values'
2266
+ // lifetimes are canonicalized, eliminating unnecessary copies.
2267
+ StackList<SILValue> ownedValues (&f);
2268
+ StackList<SILValue> guaranteedValues (&f);
2269
+ collectStoredValues (asi, ownedValues, guaranteedValues);
2270
+
2195
2271
// The blocks which still have new phis after fixBranchesAndUses runs.
2196
2272
// These are not necessarily the same as phiBlocks because
2197
2273
// fixBranchesAndUses removes superfluous proactive phis.
@@ -2202,6 +2278,7 @@ bool MemoryToRegisters::run() {
2202
2278
}
2203
2279
instructionsToDelete.clear ();
2204
2280
++NumInstRemoved;
2281
+ canonicalizeValueLifetimes (ownedValues, guaranteedValues);
2205
2282
madeChange = true ;
2206
2283
}
2207
2284
}
@@ -2222,9 +2299,13 @@ class SILMem2Reg : public SILFunctionTransform {
2222
2299
LLVM_DEBUG (llvm::dbgs ()
2223
2300
<< " ** Mem2Reg on function: " << f->getName () << " **\n " );
2224
2301
2225
- auto *da = PM->getAnalysis <DominanceAnalysis>();
2302
+ auto *da = getAnalysis<DominanceAnalysis>();
2303
+ auto *calleeAnalysis = getAnalysis<BasicCalleeAnalysis>();
2304
+ auto *accessBlockAnalysis = getAnalysis<NonLocalAccessBlockAnalysis>();
2226
2305
2227
- bool madeChange = MemoryToRegisters (*f, da->get (f)).run ();
2306
+ bool madeChange =
2307
+ MemoryToRegisters (*f, da->get (f), accessBlockAnalysis, calleeAnalysis)
2308
+ .run ();
2228
2309
if (madeChange)
2229
2310
invalidateAnalysis (SILAnalysis::InvalidationKind::Instructions);
2230
2311
}
0 commit comments