92
92
// for the payload, resulting in a fixed-size lowering for recursive
93
93
// enums.
94
94
//
95
+ // For all lowerings except ResilientEnumImplStrategy, the primary enum
96
+ // operations are open-coded at usage sites. Resilient enums are accessed
97
+ // by invoking the value witnesses for these operations.
95
98
//
96
99
// ===----------------------------------------------------------------------===//
97
100
112
115
#include " IRGenModule.h"
113
116
#include " LoadableTypeInfo.h"
114
117
#include " NonFixedTypeInfo.h"
118
+ #include " ResilientTypeInfo.h"
115
119
#include " GenMeta.h"
116
120
#include " GenProto.h"
117
121
#include " GenType.h"
@@ -4047,6 +4051,305 @@ namespace {
4047
4051
return result;
4048
4052
}
4049
4053
};
4054
+
4055
+ class ResilientEnumImplStrategy final
4056
+ : public EnumImplStrategy
4057
+ {
4058
+ public:
4059
+ ResilientEnumImplStrategy (IRGenModule &IGM,
4060
+ unsigned NumElements,
4061
+ std::vector<Element> &&WithPayload,
4062
+ std::vector<Element> &&WithNoPayload)
4063
+ : EnumImplStrategy(IGM, Opaque, IsFixedSize,
4064
+ NumElements,
4065
+ std::move (WithPayload),
4066
+ std::move(WithNoPayload))
4067
+ { }
4068
+
4069
+ TypeInfo *completeEnumTypeLayout (TypeConverter &TC,
4070
+ SILType Type,
4071
+ EnumDecl *theEnum,
4072
+ llvm::StructType *enumTy) override ;
4073
+
4074
+ void destructiveProjectDataForLoad (IRGenFunction &IGF,
4075
+ SILType T,
4076
+ Address enumAddr) const override {
4077
+ emitDestructiveProjectEnumDataCall (IGF, T, enumAddr.getAddress ());
4078
+ }
4079
+
4080
+ void storeTag (IRGenFunction &IGF,
4081
+ SILType T,
4082
+ Address enumAddr,
4083
+ EnumElementDecl *Case) const override {
4084
+ llvm_unreachable (" resilient enums cannot be constructed directly" );
4085
+ }
4086
+
4087
+ llvm::Value *
4088
+ emitIndirectCaseTest (IRGenFunction &IGF, SILType T,
4089
+ Address enumAddr,
4090
+ EnumElementDecl *Case) const override {
4091
+ llvm::Value *tag = emitGetEnumTagCall (IGF, T, enumAddr.getAddress ());
4092
+ llvm::Value *expectedTag = llvm::ConstantInt::get (IGF.IGM .Int32Ty ,
4093
+ getTagIndex (Case));
4094
+ return IGF.Builder .CreateICmpEQ (tag, expectedTag);
4095
+ }
4096
+
4097
+ void emitIndirectSwitch (IRGenFunction &IGF,
4098
+ SILType T,
4099
+ Address enumAddr,
4100
+ ArrayRef<std::pair<EnumElementDecl*,
4101
+ llvm::BasicBlock*>> dests,
4102
+ llvm::BasicBlock *defaultDest) const override {
4103
+ // Switch on the tag value.
4104
+ llvm::Value *tag = emitGetEnumTagCall (IGF, T, enumAddr.getAddress ());
4105
+
4106
+ // Create a map of the destination blocks for quicker lookup.
4107
+ llvm::DenseMap<EnumElementDecl*,llvm::BasicBlock*> destMap (dests.begin (),
4108
+ dests.end ());
4109
+
4110
+ // Create an unreachable branch for unreachable switch defaults.
4111
+ auto &C = IGF.IGM .getLLVMContext ();
4112
+ auto *unreachableBB = llvm::BasicBlock::Create (C);
4113
+
4114
+ // If there was no default branch in SIL, use the unreachable branch as
4115
+ // the default.
4116
+ if (!defaultDest)
4117
+ defaultDest = unreachableBB;
4118
+
4119
+ auto *tagSwitch = IGF.Builder .CreateSwitch (tag, defaultDest, NumElements);
4120
+
4121
+ unsigned tagIndex = 0 ;
4122
+
4123
+ // Payload tags come first.
4124
+ for (auto &elt : ElementsWithPayload) {
4125
+ auto found = destMap.find (elt.decl );
4126
+ if (found != destMap.end ()) {
4127
+ auto tagVal = llvm::ConstantInt::get (IGF.IGM .Int32Ty , tagIndex);
4128
+ tagSwitch->addCase (tagVal, found->second );
4129
+ }
4130
+ ++tagIndex;
4131
+ }
4132
+
4133
+ // Next come empty tags.
4134
+ for (auto &elt : ElementsWithNoPayload) {
4135
+ auto found = destMap.find (elt.decl );
4136
+ if (found != destMap.end ()) {
4137
+ auto tagVal = llvm::ConstantInt::get (IGF.IGM .Int32Ty , tagIndex);
4138
+ tagSwitch->addCase (tagVal, found->second );
4139
+ }
4140
+ ++tagIndex;
4141
+ }
4142
+
4143
+ assert (tagIndex == NumElements);
4144
+
4145
+ // Delete the unreachable default block if we didn't use it, or emit it
4146
+ // if we did.
4147
+ if (unreachableBB->use_empty ()) {
4148
+ delete unreachableBB;
4149
+ } else {
4150
+ IGF.Builder .emitBlock (unreachableBB);
4151
+ IGF.Builder .CreateUnreachable ();
4152
+ }
4153
+ }
4154
+
4155
+ void assignWithCopy (IRGenFunction &IGF, Address dest, Address src,
4156
+ SILType T)
4157
+ const override {
4158
+ emitAssignWithCopyCall (IGF, T,
4159
+ dest.getAddress (), src.getAddress ());
4160
+ }
4161
+
4162
+ void assignWithTake (IRGenFunction &IGF, Address dest, Address src,
4163
+ SILType T)
4164
+ const override {
4165
+ emitAssignWithTakeCall (IGF, T,
4166
+ dest.getAddress (), src.getAddress ());
4167
+ }
4168
+
4169
+ void initializeWithCopy (IRGenFunction &IGF, Address dest, Address src,
4170
+ SILType T)
4171
+ const override {
4172
+ emitInitializeWithCopyCall (IGF, T,
4173
+ dest.getAddress (), src.getAddress ());
4174
+ }
4175
+
4176
+ void initializeWithTake (IRGenFunction &IGF, Address dest, Address src,
4177
+ SILType T)
4178
+ const override {
4179
+ emitInitializeWithTakeCall (IGF, T,
4180
+ dest.getAddress (), src.getAddress ());
4181
+ }
4182
+
4183
+ void destroy (IRGenFunction &IGF, Address addr, SILType T)
4184
+ const override {
4185
+ emitDestroyCall (IGF, T, addr.getAddress ());
4186
+ }
4187
+
4188
+ // \group Operations for loadable enums
4189
+
4190
+ ClusteredBitVector
4191
+ getTagBitsForPayloads () const override {
4192
+ llvm_unreachable (" resilient enums are always indirect" );
4193
+ }
4194
+
4195
+ ClusteredBitVector
4196
+ getBitPatternForNoPayloadElement (EnumElementDecl *theCase)
4197
+ const override {
4198
+ llvm_unreachable (" resilient enums are always indirect" );
4199
+ }
4200
+
4201
+ ClusteredBitVector
4202
+ getBitMaskForNoPayloadElements () const override {
4203
+ llvm_unreachable (" resilient enums are always indirect" );
4204
+ }
4205
+
4206
+ void initializeFromParams (IRGenFunction &IGF, Explosion ¶ms,
4207
+ Address dest, SILType T) const override {
4208
+ llvm_unreachable (" resilient enums are always indirect" );
4209
+ }
4210
+
4211
+ void emitValueInjection (IRGenFunction &IGF,
4212
+ EnumElementDecl *elt,
4213
+ Explosion ¶ms,
4214
+ Explosion &out) const override {
4215
+ llvm_unreachable (" resilient enums are always indirect" );
4216
+ }
4217
+
4218
+ llvm::Value *
4219
+ emitValueCaseTest (IRGenFunction &IGF, Explosion &value,
4220
+ EnumElementDecl *Case) const override {
4221
+ llvm_unreachable (" resilient enums are always indirect" );
4222
+ }
4223
+
4224
+ void emitValueSwitch (IRGenFunction &IGF,
4225
+ Explosion &value,
4226
+ ArrayRef<std::pair<EnumElementDecl*,
4227
+ llvm::BasicBlock*>> dests,
4228
+ llvm::BasicBlock *defaultDest) const override {
4229
+ llvm_unreachable (" resilient enums are always indirect" );
4230
+ }
4231
+
4232
+ void emitValueProject (IRGenFunction &IGF,
4233
+ Explosion &inValue,
4234
+ EnumElementDecl *theCase,
4235
+ Explosion &out) const override {
4236
+ llvm_unreachable (" resilient enums are always indirect" );
4237
+ }
4238
+
4239
+ void getSchema (ExplosionSchema &schema) const override {
4240
+ llvm_unreachable (" resilient enums are always indirect" );
4241
+ }
4242
+
4243
+ unsigned getExplosionSize () const override {
4244
+ llvm_unreachable (" resilient enums are always indirect" );
4245
+ }
4246
+
4247
+ void loadAsCopy (IRGenFunction &IGF, Address addr,
4248
+ Explosion &e) const override {
4249
+ llvm_unreachable (" resilient enums are always indirect" );
4250
+ }
4251
+
4252
+ void loadAsTake (IRGenFunction &IGF, Address addr,
4253
+ Explosion &e) const override {
4254
+ llvm_unreachable (" resilient enums are always indirect" );
4255
+ }
4256
+
4257
+ void assign (IRGenFunction &IGF, Explosion &e,
4258
+ Address addr) const override {
4259
+ llvm_unreachable (" resilient enums are always indirect" );
4260
+ }
4261
+
4262
+ void initialize (IRGenFunction &IGF, Explosion &e,
4263
+ Address addr) const override {
4264
+ llvm_unreachable (" resilient enums are always indirect" );
4265
+ }
4266
+
4267
+ void reexplode (IRGenFunction &IGF, Explosion &src,
4268
+ Explosion &dest) const override {
4269
+ llvm_unreachable (" resilient enums are always indirect" );
4270
+ }
4271
+
4272
+ void copy (IRGenFunction &IGF, Explosion &src, Explosion &dest)
4273
+ const override {
4274
+ llvm_unreachable (" resilient enums are always indirect" );
4275
+ }
4276
+
4277
+ void consume (IRGenFunction &IGF, Explosion &src) const override {
4278
+ llvm_unreachable (" resilient enums are always indirect" );
4279
+ }
4280
+
4281
+ void fixLifetime (IRGenFunction &IGF, Explosion &src) const override {
4282
+ llvm_unreachable (" resilient enums are always indirect" );
4283
+ }
4284
+
4285
+ void packIntoEnumPayload (IRGenFunction &IGF,
4286
+ EnumPayload &outerPayload,
4287
+ Explosion &src,
4288
+ unsigned offset) const override {
4289
+ llvm_unreachable (" resilient enums are always indirect" );
4290
+ }
4291
+
4292
+ void unpackFromEnumPayload (IRGenFunction &IGF,
4293
+ const EnumPayload &outerPayload,
4294
+ Explosion &dest,
4295
+ unsigned offset) const override {
4296
+ llvm_unreachable (" resilient enums are always indirect" );
4297
+ }
4298
+
4299
+ // / \group Operations for emitting type metadata
4300
+
4301
+ llvm::Value *
4302
+ emitGetEnumTag (IRGenFunction &IGF, SILType T, Address addr)
4303
+ const override {
4304
+ llvm_unreachable (" resilient enums cannot be defined" );
4305
+ }
4306
+
4307
+ bool needsPayloadSizeInMetadata () const override {
4308
+ llvm_unreachable (" resilient enums cannot be defined" );
4309
+ }
4310
+
4311
+ void initializeMetadata (IRGenFunction &IGF,
4312
+ llvm::Value *metadata,
4313
+ llvm::Value *vwtable,
4314
+ SILType T) const override {
4315
+ llvm_unreachable (" resilient enums cannot be defined" );
4316
+ }
4317
+
4318
+ // / \group Extra inhabitants
4319
+
4320
+ bool mayHaveExtraInhabitants (IRGenModule &) const override {
4321
+ return true ;
4322
+ }
4323
+
4324
+ llvm::Value *getExtraInhabitantIndex (IRGenFunction &IGF,
4325
+ Address src,
4326
+ SILType T) const override {
4327
+ return emitGetExtraInhabitantIndexCall (IGF, T, src.getAddress ());
4328
+ }
4329
+
4330
+ void storeExtraInhabitant (IRGenFunction &IGF,
4331
+ llvm::Value *index,
4332
+ Address dest,
4333
+ SILType T) const override {
4334
+ emitStoreExtraInhabitantCall (IGF, T, index , dest.getAddress ());
4335
+ }
4336
+
4337
+ APInt
4338
+ getFixedExtraInhabitantMask (IRGenModule &IGM) const override {
4339
+ llvm_unreachable (" resilient enum is not fixed size" );
4340
+ }
4341
+
4342
+ unsigned getFixedExtraInhabitantCount (IRGenModule &IGM) const override {
4343
+ llvm_unreachable (" resilient enum is not fixed size" );
4344
+ }
4345
+
4346
+ APInt
4347
+ getFixedExtraInhabitantValue (IRGenModule &IGM,
4348
+ unsigned bits,
4349
+ unsigned index) const override {
4350
+ llvm_unreachable (" resilient enum is not fixed size" );
4351
+ }
4352
+ };
4050
4353
} // end anonymous namespace
4051
4354
4052
4355
EnumImplStrategy *EnumImplStrategy::get (TypeConverter &TC,
@@ -4122,6 +4425,18 @@ EnumImplStrategy *EnumImplStrategy::get(TypeConverter &TC,
4122
4425
+ elementsWithNoPayload.size ()
4123
4426
&& " not all elements accounted for" );
4124
4427
4428
+ // Resilient enums are manipulated as opaque values, except we still
4429
+ // make the following assumptions:
4430
+ // 1) Physical case indices won't change
4431
+ // 2) The indirect-ness of cases won't change
4432
+ // 3) Payload types won't change in a non-resilient way
4433
+ if (TC.IGM .isResilient (theEnum, ResilienceScope::Component)) {
4434
+ return new ResilientEnumImplStrategy (TC.IGM ,
4435
+ numElements,
4436
+ std::move (elementsWithPayload),
4437
+ std::move (elementsWithNoPayload));
4438
+ }
4439
+
4125
4440
// Enums imported from Clang or marked with @objc use C-compatible layout.
4126
4441
if (theEnum->hasClangNode () || theEnum->isObjC ()) {
4127
4442
assert (elementsWithPayload.size () == 0 && " C enum with payload?!" );
@@ -4331,6 +4646,16 @@ namespace {
4331
4646
IsBitwiseTakable_t bt)
4332
4647
: EnumTypeInfoBase(strategy, irTy, align, pod, bt) {}
4333
4648
};
4649
+
4650
+ // / TypeInfo for dynamically-sized enum types.
4651
+ class ResilientEnumTypeInfo
4652
+ : public EnumTypeInfoBase<ResilientTypeInfo<ResilientEnumTypeInfo>>
4653
+ {
4654
+ public:
4655
+ ResilientEnumTypeInfo (EnumImplStrategy &strategy,
4656
+ llvm::Type *irTy)
4657
+ : EnumTypeInfoBase(strategy, irTy) {}
4658
+ };
4334
4659
} // end anonymous namespace
4335
4660
4336
4661
const EnumImplStrategy &
@@ -4789,12 +5114,26 @@ MultiPayloadEnumImplStrategy::completeEnumTypeLayout(TypeConverter &TC,
4789
5114
return completeDynamicLayout (TC, Type, theEnum, enumTy);
4790
5115
}
4791
5116
5117
+ TypeInfo *
5118
+ ResilientEnumImplStrategy::completeEnumTypeLayout (TypeConverter &TC,
5119
+ SILType Type,
5120
+ EnumDecl *theEnum,
5121
+ llvm::StructType *enumTy) {
5122
+ return registerEnumTypeInfo (new ResilientEnumTypeInfo (*this , enumTy));
5123
+ }
5124
+
4792
5125
const TypeInfo *TypeConverter::convertEnumType (TypeBase *key, CanType type,
4793
5126
EnumDecl *theEnum) {
4794
- llvm::StructType *convertedStruct = IGM.createNominalType (theEnum);
5127
+ llvm::StructType *storageType;
5128
+
5129
+ // Resilient enum types lower down to the same opaque type.
5130
+ if (IGM.isResilient (theEnum, ResilienceScope::Component))
5131
+ storageType = cast<llvm::StructType>(IGM.OpaquePtrTy ->getElementType ());
5132
+ else
5133
+ storageType = IGM.createNominalType (theEnum);
4795
5134
4796
5135
// Create a forward declaration for that type.
4797
- addForwardDecl (key, convertedStruct );
5136
+ addForwardDecl (key, storageType );
4798
5137
4799
5138
SILType loweredTy = SILType::getPrimitiveAddressType (type);
4800
5139
@@ -4803,7 +5142,7 @@ const TypeInfo *TypeConverter::convertEnumType(TypeBase *key, CanType type,
4803
5142
4804
5143
// Create the TI.
4805
5144
auto *ti = strategy->completeEnumTypeLayout (*this , loweredTy,
4806
- theEnum, convertedStruct );
5145
+ theEnum, storageType );
4807
5146
// Assert that the layout query functions for fixed-layout enums work, for
4808
5147
// LLDB's sake.
4809
5148
#ifndef NDEBUG
0 commit comments