Skip to content

Commit 34aca68

Browse files
Merge pull request #12697 from aschwaighofer/reapply_enum_witness
Reapply the enum value witness patch
2 parents b57ee8d + a77911e commit 34aca68

38 files changed

+1243
-347
lines changed

include/swift/ABI/ValueWitness.def

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
/// TYPE_TYPE - a pointer to type metadata
7575
/// SIZE_TYPE - size_t
7676
/// INT_TYPE - int
77+
/// UINT_TYPE - unsigned int
7778
/// VOID_TYPE - void
7879
/// Defaults to VALUE_WITNESS.
7980
/// FIXME: The 'copy' witnesses should be using immutable types but aren't.
@@ -179,8 +180,26 @@ FUNCTION_VALUE_WITNESS(initializeBufferWithTakeOfBuffer,
179180
MUTABLE_VALUE_TYPE,
180181
(MUTABLE_BUFFER_TYPE, MUTABLE_BUFFER_TYPE, TYPE_TYPE))
181182

183+
/// int (*getEnumTagSinglePayload)(const T* enum, UINT_TYPE emptyCases)
184+
/// Given an instance of valid single payload enum with a payload of this
185+
/// witness table's type (e.g Optional<ThisType>) , get the tag of the enum.
186+
FUNCTION_VALUE_WITNESS(getEnumTagSinglePayload,
187+
GetEnumTagSinglePayload,
188+
INT_TYPE,
189+
(IMMUTABLE_VALUE_TYPE, UINT_TYPE, TYPE_TYPE))
190+
191+
/// void (*storeEnumTagSinglePayload)(T* enum, INT_TYPE whichCase,
192+
/// UINT_TYPE emptyCases)
193+
/// Given uninitialized memory for an instance of a single payload enum with a
194+
/// payload of this witness table's type (e.g Optional<ThisType>), store the
195+
/// tag.
196+
FUNCTION_VALUE_WITNESS(storeEnumTagSinglePayload,
197+
StoreEnumTagSinglePayload,
198+
VOID_TYPE,
199+
(MUTABLE_VALUE_TYPE, INT_TYPE, UINT_TYPE, TYPE_TYPE))
200+
182201
END_VALUE_WITNESS_RANGE(RequiredValueWitnessFunction,
183-
InitializeBufferWithTakeOfBuffer)
202+
StoreEnumTagSinglePayload)
184203

185204
/// size_t size;
186205
///

include/swift/Demangling/ValueWitnessMangling.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,7 @@ VALUE_WITNESS(xg, GetExtraInhabitantIndex)
3535
VALUE_WITNESS(ug, GetEnumTag)
3636
VALUE_WITNESS(up, DestructiveProjectEnumData)
3737
VALUE_WITNESS(ui, DestructiveInjectEnumTag)
38+
VALUE_WITNESS(et, GetEnumTagSinglePayload)
39+
VALUE_WITNESS(st, StoreEnumTagSinglePayload)
3840

3941
#undef VALUE_WITNESS

include/swift/Runtime/Metadata.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ namespace value_witness_types {
357357
#define TYPE_TYPE const Metadata *
358358
#define SIZE_TYPE size_t
359359
#define INT_TYPE int
360+
#define UINT_TYPE unsigned
360361
#define VOID_TYPE void
361362
#include "swift/ABI/ValueWitness.def"
362363

lib/Demangling/NodePrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,10 @@ static StringRef toString(ValueWitnessKind k) {
149149
return "destructiveProjectEnumData";
150150
case ValueWitnessKind::DestructiveInjectEnumTag:
151151
return "destructiveInjectEnumTag";
152+
case ValueWitnessKind::GetEnumTagSinglePayload:
153+
return "getEnumTagSinglePayload";
154+
case ValueWitnessKind::StoreEnumTagSinglePayload:
155+
return "storeEnumTagSinglePayload";
152156
}
153157
printer_unreachable("bad value witness kind");
154158
}

lib/IRGen/FixedTypeInfo.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,16 @@ class FixedTypeInfo : public TypeInfo {
227227
llvm::Value *metadata,
228228
llvm::Value *vwtable,
229229
SILType T) const override {}
230-
230+
231+
llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
232+
llvm::Value *numEmptyCases,
233+
Address enumAddr,
234+
SILType T) const override;
235+
236+
void storeEnumTagSinglePayload(IRGenFunction &IGF, llvm::Value *whichCase,
237+
llvm::Value *numEmptyCases, Address enumAddr,
238+
SILType T) const override;
239+
231240
static bool classof(const FixedTypeInfo *type) { return true; }
232241
static bool classof(const TypeInfo *type) { return type->isFixedSize(); }
233242
};

