Skip to content

Commit 4ff4bc0

Browse files
authored
Merge pull request #58933 from eeckstein/case-index-caching
SIL: cache case indices in enum instructions.
2 parents 47721d2 + f3adbd5 commit 4ff4bc0

File tree

8 files changed

+184
-77
lines changed

8 files changed

+184
-77
lines changed

include/swift/SIL/SILInstruction.h

Lines changed: 78 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,10 @@ class SILInstruction : public llvm::ilist_node<SILInstruction> {
812812

813813
/// This is supportable but usually suggests a logic mistake.
814814
static bool classof(const ValueBase *) = delete;
815+
816+
protected:
817+
unsigned getCachedFieldIndex(NominalTypeDecl *decl, VarDecl *property);
818+
unsigned getCachedCaseIndex(EnumElementDecl *enumElement);
815819
};
816820

817821
inline SILNodePointer::SILNodePointer(const SILInstruction *inst) :
@@ -6010,6 +6014,7 @@ class EnumInst
60106014
: public InstructionBase<SILInstructionKind::EnumInst,
60116015
FirstArgOwnershipForwardingSingleValueInst> {
60126016
friend SILBuilder;
6017+
enum : unsigned { InvalidCaseIndex = ~unsigned(0) };
60136018

60146019
Optional<FixedOperandList<1>> OptionalOperand;
60156020
EnumElementDecl *Element;
@@ -6019,6 +6024,8 @@ class EnumInst
60196024
ValueOwnershipKind forwardingOwnershipKind)
60206025
: InstructionBase(DebugLoc, ResultTy, forwardingOwnershipKind),
60216026
Element(Element) {
6027+
SILNode::Bits.EnumInst.CaseIndex = InvalidCaseIndex;
6028+
60226029
if (Operand) {
60236030
OptionalOperand.emplace(this, Operand);
60246031
}
@@ -6027,6 +6034,16 @@ class EnumInst
60276034
public:
60286035
EnumElementDecl *getElement() const { return Element; }
60296036

6037+
unsigned getCaseIndex() {
6038+
unsigned idx = SILNode::Bits.EnumInst.CaseIndex;
6039+
if (idx != InvalidCaseIndex)
6040+
return idx;
6041+
6042+
unsigned index = getCachedCaseIndex(getElement());
6043+
SILNode::Bits.EnumInst.CaseIndex = index;
6044+
return index;
6045+
}
6046+
60306047
bool hasOperand() const { return OptionalOperand.hasValue(); }
60316048
SILValue getOperand() const { return OptionalOperand->asValueArray()[0]; }
60326049

@@ -6048,6 +6065,7 @@ class UncheckedEnumDataInst
60486065
: public UnaryInstructionBase<SILInstructionKind::UncheckedEnumDataInst,
60496066
FirstArgOwnershipForwardingSingleValueInst> {
60506067
friend SILBuilder;
6068+
enum : unsigned { InvalidCaseIndex = ~unsigned(0) };
60516069

60526070
EnumElementDecl *Element;
60536071

@@ -6056,11 +6074,23 @@ class UncheckedEnumDataInst
60566074
ValueOwnershipKind forwardingOwnershipKind)
60576075
: UnaryInstructionBase(DebugLoc, Operand, ResultTy,
60586076
forwardingOwnershipKind),
6059-
Element(Element) {}
6077+
Element(Element) {
6078+
SILNode::Bits.UncheckedEnumDataInst.CaseIndex = InvalidCaseIndex;
6079+
}
60606080

60616081
public:
60626082
EnumElementDecl *getElement() const { return Element; }
60636083

6084+
unsigned getCaseIndex() {
6085+
unsigned idx = SILNode::Bits.UncheckedEnumDataInst.CaseIndex;
6086+
if (idx != InvalidCaseIndex)
6087+
return idx;
6088+
6089+
unsigned index = getCachedCaseIndex(getElement());
6090+
SILNode::Bits.UncheckedEnumDataInst.CaseIndex = index;
6091+
return index;
6092+
}
6093+
60646094
EnumDecl *getEnumDecl() const {
60656095
auto *E = getOperand()->getType().getEnumOrBoundGenericEnum();
60666096
assert(E && "Operand of unchecked_enum_data must be of enum type");
@@ -6086,15 +6116,28 @@ class InitEnumDataAddrInst
60866116
SingleValueInstruction>
60876117
{
60886118
friend SILBuilder;
6119+
enum : unsigned { InvalidCaseIndex = ~unsigned(0) };
60896120

60906121
EnumElementDecl *Element;
60916122

60926123
InitEnumDataAddrInst(SILDebugLocation DebugLoc, SILValue Operand,
60936124
EnumElementDecl *Element, SILType ResultTy)
6094-
: UnaryInstructionBase(DebugLoc, Operand, ResultTy), Element(Element) {}
6125+
: UnaryInstructionBase(DebugLoc, Operand, ResultTy), Element(Element) {
6126+
SILNode::Bits.InitEnumDataAddrInst.CaseIndex = InvalidCaseIndex;
6127+
}
60956128

60966129
public:
60976130
EnumElementDecl *getElement() const { return Element; }
6131+
6132+
unsigned getCaseIndex() {
6133+
unsigned idx = SILNode::Bits.InitEnumDataAddrInst.CaseIndex;
6134+
if (idx != InvalidCaseIndex)
6135+
return idx;
6136+
6137+
unsigned index = getCachedCaseIndex(getElement());
6138+
SILNode::Bits.InitEnumDataAddrInst.CaseIndex = index;
6139+
return index;
6140+
}
60986141
};
60996142

61006143
/// InjectEnumAddrInst - Tags an enum as containing a case. The data for
@@ -6104,15 +6147,28 @@ class InjectEnumAddrInst
61046147
NonValueInstruction>
61056148
{
61066149
friend SILBuilder;
6150+
enum : unsigned { InvalidCaseIndex = ~unsigned(0) };
61076151

61086152
EnumElementDecl *Element;
61096153

61106154
InjectEnumAddrInst(SILDebugLocation DebugLoc, SILValue Operand,
61116155
EnumElementDecl *Element)
6112-
: UnaryInstructionBase(DebugLoc, Operand), Element(Element) {}
6156+
: UnaryInstructionBase(DebugLoc, Operand), Element(Element) {
6157+
SILNode::Bits.InjectEnumAddrInst.CaseIndex = InvalidCaseIndex;
6158+
}
61136159

61146160
public:
61156161
EnumElementDecl *getElement() const { return Element; }
6162+
6163+
unsigned getCaseIndex() {
6164+
unsigned idx = SILNode::Bits.InjectEnumAddrInst.CaseIndex;
6165+
if (idx != InvalidCaseIndex)
6166+
return idx;
6167+
6168+
unsigned index = getCachedCaseIndex(getElement());
6169+
SILNode::Bits.InjectEnumAddrInst.CaseIndex = index;
6170+
return index;
6171+
}
61166172
};
61176173

61186174
/// Invalidate an enum value and take ownership of its payload data
@@ -6122,34 +6178,35 @@ class UncheckedTakeEnumDataAddrInst
61226178
SingleValueInstruction>
61236179
{
61246180
friend SILBuilder;
6181+
enum : unsigned { InvalidCaseIndex = ~unsigned(0) };
61256182

61266183
EnumElementDecl *Element;
61276184

61286185
UncheckedTakeEnumDataAddrInst(SILDebugLocation DebugLoc, SILValue Operand,
61296186
EnumElementDecl *Element, SILType ResultTy)
6130-
: UnaryInstructionBase(DebugLoc, Operand, ResultTy), Element(Element) {}
6187+
: UnaryInstructionBase(DebugLoc, Operand, ResultTy), Element(Element) {
6188+
SILNode::Bits.UncheckedTakeEnumDataAddrInst.CaseIndex = InvalidCaseIndex;
6189+
}
61316190

61326191
public:
61336192
EnumElementDecl *getElement() const { return Element; }
61346193

6194+
unsigned getCaseIndex() {
6195+
unsigned idx = SILNode::Bits.UncheckedTakeEnumDataAddrInst.CaseIndex;
6196+
if (idx != InvalidCaseIndex)
6197+
return idx;
6198+
6199+
unsigned index = getCachedCaseIndex(getElement());
6200+
SILNode::Bits.UncheckedTakeEnumDataAddrInst.CaseIndex = index;
6201+
return index;
6202+
}
6203+
61356204
EnumDecl *getEnumDecl() const {
61366205
auto *E = getOperand()->getType().getEnumOrBoundGenericEnum();
61376206
assert(E && "Operand of unchecked_take_enum_data_addr must be of enum"
61386207
" type");
61396208
return E;
61406209
}
6141-
6142-
unsigned getElementNo() const {
6143-
unsigned i = 0;
6144-
for (EnumElementDecl *E : getEnumDecl()->getAllElements()) {
6145-
if (E == Element)
6146-
return i;
6147-
++i;
6148-
}
6149-
llvm_unreachable(
6150-
"An unchecked_enum_data_addr's enumdecl should have at least "
6151-
"on element, the element that is being extracted");
6152-
}
61536210
};
61546211

61556212
// Abstract base class of all select instructions like select_enum,
@@ -6520,19 +6577,6 @@ class TupleElementAddrInst
65206577
}
65216578
};
65226579

