@@ -590,17 +590,32 @@ llvm::Value *irgen::emitWitnessTablePackRef(IRGenFunction &IGF,
590
590
return result;
591
591
}
592
592
593
- llvm::Value *
594
- irgen::emitTypeMetadataPackElementRef (IRGenFunction &IGF, CanPackType packType,
595
- llvm::Value *index,
596
- DynamicMetadataRequest request) {
597
- // If the pack has already been materialized, just gep into it.
598
- if (auto pack = tryGetLocalPackTypeMetadata (IGF, packType, request)) {
599
- auto *gep = IGF.Builder .CreateInBoundsGEP (IGF.IGM .TypeMetadataPtrTy ,
600
- pack.getMetadata (), index);
593
+ llvm::Value *irgen::emitTypeMetadataPackElementRef (
594
+ IRGenFunction &IGF, CanPackType packType,
595
+ ArrayRef<ProtocolDecl *> protocols, llvm::Value *index,
596
+ DynamicMetadataRequest request,
597
+ llvm::SmallVectorImpl<llvm::Value *> &wtables) {
598
+ // If the packs have already been materialized, just gep into it.
599
+ auto materializedMetadataPack =
600
+ tryGetLocalPackTypeMetadata (IGF, packType, request);
601
+ llvm::SmallVector<llvm::Value *> materializedWtablePacks;
602
+ for (auto protocol : protocols) {
603
+ auto wtable = IGF.tryGetLocalTypeData (
604
+ packType, LocalTypeDataKind::forAbstractProtocolWitnessTable (protocol));
605
+ materializedWtablePacks.push_back (wtable);
606
+ }
607
+ if (materializedMetadataPack &&
608
+ llvm::all_of (materializedWtablePacks,
609
+ [](auto *wtable) { return wtable; })) {
610
+ auto *gep = IGF.Builder .CreateInBoundsGEP (
611
+ IGF.IGM .TypeMetadataPtrTy , materializedMetadataPack.getMetadata (),
612
+ index);
601
613
auto addr =
602
614
Address (gep, IGF.IGM .TypeMetadataPtrTy , IGF.IGM .getPointerAlignment ());
603
615
auto *metadata = IGF.Builder .CreateLoad (addr);
616
+ for (auto *wtable : materializedWtablePacks) {
617
+ wtables.push_back (wtable);
618
+ }
604
619
return metadata;
605
620
}
606
621
@@ -619,6 +634,11 @@ irgen::emitTypeMetadataPackElementRef(IRGenFunction &IGF, CanPackType packType,
619
634
auto ty = packType.getElementType (index);
620
635
auto response = IGF.emitTypeMetadataRef (ty, request);
621
636
auto *metadata = response.getMetadata ();
637
+ for (auto protocol : protocols) {
638
+ auto *wtable = emitWitnessTableRef (IGF, ty, /* srcMetadataCache=*/ nullptr ,
639
+ ProtocolConformanceRef (protocol));
640
+ wtables.push_back (wtable);
641
+ }
622
642
return metadata;
623
643
}
624
644
@@ -657,8 +677,8 @@ irgen::emitTypeMetadataPackElementRef(IRGenFunction &IGF, CanPackType packType,
657
677
// ----%inner---> ^^^
658
678
//
659
679
// In fact, we won't ever materialize %outer into any register. Instead, we
660
- // can just brach to materializing the metadata once we've determined which
661
- // outer element's range contains %index.
680
+ // can just brach to materializing the metadata (and witness tables) once
681
+ // we've determined which outer element's range contains %index.
662
682
//
663
683
// As for %inner, it will only be materialized in those blocks corresponding
664
684
// to pack expansions.
@@ -678,6 +698,8 @@ irgen::emitTypeMetadataPackElementRef(IRGenFunction &IGF, CanPackType packType,
678
698
// |emit_1: | |emit_N: |
679
699
// | %inner=0 | | %inner = %index - %lN |
680
700
// | %m_1 = | | %m_N = |
701
+ // | %wt_1_1= | | %wt_1_N = |
702
+ // | %wt_k_1= | | %wt_k_N = |
681
703
// +----------+ +-----------------------+
682
704
// | |
683
705
// V V
@@ -686,36 +708,50 @@ irgen::emitTypeMetadataPackElementRef(IRGenFunction &IGF, CanPackType packType,
686
708
// | %m = phi [ %m_1, %emit_1 ],
687
709
// | ...
688
710
// | [ %m_N, %emit_N ]
711
+ // | %wt_1 = phi [ %wt_1_1, %emit_1 ],
712
+ // | ...
713
+ // | [ %m_1_N, %emit_N ]
714
+ // | ...
715
+ // | %wt_k = phi [ %wt_k_1, %emit_1 ],
716
+ // | ...
717
+ // | [ %m_k_N, %emit_N ]
689
718
auto *current = IGF.Builder .GetInsertBlock ();
690
719
691
- // Terminate the block that branches to continue checking or metadata emission
692
- // depending on whether the index is in the pack expansion's bounds.
720
+ // Terminate the block that branches to continue checking or metadata/wtable
721
+ // emission depending on whether the index is in the pack expansion's bounds.
693
722
auto emitCheckBranch = [&IGF](llvm::Value *condition,
694
723
llvm::BasicBlock *inBounds,
695
724
llvm::BasicBlock *outOfBounds) {
696
725
if (condition) {
697
726
IGF.Builder .CreateCondBr (condition, inBounds, outOfBounds);
698
727
} else {
699
728
assert (!inBounds &&
700
- " no condition to check but a metadata materialization block!?" );
729
+ " no condition to check but a materialization block!?" );
701
730
IGF.Builder .CreateBr (outOfBounds);
702
731
}
703
732
};
704
733
705
- // The block which emission will continue in after we finish emitting metadata
706
- // for this element.
734
+ // The block which emission will continue in after we finish emitting
735
+ // metadata/wtables for this element.
707
736
auto *exit = IGF.createBasicBlock (" pack-index-element-exit" );
708
737
IGF.Builder .emitBlock (exit);
709
738
auto *metadataPhi = IGF.Builder .CreatePHI (IGF.IGM .TypeMetadataPtrTy ,
710
739
packType.getElementTypes ().size ());
740
+ llvm::SmallVector<llvm::PHINode *, 2 > wtablePhis;
741
+ wtablePhis.reserve (protocols.size ());
742
+ for (auto idx : indices (protocols)) {
743
+ (void )idx;
744
+ wtablePhis.push_back (IGF.Builder .CreatePHI (
745
+ IGF.IGM .WitnessTablePtrTy , packType.getElementTypes ().size ()));
746
+ }
711
747
712
748
IGF.Builder .SetInsertPoint (current);
713
749
// The previous checkBounds' block's comparision of %index. Use it to emit a
714
- // branch to the current block or the previous block's metadata emission
715
- // block.
750
+ // branch to the current block or the previous block's metadata/wtable
751
+ // emission block.
716
752
llvm::Value *previousCondition = nullptr ;
717
- // The previous type's materializeMetadata block. Use it as the inBounds
718
- // target when branching from the previous block.
753
+ // The previous type's materialize block. Use it as the inBounds target when
754
+ // branching from the previous block.
719
755
llvm::BasicBlock *previousInBounds = nullptr ;
720
756
// The lower bound of indices for the current pack expansion. Inclusive.
721
757
llvm::Value *lowerBound = llvm::ConstantInt::get (IGF.IGM .SizeTy , 0 );
@@ -726,7 +762,7 @@ irgen::emitTypeMetadataPackElementRef(IRGenFunction &IGF, CanPackType packType,
726
762
// Finish emitting the previous block, either entry or check_i-1.
727
763
//
728
764
// Branch from the previous bounds-check block either to this bounds-check
729
- // block or to the previous metadata- emission block.
765
+ // block or to the previous metadata/wtable emission block.
730
766
emitCheckBranch (previousCondition, previousInBounds, checkBounds);
731
767
732
768
// (1) Emit check_i {{
@@ -758,23 +794,40 @@ irgen::emitTypeMetadataPackElementRef(IRGenFunction &IGF, CanPackType packType,
758
794
// available.
759
795
760
796
// (2) Emit emit_i {{
761
- // The block within which the metadata corresponding to %inner will be
762
- // materialized.
763
- auto *materializeMetadata =
764
- IGF.createBasicBlock (" pack-index-element-metadata" );
765
- IGF.Builder .emitBlock (materializeMetadata);
797
+ // The block within which the metadata/wtables corresponding to %inner will
798
+ // be materialized.
799
+ auto *materialize = IGF.createBasicBlock (" pack-index-element-metadata" );
800
+ IGF.Builder .emitBlock (materialize);
766
801
767
802
llvm::Value *metadata = nullptr ;
803
+ llvm::SmallVector<llvm::Value *, 2 > wtables;
804
+ wtables.reserve (protocols.size ());
768
805
if (auto expansionTy = dyn_cast<PackExpansionType>(elementTy)) {
769
806
// Actually materialize %inner. Then use it to get the metadata from the
770
807
// pack expansion at that index.
771
808
auto *relativeIndex = IGF.Builder .CreateSub (index, lowerBound);
772
809
metadata = emitPackExpansionElementMetadata (IGF, expansionTy,
773
810
relativeIndex, request);
811
+ for (auto protocol : protocols) {
812
+ auto *wtable = emitPackExpansionElementWitnessTable (
813
+ IGF, expansionTy, ProtocolConformanceRef (protocol), relativeIndex);
814
+ wtables.push_back (wtable);
815
+ }
774
816
} else {
775
817
metadata = IGF.emitTypeMetadataRef (elementTy, request).getMetadata ();
818
+ for (auto protocol : protocols) {
819
+ auto *wtable =
820
+ emitWitnessTableRef (IGF, elementTy, /* srcMetadataCache=*/ nullptr ,
821
+ ProtocolConformanceRef (protocol));
822
+ wtables.push_back (wtable);
823
+ }
824
+ }
825
+ metadataPhi->addIncoming (metadata, materialize);
826
+ for (auto i : indices (wtables)) {
827
+ auto *wtable = wtables[i];
828
+ auto *wtablePhi = wtablePhis[i];
829
+ wtablePhi->addIncoming (wtable, materialize);
776
830
}
777
- metadataPhi->addIncoming (metadata, materializeMetadata);
778
831
IGF.Builder .CreateBr (exit);
779
832
// }} Finished emitting emit_i.
780
833
@@ -783,7 +836,7 @@ irgen::emitTypeMetadataPackElementRef(IRGenFunction &IGF, CanPackType packType,
783
836
IGF.Builder .SetInsertPoint (checkBounds);
784
837
785
838
// Set up the values for the next iteration.
786
- previousInBounds = materializeMetadata ;
839
+ previousInBounds = materialize ;
787
840
previousCondition = condition;
788
841
lowerBound = upperBound;
789
842
}
@@ -795,6 +848,9 @@ irgen::emitTypeMetadataPackElementRef(IRGenFunction &IGF, CanPackType packType,
795
848
/* EmitUnreachable=*/ true );
796
849
797
850
IGF.Builder .SetInsertPoint (exit);
851
+ for (auto *wtablePhi : wtablePhis) {
852
+ wtables.push_back (wtablePhi);
853
+ }
798
854
return metadataPhi;
799
855
}
800
856
0 commit comments