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