6523-
/// Get a unique index for a struct or class field in layout order.
6524-
///
6525-
/// Precondition: \p decl must be a non-resilient struct or class.
6526-
///
6527-
/// Precondition: \p field must be a stored property declared in \p decl,
6528-
/// not in a superclass.
6529-
///
6530-
/// Postcondition: The returned index is unique across all properties in the
6531-
/// object, including properties declared in a superclass.
6532-
unsigned getFieldIndex(NominalTypeDecl *decl, VarDecl *property);
6533-
6534-
unsigned getCaseIndex(EnumElementDecl *enumElement);
6535-
65366580
unsigned getNumFieldsInNominal(NominalTypeDecl *decl);
65376581

65386582
/// Get the property for a struct or class by its unique index, or nullptr if
@@ -6579,12 +6623,14 @@ class FieldIndexCacheBase : public ParentTy {
65796623

65806624
VarDecl *getField() const { return field; }
65816625

6582-
unsigned getFieldIndex() const {
6626+
unsigned getFieldIndex() {
65836627
unsigned idx = SILNode::Bits.FieldIndexCacheBase.FieldIndex;
65846628
if (idx != InvalidFieldIndex)
65856629
return idx;
6586-
6587-
return const_cast<FieldIndexCacheBase *>(this)->cacheFieldIndex();
6630+
6631+
idx = ParentTy::getCachedFieldIndex(getParentDecl(), getField());
6632+
SILNode::Bits.FieldIndexCacheBase.FieldIndex = idx;
6633+
return idx;
65886634
}
65896635

65906636
NominalTypeDecl *getParentDecl() const {
@@ -6600,13 +6646,6 @@ class FieldIndexCacheBase : public ParentTy {
66006646
kind == SILNodeKind::StructElementAddrInst ||
66016647
kind == SILNodeKind::RefElementAddrInst;
66026648
}
6603-
6604-
private:
6605-
unsigned cacheFieldIndex() {
6606-
unsigned index = swift::getFieldIndex(getParentDecl(), getField());
6607-
SILNode::Bits.FieldIndexCacheBase.FieldIndex = index;
6608-
return index;
6609-
}
66106649
};
66116650

66126651
/// Extract a physical, fragile field out of a value of struct type.

include/swift/SIL/SILModule.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,9 @@ class SILModule {
303303
/// This is the set of undef values we've created, for uniquing purposes.
304304
llvm::DenseMap<SILType, SILUndef *> UndefValues;
305305

306+
llvm::DenseMap<std::pair<Decl *, VarDecl *>, unsigned> fieldIndices;
307+
llvm::DenseMap<EnumElementDecl *, unsigned> enumCaseIndices;
308+
306309
/// The stage of processing this module is at.
307310
SILStage Stage;
308311

@@ -448,6 +451,19 @@ class SILModule {
448451
/// This should only be the case during parsing or deserialization.
449452
bool hasUnresolvedOpenedArchetypeDefinitions();
450453

454+
/// Get a unique index for a struct or class field in layout order.
455+
///
456+
/// Precondition: \p decl must be a non-resilient struct or class.
457+
///
458+
/// Precondition: \p field must be a stored property declared in \p decl,
459+
/// not in a superclass.
460+
///
461+
/// Postcondition: The returned index is unique across all properties in the
462+
/// object, including properties declared in a superclass.
463+
unsigned getFieldIndex(NominalTypeDecl *decl, VarDecl *property);
464+
465+
unsigned getCaseIndex(EnumElementDecl *enumElement);
466+
451467
/// Called by SILBuilder whenever a new instruction is created and inserted.
452468
void notifyAddedInstruction(SILInstruction *inst);
453469

include/swift/SIL/SILNode.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,36 @@ class alignas(8) SILNode :
356356
FieldIndex : 32
357357
);
358358

359+
SWIFT_INLINE_BITFIELD_FULL(EnumInst,
360+
SingleValueInstruction, 32,
361+
: NumPadBits,
362+
CaseIndex : 32
363+
);
364+
365+
SWIFT_INLINE_BITFIELD_FULL(UncheckedEnumDataInst,
366+
SingleValueInstruction, 32,
367+
: NumPadBits,
368+
CaseIndex : 32
369+
);
370+
371+
SWIFT_INLINE_BITFIELD_FULL(InjectEnumAddrInst,
372+
SILInstruction, 32,
373+
: NumPadBits,
374+
CaseIndex : 32
375+
);
376+
377+
SWIFT_INLINE_BITFIELD_FULL(InitEnumDataAddrInst,
378+
SingleValueInstruction, 32,
379+
: NumPadBits,
380+
CaseIndex : 32
381+
);
382+
383+
SWIFT_INLINE_BITFIELD_FULL(UncheckedTakeEnumDataAddrInst,
384+
SingleValueInstruction, 32,
385+
: NumPadBits,
386+
CaseIndex : 32
387+
);
388+
359389
SWIFT_INLINE_BITFIELD_EMPTY(MethodInst, SingleValueInstruction);
360390
// Ensure that WitnessMethodInst bitfield does not overflow.
361391
IBWTO_BITFIELD_EMPTY(WitnessMethodInst, MethodInst);

lib/SIL/IR/SILInstruction.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1387,6 +1387,15 @@ bool SILInstruction::isMetaInstruction() const {
13871387
llvm_unreachable("Instruction not handled in isMetaInstruction()!");
13881388
}
13891389

1390+
unsigned SILInstruction::getCachedFieldIndex(NominalTypeDecl *decl,
1391+
VarDecl *property) {
1392+
return getModule().getFieldIndex(decl, property);
1393+
}
1394+
1395+
unsigned SILInstruction::getCachedCaseIndex(EnumElementDecl *enumElement) {
1396+
return getModule().getCaseIndex(enumElement);
1397+
}
1398+
13901399
//===----------------------------------------------------------------------===//
13911400
// Utilities
13921401
//===----------------------------------------------------------------------===//

lib/SIL/IR/SILInstructions.cpp

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,26 +1378,6 @@ bool TupleExtractInst::isEltOnlyNonTrivialElt() const {
13781378
return true;
13791379
}
13801380

1381-
/// Get a unique index for a struct or class field in layout order.
1382-
unsigned swift::getFieldIndex(NominalTypeDecl *decl, VarDecl *field) {
1383-
unsigned index = 0;
1384-
if (auto *classDecl = dyn_cast<ClassDecl>(decl)) {
1385-
for (auto *superDecl = classDecl->getSuperclassDecl(); superDecl != nullptr;
1386-
superDecl = superDecl->getSuperclassDecl()) {
1387-
index += superDecl->getStoredProperties().size();
1388-
}
1389-
}
1390-
for (VarDecl *property : decl->getStoredProperties()) {
1391-
if (field == property) {
1392-
return index;
1393-
}
1394-
++index;
1395-
}
1396-
llvm_unreachable("The field decl for a struct_extract, struct_element_addr, "
1397-
"or ref_element_addr must be an accessible stored "
1398-
"property of the operand type");
1399-
}
1400-
14011381
unsigned swift::getNumFieldsInNominal(NominalTypeDecl *decl) {
14021382
unsigned count = 0;
14031383
if (auto *classDecl = dyn_cast<ClassDecl>(decl)) {
@@ -1409,16 +1389,6 @@ unsigned swift::getNumFieldsInNominal(NominalTypeDecl *decl) {
14091389
return count + decl->getStoredProperties().size();
14101390
}
14111391

1412-
unsigned swift::getCaseIndex(EnumElementDecl *enumElement) {
1413-
unsigned idx = 0;
1414-
for (EnumElementDecl *e : enumElement->getParentEnum()->getAllElements()) {
1415-
if (e == enumElement)
1416-
return idx;
1417-
++idx;
1418-
}
1419-
llvm_unreachable("enum element not found in enum decl");
1420-
}
1421-
14221392
/// Get the property for a struct or class by its unique index.
14231393
VarDecl *swift::getIndexedField(NominalTypeDecl *decl, unsigned index) {
14241394
if (auto *structDecl = dyn_cast<StructDecl>(decl)) {

0 commit comments

Comments
 (0)