lib/IRGen/GenEnum.cpp

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,19 +1591,17 @@ namespace {
15911591
/// Emit a call into the runtime to get the current enum payload tag.
15921592
/// This returns a tag index in the range
15931593
/// [-ElementsWithPayload..ElementsWithNoPayload-1].
1594-
llvm::Value *
1595-
emitGetEnumTag(IRGenFunction &IGF, SILType T, Address enumAddr)
1596-
const override {
1597-
auto payloadMetadata = emitPayloadMetadataForLayout(IGF, T);
1598-
auto numEmptyCases = llvm::ConstantInt::get(IGF.IGM.Int32Ty,
1599-
ElementsWithNoPayload.size());
1600-
1601-
auto opaqueAddr = IGF.Builder.CreateBitCast(enumAddr.getAddress(),
1602-
IGF.IGM.OpaquePtrTy);
1594+
llvm::Value *emitGetEnumTag(IRGenFunction &IGF, SILType T,
1595+
Address enumAddr) const override {
1596+
auto numEmptyCases =
1597+
llvm::ConstantInt::get(IGF.IGM.Int32Ty, ElementsWithNoPayload.size());
16031598

1604-
return IGF.Builder.CreateCall(
1605-
IGF.IGM.getGetEnumCaseSinglePayloadFn(),
1606-
{opaqueAddr, payloadMetadata, numEmptyCases});
1599+
auto PayloadT = getPayloadType(IGF.IGM, T);
1600+
auto opaqueAddr = Address(
1601+
IGF.Builder.CreateBitCast(enumAddr.getAddress(), IGF.IGM.OpaquePtrTy),
1602+
enumAddr.getAlignment());
1603+
return emitGetEnumTagSinglePayloadCall(IGF, PayloadT, numEmptyCases,
1604+
opaqueAddr);
16071605
}
16081606

16091607
/// The payload for a single-payload enum is always placed in front and
@@ -2411,16 +2409,16 @@ namespace {
24112409
}
24122410
return;
24132411
}
2412+
llvm::Value *opaqueAddr =
2413+
IGF.Builder.CreateBitCast(dest.getAddress(), IGF.IGM.OpaquePtrTy);
24142414

2415-
// Ask the runtime to store the tag.
2416-
llvm::Value *opaqueAddr = IGF.Builder.CreateBitCast(dest.getAddress(),
2417-
IGF.IGM.OpaquePtrTy);
2418-
llvm::Value *metadata = emitPayloadMetadataForLayout(IGF, T);
2419-
IGF.Builder.CreateCall(IGF.IGM.getStoreEnumTagSinglePayloadFn(),
2420-
{opaqueAddr, metadata,
2421-
llvm::ConstantInt::getSigned(IGF.IGM.Int32Ty, -1),
2422-
llvm::ConstantInt::get(IGF.IGM.Int32Ty,
2423-
ElementsWithNoPayload.size())});
2415+
auto PayloadT = getPayloadType(IGF.IGM, T);
2416+
auto Addr = Address(opaqueAddr, dest.getAlignment());
2417+
auto *whichCase = llvm::ConstantInt::getSigned(IGF.IGM.Int32Ty, -1);
2418+
auto *numEmptyCases =
2419+
llvm::ConstantInt::get(IGF.IGM.Int32Ty, ElementsWithNoPayload.size());
2420+
emitStoreEnumTagSinglePayloadCall(IGF, PayloadT, whichCase, numEmptyCases,
2421+
Addr);
24242422
}
24252423

