Skip to content

Commit ddf0936

Browse files
Merge pull request #63502 from nate-chandler/variadic-generics/irgen/open_pack_element_witnesses
[IRGen] Bind wtables at open_pack_element.
2 parents 1a763c0 + cd7e675 commit ddf0936

File tree

4 files changed

+324
-48
lines changed

4 files changed

+324
-48
lines changed

lib/IRGen/GenPack.cpp

Lines changed: 83 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -590,17 +590,32 @@ llvm::Value *irgen::emitWitnessTablePackRef(IRGenFunction &IGF,
590590
return result;
591591
}
592592

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);
601613
auto addr =
602614
Address(gep, IGF.IGM.TypeMetadataPtrTy, IGF.IGM.getPointerAlignment());
603615
auto *metadata = IGF.Builder.CreateLoad(addr);
616+
for (auto *wtable : materializedWtablePacks) {
617+
wtables.push_back(wtable);
618+
}
604619
return metadata;
605620
}
606621

@@ -619,6 +634,11 @@ irgen::emitTypeMetadataPackElementRef(IRGenFunction &IGF, CanPackType packType,
619634
auto ty = packType.getElementType(index);
620635
auto response = IGF.emitTypeMetadataRef(ty, request);
621636
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+
}
622642
return metadata;
623643
}
624644

