Skip to content

SIL: cache case indices in enum instructions. #58933

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 78 additions & 39 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,10 @@ class SILInstruction : public llvm::ilist_node<SILInstruction> {

/// This is supportable but usually suggests a logic mistake.
static bool classof(const ValueBase *) = delete;

protected:
unsigned getCachedFieldIndex(NominalTypeDecl *decl, VarDecl *property);
unsigned getCachedCaseIndex(EnumElementDecl *enumElement);
};

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

Optional<FixedOperandList<1>> OptionalOperand;
EnumElementDecl *Element;
Expand All @@ -6019,6 +6024,8 @@ class EnumInst
ValueOwnershipKind forwardingOwnershipKind)
: InstructionBase(DebugLoc, ResultTy, forwardingOwnershipKind),
Element(Element) {
SILNode::Bits.EnumInst.CaseIndex = InvalidCaseIndex;

if (Operand) {
OptionalOperand.emplace(this, Operand);
}
Expand All @@ -6027,6 +6034,16 @@ class EnumInst
public:
EnumElementDecl *getElement() const { return Element; }

unsigned getCaseIndex() {
unsigned idx = SILNode::Bits.EnumInst.CaseIndex;
if (idx != InvalidCaseIndex)
return idx;

unsigned index = getCachedCaseIndex(getElement());
SILNode::Bits.EnumInst.CaseIndex = index;
return index;
}

bool hasOperand() const { return OptionalOperand.hasValue(); }
SILValue getOperand() const { return OptionalOperand->asValueArray()[0]; }

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

EnumElementDecl *Element;

Expand All @@ -6056,11 +6074,23 @@ class UncheckedEnumDataInst
ValueOwnershipKind forwardingOwnershipKind)
: UnaryInstructionBase(DebugLoc, Operand, ResultTy,
forwardingOwnershipKind),
Element(Element) {}
Element(Element) {
SILNode::Bits.UncheckedEnumDataInst.CaseIndex = InvalidCaseIndex;
}

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

unsigned getCaseIndex() {
unsigned idx = SILNode::Bits.UncheckedEnumDataInst.CaseIndex;
if (idx != InvalidCaseIndex)
return idx;

unsigned index = getCachedCaseIndex(getElement());
SILNode::Bits.UncheckedEnumDataInst.CaseIndex = index;
return index;
}

EnumDecl *getEnumDecl() const {
auto *E = getOperand()->getType().getEnumOrBoundGenericEnum();
assert(E && "Operand of unchecked_enum_data must be of enum type");
Expand All @@ -6086,15 +6116,28 @@ class InitEnumDataAddrInst
SingleValueInstruction>
{
friend SILBuilder;
enum : unsigned { InvalidCaseIndex = ~unsigned(0) };

EnumElementDecl *Element;

InitEnumDataAddrInst(SILDebugLocation DebugLoc, SILValue Operand,
EnumElementDecl *Element, SILType ResultTy)
: UnaryInstructionBase(DebugLoc, Operand, ResultTy), Element(Element) {}
: UnaryInstructionBase(DebugLoc, Operand, ResultTy), Element(Element) {
SILNode::Bits.InitEnumDataAddrInst.CaseIndex = InvalidCaseIndex;
}

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

unsigned getCaseIndex() {
unsigned idx = SILNode::Bits.InitEnumDataAddrInst.CaseIndex;
if (idx != InvalidCaseIndex)
return idx;

unsigned index = getCachedCaseIndex(getElement());
SILNode::Bits.InitEnumDataAddrInst.CaseIndex = index;
return index;
}
};

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

EnumElementDecl *Element;

InjectEnumAddrInst(SILDebugLocation DebugLoc, SILValue Operand,
EnumElementDecl *Element)
: UnaryInstructionBase(DebugLoc, Operand), Element(Element) {}
: UnaryInstructionBase(DebugLoc, Operand), Element(Element) {
SILNode::Bits.InjectEnumAddrInst.CaseIndex = InvalidCaseIndex;
}

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

unsigned getCaseIndex() {
unsigned idx = SILNode::Bits.InjectEnumAddrInst.CaseIndex;
if (idx != InvalidCaseIndex)
return idx;

unsigned index = getCachedCaseIndex(getElement());
SILNode::Bits.InjectEnumAddrInst.CaseIndex = index;
return index;
}
};

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

