Skip to content

Commit b481d05

Browse files
authored
Merge pull request #62547 from rjmccall/sil-type-dep-refactors
Prepare SIL type dependencies for multi-definition instructions
2 parents b93834f + f524f3d commit b481d05

File tree

7 files changed

+218
-130
lines changed

7 files changed

+218
-130
lines changed

include/swift/SIL/SILInstruction.h

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,14 @@ class SILInstruction : public llvm::ilist_node<SILInstruction> {
685685
return getResultsImpl().getTypes();
686686
}
687687

688+
/// Run the given function for each opened archetype this instruction
689+
/// defines, passing the value that should be used to record the
690+
/// dependency.
691+
void forEachDefinedOpenedArchetype(
692+
llvm::function_ref<void(CanOpenedArchetypeType archetype,
693+
SILValue typeDependency)> function) const;
694+
bool definesOpenedArchetypes() const;
695+
688696
MemoryBehavior getMemoryBehavior() const;
689697
ReleasingBehavior getReleasingBehavior() const;
690698

@@ -1096,10 +1104,6 @@ class SingleValueInstruction : public SILInstruction, public ValueBase {
10961104
node->getKind() <= SILNodeKind::Last_SingleValueInstruction;
10971105
}
10981106

1099-
/// If this is an instruction which "defines" a root opened archetype, it is
1100-
/// returned.
1101-
CanOpenedArchetypeType getDefinedOpenedArchetype() const;
1102-
11031107
SILInstruction *getPreviousInstruction() {
11041108
return SILInstruction::getPreviousInstruction();
11051109
}
@@ -7137,6 +7141,13 @@ class OpenExistentialAddrInst
71377141
}
71387142

71397143
OpenedExistentialAccess getAccessKind() const { return ForAccess; }
7144+
7145+
CanOpenedArchetypeType getDefinedOpenedArchetype() const {
7146+
const auto archetype = getOpenedArchetypeOf(getType().getASTType());
7147+
assert(archetype && archetype->isRoot() &&
7148+
"Type should be a root opened archetype");
7149+
return archetype;
7150+
}
71407151
};
71417152

71427153
/// Given an opaque value referring to an existential, "opens" the
@@ -7150,6 +7161,14 @@ class OpenExistentialValueInst
71507161
OpenExistentialValueInst(SILDebugLocation debugLoc, SILValue operand,
71517162
SILType selfTy,
71527163
ValueOwnershipKind forwardingOwnershipKind);
7164+
7165+
public:
7166+
CanOpenedArchetypeType getDefinedOpenedArchetype() const {
7167+
const auto archetype = getOpenedArchetypeOf(getType().getASTType());
7168+
assert(archetype && archetype->isRoot() &&
7169+
"Type should be a root opened archetype");
7170+
return archetype;
7171+
}
71537172
};
71547173

71557174
/// Given a class existential, "opens" the
@@ -7163,6 +7182,14 @@ class OpenExistentialRefInst
71637182
OpenExistentialRefInst(SILDebugLocation DebugLoc, SILValue Operand,
71647183
SILType Ty,
71657184
ValueOwnershipKind forwardingOwnershipKind);
7185+
7186+
public:
7187+
CanOpenedArchetypeType getDefinedOpenedArchetype() const {
7188+
const auto archetype = getOpenedArchetypeOf(getType().getASTType());
7189+
assert(archetype && archetype->isRoot() &&
7190+
"Type should be a root opened archetype");
7191+
return archetype;
7192+
}
71667193
};
71677194

71687195
/// Given an existential metatype,
@@ -7177,6 +7204,14 @@ class OpenExistentialMetatypeInst
71777204

71787205
OpenExistentialMetatypeInst(SILDebugLocation DebugLoc, SILValue operand,
71797206
SILType ty);
7207+
7208+
public:
7209+
CanOpenedArchetypeType getDefinedOpenedArchetype() const {
7210+
const auto archetype = getOpenedArchetypeOf(getType().getASTType());
7211+
assert(archetype && archetype->isRoot() &&
7212+
"Type should be a root opened archetype");
7213+
return archetype;
7214+
}
71807215
};
71817216