@@ -657,8 +677,8 @@ irgen::emitTypeMetadataPackElementRef(IRGenFunction &IGF, CanPackType packType,
657677
// ----%inner---> ^^^
658678
//
659679
// 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.
662682
//
663683
// As for %inner, it will only be materialized in those blocks corresponding
664684
// to pack expansions.
@@ -678,6 +698,8 @@ irgen::emitTypeMetadataPackElementRef(IRGenFunction &IGF, CanPackType packType,
678698
// |emit_1: | |emit_N: |
679699
// | %inner=0 | | %inner = %index - %lN |
680700
// | %m_1 = | | %m_N = |
701+
// | %wt_1_1= | | %wt_1_N = |
702+
// | %wt_k_1= | | %wt_k_N = |
681703
// +----------+ +-----------------------+
682704
// | |
683705
// V V
@@ -686,36 +708,50 @@ irgen::emitTypeMetadataPackElementRef(IRGenFunction &IGF, CanPackType packType,
686708
// | %m = phi [ %m_1, %emit_1 ],
687709
// | ...
688710
// | [ %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 ]
689718
auto *current = IGF.Builder.GetInsertBlock();
690719

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.
693722
auto emitCheckBranch = [&IGF](llvm::Value *condition,
694723
llvm::BasicBlock *inBounds,
695724
llvm::BasicBlock *outOfBounds) {
696725
if (condition) {
697726
IGF.Builder.CreateCondBr(condition, inBounds, outOfBounds);
698727
} else {
699728
assert(!inBounds &&
700-
"no condition to check but a metadata materialization block!?");
729+
"no condition to check but a materialization block!?");
701730
IGF.Builder.CreateBr(outOfBounds);
702731
}
703732
};
704733

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.
707736
auto *exit = IGF.createBasicBlock("pack-index-element-exit");
708737
IGF.Builder.emitBlock(exit);
709738
auto *metadataPhi = IGF.Builder.CreatePHI(IGF.IGM.TypeMetadataPtrTy,
710739
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+
}
711747

712748
IGF.Builder.SetInsertPoint(current);
713749
// 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.
716752
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.
719755
llvm::BasicBlock *previousInBounds = nullptr;
720756
// The lower bound of indices for the current pack expansion. Inclusive.
721757
llvm::Value *lowerBound = llvm::ConstantInt::get(IGF.IGM.SizeTy, 0);
@@ -726,7 +762,7 @@ irgen::emitTypeMetadataPackElementRef(IRGenFunction &IGF, CanPackType packType,
726762
// Finish emitting the previous block, either entry or check_i-1.
727763
//
728764
// 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.
730766
emitCheckBranch(previousCondition, previousInBounds, checkBounds);
731767

732768
// (1) Emit check_i {{
@@ -758,23 +794,40 @@ irgen::emitTypeMetadataPackElementRef(IRGenFunction &IGF, CanPackType packType,
758794
// available.
759795

760796
// (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);
766801

767802
llvm::Value *metadata = nullptr;
803+
llvm::SmallVector<llvm::Value *, 2> wtables;
804+
wtables.reserve(protocols.size());
768805
if (auto expansionTy = dyn_cast<PackExpansionType>(elementTy)) {
769806
// Actually materialize %inner. Then use it to get the metadata from the
770807
// pack expansion at that index.
771808
auto *relativeIndex = IGF.Builder.CreateSub(index, lowerBound);
772809
metadata = emitPackExpansionElementMetadata(IGF, expansionTy,
773810
relativeIndex, request);
811+
for (auto protocol : protocols) {
812+
auto *wtable = emitPackExpansionElementWitnessTable(
813+
IGF, expansionTy, ProtocolConformanceRef(protocol), relativeIndex);
814+
wtables.push_back(wtable);
815+
}
774816
} else {
775817
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);
776830
}
777-
metadataPhi->addIncoming(metadata, materializeMetadata);
778831
IGF.Builder.CreateBr(exit);
779832
// }} Finished emitting emit_i.
780833

@@ -783,7 +836,7 @@ irgen::emitTypeMetadataPackElementRef(IRGenFunction &IGF, CanPackType packType,
783836
IGF.Builder.SetInsertPoint(checkBounds);
784837

785838
// Set up the values for the next iteration.
786-
previousInBounds = materializeMetadata;
839+
previousInBounds = materialize;
787840
previousCondition = condition;
788841
lowerBound = upperBound;
789842
}
@@ -795,6 +848,9 @@ irgen::emitTypeMetadataPackElementRef(IRGenFunction &IGF, CanPackType packType,
795848
/*EmitUnreachable=*/true);
796849

797850
IGF.Builder.SetInsertPoint(exit);
851+
for (auto *wtablePhi : wtablePhis) {
852+
wtables.push_back(wtablePhi);
853+
}
798854
return metadataPhi;
799855
}
800856

lib/IRGen/GenPack.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "swift/AST/Types.h"
2121
#include "llvm/ADT/STLExtras.h"
22+
#include "llvm/ADT/SmallVector.h"
2223

2324
namespace llvm {
2425

@@ -50,10 +51,12 @@ emitTypeMetadataPackRef(IRGenFunction &IGF,
5051
CanPackType packType,
5152
DynamicMetadataRequest request);
5253

53-
llvm::Value *emitTypeMetadataPackElementRef(IRGenFunction &IGF,
54-
CanPackType packType,
55-
llvm::Value *index,
56-
DynamicMetadataRequest request);
54+
llvm::Value *
55+
emitTypeMetadataPackElementRef(IRGenFunction &IGF, CanPackType packType,
56+
ArrayRef<ProtocolDecl *> protocols,
57+
llvm::Value *index,
58+
DynamicMetadataRequest request,
59+
llvm::SmallVectorImpl<llvm::Value *> &wtables);
5760

5861
void cleanupTypeMetadataPack(IRGenFunction &IGF,
5962
StackAddress pack,

lib/IRGen/IRGenSIL.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6878,10 +6878,13 @@ void IRGenSILFunction::visitOpenPackElementInst(swift::OpenPackElementInst *i) {
68786878

68796879
i->getOpenedGenericEnvironment()->forEachPackElementBinding(
68806880
[&](auto *archetype, auto *pack) {
6881+
auto protocols = archetype->getConformsTo();
6882+
llvm::SmallVector<llvm::Value *, 2> wtables;
68816883
auto *metadata = emitTypeMetadataPackElementRef(
6882-
*this, CanPackType(pack), index, MetadataState::Complete);
6883-
this->bindArchetype(CanElementArchetypeType(archetype), metadata,
6884-
MetadataState::Complete, {});
6884+
*this, CanPackType(pack), protocols, index, MetadataState::Complete,
6885+
wtables);
6886+
bindArchetype(CanElementArchetypeType(archetype), metadata,
6887+
MetadataState::Complete, wtables);
68856888
});
68866889

68876890
// The result is just used for type dependencies.

0 commit comments

Comments
 (0)