EnumElementDecl *Element;

UncheckedTakeEnumDataAddrInst(SILDebugLocation DebugLoc, SILValue Operand,
EnumElementDecl *Element, SILType ResultTy)
: UnaryInstructionBase(DebugLoc, Operand, ResultTy), Element(Element) {}
: UnaryInstructionBase(DebugLoc, Operand, ResultTy), Element(Element) {
SILNode::Bits.UncheckedTakeEnumDataAddrInst.CaseIndex = InvalidCaseIndex;
}

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

unsigned getCaseIndex() {
unsigned idx = SILNode::Bits.UncheckedTakeEnumDataAddrInst.CaseIndex;
if (idx != InvalidCaseIndex)
return idx;

unsigned index = getCachedCaseIndex(getElement());
SILNode::Bits.UncheckedTakeEnumDataAddrInst.CaseIndex = index;
return index;
}

EnumDecl *getEnumDecl() const {
auto *E = getOperand()->getType().getEnumOrBoundGenericEnum();
assert(E && "Operand of unchecked_take_enum_data_addr must be of enum"
" type");
return E;
}

unsigned getElementNo() const {
unsigned i = 0;
for (EnumElementDecl *E : getEnumDecl()->getAllElements()) {
if (E == Element)
return i;
++i;
}
llvm_unreachable(
"An unchecked_enum_data_addr's enumdecl should have at least "
"on element, the element that is being extracted");
}
};

// Abstract base class of all select instructions like select_enum,
Expand Down Expand Up @@ -6520,19 +6577,6 @@ class TupleElementAddrInst
}
};

/// Get a unique index for a struct or class field in layout order.
///
/// Precondition: \p decl must be a non-resilient struct or class.
///
/// Precondition: \p field must be a stored property declared in \p decl,
/// not in a superclass.
///
/// Postcondition: The returned index is unique across all properties in the
/// object, including properties declared in a superclass.
unsigned getFieldIndex(NominalTypeDecl *decl, VarDecl *property);

unsigned getCaseIndex(EnumElementDecl *enumElement);

unsigned getNumFieldsInNominal(NominalTypeDecl *decl);

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

VarDecl *getField() const { return field; }

