Skip to content

Commit 24dfb18

Browse files
authored
Merge pull request #60763 from meg-gupta/looprotateaddressphi
Ban address phis in non-OSSA SIL
2 parents f2995a1 + 17285c0 commit 24dfb18

18 files changed

+187
-407
lines changed

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -985,24 +985,6 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
985985
return InstNumbers[a] < InstNumbers[b];
986986
}
987987

988-
// FIXME: For sanity, address-type phis should be prohibited at all SIL
989-
// stages. However, the optimizer currently breaks the invariant in three
990-
// places:
991-
// 1. Normal Simplify CFG during conditional branch simplification
992-
// (sneaky jump threading).
993-
// 2. Simplify CFG via Jump Threading.
994-
// 3. Loop Rotation.
995-
//
996-
// BasicBlockCloner::canCloneInstruction and sinkAddressProjections is
997-
// designed to avoid this issue, we just need to make sure all passes use it
998-
// correctly.
999-
//
1000-
// Minimally, we must prevent address-type phis as long as access markers are
1001-
// preserved. A goal is to preserve access markers in OSSA.
1002-
bool prohibitAddressPhis() {
1003-
return F.hasOwnership();
1004-
}
1005-
1006988
void visitSILPhiArgument(SILPhiArgument *arg) {
1007989
// Verify that the `isPhiArgument` property is sound:
1008990
// - Phi arguments come from branches.
@@ -1026,7 +1008,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
10261008
"All phi argument inputs must be from branches.");
10271009
}
10281010
}
1029-
if (arg->isPhi() && prohibitAddressPhis()) {
1011+
if (arg->isPhi()) {
10301012
// As a property of well-formed SIL, we disallow address-type
10311013
// phis. Supporting them would prevent reliably reasoning about the
10321014
// underlying storage of memory access. This reasoning is important for

lib/SILOptimizer/LoopTransforms/ArrayPropertyOpt.cpp

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,18 +53,19 @@
5353
#define DEBUG_TYPE "array-property-opt"
5454

5555
#include "ArrayOpt.h"
56-
#include "swift/SILOptimizer/Analysis/ArraySemantic.h"
57-
#include "swift/SILOptimizer/Analysis/LoopAnalysis.h"
58-
#include "swift/SILOptimizer/PassManager/Transforms.h"
59-
#include "swift/SILOptimizer/Utils/CFGOptUtils.h"
60-
#include "swift/SILOptimizer/Utils/SILSSAUpdater.h"
56+
#include "swift/SIL/BasicBlockBits.h"
6157
#include "swift/SIL/CFG.h"
6258
#include "swift/SIL/DebugUtils.h"
6359
#include "swift/SIL/InstructionUtils.h"
64-
#include "swift/SIL/Projection.h"
6560
#include "swift/SIL/LoopInfo.h"
66-
#include "swift/SIL/BasicBlockBits.h"
61+
#include "swift/SIL/Projection.h"
6762
#include "swift/SIL/SILCloner.h"
63+
#include "swift/SILOptimizer/Analysis/ArraySemantic.h"
64+
#include "swift/SILOptimizer/Analysis/LoopAnalysis.h"
65+
#include "swift/SILOptimizer/PassManager/Transforms.h"
66+
#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h"
67+
#include "swift/SILOptimizer/Utils/CFGOptUtils.h"
68+
#include "swift/SILOptimizer/Utils/SILSSAUpdater.h"
6869
#include "llvm/ADT/SmallSet.h"
6970
#include "llvm/Support/CommandLine.h"
7071
#include "llvm/Support/Debug.h"
@@ -85,6 +86,8 @@ class ArrayPropertiesAnalysis {
8586
SILBasicBlock *Preheader;
8687
DominanceInfo *DomTree;
8788

89+
SinkAddressProjections sinkProj;
90+
8891
llvm::DenseMap<SILFunction *, uint32_t> InstCountCache;
8992
llvm::SmallSet<SILValue, 16> HoistableArray;
9093

@@ -168,13 +171,18 @@ class ArrayPropertiesAnalysis {
168171

169172
bool FoundHoistable = false;
170173
uint32_t LoopInstCount = 0;
174+
171175
for (auto *BB : Loop->getBlocks()) {
172176
for (auto &Inst : *BB) {
173177
// Can't clone alloc_stack instructions whose dealloc_stack is outside
174178
// the loop.
175179
if (!Loop->canDuplicate(&Inst))
176180
return false;
177181

182+
if (!sinkProj.analyzeAddressProjections(&Inst)) {
183+
return false;
184+
}
185+
178186
ArraySemanticsCall ArrayPropsInst(&Inst, "array.props", true);
179187
if (!ArrayPropsInst)
180188
continue;
@@ -536,10 +544,15 @@ class RegionCloner : public SILCloner<RegionCloner> {
536544
for (auto *arg : origBB->getArguments())
537545
updateSSAForValue(origBB, arg, SSAUp);
538546

547+
SinkAddressProjections sinkProj;
539548
// Update outside used instruction values.
540549
for (auto &inst : *origBB) {
541-
for (auto result : inst.getResults())
550+
for (auto result : inst.getResults()) {
551+
bool success = sinkProj.analyzeAddressProjections(&inst);
552+
assert(success);
553+
sinkProj.cloneProjections();
542554
updateSSAForValue(origBB, result, SSAUp);
555+
}
543556
}
544557
}
545558
}

lib/SILOptimizer/LoopTransforms/LoopRotate.cpp

Lines changed: 66 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -65,49 +65,67 @@ hasLoopInvariantOperands(SILInstruction *inst, SILLoop *loop,
6565
static bool
6666
canDuplicateOrMoveToPreheader(SILLoop *loop, SILBasicBlock *preheader,
6767
SILBasicBlock *bb,
68-
SmallVectorImpl<SILInstruction *> &moves) {
68+
SmallVectorImpl<SILInstruction *> &moves,
69+
SinkAddressProjections &sinkProj) {
6970
llvm::DenseSet<SILInstruction *> invariants;
7071
int cost = 0;
7172
for (auto &instRef : *bb) {
72-
OwnershipForwardingMixin *ofm = nullptr;
7373
auto *inst = &instRef;
74-
if (auto *MI = dyn_cast<MethodInst>(inst)) {
75-
if (MI->getMember().isForeign)
76-
return false;
77-
if (!hasLoopInvariantOperands(inst, loop, invariants))
78-
continue;
79-
moves.push_back(inst);
80-
invariants.insert(inst);
81-
} else if (!inst->isTriviallyDuplicatable())
74+
if (!inst->isTriviallyDuplicatable()) {
8275
return false;
76+
}
8377
// It wouldn't make sense to rotate dealloc_stack without also rotating the
8478
// alloc_stack, which is covered by isTriviallyDuplicatable.
85-
else if (isa<DeallocStackInst>(inst))
79+
if (isa<DeallocStackInst>(inst)) {
80+
return false;
81+
}
82+
OwnershipForwardingMixin *ofm = nullptr;
83+
if ((ofm = OwnershipForwardingMixin::get(inst)) &&
84+
ofm->getForwardingOwnershipKind() == OwnershipKind::Guaranteed) {
8685
return false;
87-
else if (isa<FunctionRefInst>(inst)) {
86+
}
87+
if (isa<FunctionRefInst>(inst)) {
8888
moves.push_back(inst);
8989
invariants.insert(inst);
90-
} else if (isa<DynamicFunctionRefInst>(inst)) {
90+
continue;
91+
}
92+
if (isa<DynamicFunctionRefInst>(inst)) {
9193
moves.push_back(inst);
9294
invariants.insert(inst);
93-
} else if (isa<PreviousDynamicFunctionRefInst>(inst)) {
95+
continue;
96+
}
97+
if (isa<PreviousDynamicFunctionRefInst>(inst)) {
9498
moves.push_back(inst);
9599
invariants.insert(inst);
96-
} else if (isa<IntegerLiteralInst>(inst)) {
100+
continue;
101+
}
102+
if (isa<IntegerLiteralInst>(inst)) {
97103
moves.push_back(inst);
98104
invariants.insert(inst);
99-
} else if ((ofm = OwnershipForwardingMixin::get(inst)) &&
100-
ofm->getForwardingOwnershipKind() == OwnershipKind::Guaranteed) {
101-
return false;
102-
} else if (!inst->mayHaveSideEffects() && !inst->mayReadFromMemory()
103-
&& !isa<TermInst>(inst) && !isa<AllocationInst>(inst)
104-
&& /* not marked mayhavesideffects */
105-
hasLoopInvariantOperands(inst, loop, invariants)) {
105+
continue;
106+
}
107+
if (auto *MI = dyn_cast<MethodInst>(inst)) {
108+
if (MI->getMember().isForeign)
109+
return false;
110+
if (!hasLoopInvariantOperands(inst, loop, invariants))
111+
continue;
112+
moves.push_back(inst);
113+
invariants.insert(inst);
114+
continue;
115+
}
116+
if (!inst->mayHaveSideEffects() && !inst->mayReadFromMemory() &&
117+
!isa<TermInst>(inst) &&
118+
!isa<AllocationInst>(inst) && /* not marked mayhavesideffects */
119+
hasLoopInvariantOperands(inst, loop, invariants)) {
106120
moves.push_back(inst);
107121
invariants.insert(inst);
108-
} else {
109-
cost += (int)instructionInlineCost(instRef);
122+
continue;
123+
}
124+
if (!sinkProj.analyzeAddressProjections(inst)) {
125+
return false;
110126
}
127+
128+
cost += (int)instructionInlineCost(instRef);
111129
}
112130

113131
return cost < LoopRotateSizeLimit;
@@ -129,9 +147,7 @@ static void mapOperands(SILInstruction *inst,
129147
static void updateSSAForUseOfValue(
130148
SILSSAUpdater &updater, SmallVectorImpl<SILPhiArgument *> &insertedPhis,
131149
const llvm::DenseMap<ValueBase *, SILValue> &valueMap,
132-
SILBasicBlock *Header, SILBasicBlock *EntryCheckBlock, SILValue Res,
133-
SmallVectorImpl<std::pair<SILBasicBlock *, unsigned>>
134-
&accumulatedAddressPhis) {
150+
SILBasicBlock *Header, SILBasicBlock *EntryCheckBlock, SILValue Res) {
135151
// Find the mapped instruction.
136152
assert(valueMap.count(Res) && "Expected to find value in map!");
137153
SILValue MappedValue = valueMap.find(Res)->second;
@@ -161,14 +177,13 @@ static void updateSSAForUseOfValue(
161177
if (user->getParent() == Header)
162178
continue;
163179

164-
assert(user->getParent() != EntryCheckBlock
165-
&& "The entry check block should dominate the header");
180+
assert(user->getParent() != EntryCheckBlock &&
181+
"The entry check block should dominate the header");
166182
updater.rewriteUse(*use);
167183
}
168184

169185
// Canonicalize inserted phis to avoid extra BB Args and if we find an address
170186
// phi, stash it so we can handle it after we are done rewriting.
171-
bool hasOwnership = Header->getParent()->hasOwnership();
172187
for (SILPhiArgument *arg : insertedPhis) {
173188
if (SILValue inst = replaceBBArgWithCast(arg)) {
174189
arg->replaceAllUsesWith(inst);
@@ -177,30 +192,24 @@ static void updateSSAForUseOfValue(
177192
// SimplifyCFG deletes the dead BB arg.
178193
continue;
179194
}
180-
181-
// If we didn't simplify and have an address phi, stash the value so we can
182-
// fix it up.
183-
if (hasOwnership && arg->getType().isAddress())
184-
accumulatedAddressPhis.emplace_back(arg->getParent(), arg->getIndex());
185195
}
186196
}
187197

188-
static void updateSSAForUseOfInst(
189-
SILSSAUpdater &updater, SmallVectorImpl<SILPhiArgument *> &insertedPhis,
190-
const llvm::DenseMap<ValueBase *, SILValue> &valueMap,
191-
SILBasicBlock *header, SILBasicBlock *entryCheckBlock, SILInstruction *inst,
192-
SmallVectorImpl<std::pair<SILBasicBlock *, unsigned>>
193-
&accumulatedAddressPhis) {
198+
static void
199+
updateSSAForUseOfInst(SILSSAUpdater &updater,
200+
SmallVectorImpl<SILPhiArgument *> &insertedPhis,
201+
const llvm::DenseMap<ValueBase *, SILValue> &valueMap,
202+
SILBasicBlock *header, SILBasicBlock *entryCheckBlock,
203+
SILInstruction *inst) {
194204
for (auto result : inst->getResults())
195205
updateSSAForUseOfValue(updater, insertedPhis, valueMap, header,
196-
entryCheckBlock, result, accumulatedAddressPhis);
206+
entryCheckBlock, result);
197207
}
198208

199209
/// Rewrite the code we just created in the preheader and update SSA form.
200210
static void rewriteNewLoopEntryCheckBlock(
201211
SILBasicBlock *header, SILBasicBlock *entryCheckBlock,
202212
const llvm::DenseMap<ValueBase *, SILValue> &valueMap) {
203-
SmallVector<std::pair<SILBasicBlock *, unsigned>, 8> accumulatedAddressPhis;
204213
SmallVector<SILPhiArgument *, 8> insertedPhis;
205214
SILSSAUpdater updater(&insertedPhis);
206215

@@ -209,7 +218,7 @@ static void rewriteNewLoopEntryCheckBlock(
209218
for (unsigned i : range(header->getNumArguments())) {
210219
auto *arg = header->getArguments()[i];
211220
updateSSAForUseOfValue(updater, insertedPhis, valueMap, header,
212-
entryCheckBlock, arg, accumulatedAddressPhis);
221+
entryCheckBlock, arg);
213222
}
214223

215224
auto instIter = header->begin();
@@ -218,43 +227,9 @@ static void rewriteNewLoopEntryCheckBlock(
218227
while (instIter != header->end()) {
219228
auto &inst = *instIter;
220229
updateSSAForUseOfInst(updater, insertedPhis, valueMap, header,
221-
entryCheckBlock, &inst, accumulatedAddressPhis);
230+
entryCheckBlock, &inst);
222231
++instIter;
223232
}
224-
225-
// Then see if any of our phis were address phis. In such a case, rewrite the
226-
// address to be a smuggled through raw pointer. We do this late to
227-
// conservatively not interfere with the previous code's invariants.
228-
//
229-
// We also translate the phis into a BasicBlock, Index form so we are careful
230-
// with invalidation issues around branches/args.
231-
auto rawPointerTy =
232-
SILType::getRawPointerType(header->getParent()->getASTContext());
233-
auto rawPointerUndef = SILUndef::get(rawPointerTy, header->getModule());
234-
auto loc = RegularLocation::getAutoGeneratedLocation();
235-
while (!accumulatedAddressPhis.empty()) {
236-
SILBasicBlock *block;
237-
unsigned argIndex;
238-
std::tie(block, argIndex) = accumulatedAddressPhis.pop_back_val();
239-
auto *arg = cast<SILPhiArgument>(block->getArgument(argIndex));
240-
assert(arg->getType().isAddress() && "Not an address phi?!");
241-
for (auto *predBlock : block->getPredecessorBlocks()) {
242-
Operand *predUse = arg->getIncomingPhiOperand(predBlock);
243-
SILBuilderWithScope builder(predUse->getUser());
244-
auto *newIncomingValue =
245-
builder.createAddressToPointer(loc, predUse->get(), rawPointerTy);
246-
predUse->set(newIncomingValue);
247-
}
248-
SILBuilderWithScope builder(arg->getNextInstruction());
249-
SILType oldArgType = arg->getType();
250-
auto *phiShim = builder.createPointerToAddress(
251-
loc, rawPointerUndef, oldArgType, true /*isStrict*/,
252-
false /*is invariant*/);
253-
arg->replaceAllUsesWith(phiShim);
254-
SILArgument *newArg = block->replacePhiArgument(
255-
argIndex, rawPointerTy, OwnershipKind::None, nullptr);
256-
phiShim->setOperand(newArg);
257-
}
258233
}
259234

260235
/// Update the dominator tree after rotating the loop.
@@ -378,8 +353,9 @@ bool swift::rotateLoop(SILLoop *loop, DominanceInfo *domInfo,
378353

379354
// Make sure we can duplicate the header.
380355
SmallVector<SILInstruction *, 8> moveToPreheader;
381-
if (!canDuplicateOrMoveToPreheader(loop, preheader, header,
382-
moveToPreheader)) {
356+
SinkAddressProjections sinkProj;
357+
if (!canDuplicateOrMoveToPreheader(loop, preheader, header, moveToPreheader,
358+
sinkProj)) {
383359
LLVM_DEBUG(llvm::dbgs()
384360
<< *loop << " instructions in header preventing rotating\n");
385361
return false;
@@ -425,6 +401,14 @@ bool swift::rotateLoop(SILLoop *loop, DominanceInfo *domInfo,
425401

426402
// The other instructions are just cloned to the preheader.
427403
TermInst *preheaderBranch = preheader->getTerminator();
404+
405+
// sink address projections to avoid address phis.
406+
for (auto &inst : *header) {
407+
bool success = sinkProj.analyzeAddressProjections(&inst);
408+
assert(success);
409+
sinkProj.cloneProjections();
410+
}
411+
428412
for (auto &inst : *header) {
429413
if (SILInstruction *cloned = inst.clone(preheaderBranch)) {
430414
mapOperands(cloned, valueMap);
@@ -488,16 +472,10 @@ namespace {
488472
class LoopRotation : public SILFunctionTransform {
489473

490474
void run() override {
475+
SILFunction *f = getFunction();
491476
SILLoopAnalysis *loopAnalysis = PM->getAnalysis<SILLoopAnalysis>();
492-
assert(loopAnalysis);
493477
DominanceAnalysis *domAnalysis = PM->getAnalysis<DominanceAnalysis>();
494-
assert(domAnalysis);
495-
496-
SILFunction *f = getFunction();
497-
assert(f);
498-
499478
SILLoopInfo *loopInfo = loopAnalysis->get(f);
500-
assert(loopInfo);
501479
DominanceInfo *domInfo = domAnalysis->get(f);
502480

503481
if (loopInfo->empty()) {

0 commit comments

Comments
 (0)