Skip to content

Commit 2259db2

Browse files
authored
Merge pull request #35872 from gottesmm/ossa-serialize-then-lower-ownership
2 parents d6a7e9b + dd6439d commit 2259db2

30 files changed

+987
-322
lines changed

include/swift/AST/SILOptions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,11 @@ class SILOptions {
153153
/// Emit extra exclusvity markers for memory access and verify coverage.
154154
bool VerifyExclusivity = false;
155155

156+
/// When building the stdlib with opts should we lower ownership after
157+
/// serialization? Otherwise we do before. Only set to true on Darwin for now.
158+
///
159+
bool SerializeStdlibWithOwnershipWithOpts = false;
160+
156161
/// Calls to the replaced method inside of the replacement method will call
157162
/// the previous implementation.
158163
///

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/Frontend/CompilerInvocation.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,6 +1204,11 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
12041204
Args.hasArg(OPT_sil_stop_optzns_before_lowering_ownership);
12051205
if (const Arg *A = Args.getLastArg(OPT_external_pass_pipeline_filename))
12061206
Opts.ExternalPassPipelineFilename = A->getValue();
1207+
// If our triple is a darwin triple, lower ownership on the stdlib after we
1208+
// serialize.
1209+
if (Triple.isOSDarwin()) {
1210+
Opts.SerializeStdlibWithOwnershipWithOpts = true;
1211+
}
12071212

12081213
Opts.GenerateProfile |= Args.hasArg(OPT_profile_generate);
12091214
const Arg *ProfileUse = Args.getLastArg(OPT_profile_use);

lib/IRGen/IRGenSIL.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
//
1616
//===----------------------------------------------------------------------===//
1717

18-
#include "llvm/IR/Constant.h"
1918
#define DEBUG_TYPE "irgensil"
19+
2020
#include "swift/AST/ASTContext.h"
2121
#include "swift/AST/IRGenOptions.h"
2222
#include "swift/AST/ParameterList.h"
@@ -47,6 +47,8 @@
4747
#include "llvm/ADT/MapVector.h"
4848
#include "llvm/ADT/SmallBitVector.h"
4949
#include "llvm/ADT/TinyPtrVector.h"
50+
#include "llvm/IR/Constant.h"
51+
#include "llvm/IR/Constants.h"
5052
#include "llvm/IR/DIBuilder.h"
5153
#include "llvm/IR/Function.h"
5254
#include "llvm/IR/InlineAsm.h"
@@ -700,6 +702,10 @@ class IRGenSILFunction :
700702
///
701703
/// - CodeGen Prepare may drop dbg.values pointing to PHI instruction.
702704
bool needsShadowCopy(llvm::Value *Storage) {
705+
// If we have a constant data vector, we always need a shadow copy due to
706+
// bugs in LLVM.
707+
if (isa<llvm::ConstantDataVector>(Storage))
708+
return true;
703709
return !isa<llvm::Constant>(Storage);
704710
}
705711

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/SIL/Verifier/MemoryLifetime.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ static bool canHandleAllocStack(AllocStackInst *asi) {
142142
if (asi->hasDynamicLifetime())
143143
return false;
144144

145+
SILType stackType = asi->getType();
146+
145147
// Currently in this verifier, we stop verifying if we find a switch_enum_addr
146148
// use. This creates a problem since no one has gone through and changed the
147149
// frontend/optimizer to understand that it needs to insert destroy_addr on
@@ -155,9 +157,16 @@ static bool canHandleAllocStack(AllocStackInst *asi) {
155157
// implemented.
156158
//
157159
// https://bugs.swift.org/browse/SR-14123
158-
if (asi->getType().getEnumOrBoundGenericEnum())
160+
if (stackType.getEnumOrBoundGenericEnum())
159161
return false;
160162

163+
// Same for tuples that have an enum element. We are just working around this
164+
// for now until the radar above is solved.
165+
if (auto tt = stackType.getAs<TupleType>())
166+
for (unsigned i : range(tt->getNumElements()))
167+
if (stackType.getTupleElementType(i).getEnumOrBoundGenericEnum())
168+
return false;
169+
161170
// Otherwise we can optimize!
162171
return true;
163172
}

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,31 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
682682
LoadBorrowImmutabilityAnalysis loadBorrowImmutabilityAnalysis;
683683
bool SingleFunction = true;
684684

685+
/// A cache of the isOperandInValueUse check. When we process an operand, we
686+
/// fix this for each of its uses.
687+
llvm::DenseSet<std::pair<SILValue, const Operand *>> isOperandInValueUsesCache;
688+
689+
/// Check that this operand appears in the use-chain of the value it uses.
690+
bool isOperandInValueUses(const Operand *operand) {
691+
SILValue value = operand->get();
692+
693+
// First check the cache.
694+
if (isOperandInValueUsesCache.contains({value, operand}))
695+
return true;
696+
697+
// Otherwise, compute the value and initialize the cache for each of the
698+
// operand's value uses.
699+
bool foundUse = false;
700+
for (auto *use : value->getUses()) {
701+
if (use == operand) {
702+
foundUse = true;
703+
}
704+
isOperandInValueUsesCache.insert({value, use});
705+
}
706+
707+
return foundUse;
708+
}
709+
685710
SILVerifier(const SILVerifier&) = delete;
686711
void operator=(const SILVerifier&) = delete;
687712
public:
@@ -1112,7 +1137,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
11121137

11131138
require(operand.getUser() == I,
11141139
"instruction's operand's owner isn't the instruction");
1115-
require(isInValueUses(&operand), "operand value isn't used by operand");
1140+
require(isOperandInValueUses(&operand), "operand value isn't used by operand");
11161141

11171142
if (operand.isTypeDependent()) {
11181143
require(isa<SILInstruction>(I),
@@ -1311,14 +1336,6 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
13111336
});
13121337
}
13131338

1314-
/// Check that this operand appears in the use-chain of the value it uses.
1315-
static bool isInValueUses(const Operand *operand) {
1316-
for (auto use : operand->get()->getUses())
1317-
if (use == operand)
1318-
return true;
1319-
return false;
1320-
}
1321-
13221339
/// \return True if all of the users of the AllocStack instruction \p ASI are
13231340
/// inside the same basic block.
13241341
static bool isSingleBlockUsage(AllocStackInst *ASI, DominanceInfo *Dominance){

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.

0 commit comments

Comments
 (0)