@@ -1181,7 +1181,7 @@ namespace {
1181
1181
// discriminate enum cases.
1182
1182
unsigned ExtraTagBitCount = ~0u ;
1183
1183
// The number of possible values for the extra tag bits that are used.
1184
- // Log2(NumExtraTagValues - 1) + 1 = = ExtraTagBitCount
1184
+ // Log2(NumExtraTagValues - 1) + 1 < = ExtraTagBitCount
1185
1185
unsigned NumExtraTagValues = ~0u ;
1186
1186
1187
1187
APInt getExtraTagBitConstant (uint64_t value) const {
@@ -4817,41 +4817,161 @@ namespace {
4817
4817
4818
4818
// / \group Extra inhabitants
4819
4819
4820
- // TODO
4820
+ // If we didn't use all of the available tag bit representations, offer
4821
+ // the remaining ones as extra inhabitants.
4821
4822
4822
- bool mayHaveExtraInhabitants (IRGenModule &) const override { return false ; }
4823
+ bool mayHaveExtraInhabitants (IRGenModule &IGM) const override {
4824
+ if (TIK >= Fixed)
4825
+ return getFixedExtraInhabitantCount (IGM) > 0 ;
4826
+ return true ;
4827
+ }
4828
+
4829
+ // / Rounds the extra tag bit count up to the next byte size.
4830
+ unsigned getExtraTagBitCountForExtraInhabitants () const {
4831
+ if (!ExtraTagTy)
4832
+ return 0 ;
4833
+ return (ExtraTagTy->getBitWidth () + 7 ) & ~7 ;
4834
+ }
4835
+
4836
+ Address projectExtraTagBitsForExtraInhabitants (IRGenFunction &IGF,
4837
+ Address base) const {
4838
+ auto addr = projectExtraTagBits (IGF, base);
4839
+ if (ExtraTagTy->getBitWidth () != getExtraTagBitCountForExtraInhabitants ()) {
4840
+ addr = IGF.Builder .CreateBitCast (addr,
4841
+ llvm::IntegerType::get (IGF.IGM .getLLVMContext (),
4842
+ getExtraTagBitCountForExtraInhabitants ())
4843
+ ->getPointerTo ());
4844
+ }
4845
+ return addr;
4846
+ }
4823
4847
4824
4848
llvm::Value *getExtraInhabitantIndex (IRGenFunction &IGF,
4825
4849
Address src,
4826
4850
SILType T,
4827
4851
bool isOutlined) const override {
4828
- llvm_unreachable (" extra inhabitants for multi-payload enums not implemented" );
4852
+ // For dynamic layouts, the runtime provides a value witness to do this.
4853
+ if (TIK < Fixed) {
4854
+ return emitGetExtraInhabitantIndexCall (IGF, T, src);
4855
+ }
4856
+
4857
+ llvm::Value *tag;
4858
+ if (CommonSpareBits.count ()) {
4859
+ auto payload = EnumPayload::load (IGF, projectPayload (IGF, src),
4860
+ PayloadSchema);
4861
+ tag = payload.emitGatherSpareBits (IGF, CommonSpareBits, 0 , 32 );
4862
+ if (getExtraTagBitCountForExtraInhabitants ()) {
4863
+ auto extraTagAddr = projectExtraTagBitsForExtraInhabitants (IGF, src);
4864
+ auto extraTag = IGF.Builder .CreateLoad (extraTagAddr);
4865
+ auto extraTagBits =
4866
+ IGF.Builder .CreateZExtOrTrunc (extraTag, IGF.IGM .Int32Ty );
4867
+ extraTagBits =
4868
+ IGF.Builder .CreateShl (extraTagBits, CommonSpareBits.count ());
4869
+ tag = IGF.Builder .CreateOr (tag, extraTagBits);
4870
+ }
4871
+ } else {
4872
+ auto extraTagAddr = projectExtraTagBitsForExtraInhabitants (IGF, src);
4873
+ auto extraTag = IGF.Builder .CreateLoad (extraTagAddr);
4874
+ tag = IGF.Builder .CreateZExtOrTrunc (extraTag, IGF.IGM .Int32Ty );
4875
+ }
4876
+
4877
+ // Check whether it really is an extra inhabitant.
4878
+ auto tagBits = CommonSpareBits.count () + getExtraTagBitCountForExtraInhabitants ();
4879
+ auto maxTag = tagBits >= 32 ? ~0u : (1 << tagBits) - 1 ;
4880
+ auto index = IGF.Builder .CreateSub (
4881
+ llvm::ConstantInt::get (IGF.IGM .Int32Ty , maxTag),
4882
+ tag);
4883
+ auto isExtraInhabitant = IGF.Builder .CreateICmpULT (index,
4884
+ llvm::ConstantInt::get (IGF.IGM .Int32Ty ,
4885
+ getFixedExtraInhabitantCount (IGF.IGM )));
4886
+ return IGF.Builder .CreateSelect (isExtraInhabitant,
4887
+ index, llvm::ConstantInt::get (IGF.IGM .Int32Ty , -1 ));
4829
4888
}
4830
4889
4831
4890
void storeExtraInhabitant (IRGenFunction &IGF,
4832
4891
llvm::Value *index,
4833
4892
Address dest,
4834
4893
SILType T,
4835
4894
bool isOutlined) const override {
4836
- llvm_unreachable (" extra inhabitants for multi-payload enums not implemented" );
4895
+ // For dynamic layouts, the runtime provides a value witness to do this.
4896
+ if (TIK < Fixed) {
4897
+ emitStoreExtraInhabitantCall (IGF, T, index, dest);
4898
+ return ;
4899
+ }
4900
+
4901
+ auto indexValue = IGF.Builder .CreateNot (index);
4902
+ if (CommonSpareBits.count ()) {
4903
+ // Factor the index value into parts to scatter into the payload and
4904
+ // to store in the extra tag bits, if any.
4905
+ EnumPayload payload =
4906
+ interleaveSpareBits (IGF, PayloadSchema, CommonSpareBits, indexValue);
4907
+ payload.store (IGF, projectPayload (IGF, dest));
4908
+ if (getExtraTagBitCountForExtraInhabitants () > 0 ) {
4909
+ auto tagBits = IGF.Builder .CreateLShr (indexValue,
4910
+ llvm::ConstantInt::get (IGF.IGM .Int32Ty , CommonSpareBits.count ()));
4911
+ auto tagAddr = projectExtraTagBitsForExtraInhabitants (IGF, dest);
4912
+ tagBits = IGF.Builder .CreateZExtOrTrunc (tagBits,
4913
+ tagAddr.getAddress ()->getType ()->getPointerElementType ());
4914
+ IGF.Builder .CreateStore (tagBits, tagAddr);
4915
+ }
4916
+ } else {
4917
+ // Only need to store the tag value.
4918
+ auto tagAddr = projectExtraTagBitsForExtraInhabitants (IGF, dest);
4919
+ indexValue = IGF.Builder .CreateZExtOrTrunc (indexValue,
4920
+ tagAddr.getAddress ()->getType ()->getPointerElementType ());
4921
+ IGF.Builder .CreateStore (indexValue, tagAddr);
4922
+ }
4837
4923
}
4838
4924
4839
4925
APInt
4840
4926
getFixedExtraInhabitantMask (IRGenModule &IGM) const override {
4841
- // TODO may not always be all-ones
4842
- return APInt::getAllOnesValue (
4843
- cast<FixedTypeInfo>(TI)->getFixedSize ().getValueInBits ());
4927
+ // The extra inhabitant goes into the tag bits.
4928
+ auto tagBits = CommonSpareBits.asAPInt ();
4929
+ auto fixedTI = cast<FixedTypeInfo>(TI);
4930
+ if (getExtraTagBitCountForExtraInhabitants () > 0 ) {
4931
+ auto bitSize = fixedTI->getFixedSize ().getValueInBits ();
4932
+ tagBits = tagBits.zext (bitSize);
4933
+ auto extraTagMask = APInt::getAllOnesValue (bitSize)
4934
+ .shl (CommonSpareBits.size ());
4935
+ tagBits |= extraTagMask;
4936
+ }
4937
+ return tagBits;
4844
4938
}
4845
4939
4846
4940
unsigned getFixedExtraInhabitantCount (IRGenModule &IGM) const override {
4847
- return 0 ;
4941
+ unsigned totalTagBits = CommonSpareBits.count () + getExtraTagBitCountForExtraInhabitants ();
4942
+ if (totalTagBits >= 32 )
4943
+ return INT_MAX;
4944
+ unsigned totalTags = 1u << totalTagBits;
4945
+ return totalTags - ElementsWithPayload.size () - NumEmptyElementTags;
4848
4946
}
4849
4947
4850
4948
APInt
4851
4949
getFixedExtraInhabitantValue (IRGenModule &IGM,
4852
4950
unsigned bits,
4853
4951
unsigned index) const override {
4854
- llvm_unreachable (" extra inhabitants for multi-payload enums not implemented" );
4952
+ // Count down from all-ones since a small negative number constant is
4953
+ // likely to be easier to reify.
4954
+ auto mask = ~index;
4955
+ auto extraTagMask = getExtraTagBitCountForExtraInhabitants () >= 32
4956
+ ? ~0u : (1 << getExtraTagBitCountForExtraInhabitants ()) - 1 ;
4957
+
4958
+ if (auto payloadBitCount = CommonSpareBits.count ()) {
4959
+ auto payloadTagMask = payloadBitCount >= 32
4960
+ ? ~0u : (1 << payloadBitCount) - 1 ;
4961
+ auto payloadPart = mask & payloadTagMask;
4962
+ auto payloadBits = interleaveSpareBits (IGM, CommonSpareBits,
4963
+ bits, payloadPart, 0 );
4964
+ if (getExtraTagBitCountForExtraInhabitants () > 0 ) {
4965
+ auto extraBits = APInt (bits,
4966
+ (mask >> payloadBitCount) & extraTagMask)
4967
+ .shl (CommonSpareBits.size ());
4968
+ payloadBits |= extraBits;
4969
+ }
4970
+ return payloadBits;
4971
+ } else {
4972
+ auto value = APInt (bits, mask & extraTagMask);
4973
+ return value.shl (CommonSpareBits.size ());
4974
+ }
4855
4975
}
4856
4976
4857
4977
ClusteredBitVector
0 commit comments