@@ -5535,39 +5535,74 @@ class TupleElementAddrInst
5535
5535
}
5536
5536
};
5537
5537
5538
- // / Extract a physical, fragile field out of a value of struct type.
5539
- class StructExtractInst
5540
- : public UnaryInstructionBase<SILInstructionKind::StructExtractInst,
5541
- SingleValueInstruction>
5542
- {
5543
- friend SILBuilder;
5544
-
5545
- VarDecl *Field;
5538
+ // / A common base for instructions that require a cached field index.
5539
+ // /
5540
+ // / "Field" is a term used here to refer to the ordered, accessible stored
5541
+ // / properties of a class or struct.
5542
+ // /
5543
+ // / The field's ordinal value is the basis of efficiently comparing and sorting
5544
+ // / access paths in SIL. For example, whenever a Projection object is created,
5545
+ // / it stores the field index. Finding the field index initially requires
5546
+ // / searching the type declaration's array of all stored properties. If this
5547
+ // / index is not cached, it will cause widespread quadratic complexity in any
5548
+ // / pass that queries projections, including the SIL verifier.
5549
+ // /
5550
+ // / FIXME: This cache may not be necessary if the Decl TypeChecker instead
5551
+ // / caches a field index in the VarDecl itself. This solution would be superior
5552
+ // / because it would allow constant time lookup of either the VarDecl or the
5553
+ // / index from a single pointer without referring back to a projection
5554
+ // / instruction.
5555
+ class FieldIndexCacheBase : public SingleValueInstruction {
5556
+ enum : unsigned { InvalidFieldIndex = ~unsigned (0 ) };
5546
5557
5547
- StructExtractInst (SILDebugLocation DebugLoc, SILValue Operand,
5548
- VarDecl *Field, SILType ResultTy)
5549
- : UnaryInstructionBase(DebugLoc, Operand, ResultTy), Field(Field) {}
5558
+ VarDecl *field;
5550
5559
5551
5560
public:
5552
- VarDecl *getField () const { return Field; }
5561
+ FieldIndexCacheBase (SILInstructionKind kind, SILDebugLocation loc,
5562
+ SILType type, VarDecl *field)
5563
+ : SingleValueInstruction(kind, loc, type), field(field) {
5564
+ SILInstruction::Bits.FieldIndexCacheBase .FieldIndex = InvalidFieldIndex;
5565
+ // This needs to be a concrete class to hold bitfield information. However,
5566
+ // it should only be extended by UnaryInstructions.
5567
+ assert (getNumOperands () == 1 );
5568
+ }
5553
5569
5570
+ VarDecl *getField () const { return field; }
5571
+
5572
+ // FIXME: this should be called getFieldIndex().
5554
5573
unsigned getFieldNo () const {
5555
- unsigned i = 0 ;
5556
- for (VarDecl *D : getStructDecl ()->getStoredProperties ()) {
5557
- if (Field == D)
5558
- return i;
5559
- ++i;
5560
- }
5561
- llvm_unreachable (" A struct_extract's structdecl has at least 1 field, the "
5562
- " field of the struct_extract." );
5574
+ unsigned idx = SILInstruction::Bits.FieldIndexCacheBase .FieldIndex ;
5575
+ if (idx != InvalidFieldIndex)
5576
+ return idx;
5577
+
5578
+ return const_cast <FieldIndexCacheBase *>(this )->cacheFieldIndex ();
5563
5579
}
5564
5580
5565
- StructDecl * getStructDecl () const {
5566
- auto s = getOperand ()->getType ().getStructOrBoundGenericStruct ();
5581
+ NominalTypeDecl * getParentDecl () const {
5582
+ auto s = getOperand (0 )->getType ().getNominalOrBoundGenericNominal ();
5567
5583
assert (s);
5568
5584
return s;
5569
5585
}
5570
5586
5587
+ private:
5588
+ unsigned cacheFieldIndex ();
5589
+ };
5590
+
5591
+ // / Extract a physical, fragile field out of a value of struct type.
5592
+ class StructExtractInst
5593
+ : public UnaryInstructionBase<SILInstructionKind::StructExtractInst,
5594
+ FieldIndexCacheBase> {
5595
+ friend SILBuilder;
5596
+
5597
+ StructExtractInst (SILDebugLocation DebugLoc, SILValue Operand, VarDecl *Field,
5598
+ SILType ResultTy)
5599
+ : UnaryInstructionBase(DebugLoc, Operand, ResultTy, Field) {}
5600
+
5601
+ public:
5602
+ StructDecl *getStructDecl () const {
5603
+ return cast<StructDecl>(getParentDecl ());
5604
+ }
5605
+
5571
5606
// / Returns true if this is a trivial result of a struct that is non-trivial
5572
5607
// / and represents one RCID.
5573
5608
bool isTrivialFieldOfOneRCIDStruct () const ;
@@ -5580,71 +5615,33 @@ class StructExtractInst
5580
5615
5581
5616
// / Derive the address of a physical field from the address of a struct.
5582
5617
class StructElementAddrInst
5583
- : public UnaryInstructionBase<SILInstructionKind::StructElementAddrInst,
5584
- SingleValueInstruction>
5585
- {
5618
+ : public UnaryInstructionBase<SILInstructionKind::StructElementAddrInst,
5619
+ FieldIndexCacheBase> {
5586
5620
friend SILBuilder;
5587
5621
5588
- VarDecl *Field;
5589
-
5590
5622
StructElementAddrInst (SILDebugLocation DebugLoc, SILValue Operand,
5591
5623
VarDecl *Field, SILType ResultTy)
5592
- : UnaryInstructionBase(DebugLoc, Operand, ResultTy), Field( Field) {}
5624
+ : UnaryInstructionBase(DebugLoc, Operand, ResultTy, Field) {}
5593
5625
5594
5626
public:
5595
- VarDecl *getField () const { return Field; }
5596
-
5597
- unsigned getFieldNo () const {
5598
- unsigned i = 0 ;
5599
- for (auto *D : getStructDecl ()->getStoredProperties ()) {
5600
- if (Field == D)
5601
- return i;
5602
- ++i;
5603
- }
5604
- llvm_unreachable (" A struct_element_addr's structdecl has at least 1 field, "
5605
- " the field of the struct_element_addr." );
5606
- }
5607
-
5608
5627
StructDecl *getStructDecl () const {
5609
- auto s = getOperand ()->getType ().getStructOrBoundGenericStruct ();
5610
- assert (s);
5611
- return s;
5628
+ return cast<StructDecl>(getParentDecl ());
5612
5629
}
5613
5630
};
5614
5631
5615
5632
// / RefElementAddrInst - Derive the address of a named element in a reference
5616
5633
// / type instance.
5617
5634
class RefElementAddrInst
5618
- : public UnaryInstructionBase<SILInstructionKind::RefElementAddrInst,
5619
- SingleValueInstruction>
5620
- {
5635
+ : public UnaryInstructionBase<SILInstructionKind::RefElementAddrInst,
5636
+ FieldIndexCacheBase> {
5621
5637
friend SILBuilder;
5622
5638
5623
- VarDecl *Field;
5624
-
5625
5639
RefElementAddrInst (SILDebugLocation DebugLoc, SILValue Operand,
5626
5640
VarDecl *Field, SILType ResultTy)
5627
- : UnaryInstructionBase(DebugLoc, Operand, ResultTy), Field( Field) {}
5641
+ : UnaryInstructionBase(DebugLoc, Operand, ResultTy, Field) {}
5628
5642
5629
5643
public:
5630
- VarDecl *getField () const { return Field; }
5631
-
5632
- unsigned getFieldNo () const {
5633
- unsigned i = 0 ;
5634
- for (auto *D : getClassDecl ()->getStoredProperties ()) {
5635
- if (Field == D)
5636
- return i;
5637
- ++i;
5638
- }
5639
- llvm_unreachable (" A ref_element_addr's classdecl has at least 1 field, the "
5640
- " field of the ref_element_addr." );
5641
- }
5642
-
5643
- ClassDecl *getClassDecl () const {
5644
- auto s = getOperand ()->getType ().getClassOrBoundGenericClass ();
5645
- assert (s);
5646
- return s;
5647
- }
5644
+ ClassDecl *getClassDecl () const { return cast<ClassDecl>(getParentDecl ()); }
5648
5645
};
5649
5646
5650
5647
// / RefTailAddrInst - Derive the address of the first element of the first
0 commit comments