unsigned getFieldIndex() const {
unsigned getFieldIndex() {
unsigned idx = SILNode::Bits.FieldIndexCacheBase.FieldIndex;
if (idx != InvalidFieldIndex)
return idx;

return const_cast<FieldIndexCacheBase *>(this)->cacheFieldIndex();

idx = ParentTy::getCachedFieldIndex(getParentDecl(), getField());
SILNode::Bits.FieldIndexCacheBase.FieldIndex = idx;
return idx;
}

NominalTypeDecl *getParentDecl() const {
Expand All @@ -6600,13 +6646,6 @@ class FieldIndexCacheBase : public ParentTy {
kind == SILNodeKind::StructElementAddrInst ||
kind == SILNodeKind::RefElementAddrInst;
}

private:
unsigned cacheFieldIndex() {
unsigned index = swift::getFieldIndex(getParentDecl(), getField());
SILNode::Bits.FieldIndexCacheBase.FieldIndex = index;
return index;
}
};

/// Extract a physical, fragile field out of a value of struct type.
Expand Down
16 changes: 16 additions & 0 deletions include/swift/SIL/SILModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,9 @@ class SILModule {
/// This is the set of undef values we've created, for uniquing purposes.
llvm::DenseMap<SILType, SILUndef *> UndefValues;

llvm::DenseMap<std::pair<Decl *, VarDecl *>, unsigned> fieldIndices;
llvm::DenseMap<EnumElementDecl *, unsigned> enumCaseIndices;

/// The stage of processing this module is at.
SILStage Stage;

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

/// Get a unique index for a struct or class field in layout order.
///
/// Precondition: \p decl must be a non-resilient struct or class.
///
/// Precondition: \p field must be a stored property declared in \p decl,
/// not in a superclass.
///
/// Postcondition: The returned index is unique across all properties in the
/// object, including properties declared in a superclass.
unsigned getFieldIndex(NominalTypeDecl *decl, VarDecl *property);

unsigned getCaseIndex(EnumElementDecl *enumElement);

/// Called by SILBuilder whenever a new instruction is created and inserted.
void notifyAddedInstruction(SILInstruction *inst);

Expand Down
30 changes: 30 additions & 0 deletions include/swift/SIL/SILNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,36 @@ class alignas(8) SILNode :
FieldIndex : 32
);

SWIFT_INLINE_BITFIELD_FULL(EnumInst,
SingleValueInstruction, 32,
: NumPadBits,
CaseIndex : 32
);

SWIFT_INLINE_BITFIELD_FULL(UncheckedEnumDataInst,
SingleValueInstruction, 32,
: NumPadBits,
CaseIndex : 32
);

SWIFT_INLINE_BITFIELD_FULL(InjectEnumAddrInst,
SILInstruction, 32,
: NumPadBits,
CaseIndex : 32
);

SWIFT_INLINE_BITFIELD_FULL(InitEnumDataAddrInst,
SingleValueInstruction, 32,
: NumPadBits,
CaseIndex : 32
);

SWIFT_INLINE_BITFIELD_FULL(UncheckedTakeEnumDataAddrInst,
SingleValueInstruction, 32,
: NumPadBits,
CaseIndex : 32
);

SWIFT_INLINE_BITFIELD_EMPTY(MethodInst, SingleValueInstruction);
// Ensure that WitnessMethodInst bitfield does not overflow.
IBWTO_BITFIELD_EMPTY(WitnessMethodInst, MethodInst);
Expand Down
9 changes: 9 additions & 0 deletions lib/SIL/IR/SILInstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1387,6 +1387,15 @@ bool SILInstruction::isMetaInstruction() const {
llvm_unreachable("Instruction not handled in isMetaInstruction()!");
}

unsigned SILInstruction::getCachedFieldIndex(NominalTypeDecl *decl,
VarDecl *property) {
return getModule().getFieldIndex(decl, property);
}

unsigned SILInstruction::getCachedCaseIndex(EnumElementDecl *enumElement) {
return getModule().getCaseIndex(enumElement);
}

//===----------------------------------------------------------------------===//
// Utilities
//===----------------------------------------------------------------------===//
Expand Down
30 changes: 0 additions & 30 deletions lib/SIL/IR/SILInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1378,26 +1378,6 @@ bool TupleExtractInst::isEltOnlyNonTrivialElt() const {
return true;
}

/// Get a unique index for a struct or class field in layout order.
unsigned swift::getFieldIndex(NominalTypeDecl *decl, VarDecl *field) {
unsigned index = 0;
if (auto *classDecl = dyn_cast<ClassDecl>(decl)) {
for (auto *superDecl = classDecl->getSuperclassDecl(); superDecl != nullptr;
superDecl = superDecl->getSuperclassDecl()) {
index += superDecl->getStoredProperties().size();
}
}
for (VarDecl *property : decl->getStoredProperties()) {
if (field == property) {
return index;
}
++index;
}
llvm_unreachable("The field decl for a struct_extract, struct_element_addr, "
"or ref_element_addr must be an accessible stored "
"property of the operand type");
}

unsigned swift::getNumFieldsInNominal(NominalTypeDecl *decl) {
unsigned count = 0;
if (auto *classDecl = dyn_cast<ClassDecl>(decl)) {
Expand All @@ -1409,16 +1389,6 @@ unsigned swift::getNumFieldsInNominal(NominalTypeDecl *decl) {
return count + decl->getStoredProperties().size();
}

unsigned swift::getCaseIndex(EnumElementDecl *enumElement) {
unsigned idx = 0;
for (EnumElementDecl *e : enumElement->getParentEnum()->getAllElements()) {
if (e == enumElement)
return idx;
++idx;
}
llvm_unreachable("enum element not found in enum decl");
}

/// Get the property for a struct or class by its unique index.
VarDecl *swift::getIndexedField(NominalTypeDecl *decl, unsigned index) {
if (auto *structDecl = dyn_cast<StructDecl>(decl)) {
Expand Down
Loading