71827217
/// Given a boxed existential container,
@@ -7190,6 +7225,14 @@ class OpenExistentialBoxInst
71907225

71917226
OpenExistentialBoxInst(SILDebugLocation DebugLoc, SILValue operand,
71927227
SILType ty);
7228+
7229+
public:
7230+
CanOpenedArchetypeType getDefinedOpenedArchetype() const {
7231+
const auto archetype = getOpenedArchetypeOf(getType().getASTType());
7232+
assert(archetype && archetype->isRoot() &&
7233+
"Type should be a root opened archetype");
7234+
return archetype;
7235+
}
71937236
};
71947237

71957238
/// Given a boxed existential container, "opens" the existential by returning a
@@ -7203,6 +7246,14 @@ class OpenExistentialBoxValueInst
72037246
OpenExistentialBoxValueInst(SILDebugLocation DebugLoc, SILValue operand,
72047247
SILType ty,
72057248
ValueOwnershipKind forwardingOwnershipKind);
7249+
7250+
public:
7251+
CanOpenedArchetypeType getDefinedOpenedArchetype() const {
7252+
const auto archetype = getOpenedArchetypeOf(getType().getASTType());
7253+
assert(archetype && archetype->isRoot() &&
7254+
"Type should be a root opened archetype");
7255+
return archetype;
7256+
}
72067257
};
72077258

72087259
/// Given an address to an uninitialized buffer of

lib/SIL/IR/SILInstruction.cpp

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1528,24 +1528,37 @@ const ValueBase *SILInstructionResultArray::back() const {
15281528
}
15291529

15301530
//===----------------------------------------------------------------------===//
1531-
// SingleValueInstruction
1531+
// Defined opened archetypes
15321532
//===----------------------------------------------------------------------===//
15331533

