Skip to content

Commit df4fb64

Browse files
authored
Merge pull request #72955 from gottesmm/rdar126170014
[region-isolation] Include the region -> transferring operand map in the dataflow convergence.
2 parents c531f29 + d2bdec2 commit df4fb64

File tree

7 files changed

+286
-262
lines changed

7 files changed

+286
-262
lines changed

include/swift/SILOptimizer/Analysis/RegionAnalysis.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,13 @@ class BlockPartitionState {
8888

8989
TransferringOperandSetFactory &ptrSetFactory;
9090

91+
TransferringOperandToStateMap &transferringOpToStateMap;
92+
9193
BlockPartitionState(SILBasicBlock *basicBlock,
9294
PartitionOpTranslator &translator,
9395
TransferringOperandSetFactory &ptrSetFactory,
94-
IsolationHistory::Factory &isolationHistoryFactory);
96+
IsolationHistory::Factory &isolationHistoryFactory,
97+
TransferringOperandToStateMap &transferringOpToStateMap);
9598

9699
public:
97100
bool getLiveness() const { return isLive; }
@@ -397,6 +400,8 @@ class RegionAnalysisFunctionInfo {
397400

398401
IsolationHistory::Factory isolationHistoryFactory;
399402

403+
TransferringOperandToStateMap transferringOpToStateMap;
404+
400405
// We make this optional to prevent an issue that we have seen on windows when
401406
// capturing a field in a closure that is used to initialize a different
402407
// field.
@@ -492,6 +497,16 @@ class RegionAnalysisFunctionInfo {
492497
return valueMap;
493498
}
494499

500+
IsolationHistory::Factory &getIsolationHistoryFactory() {
501+
assert(supportedFunction && "Unsupported Function?!");
502+
return isolationHistoryFactory;
503+
}
504+
505+
TransferringOperandToStateMap &getTransferringOpToStateMap() {
506+
assert(supportedFunction && "Unsupported Function?!");
507+
return transferringOpToStateMap;
508+
}
509+
495510
bool isClosureCaptured(SILValue value, Operand *op);
496511

497512
static SILValue getUnderlyingTrackedValue(SILValue value);

include/swift/SILOptimizer/Utils/PartitionUtils.h

Lines changed: 68 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,12 @@
1919
#include "swift/Basic/LLVM.h"
2020
#include "swift/SIL/SILFunction.h"
2121
#include "swift/SIL/SILInstruction.h"
22+
23+
#include "llvm/ADT/MapVector.h"
24+
#include "llvm/ADT/STLExtras.h"
2225
#include "llvm/ADT/SmallVector.h"
2326
#include "llvm/Support/Debug.h"
27+
2428
#include <algorithm>
2529
#include <variant>
2630

@@ -223,6 +227,7 @@ class SILIsolationInfo {
223227
};
224228

225229
class Partition;
230+
class TransferringOperandToStateMap;
226231

227232
/// A persistent data structure that is used to "rewind" partition history so
228233
/// that we can discover when values become part of the same region.
@@ -244,6 +249,7 @@ class IsolationHistory {
244249

245250
// TODO: This shouldn't need to be a friend.
246251
friend class Partition;
252+
friend TransferringOperandToStateMap;
247253

248254
/// First node in the immutable linked list.
249255
Node *head = nullptr;
@@ -297,6 +303,11 @@ class IsolationHistory {
297303
/// Push that \p other should be merged into this region.
298304
void pushCFGHistoryJoin(Node *otherNode);
299305

306+
/// Push the top node of \p history as a CFG history join.
307+
void pushCFGHistoryJoin(IsolationHistory history) {
308+
return pushCFGHistoryJoin(history.getHead());
309+
}
310+
300311
Node *pop();
301312
};
302313

@@ -456,10 +467,7 @@ class IsolationHistory::Factory {
456467
IsolationHistory get() { return IsolationHistory(this); }
457468
};
458469

459-
class TransferringOperand {
460-
using ValueType = llvm::PointerIntPair<Operand *, 1>;
461-
ValueType value;
462-
470+
struct TransferringOperandState {
463471
/// The dynamic isolation info of the region of value when we transferred.
464472
///
465473
/// This will contain the isolated value if we found one.
@@ -468,65 +476,30 @@ class TransferringOperand {
468476
/// The dynamic isolation history at this point.
469477
IsolationHistory isolationHistory;
470478

471-
TransferringOperand(ValueType newValue, SILIsolationInfo isolationRegionInfo,
472-
IsolationHistory isolationHistory)
473-
: value(newValue), isolationInfo(isolationRegionInfo),
474-
isolationHistory(isolationHistory) {
475-
assert(isolationInfo && "Should never see unknown isolation info");
476-
}
477-
478-
public:
479-
TransferringOperand(Operand *op, bool isClosureCaptured,
480-
SILIsolationInfo isolationRegionInfo,
481-
IsolationHistory isolationHistory)
482-
: TransferringOperand({op, isClosureCaptured}, isolationRegionInfo,
483-
isolationHistory) {}
484-
explicit TransferringOperand(Operand *op,
485-
SILIsolationInfo isolationRegionInfo,
486-
IsolationHistory isolationHistory)
487-
: TransferringOperand({op, false}, isolationRegionInfo,
488-
isolationHistory) {}
489-
490-
operator bool() const { return bool(value.getPointer()); }
491-
492-
Operand *getOperand() const { return value.getPointer(); }
493-
494-
SILValue get() const { return getOperand()->get(); }
495-
496-
bool isClosureCaptured() const { return value.getInt(); }
479+
/// Set to true if the element associated with the operand's vlaue is closure
480+
/// captured by the user. In such a case, if our element is a sendable var of
481+
/// a non-Sendable type, we cannot access it since we could race against an
482+
/// assignment to the var in a closure.
483+
bool isClosureCaptured;
497484

498-
SILInstruction *getUser() const { return getOperand()->getUser(); }
499-
500-
SILIsolationInfo getIsolationInfo() const { return isolationInfo; }
501-
502-
IsolationHistory getIsolationHistory() const { return isolationHistory; }
503-
504-
unsigned getOperandNumber() const { return getOperand()->getOperandNumber(); }
505-
506-
void print(llvm::raw_ostream &os) const {
507-
os << "Op Num: " << getOperand()->getOperandNumber() << ". "
508-
<< "Capture: " << (isClosureCaptured() ? "yes. " : "no. ")
509-
<< "IsolationInfo: ";
510-
isolationInfo.print(os);
511-
os << "\nUser: " << *getUser();
512-
}
485+
TransferringOperandState(IsolationHistory history)
486+
: isolationInfo(), isolationHistory(history), isClosureCaptured(false) {}
487+
};
513488

514-
static void Profile(llvm::FoldingSetNodeID &id, Operand *op,
515-
bool isClosureCaptured,
516-
SILIsolationInfo isolationRegionInfo,
517-
IsolationHistory isolationHistory) {
518-
id.AddPointer(op);
519-
id.AddBoolean(isClosureCaptured);
520-
isolationRegionInfo.Profile(id);
521-
id.AddPointer(isolationHistory.getHead());
522-
}
489+
class TransferringOperandToStateMap {
490+
llvm::SmallDenseMap<Operand *, TransferringOperandState> internalMap;
491+
IsolationHistory::Factory &isolationHistoryFactory;
523492

524-
void Profile(llvm::FoldingSetNodeID &id) const {
525-
Profile(id, getOperand(), isClosureCaptured(), isolationInfo,
526-
isolationHistory);
493+
public:
494+
TransferringOperandToStateMap(
495+
IsolationHistory::Factory &isolationHistoryFactory)
496+
: isolationHistoryFactory(isolationHistoryFactory) {}
497+
TransferringOperandState &get(Operand *op) const {
498+
auto *self = const_cast<TransferringOperandToStateMap *>(this);
499+
auto history = IsolationHistory(&isolationHistoryFactory);
500+
return self->internalMap.try_emplace(op, TransferringOperandState(history))
501+
.first->getSecond();
527502
}
528-
529-
SWIFT_DEBUG_DUMP { print(llvm::dbgs()); }
530503
};
531504

532505
} // namespace swift
@@ -675,9 +648,8 @@ class Partition {
675648

676649
using Element = PartitionPrimitives::Element;
677650
using Region = PartitionPrimitives::Region;
678-
using TransferringOperandSet = ImmutablePointerSet<TransferringOperand *>;
679-
using TransferringOperandSetFactory =
680-
ImmutablePointerSetFactory<TransferringOperand *>;
651+
using TransferringOperandSet = ImmutablePointerSet<Operand *>;
652+
using TransferringOperandSetFactory = ImmutablePointerSetFactory<Operand *>;
681653
using IsolationHistoryNode = IsolationHistory::Node;
682654

683655
private:
@@ -689,7 +661,7 @@ class Partition {
689661
/// multi map here. The implication of this is that when we are performing
690662
/// dataflow we use a union operation to combine CFG elements and just take
691663
/// the first instruction that we see.
692-
llvm::SmallDenseMap<Region, TransferringOperandSet *, 2>
664+
llvm::SmallMapVector<Region, TransferringOperandSet *, 2>
693665
regionToTransferredOpMap;
694666

695667
/// Label each index with a non-negative (unsigned) label if it is associated
@@ -736,7 +708,16 @@ class Partition {
736708
fst.canonicalize();
737709
snd.canonicalize();
738710

739-
return fst.elementToRegionMap == snd.elementToRegionMap;
711+
return fst.elementToRegionMap == snd.elementToRegionMap &&
712+
fst.regionToTransferredOpMap.size() ==
713+
snd.regionToTransferredOpMap.size() &&
714+
llvm::all_of(
715+
fst.regionToTransferredOpMap,
716+
[&snd](const std::pair<Region, TransferringOperandSet *> &p) {
717+
auto sndIter = snd.regionToTransferredOpMap.find(p.first);
718+
return sndIter != snd.regionToTransferredOpMap.end() &&
719+
sndIter->second == p.second;
720+
});
740721
}
741722

742723
bool isTrackingElement(Element val) const {
@@ -1013,13 +994,16 @@ struct PartitionOpEvaluator {
1013994

1014995
protected:
1015996
TransferringOperandSetFactory &ptrSetFactory;
997+
TransferringOperandToStateMap &operandToStateMap;
1016998

1017999
Partition &p;
10181000

10191001
public:
10201002
PartitionOpEvaluator(Partition &p,
1021-
TransferringOperandSetFactory &ptrSetFactory)
1022-
: ptrSetFactory(ptrSetFactory), p(p) {}
1003+
TransferringOperandSetFactory &ptrSetFactory,
1004+
TransferringOperandToStateMap &operandToStateMap)
1005+
: ptrSetFactory(ptrSetFactory), operandToStateMap(operandToStateMap),
1006+
p(p) {}
10231007

10241008
/// Call shouldEmitVerboseLogging on our CRTP subclass.
10251009
bool shouldEmitVerboseLogging() const {
@@ -1028,7 +1012,7 @@ struct PartitionOpEvaluator {
10281012

10291013
/// Call handleLocalUseAfterTransfer on our CRTP subclass.
10301014
void handleLocalUseAfterTransfer(const PartitionOp &op, Element elt,
1031-
TransferringOperand *transferringOp) const {
1015+
Operand *transferringOp) const {
10321016
return asImpl().handleLocalUseAfterTransfer(op, elt, transferringOp);
10331017
}
10341018

@@ -1193,9 +1177,13 @@ struct PartitionOpEvaluator {
11931177
}
11941178

11951179
// Mark op.getOpArgs()[0] as transferred.
1196-
auto *ptrSet = ptrSetFactory.emplace(
1197-
op.getSourceOp(), isClosureCapturedElt, transferredRegionIsolation,
1198-
p.getIsolationHistory());
1180+
TransferringOperandState &state = operandToStateMap.get(op.getSourceOp());
1181+
state.isClosureCaptured |= isClosureCapturedElt;
1182+
state.isolationInfo =
1183+
state.isolationInfo.merge(transferredRegionIsolation);
1184+
assert(state.isolationInfo && "Cannot have unknown");
1185+
state.isolationHistory.pushCFGHistoryJoin(p.getIsolationHistory());
1186+
auto *ptrSet = ptrSetFactory.get(op.getSourceOp());
11991187
p.markTransferred(op.getOpArgs()[0], ptrSet);
12001188
return;
12011189
}
@@ -1265,9 +1253,8 @@ struct PartitionOpEvaluator {
12651253
private:
12661254
// Private helper that squelches the error if our transfer instruction and our
12671255
// use have the same isolation.
1268-
void
1269-
handleLocalUseAfterTransferHelper(const PartitionOp &op, Element elt,
1270-
TransferringOperand *transferringOp) const {
1256+
void handleLocalUseAfterTransferHelper(const PartitionOp &op, Element elt,
1257+
Operand *transferringOp) const {
12711258
if (shouldTryToSquelchErrors()) {
12721259
if (auto isolationInfo = SILIsolationInfo::get(op.getSourceInst())) {
12731260
if (isolationInfo.isActorIsolated() &&
@@ -1305,8 +1292,9 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
13051292
using Super = PartitionOpEvaluator<Subclass>;
13061293

13071294
PartitionOpEvaluatorBaseImpl(Partition &workingPartition,
1308-
TransferringOperandSetFactory &ptrSetFactory)
1309-
: Super(workingPartition, ptrSetFactory) {}
1295+
TransferringOperandSetFactory &ptrSetFactory,
1296+
TransferringOperandToStateMap &operandToStateMap)
1297+
: Super(workingPartition, ptrSetFactory, operandToStateMap) {}
13101298

13111299
/// Should we emit extra verbose logging statements when evaluating
13121300
/// PartitionOps.
@@ -1325,7 +1313,7 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
13251313
/// region. Can be used to get the immediate value transferred or the
13261314
/// transferring instruction.
13271315
void handleLocalUseAfterTransfer(const PartitionOp &op, Element elt,
1328-
TransferringOperand *transferringOp) const {}
1316+
Operand *transferringOp) const {}
13291317

13301318
/// This is called if we detect a never transferred element that was passed to
13311319
/// a transfer instruction.
@@ -1373,8 +1361,10 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
13731361
struct PartitionOpEvaluatorBasic final
13741362
: PartitionOpEvaluatorBaseImpl<PartitionOpEvaluatorBasic> {
13751363
PartitionOpEvaluatorBasic(Partition &workingPartition,
1376-
TransferringOperandSetFactory &ptrSetFactory)
1377-
: PartitionOpEvaluatorBaseImpl(workingPartition, ptrSetFactory) {}
1364+
TransferringOperandSetFactory &ptrSetFactory,
1365+
TransferringOperandToStateMap &operandToStateMap)
1366+
: PartitionOpEvaluatorBaseImpl(workingPartition, ptrSetFactory,
1367+
operandToStateMap) {}
13781368
};
13791369

13801370
} // namespace swift

lib/SILOptimizer/Analysis/RegionAnalysis.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2955,10 +2955,12 @@ TranslationSemantics PartitionOpTranslator::visitCheckedCastAddrBranchInst(
29552955
BlockPartitionState::BlockPartitionState(
29562956
SILBasicBlock *basicBlock, PartitionOpTranslator &translator,
29572957
TransferringOperandSetFactory &ptrSetFactory,
2958-
IsolationHistory::Factory &isolationHistoryFactory)
2958+
IsolationHistory::Factory &isolationHistoryFactory,
2959+
TransferringOperandToStateMap &transferringOpToStateMap)
29592960
: entryPartition(isolationHistoryFactory.get()),
29602961
exitPartition(isolationHistoryFactory.get()), basicBlock(basicBlock),
2961-
ptrSetFactory(ptrSetFactory) {
2962+
ptrSetFactory(ptrSetFactory),
2963+
transferringOpToStateMap(transferringOpToStateMap) {
29622964
translator.translateSILBasicBlock(basicBlock, blockPartitionOps);
29632965
}
29642966

@@ -2972,8 +2974,10 @@ bool BlockPartitionState::recomputeExitFromEntry(
29722974

29732975
ComputeEvaluator(Partition &workingPartition,
29742976
TransferringOperandSetFactory &ptrSetFactory,
2975-
PartitionOpTranslator &translator)
2976-
: PartitionOpEvaluatorBaseImpl(workingPartition, ptrSetFactory),
2977+
PartitionOpTranslator &translator,
2978+
TransferringOperandToStateMap &transferringOpToStateMap)
2979+
: PartitionOpEvaluatorBaseImpl(workingPartition, ptrSetFactory,
2980+
transferringOpToStateMap),
29772981
translator(translator) {}
29782982

29792983
SILIsolationInfo getIsolationRegionInfo(Element elt) const {
@@ -2990,7 +2994,8 @@ bool BlockPartitionState::recomputeExitFromEntry(
29902994
return translator.isClosureCaptured(value, op->getUser());
29912995
}
29922996
};
2993-
ComputeEvaluator eval(workingPartition, ptrSetFactory, translator);
2997+
ComputeEvaluator eval(workingPartition, ptrSetFactory, translator,
2998+
transferringOpToStateMap);
29942999
for (const auto &partitionOp : blockPartitionOps) {
29953000
// By calling apply without providing any error handling callbacks, errors
29963001
// will be surpressed. will be suppressed
@@ -3002,6 +3007,8 @@ bool BlockPartitionState::recomputeExitFromEntry(
30023007
exitPartition = workingPartition;
30033008
LLVM_DEBUG(llvm::dbgs() << " Exit Partition: ";
30043009
exitPartition.print(llvm::dbgs()));
3010+
LLVM_DEBUG(llvm::dbgs() << " Updated Partition: "
3011+
<< (exitUpdated ? "yes\n" : "no\n"));
30053012
return exitUpdated;
30063013
}
30073014

@@ -3073,8 +3080,9 @@ static bool canComputeRegionsForFunction(SILFunction *fn) {
30733080
RegionAnalysisFunctionInfo::RegionAnalysisFunctionInfo(
30743081
SILFunction *fn, PostOrderFunctionInfo *pofi)
30753082
: allocator(), fn(fn), valueMap(fn), translator(), ptrSetFactory(allocator),
3076-
isolationHistoryFactory(allocator), blockStates(), pofi(pofi),
3077-
solved(false), supportedFunction(true) {
3083+
isolationHistoryFactory(allocator),
3084+
transferringOpToStateMap(isolationHistoryFactory), blockStates(),
3085+
pofi(pofi), solved(false), supportedFunction(true) {
30783086
// Before we do anything, make sure that we support processing this function.
30793087
//
30803088
// NOTE: See documentation on supportedFunction for criteria.
@@ -3087,7 +3095,8 @@ RegionAnalysisFunctionInfo::RegionAnalysisFunctionInfo(
30873095
PartitionOpTranslator(fn, pofi, valueMap, isolationHistoryFactory);
30883096
blockStates.emplace(fn, [this](SILBasicBlock *block) -> BlockPartitionState {
30893097
return BlockPartitionState(block, *translator, ptrSetFactory,
3090-
isolationHistoryFactory);
3098+
isolationHistoryFactory,
3099+
transferringOpToStateMap);
30913100
});
30923101
// Mark all blocks as needing to be updated.
30933102
for (auto &block : *fn) {

0 commit comments

Comments
 (0)