Skip to content

Commit f732762

Browse files
committed
[loop-rotate] In OSSA, instead of creating address phis, sneak the address through the phi using a RawPointer.
In OSSA, we do not allow for address phis, but in certain cases the logic of LoopRotate really wants them. To work around this issue, I added some code in this PR to loop rotate that as a post-pass fixes up any address phis by inserting address <-> raw pointer adapters and changing the address phi to instead be of raw pointer type.
1 parent 142c3bd commit f732762

File tree

4 files changed

+130
-14
lines changed

4 files changed

+130
-14
lines changed

include/swift/SIL/SILArgument.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,12 @@ class SILPhiArgument : public SILArgument {
215215
/// this will be guaranteed to return a valid SILValue.
216216
SILValue getIncomingPhiValue(SILBasicBlock *predBlock) const;
217217

218+
/// If this argument is a true phi, return the operand in the \p predBLock
219+
/// associated with an incoming value.
220+
///
221+
/// \returns the operand or nullptr if this is not a true phi.
222+
Operand *getIncomingPhiOperand(SILBasicBlock *predBlock) const;
223+
218224
/// If this argument is a phi, populate `OutArray` with the incoming phi
219225
/// values for each predecessor BB. If this argument is not a phi, return
220226
/// false.

lib/SIL/IR/SILArgument.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,12 @@ bool SILPhiArgument::getIncomingPhiValues(
161161
return true;
162162
}
163163

164+
Operand *SILPhiArgument::getIncomingPhiOperand(SILBasicBlock *predBlock) const {
165+
if (!isPhiArgument())
166+
return nullptr;
167+
return getIncomingPhiOperandForPred(getParent(), predBlock, getIndex());
168+
}
169+
164170
bool SILPhiArgument::getIncomingPhiOperands(
165171
SmallVectorImpl<Operand *> &returnedPhiOperands) const {
166172
if (!isPhiArgument())

lib/SILOptimizer/LoopTransforms/LoopRotate.cpp

Lines changed: 63 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,9 @@ static void mapOperands(SILInstruction *inst,
125125
static void updateSSAForUseOfValue(
126126
SILSSAUpdater &updater, SmallVectorImpl<SILPhiArgument *> &insertedPhis,
127127
const llvm::DenseMap<ValueBase *, SILValue> &valueMap,
128-
SILBasicBlock *Header, SILBasicBlock *EntryCheckBlock, SILValue Res) {
128+
SILBasicBlock *Header, SILBasicBlock *EntryCheckBlock, SILValue Res,
129+
SmallVectorImpl<std::pair<SILBasicBlock *, unsigned>>
130+
&accumulatedAddressPhis) {
129131
// Find the mapped instruction.
130132
assert(valueMap.count(Res) && "Expected to find value in map!");
131133
SILValue MappedValue = valueMap.find(Res)->second;
@@ -159,49 +161,96 @@ static void updateSSAForUseOfValue(
159161
&& "The entry check block should dominate the header");
160162
updater.rewriteUse(*use);
161163
}
162-
// Canonicalize inserted phis to avoid extra BB Args.
164+
165+
// Canonicalize inserted phis to avoid extra BB Args and if we find an address
166+
// phi, stash it so we can handle it after we are done rewriting.
167+
bool hasOwnership = Header->getParent()->hasOwnership();
163168
for (SILPhiArgument *arg : insertedPhis) {
164169
if (SILValue inst = replaceBBArgWithCast(arg)) {
165170
arg->replaceAllUsesWith(inst);
166171
// DCE+SimplifyCFG runs as a post-pass cleanup.
167172
// DCE replaces dead arg values with undef.
168173
// SimplifyCFG deletes the dead BB arg.
174+
continue;
169175
}
176+
177+
// If we didn't simplify and have an address phi, stash the value so we can
178+
// fix it up.
179+
if (hasOwnership && arg->getType().isAddress())
180+
accumulatedAddressPhis.emplace_back(arg->getParent(), arg->getIndex());
170181
}
171182
}
172183

173-
static void
174-
updateSSAForUseOfInst(SILSSAUpdater &updater,
175-
SmallVectorImpl<SILPhiArgument *> &insertedPhis,
176-
const llvm::DenseMap<ValueBase *, SILValue> &valueMap,
177-
SILBasicBlock *header, SILBasicBlock *entryCheckBlock,
178-
SILInstruction *inst) {
184+
static void updateSSAForUseOfInst(
185+
SILSSAUpdater &updater, SmallVectorImpl<SILPhiArgument *> &insertedPhis,
186+
const llvm::DenseMap<ValueBase *, SILValue> &valueMap,
187+
SILBasicBlock *header, SILBasicBlock *entryCheckBlock, SILInstruction *inst,
188+
SmallVectorImpl<std::pair<SILBasicBlock *, unsigned>>
189+
&accumulatedAddressPhis) {
179190
for (auto result : inst->getResults())
180191
updateSSAForUseOfValue(updater, insertedPhis, valueMap, header,
181-
entryCheckBlock, result);
192+
entryCheckBlock, result, accumulatedAddressPhis);
182193
}
183194

184195
/// Rewrite the code we just created in the preheader and update SSA form.
185196
static void rewriteNewLoopEntryCheckBlock(
186197
SILBasicBlock *header, SILBasicBlock *entryCheckBlock,
187198
const llvm::DenseMap<ValueBase *, SILValue> &valueMap) {
188-
SmallVector<SILPhiArgument *, 4> insertedPhis;
199+
SmallVector<std::pair<SILBasicBlock *, unsigned>, 8> accumulatedAddressPhis;
200+
SmallVector<SILPhiArgument *, 8> insertedPhis;
189201
SILSSAUpdater updater(&insertedPhis);
190202

191-
// Fix PHIs (incoming arguments).
192-
for (auto *arg : header->getArguments())
203+
// Fix PHIs (incoming arguments). We iterate by index in case we replace the
204+
// phi argument so we do not invalidate iterators.
205+
for (unsigned i : range(header->getNumArguments())) {
206+
auto *arg = header->getArguments()[i];
193207
updateSSAForUseOfValue(updater, insertedPhis, valueMap, header,
194-
entryCheckBlock, arg);
208+
entryCheckBlock, arg, accumulatedAddressPhis);
209+
}
195210

196211
auto instIter = header->begin();
197212

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

207256
/// Update the dominator tree after rotating the loop.

test/SILOptimizer/looprotate_ossa.sil

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,3 +472,58 @@ bb2:
472472
return %1 : $()
473473
}
474474

475+
// Make sure that we do not create address phis.
476+
//
477+
// CHECK-LABEL: sil [ossa] @addressPhiFixUp : $@convention(thin) (Builtin.RawPointer) -> Builtin.RawPointer {
478+
// CHECK: bb1:
479+
// CHECK: [[NEXT:%.*]] = address_to_pointer {{%.*}} : $*UInt8 to $Builtin.RawPointer
480+
// CHECK: cond_br {{%.*}}, bb3, bb2
481+
//
482+
// CHECK: bb2:
483+
// CHECK-NEXT: br bb7(%0 : $Builtin.RawPointer)
484+
//
485+
// CHECK: bb3:
486+
// CHECK-NEXT: br bb4([[NEXT]] : $Builtin.RawPointer)
487+
//
488+
// CHECK: bb4([[ARG:%.*]] :
489+
// CHECK: [[CAST_BACK:%.*]] = pointer_to_address [[ARG]] : $Builtin.RawPointer to [strict] $*UInt8
490+
// CHECK: [[GEP:%.*]] = index_addr [[CAST_BACK]] :
491+
// CHECK: [[CAST_ROUND_TRIP_START:%.*]] = address_to_pointer [[GEP]]
492+
// CHECK: [[CAST_ROUND_TRIP_END:%.*]] = pointer_to_address [[CAST_ROUND_TRIP_START]] : $Builtin.RawPointer to [strict] $*UInt8
493+
// CHECK: [[BACK_TO_RAWPOINTER:%.*]] = address_to_pointer [[CAST_ROUND_TRIP_END]]
494+
// CHECK: cond_br {{%.*}}, bb6, bb5
495+
//
496+
// CHECK: bb5:
497+
// CHECK-NEXT: br bb7([[CAST_ROUND_TRIP_START]] :
498+
//
499+
// CHECK: bb6:
500+
// CHECK-NEXT: br bb4([[BACK_TO_RAWPOINTER]] :
501+
//
502+
// CHECK: bb7([[RESULT:%.*]] :
503+
// CHECK-NEXT: return [[RESULT]]
504+
// CHECK: } // end sil function 'addressPhiFixUp'
505+
sil [ossa] @addressPhiFixUp : $@convention(thin) (Builtin.RawPointer) -> Builtin.RawPointer {
506+
bb0(%0 : $Builtin.RawPointer):
507+
br bb1
508+
509+
bb1:
510+
br bb2(%0 : $Builtin.RawPointer)
511+
512+
bb2(%1 : $Builtin.RawPointer):
513+
%2 = pointer_to_address %1 : $Builtin.RawPointer to [strict] $*UInt8
514+
%3 = load [trivial] %2 : $*UInt8
515+
%4 = destructure_struct %3 : $UInt8
516+
%5 = integer_literal $Builtin.Int64, 0
517+
%6 = builtin "zextOrBitCast_Int8_Int64"(%4 : $Builtin.Int8) : $Builtin.Int64
518+
%7 = builtin "cmp_eq_Int64"(%6 : $Builtin.Int64, %5 : $Builtin.Int64) : $Builtin.Int1
519+
cond_br %7, bb3, bb4
520+
521+
bb3:
522+
%8 = integer_literal $Builtin.Word, 1
523+
%9 = index_addr %2 : $*UInt8, %8 : $Builtin.Word
524+
%10 = address_to_pointer %9 : $*UInt8 to $Builtin.RawPointer
525+
br bb2(%10 : $Builtin.RawPointer)
526+
527+
bb4:
528+
return %1 : $Builtin.RawPointer
529+
}

0 commit comments

Comments
 (0)