1534-
CanOpenedArchetypeType
1535-
SingleValueInstruction::getDefinedOpenedArchetype() const {
1534+
bool SILInstruction::definesOpenedArchetypes() const {
1535+
bool definesAny = false;
1536+
forEachDefinedOpenedArchetype([&](CanOpenedArchetypeType type,
1537+
SILValue dependency) {
1538+
definesAny = true;
1539+
});
1540+
return definesAny;
1541+
}
1542+
1543+
void SILInstruction::forEachDefinedOpenedArchetype(
1544+
llvm::function_ref<void(CanOpenedArchetypeType, SILValue)> fn) const {
15361545
switch (getKind()) {
1537-
case SILInstructionKind::OpenExistentialAddrInst:
1538-
case SILInstructionKind::OpenExistentialRefInst:
1539-
case SILInstructionKind::OpenExistentialBoxInst:
1540-
case SILInstructionKind::OpenExistentialBoxValueInst:
1541-
case SILInstructionKind::OpenExistentialMetatypeInst:
1542-
case SILInstructionKind::OpenExistentialValueInst: {
1543-
const auto Ty = getOpenedArchetypeOf(getType().getASTType());
1544-
assert(Ty && Ty->isRoot() && "Type should be a root opened archetype");
1545-
return Ty;
1546+
#define SINGLE_VALUE_SINGLE_OPEN(TYPE) \
1547+
case SILInstructionKind::TYPE: { \
1548+
auto I = cast<TYPE>(this); \
1549+
auto archetype = I->getDefinedOpenedArchetype(); \
1550+
assert(archetype); \
1551+
return fn(archetype, I); \
15461552
}
1553+
SINGLE_VALUE_SINGLE_OPEN(OpenExistentialAddrInst)
1554+
SINGLE_VALUE_SINGLE_OPEN(OpenExistentialRefInst)
1555+
SINGLE_VALUE_SINGLE_OPEN(OpenExistentialBoxInst)
1556+
SINGLE_VALUE_SINGLE_OPEN(OpenExistentialBoxValueInst)
1557+
SINGLE_VALUE_SINGLE_OPEN(OpenExistentialMetatypeInst)
1558+
SINGLE_VALUE_SINGLE_OPEN(OpenExistentialValueInst)
1559+
#undef SINGLE_VALUE_SINGLE_OPEN
15471560
default:
1548-
return CanOpenedArchetypeType();
1561+
return;
15491562
}
15501563
}
15511564

lib/SIL/IR/SILInstructions.cpp

Lines changed: 82 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -43,70 +43,105 @@ static void *allocateTrailingInst(SILFunction &F, CountTypes... counts) {
4343
alignof(Inst));
4444
}
4545

46+
namespace {
47+
class TypeDependentOperandCollector {
48+
SmallVector<CanOpenedArchetypeType, 4> rootOpenedArchetypes;
49+
bool hasDynamicSelf = false;
50+
public:
51+
void collect(CanType type);
52+
void collect(SubstitutionMap subs);
53+
void collect(SILType type) {
54+
collect(type.getASTType());
55+
}
56+
template <class T>
57+
void collect(ArrayRef<T> array) {
58+
for (auto &elt: array)
59+
collect(elt);
60+
}
61+
62+
void collectAll() {}
63+
template <class T, class... Ts>
64+
void collectAll(T &&first, Ts &&...rest) {
65+
collect(first);
66+
collectAll(std::forward<Ts>(rest)...);
67+
}
68+
69+
void addTo(SmallVectorImpl<SILValue> &typeDependentOperands,
70+
SILFunction &f);
71+
};
72+
73+
}
74+
4675
/// Collect root open archetypes from a given type into \p RootOpenedArchetypes.
4776
/// \p RootOpenedArchetypes is being used as a set. We don't use a real set type
4877
/// here for performance reasons.
49-
static void collectDependentTypeInfo(
50-
CanType Ty, SmallVectorImpl<CanOpenedArchetypeType> &RootOpenedArchetypes,
51-
bool &hasDynamicSelf) {
52-
if (!Ty)
78+
void TypeDependentOperandCollector::collect(CanType type) {
79+
if (!type)
5380
return;
54-
if (Ty->hasDynamicSelfType())
81+
if (type->hasDynamicSelfType())
5582
hasDynamicSelf = true;
56-
if (!Ty->hasOpenedExistential())
83+
if (!type->hasOpenedExistential())
5784
return;
58-
Ty.visit([&](CanType t) {
85+
type.visit([&](CanType t) {
5986
if (const auto opened = dyn_cast<OpenedArchetypeType>(t)) {
6087
const auto root = opened.getRoot();
6188

6289
// Add this root opened archetype if it was not seen yet.
6390
// We don't use a set here, because the number of open archetypes
6491
// is usually very small and using a real set may introduce too
6592
// much overhead.
66-
if (std::find(RootOpenedArchetypes.begin(), RootOpenedArchetypes.end(),
67-
root) == RootOpenedArchetypes.end())
68-
RootOpenedArchetypes.push_back(root);
93+
if (std::find(rootOpenedArchetypes.begin(), rootOpenedArchetypes.end(),
94+
root) == rootOpenedArchetypes.end())
95+
rootOpenedArchetypes.push_back(root);
6996
}
7097
});
7198
}
7299

73-
/// Takes a set of root opened archetypes as input and produces a set of
74-
/// references to their definitions.
75-
static void buildTypeDependentOperands(
76-
SmallVectorImpl<CanOpenedArchetypeType> &RootOpenedArchetypes,
77-
bool hasDynamicSelf, SmallVectorImpl<SILValue> &TypeDependentOperands,
78-
SILFunction &F) {
100+
/// Collect type dependencies from the replacement types of a
101+
/// substitution map.
102+
void TypeDependentOperandCollector::collect(SubstitutionMap subs) {
103+
for (Type replacement : subs.getReplacementTypes()) {
104+
// Substitutions in SIL should really be canonical.
105+
auto ReplTy = replacement->getCanonicalType();
106+
collect(ReplTy);
107+
}
108+
}
79109

80-
for (const auto &archetype : RootOpenedArchetypes) {
110+
/// Given that we've collected a set of type dependencies, add operands
111+
/// for those dependencies to the given vector.
112+
void TypeDependentOperandCollector::addTo(SmallVectorImpl<SILValue> &operands,
113+
SILFunction &F) {
114+
size_t firstArchetypeOperand = operands.size();
115+
for (CanOpenedArchetypeType archetype : rootOpenedArchetypes) {
81116
SILValue def = F.getModule().getRootOpenedArchetypeDef(archetype, &F);
82117
assert(def->getFunction() == &F &&
83118
"def of root opened archetype is in wrong function");
84-
TypeDependentOperands.push_back(def);
119+
120+
// The archetypes in rootOpenedArchetypes have already been uniqued,
121+
// but a single instruction can open multiple archetypes (e.g.
122+
// open_pack_element), so we also unique the actual operand values.
123+
// As above, we assume there are very few values in practice and so
124+
// a linear scan is better than maintaining a set.
125+
if (std::find(operands.begin() + firstArchetypeOperand, operands.end(),
126+
def) == operands.end())
127+
operands.push_back(def);
85128
}
86129
if (hasDynamicSelf)
87-
TypeDependentOperands.push_back(F.getDynamicSelfMetadata());
130+
operands.push_back(F.getDynamicSelfMetadata());
88131
}
89132

90133
/// Collects all root opened archetypes from a type and a substitution list, and
91134
/// forms a corresponding list of operands.
92135
/// We need to know the number of root opened archetypes to estimate the number
93136
/// of corresponding operands for the instruction being formed, because we need
94137
/// to reserve enough memory for these operands.
138+
template <class... Sources>
95139
static void collectTypeDependentOperands(
96-
SmallVectorImpl<SILValue> &TypeDependentOperands,
97-
SILFunction &F,
98-
CanType Ty,
99-
SubstitutionMap subs = { }) {
100-
SmallVector<CanOpenedArchetypeType, 4> RootOpenedArchetypes;
101-
bool hasDynamicSelf = false;
102-
collectDependentTypeInfo(Ty, RootOpenedArchetypes, hasDynamicSelf);
103-
for (Type replacement : subs.getReplacementTypes()) {
104-
// Substitutions in SIL should really be canonical.
105-
auto ReplTy = replacement->getCanonicalType();
106-
collectDependentTypeInfo(ReplTy, RootOpenedArchetypes, hasDynamicSelf);
107-
}
108-
buildTypeDependentOperands(RootOpenedArchetypes, hasDynamicSelf,
109-
TypeDependentOperands, F);
140+
SmallVectorImpl<SILValue> &typeDependentOperands,
141+
SILFunction &F, Sources &&... sources) {
142+
TypeDependentOperandCollector collector;
143+
collector.collectAll(std::forward<Sources>(sources)...);
144+
collector.addTo(typeDependentOperands, F);
110145
}
111146

112147
//===----------------------------------------------------------------------===//
@@ -284,10 +319,7 @@ AllocRefInst *AllocRefInst::create(SILDebugLocation Loc, SILFunction &F,
284319
assert(!objc || ElementTypes.empty());
285320
SmallVector<SILValue, 8> AllOperands(ElementCountOperands.begin(),
286321
ElementCountOperands.end());
287-
for (SILType ElemType : ElementTypes) {
288-
collectTypeDependentOperands(AllOperands, F, ElemType.getASTType());
289-
}
290-
collectTypeDependentOperands(AllOperands, F, ObjectType.getASTType());
322+
collectTypeDependentOperands(AllOperands, F, ElementTypes, ObjectType);
291323
auto Size = totalSizeToAlloc<swift::Operand, SILType>(AllOperands.size(),
292324
ElementTypes.size());
293325
auto Buffer = F.getModule().allocateInst(Size, alignof(AllocRefInst));
@@ -304,10 +336,7 @@ AllocRefDynamicInst::create(SILDebugLocation DebugLoc, SILFunction &F,
304336
SmallVector<SILValue, 8> AllOperands(ElementCountOperands.begin(),
305337
ElementCountOperands.end());
306338
AllOperands.push_back(metatypeOperand);
307-
collectTypeDependentOperands(AllOperands, F, ty.getASTType());
308-
for (SILType ElemType : ElementTypes) {
309-
collectTypeDependentOperands(AllOperands, F, ElemType.getASTType());
310-
}
339+
collectTypeDependentOperands(AllOperands, F, ty, ElementTypes);
311340
auto Size = totalSizeToAlloc<swift::Operand, SILType>(AllOperands.size(),
312341
ElementTypes.size());
313342
auto Buffer = F.getModule().allocateInst(Size, alignof(AllocRefDynamicInst));
@@ -1249,14 +1278,13 @@ UncheckedRefCastAddrInst *
12491278
UncheckedRefCastAddrInst::create(SILDebugLocation Loc, SILValue src,
12501279
CanType srcType, SILValue dest, CanType targetType, SILFunction &F) {
12511280
SILModule &Mod = F.getModule();
1252-
SmallVector<SILValue, 8> TypeDependentOperands;
1253-
collectTypeDependentOperands(TypeDependentOperands, F, srcType);
1254-
collectTypeDependentOperands(TypeDependentOperands, F, targetType);
1281+
SmallVector<SILValue, 4> allOperands;
1282+
collectTypeDependentOperands(allOperands, F, srcType, targetType);
12551283
unsigned size =
1256-
totalSizeToAlloc<swift::Operand>(2 + TypeDependentOperands.size());
1284+
totalSizeToAlloc<swift::Operand>(2 + allOperands.size());
12571285
void *Buffer = Mod.allocateInst(size, alignof(UncheckedRefCastAddrInst));
12581286
return ::new (Buffer) UncheckedRefCastAddrInst(Loc, src, srcType,
1259-
dest, targetType, TypeDependentOperands);
1287+
dest, targetType, allOperands);
12601288
}
12611289

12621290
UnconditionalCheckedCastAddrInst::UnconditionalCheckedCastAddrInst(
@@ -1269,14 +1297,13 @@ UnconditionalCheckedCastAddrInst *
12691297
UnconditionalCheckedCastAddrInst::create(SILDebugLocation Loc, SILValue src,
12701298
CanType srcType, SILValue dest, CanType targetType, SILFunction &F) {
12711299
SILModule &Mod = F.getModule();
1272-
SmallVector<SILValue, 8> TypeDependentOperands;
1273-
collectTypeDependentOperands(TypeDependentOperands, F, srcType);
1274-
collectTypeDependentOperands(TypeDependentOperands, F, targetType);
1300+
SmallVector<SILValue, 4> allOperands;
1301+
collectTypeDependentOperands(allOperands, F, srcType, targetType);
12751302
unsigned size =
1276-
totalSizeToAlloc<swift::Operand>(2 + TypeDependentOperands.size());
1303+
totalSizeToAlloc<swift::Operand>(2 + allOperands.size());
12771304
void *Buffer = Mod.allocateInst(size, alignof(UnconditionalCheckedCastAddrInst));
12781305
return ::new (Buffer) UnconditionalCheckedCastAddrInst(Loc, src, srcType,
1279-
dest, targetType, TypeDependentOperands);
1306+
dest, targetType, allOperands);
12801307
}
12811308

12821309
CheckedCastAddrBranchInst::CheckedCastAddrBranchInst(
@@ -1300,14 +1327,13 @@ CheckedCastAddrBranchInst::create(SILDebugLocation DebugLoc,
13001327
ProfileCounter Target1Count, ProfileCounter Target2Count,
13011328
SILFunction &F) {
13021329
SILModule &Mod = F.getModule();
1303-
SmallVector<SILValue, 8> TypeDependentOperands;
1304-
collectTypeDependentOperands(TypeDependentOperands, F, srcType);
1305-
collectTypeDependentOperands(TypeDependentOperands, F, targetType);
1330+
SmallVector<SILValue, 4> allOperands;
1331+
collectTypeDependentOperands(allOperands, F, srcType, targetType);
13061332
unsigned size =
1307-
totalSizeToAlloc<swift::Operand>(2 + TypeDependentOperands.size());
1333+
totalSizeToAlloc<swift::Operand>(2 + allOperands.size());
13081334
void *Buffer = Mod.allocateInst(size, alignof(CheckedCastAddrBranchInst));
13091335
return ::new (Buffer) CheckedCastAddrBranchInst(DebugLoc, consumptionKind,
1310-
src, srcType, dest, targetType, TypeDependentOperands,
1336+
src, srcType, dest, targetType, allOperands,
13111337
successBB, failureBB, Target1Count, Target2Count);
13121338
}
13131339

0 commit comments

Comments
 (0)