24262424
/// Emit a reassignment sequence from an enum at one address to another.
@@ -2625,7 +2623,6 @@ namespace {
26252623
EnumElementDecl *Case) const override {
26262624
if (TIK < Fixed) {
26272625
// If the enum isn't fixed-layout, get the runtime to do this for us.
2628-
llvm::Value *payload = emitPayloadMetadataForLayout(IGF, T);
26292626
llvm::Value *caseIndex;
26302627
if (Case == getPayloadElement()) {
26312628
caseIndex = llvm::ConstantInt::getSigned(IGF.IGM.Int32Ty, -1);
@@ -2645,10 +2642,10 @@ namespace {
26452642
llvm::Value *opaqueAddr
26462643
= IGF.Builder.CreateBitCast(enumAddr.getAddress(),
26472644
IGF.IGM.OpaquePtrTy);
2648-
2649-
IGF.Builder.CreateCall(IGF.IGM.getStoreEnumTagSinglePayloadFn(),
2650-
{opaqueAddr, payload, caseIndex, numEmptyCases});
2651-
2645+
auto PayloadT = getPayloadType(IGF.IGM, T);
2646+
auto Addr = Address(opaqueAddr, enumAddr.getAlignment());
2647+
emitStoreEnumTagSinglePayloadCall(IGF, PayloadT, caseIndex,
2648+
numEmptyCases, Addr);
26522649
return;
26532650
}
26542651

@@ -2675,20 +2672,18 @@ namespace {
26752672

26762673
/// Constructs an enum value using a tag index in the range
26772674
/// [-ElementsWithPayload..ElementsWithNoPayload-1].
2678-
void emitStoreTag(IRGenFunction &IGF,
2679-
SILType T,
2680-
Address enumAddr,
2675+
void emitStoreTag(IRGenFunction &IGF, SILType T, Address enumAddr,
26812676
llvm::Value *tag) const override {
2682-
llvm::Value *payload = emitPayloadMetadataForLayout(IGF, T);
2683-
llvm::Value *numEmptyCases = llvm::ConstantInt::get(IGF.IGM.Int32Ty,
2684-
ElementsWithNoPayload.size());
2685-
2677+
auto PayloadT = getPayloadType(IGF.IGM, T);
26862678
llvm::Value *opaqueAddr
26872679
= IGF.Builder.CreateBitCast(enumAddr.getAddress(),
2688-
IGF.IGM.OpaquePtrTy);
2680+
IGF.IGM.OpaquePtrTy);
26892681

2690-
IGF.Builder.CreateCall(IGF.IGM.getStoreEnumTagSinglePayloadFn(),
2691-
{opaqueAddr, payload, tag, numEmptyCases});
2682+
llvm::Value *numEmptyCases = llvm::ConstantInt::get(IGF.IGM.Int32Ty,
2683+
ElementsWithNoPayload.size());
2684+
auto Addr = Address(opaqueAddr, enumAddr.getAlignment());
2685+
emitStoreEnumTagSinglePayloadCall(IGF, PayloadT, tag, numEmptyCases,
2686+
Addr);
26922687
}
26932688

26942689
void initializeMetadata(IRGenFunction &IGF,

lib/IRGen/GenOpaque.cpp

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "llvm/ADT/SmallString.h"
2424
#include "llvm/Support/raw_ostream.h"
2525
#include "llvm/IR/DerivedTypes.h"
26+
#include "swift/AST/IRGenOptions.h"
2627
#include "swift/IRGen/ValueWitness.h"
2728

2829
#include "Callee.h"
@@ -141,13 +142,38 @@ static llvm::Type *createWitnessType(IRGenModule &IGM, ValueWitness index) {
141142
return llvm::FunctionType::get(voidTy, args, /*isVarArg*/ false);
142143
}
143144

145+
/// int (*getEnumTagSinglePayload)(const T* enum, UINT_TYPE emptyCases,
146+
/// M *self)
147+
case ValueWitness::GetEnumTagSinglePayload: {
148+
llvm::Type *ptrTy = IGM.OpaquePtrTy;
149+
llvm::Type *indexTy = IGM.Int32Ty;
150+
llvm::Type *metaTy = IGM.TypeMetadataPtrTy;
151+
152+
llvm::Type *args[] = { ptrTy, indexTy, metaTy };
153+
return llvm::FunctionType::get(indexTy, args, false);
154+
}
155+
156+
/// void (*storeEnumTagSinglePayload)(T* enum, INT_TYPE whichCase,
157+
/// UINT_TYPE emptyCases,
158+
/// M *self)
159+
case ValueWitness::StoreEnumTagSinglePayload: {
160+
llvm::Type *voidTy = IGM.VoidTy;
161+
llvm::Type *ptrTy = IGM.OpaquePtrTy;
162+
llvm::Type *indexTy = IGM.Int32Ty;
163+
llvm::Type *metaTy = IGM.TypeMetadataPtrTy;
164+
165+
llvm::Type *args[] = { ptrTy, indexTy, indexTy, metaTy };
166+
return llvm::FunctionType::get(voidTy, args, false);
167+
}
168+
144169
case ValueWitness::Size:
145170
case ValueWitness::Flags:
146171
case ValueWitness::Stride:
147172
case ValueWitness::ExtraInhabitantFlags:
148173
// Non-function witnesses all have type size_t.
149174
return IGM.SizeTy;
150175
}
176+
151177
llvm_unreachable("bad value witness!");
152178
}
153179

@@ -173,8 +199,15 @@ static llvm::AttributeList getValueWitnessAttrs(IRGenModule &IGM,
173199
case ValueWitness::GetEnumTag:
174200
case ValueWitness::GetExtraInhabitantIndex:
175201
case ValueWitness::StoreExtraInhabitant:
202+
case ValueWitness::StoreEnumTagSinglePayload:
176203
return attrs.addAttribute(ctx, 1, llvm::Attribute::NoAlias);
177204

205+
case ValueWitness::GetEnumTagSinglePayload:
206+
return attrs
207+
.addAttribute(ctx, llvm::AttributeList::FunctionIndex,
208+
llvm::Attribute::ReadOnly)
209+
.addAttribute(ctx, 1, llvm::Attribute::NoAlias);
210+
178211
// These have two arguments and they don't alias each other.
179212
case ValueWitness::AssignWithTake:
180213
case ValueWitness::InitializeBufferWithCopyOfBuffer:
@@ -245,6 +278,10 @@ static StringRef getValueWitnessLabel(ValueWitness index) {
245278
return "destructiveProjectEnumData";
246279
case ValueWitness::DestructiveInjectEnumTag:
247280
return "destructiveInjectEnumTag";
281+
case ValueWitness::GetEnumTagSinglePayload:
282+
return "getEnumTagSinglePayload";
283+
case ValueWitness::StoreEnumTagSinglePayload:
284+
return "storeEnumTagSinglePayload";
248285
}
249286
llvm_unreachable("bad value witness index");
250287
}
@@ -635,6 +672,107 @@ llvm::Value *irgen::emitStoreExtraInhabitantCall(IRGenFunction &IGF,
635672
return call;
636673
}
637674

675+
/// Emit a trampoline to call the getEnumTagSinglePayload witness. API:
676+
/// INT_TYPE (const T* enum, UINT_TYPE emptyCases, M *self)
677+
static llvm::Constant *
678+
getGetEnumTagSinglePayloadTrampolineFn(IRGenModule &IGM) {
679+
680+
llvm::Type *argTys[] = {IGM.OpaquePtrTy, IGM.Int32Ty, IGM.TypeMetadataPtrTy};
681+
682+
llvm::SmallString<40> fnName("__swift_getEnumTagSinglePayload");
683+
684+
auto func = IGM.getOrCreateHelperFunction(
685+
fnName, IGM.Int32Ty, argTys,
686+
[&](IRGenFunction &IGF) {
687+
auto it = IGF.CurFn->arg_begin();
688+
auto *enumAddr = &*(it++);
689+
auto *numEmptyCases = &*(it++);
690+
auto *metadata = &*(it++);
691+
auto &Builder = IGF.Builder;
692+
auto witnessFunc = emitLoadOfValueWitnessFunctionFromMetadata(
693+
IGF, metadata, ValueWitness::GetEnumTagSinglePayload);
694+
auto *result = Builder.CreateCall(witnessFunc,
695+
{enumAddr, numEmptyCases, metadata});
696+
Builder.CreateRet(result);
697+
},
698+
true /*noinline*/);
699+
700+
// This function is readonly.
701+
cast<llvm::Function>(func)->addFnAttr(llvm::Attribute::ReadOnly);
702+
return func;
703+
}
704+
705+
/// Emit a trampoline to call the storeEnumTagSinglePayload witness. API:
706+
/// VOID_TYPE (const T* enum, INT_TYPE whichCase, UINT_TYPE emptyCases,
707+
/// M *self)
708+
static llvm::Constant *
709+
getStoreEnumTagSinglePayloadTrampolineFn(IRGenModule &IGM) {
710+
711+
llvm::Type *argTys[] = {IGM.OpaquePtrTy, IGM.Int32Ty, IGM.Int32Ty,
712+
IGM.TypeMetadataPtrTy};
713+
714+
llvm::SmallString<40> fnName("__swift_storeEnumTagSinglePayload");
715+
716+
return IGM.getOrCreateHelperFunction(
717+
fnName, IGM.VoidTy, argTys,
718+
[&](IRGenFunction &IGF) {
719+
auto it = IGF.CurFn->arg_begin();
720+
auto *enumAddr = &*(it++);
721+
auto *whichCase = &*(it++);
722+
auto *numEmptyCases = &*(it++);
723+
auto *metadata = &*(it++);
724+
auto &Builder = IGF.Builder;
725+
auto witnessFunc = emitLoadOfValueWitnessFunctionFromMetadata(
726+
IGF, metadata, ValueWitness::StoreEnumTagSinglePayload);
727+
Builder.CreateCall(witnessFunc,
728+
{enumAddr, whichCase, numEmptyCases, metadata});
729+
Builder.CreateRetVoid();
730+
},
731+
true /*noinline*/);
732+
}
733+
734+
llvm::Value *irgen::emitGetEnumTagSinglePayloadCall(IRGenFunction &IGF,
735+
SILType T,
736+
llvm::Value *numEmptyCases,
737+
Address destObject) {
738+
if (!IGF.IGM.getOptions().OptimizeForSize) {
739+
llvm::Value *metadata;
740+
auto fn = IGF.emitValueWitnessFunctionRef(
741+
T, metadata, ValueWitness::GetEnumTagSinglePayload);
742+
llvm::CallInst *call = IGF.Builder.CreateCall(
743+
fn, {destObject.getAddress(), numEmptyCases, metadata});
744+
return call;
745+
}
746+
auto *metadata = IGF.emitTypeMetadataRefForLayout(T);
747+
auto *func = getGetEnumTagSinglePayloadTrampolineFn(IGF.IGM);
748+
auto *result = IGF.Builder.CreateCall(
749+
func,
750+
{IGF.Builder.CreateBitCast(destObject.getAddress(), IGF.IGM.OpaquePtrTy),
751+
numEmptyCases, metadata});
752+
return result;
753+
}
754+
755+
llvm::Value *irgen::emitStoreEnumTagSinglePayloadCall(
756+
IRGenFunction &IGF, SILType T, llvm::Value *whichCase,
757+
llvm::Value *numEmptyCases, Address destObject) {
758+
if (!IGF.IGM.getOptions().OptimizeForSize) {
759+
llvm::Value *metadata;
760+
auto fn = IGF.emitValueWitnessFunctionRef(
761+
T, metadata, ValueWitness::StoreEnumTagSinglePayload);
762+
llvm::CallInst *call = IGF.Builder.CreateCall(
763+
fn, {destObject.getAddress(), whichCase, numEmptyCases, metadata});
764+
return call;
765+
}
766+
767+
auto *metadata = IGF.emitTypeMetadataRefForLayout(T);
768+
auto *func = getStoreEnumTagSinglePayloadTrampolineFn(IGF.IGM);
769+
auto *result = IGF.Builder.CreateCall(
770+
func,
771+
{IGF.Builder.CreateBitCast(destObject.getAddress(), IGF.IGM.OpaquePtrTy),
772+
whichCase, numEmptyCases, metadata});
773+
return result;
774+
}
775+
638776
/// Emit a call to the 'getEnumTag' operation.
639777
llvm::Value *irgen::emitGetEnumTagCall(IRGenFunction &IGF,
640778
SILType T,

lib/IRGen/GenOpaque.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,17 @@ namespace irgen {
180180
llvm::Value *index,
181181
Address destObject);
182182

183+
/// Emit a call to the 'getEnumTagSinglePayload' operation.
184+
llvm::Value *emitGetEnumTagSinglePayloadCall(IRGenFunction &IGF, SILType T,
185+
llvm::Value *numEmptyCases,
186+
Address destObject);
187+
188+
/// Emit a call to the 'storeEnumTagSinglePayload' operation.
189+
llvm::Value *emitStoreEnumTagSinglePayloadCall(IRGenFunction &IGF, SILType T,
190+
llvm::Value *whichCase,
191+
llvm::Value *numEmptyCases,
192+
Address destObject);
193+
183194
/// Emit a call to the 'getEnumTag' operation.
184195
llvm::Value *emitGetEnumTagCall(IRGenFunction &IGF,
185196
SILType T,

0 commit comments

Comments
 (0)