@@ -5625,39 +5625,74 @@ class TupleElementAddrInst
5625
5625
}
5626
5626
};
5627
5627
5628
- // / Extract a physical, fragile field out of a value of struct type.
5629
- class StructExtractInst
5630
- : public UnaryInstructionBase<SILInstructionKind::StructExtractInst,
5631
- SingleValueInstruction>
5632
- {
5633
- friend SILBuilder;
5634
-
5635
- VarDecl *Field;
5628
+ // / A common base for instructions that require a cached field index.
5629
+ // /
5630
+ // / "Field" is a term used here to refer to the ordered, accessible stored
5631
+ // / properties of a class or struct.
5632
+ // /
5633
+ // / The field's ordinal value is the basis of efficiently comparing and sorting
5634
+ // / access paths in SIL. For example, whenever a Projection object is created,
5635
+ // / it stores the field index. Finding the field index initially requires
5636
+ // / searching the type declaration's array of all stored properties. If this
5637
+ // / index is not cached, it will cause widespread quadratic complexity in any
5638
+ // / pass that queries projections, including the SIL verifier.
5639
+ // /
5640
+ // / FIXME: This cache may not be necessary if the Decl TypeChecker instead
5641
+ // / caches a field index in the VarDecl itself. This solution would be superior
5642
+ // / because it would allow constant time lookup of either the VarDecl or the
5643
+ // / index from a single pointer without referring back to a projection
5644
+ // / instruction.
5645
+ class FieldIndexCacheBase : public SingleValueInstruction {
5646
+ enum : unsigned { InvalidFieldIndex = ~unsigned (0 ) };
5636
5647
5637
- StructExtractInst (SILDebugLocation DebugLoc, SILValue Operand,
5638
- VarDecl *Field, SILType ResultTy)
5639
- : UnaryInstructionBase(DebugLoc, Operand, ResultTy), Field(Field) {}
5648
+ VarDecl *field;
5640
5649
5641
5650
public:
5642
- VarDecl *getField () const { return Field; }
5651
+ FieldIndexCacheBase (SILInstructionKind kind, SILDebugLocation loc,
5652
+ SILType type, VarDecl *field)
5653
+ : SingleValueInstruction(kind, loc, type), field(field) {
5654
+ SILInstruction::Bits.FieldIndexCacheBase .FieldIndex = InvalidFieldIndex;
5655
+ // This needs to be a concrete class to hold bitfield information. However,
5656
+ // it should only be extended by UnaryInstructions.
5657
+ assert (getNumOperands () == 1 );
5658
+ }
5643
5659
5660
+ VarDecl *getField () const { return field; }
5661
+
5662
+ // FIXME: this should be called getFieldIndex().
5644
5663
unsigned getFieldNo () const {
5645
- unsigned i = 0 ;
5646
- for (VarDecl *D : getStructDecl ()->getStoredProperties ()) {
5647
- if (Field == D)
5648
- return i;
5649
- ++i;
5650
- }
5651
- llvm_unreachable (" A struct_extract's structdecl has at least 1 field, the "
5652
- " field of the struct_extract." );
5664
+ unsigned idx = SILInstruction::Bits.FieldIndexCacheBase .FieldIndex ;
5665
+ if (idx != InvalidFieldIndex)
5666
+ return idx;
5667
+
5668
+ return const_cast <FieldIndexCacheBase *>(this )->cacheFieldIndex ();
5653
5669
}
5654
5670
5655
- StructDecl * getStructDecl () const {
5656
- auto s = getOperand ()->getType ().getStructOrBoundGenericStruct ();
5671
+ NominalTypeDecl * getParentDecl () const {
5672
+ auto s = getOperand (0 )->getType ().getNominalOrBoundGenericNominal ();
5657
5673
assert (s);
5658
5674
return s;
5659
5675
}
5660
5676
5677
+ private:
5678
+ unsigned cacheFieldIndex ();
5679
+ };
5680
+
5681
+ // / Extract a physical, fragile field out of a value of struct type.
5682
+ class StructExtractInst
5683
+ : public UnaryInstructionBase<SILInstructionKind::StructExtractInst,
5684
+ FieldIndexCacheBase> {
5685
+ friend SILBuilder;
5686
+
5687
+ StructExtractInst (SILDebugLocation DebugLoc, SILValue Operand, VarDecl *Field,
5688
+ SILType ResultTy)
5689
+ : UnaryInstructionBase(DebugLoc, Operand, ResultTy, Field) {}
5690
+
5691
+ public:
5692
+ StructDecl *getStructDecl () const {
5693
+ return cast<StructDecl>(getParentDecl ());
5694
+ }
5695
+
5661
5696
// / Returns true if this is a trivial result of a struct that is non-trivial
5662
5697
// / and represents one RCID.
5663
5698
bool isTrivialFieldOfOneRCIDStruct () const ;
@@ -5670,71 +5705,33 @@ class StructExtractInst
5670
5705
5671
5706
// / Derive the address of a physical field from the address of a struct.
5672
5707
class StructElementAddrInst
5673
- : public UnaryInstructionBase<SILInstructionKind::StructElementAddrInst,
5674
- SingleValueInstruction>
5675
- {
5708
+ : public UnaryInstructionBase<SILInstructionKind::StructElementAddrInst,
5709
+ FieldIndexCacheBase> {
5676
5710
friend SILBuilder;
5677
5711
5678
- VarDecl *Field;
5679
-
5680
5712
StructElementAddrInst (SILDebugLocation DebugLoc, SILValue Operand,
5681
5713
VarDecl *Field, SILType ResultTy)
5682
- : UnaryInstructionBase(DebugLoc, Operand, ResultTy), Field( Field) {}
5714
+ : UnaryInstructionBase(DebugLoc, Operand, ResultTy, Field) {}
5683
5715
5684
5716
public:
5685
- VarDecl *getField () const { return Field; }
5686
-
5687
- unsigned getFieldNo () const {
5688
- unsigned i = 0 ;
5689
- for (auto *D : getStructDecl ()->getStoredProperties ()) {
5690
- if (Field == D)
5691
- return i;
5692
- ++i;
5693
- }
5694
- llvm_unreachable (" A struct_element_addr's structdecl has at least 1 field, "
5695
- " the field of the struct_element_addr." );
5696
- }
5697
-
5698
5717
StructDecl *getStructDecl () const {
5699
- auto s = getOperand ()->getType ().getStructOrBoundGenericStruct ();
5700
- assert (s);
5701
- return s;
5718
+ return cast<StructDecl>(getParentDecl ());
5702
5719
}
5703
5720
};
5704
5721
5705
5722
// / RefElementAddrInst - Derive the address of a named element in a reference
5706
5723
// / type instance.
5707
5724
class RefElementAddrInst
5708
- : public UnaryInstructionBase<SILInstructionKind::RefElementAddrInst,
5709
- SingleValueInstruction>
5710
- {
5725
+ : public UnaryInstructionBase<SILInstructionKind::RefElementAddrInst,
5726
+ FieldIndexCacheBase> {
5711
5727
friend SILBuilder;
5712
5728
5713
- VarDecl *Field;
5714
-
5715
5729
RefElementAddrInst (SILDebugLocation DebugLoc, SILValue Operand,
5716
5730
VarDecl *Field, SILType ResultTy)
5717
- : UnaryInstructionBase(DebugLoc, Operand, ResultTy), Field( Field) {}
5731
+ : UnaryInstructionBase(DebugLoc, Operand, ResultTy, Field) {}
5718
5732
5719
5733
public:
5720
- VarDecl *getField () const { return Field; }
5721
-
5722
- unsigned getFieldNo () const {
5723
- unsigned i = 0 ;
5724
- for (auto *D : getClassDecl ()->getStoredProperties ()) {
5725
- if (Field == D)
5726
- return i;
5727
- ++i;
5728
- }
5729
- llvm_unreachable (" A ref_element_addr's classdecl has at least 1 field, the "
5730
- " field of the ref_element_addr." );
5731
- }
5732
-
5733
- ClassDecl *getClassDecl () const {
5734
- auto s = getOperand ()->getType ().getClassOrBoundGenericClass ();
5735
- assert (s);
5736
- return s;
5737
- }
5734
+ ClassDecl *getClassDecl () const { return cast<ClassDecl>(getParentDecl ()); }
5738
5735
};
5739
5736
5740
5737
// / RefTailAddrInst - Derive the address of the first element of the first
0 commit comments