Skip to content

Commit 2e4ad96

Browse files
committed
IRGen: Make resilient enum's tag indices resilient
This allows reordering enum cases resiliently. rdar://24057946
1 parent 144d78c commit 2e4ad96

File tree

16 files changed

+157
-34
lines changed

16 files changed

+157
-34
lines changed

docs/ABI/Mangling.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ Globals
8888
global ::= type protocol-conformance 'Wl' // lazy protocol witness table accessor
8989
global ::= type 'WV' // value witness table
9090
global ::= entity 'Wv' DIRECTNESS // field offset
91+
global ::= entity 'WC' // resilient enum tag index
9192

9293
global ::= type 'Wy' // Outlined Copy Function Type
9394
global ::= type 'We' // Outlined Consume Function Type

include/swift/Demangling/DemangleNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ NODE(DynamicAttribute)
6262
NODE(DirectMethodReferenceAttribute)
6363
NODE(DynamicSelf)
6464
CONTEXT_NODE(Enum)
65+
NODE(EnumCase)
6566
NODE(ErrorType)
6667
NODE(EscapingAutoClosureType)
6768
NODE(NoEscapeFunctionType)

include/swift/IRGen/Linking.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ class LinkEntity {
116116
/// ConstructorDecl* inside a protocol or a class.
117117
DispatchThunkAllocator,
118118

119+
/// A resilient enum tag index. The pointer is a EnumElementDecl*.
120+
EnumCase,
121+
119122
/// A field offset. The pointer is a VarDecl*.
120123
FieldOffset,
121124

@@ -434,6 +437,12 @@ class LinkEntity {
434437
return entity;
435438
}
436439

440+
static LinkEntity forEnumCase(EnumElementDecl *decl) {
441+
LinkEntity entity;
442+
entity.setForDecl(Kind::EnumCase, decl);
443+
return entity;
444+
}
445+
437446
static LinkEntity forObjCClassRef(ClassDecl *decl) {
438447
LinkEntity entity;
439448
entity.setForDecl(Kind::ObjCClassRef, decl);

lib/Demangling/Demangler.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2049,6 +2049,9 @@ NodePointer Demangler::demangleSpecAttributes(Node::Kind SpecKind,
20492049

20502050
NodePointer Demangler::demangleWitness() {
20512051
switch (nextChar()) {
2052+
case 'C':
2053+
return createWithChild(Node::Kind::EnumCase,
2054+
popNode(isEntity));
20522055
case 'V':
20532056
return createWithChild(Node::Kind::ValueWitnessTable,
20542057
popNode(Node::Kind::Type));

lib/Demangling/NodePrinter.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ class NodePrinter {
333333
case Node::Kind::NoEscapeFunctionType:
334334
case Node::Kind::ExplicitClosure:
335335
case Node::Kind::Extension:
336+
case Node::Kind::EnumCase:
336337
case Node::Kind::FieldOffset:
337338
case Node::Kind::FullTypeMetadata:
338339
case Node::Kind::Function:
@@ -1397,6 +1398,12 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
13971398
print(entity, /*asContext*/ false);
13981399
return nullptr;
13991400
}
1401+
case Node::Kind::EnumCase: {
1402+
Printer << "enum case for ";
1403+
auto entity = Node->getChild(0);
1404+
print(entity, /*asContext*/ false);
1405+
return nullptr;
1406+
}
14001407
case Node::Kind::ReabstractionThunk:
14011408
case Node::Kind::ReabstractionThunkHelper: {
14021409
if (Options.ShortenThunk) {

lib/Demangling/OldRemangler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,11 @@ void Remangler::mangleFieldOffset(Node *node) {
811811
mangleChildNodes(node); // directness, entity
812812
}
813813

814+
void Remangler::mangleEnumCase(Node *node) {
815+
Out << "WC";
816+
mangleSingleChildNode(node); // enum case
817+
}
818+
814819
void Remangler::mangleProtocolWitnessTable(Node *node) {
815820
Out << "WP";
816821
mangleSingleChildNode(node); // protocol conformance

lib/Demangling/Remangler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,11 @@ void Remangler::mangleFieldOffset(Node *node) {
884884
mangleChildNode(node, 0); // directness
885885
}
886886

887+
void Remangler::mangleEnumCase(Node *node) {
888+
mangleSingleChildNode(node); // enum case
889+
Buffer << "WC";
890+
}
891+
887892
void Remangler::mangleFullTypeMetadata(Node *node) {
888893
mangleSingleChildNode(node);
889894
Buffer << "Mf";

lib/IRGen/GenDecl.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,6 +1520,12 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const {
15201520
case Kind::CoroutineContinuationPrototype:
15211521
return SILLinkage::PublicExternal;
15221522

1523+
1524+
case Kind::EnumCase: {
1525+
auto *elementDecl = cast<EnumElementDecl>(getDecl());
1526+
return getSILLinkage(getDeclLinkage(elementDecl), forDefinition);
1527+
}
1528+
15231529
case Kind::FieldOffset: {
15241530
auto *varDecl = cast<VarDecl>(getDecl());
15251531

@@ -1643,6 +1649,9 @@ bool LinkEntity::isAvailableExternally(IRGenModule &IGM) const {
16431649
case Kind::ProtocolDescriptor:
16441650
return ::isAvailableExternally(IGM, getDecl());
16451651

1652+
case Kind::EnumCase:
1653+
return ::isAvailableExternally(IGM, getDecl());
1654+
16461655
case Kind::DirectProtocolWitnessTable:
16471656
case Kind::ProtocolConformanceDescriptor:
16481657
return ::isAvailableExternally(IGM, getProtocolConformance()->getDeclContext());
@@ -3557,6 +3566,13 @@ Address IRGenModule::getAddrOfFieldOffset(VarDecl *var,
35573566
forDefinition);
35583567
}
35593568

3569+
Address IRGenModule::getAddrOfEnumCase(EnumElementDecl *Case,
3570+
ForDefinition_t forDefinition) {
3571+
LinkEntity entity = LinkEntity::forEnumCase(Case);
3572+
return getAddrOfSimpleVariable(*this, GlobalVars, entity, Int32Ty,
3573+
getPointerAlignment(), forDefinition);
3574+
}
3575+
35603576
void IRGenModule::emitNestedTypeDecls(DeclRange members) {
35613577
for (Decl *member : members) {
35623578
switch (member->getKind()) {

lib/IRGen/GenEnum.cpp

Lines changed: 65 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
#include "swift/AST/Decl.h"
108108
#include "swift/AST/Expr.h"
109109
#include "swift/AST/IRGenOptions.h"
110+
#include "swift/IRGen/Linking.h"
110111
#include "swift/SIL/SILModule.h"
111112
#include "llvm/IR/Function.h"
112113
#include "llvm/IR/GlobalVariable.h"
@@ -239,6 +240,25 @@ irgen::EnumImplStrategy::getResilientTagIndex(EnumElementDecl *Case) const {
239240
return getTagIndex(Case) - ElementsWithPayload.size();
240241
}
241242

243+
static void emitResilientTagIndex(IRGenModule &IGM,
244+
const EnumImplStrategy *strategy,
245+
EnumElementDecl *Case) {
246+
auto resilientIdx = strategy->getResilientTagIndex(Case);
247+
auto global = IGM.getAddrOfEnumCase(Case, ForDefinition);
248+
cast<llvm::GlobalVariable>(global.getAddress())
249+
->setInitializer(llvm::ConstantInt::get(IGM.Int32Ty, resilientIdx));
250+
}
251+
252+
void
253+
irgen::EnumImplStrategy::emitResilientTagIndices(IRGenModule &IGM) const {
254+
for (auto &payload : ElementsWithPayload) {
255+
emitResilientTagIndex(IGM, this, payload.decl);
256+
}
257+
for (auto &noPayload : ElementsWithNoPayload) {
258+
emitResilientTagIndex(IGM, this, noPayload.decl);
259+
}
260+
}
261+
242262
namespace {
243263
/// Implementation strategy for singleton enums, with zero or one cases.
244264
class SingletonEnumImplStrategy final : public EnumImplStrategy {
@@ -4863,6 +4883,17 @@ namespace {
48634883
std::move(WithNoPayload))
48644884
{ }
48654885

4886+
int getResilientTagIndex(EnumElementDecl *) const override {
4887+
// Resilient enum's should load the tag index from a global.
4888+
llvm_unreachable("Use loadResilientTagIndex instead");
4889+
}
4890+
4891+
llvm::Value *loadResilientTagIndex(IRGenFunction &IGF,
4892+
EnumElementDecl *Case) const {
4893+
auto address = IGF.IGM.getAddrOfEnumCase(Case, NotForDefinition);
4894+
return IGF.Builder.CreateLoad(address);
4895+
}
4896+
48664897
TypeInfo *completeEnumTypeLayout(TypeConverter &TC,
48674898
SILType Type,
48684899
EnumDecl *theEnum,
@@ -4878,8 +4909,7 @@ namespace {
48784909
SILType T,
48794910
Address enumAddr,
48804911
EnumElementDecl *Case) const override {
4881-
emitDestructiveInjectEnumTagCall(IGF, T,
4882-
getResilientTagIndex(Case),
4912+
emitDestructiveInjectEnumTagCall(IGF, T, loadResilientTagIndex(IGF, Case),
48834913
enumAddr);
48844914
}
48854915

@@ -4888,9 +4918,7 @@ namespace {
48884918
Address enumAddr,
48894919
EnumElementDecl *Case) const override {
48904920
llvm::Value *tag = emitGetEnumTagCall(IGF, T, enumAddr);
4891-
llvm::Value *expectedTag =
4892-
llvm::ConstantInt::get(IGF.IGM.Int32Ty,
4893-
getResilientTagIndex(Case));
4921+
llvm::Value *expectedTag = loadResilientTagIndex(IGF, Case);
48944922
return IGF.Builder.CreateICmpEQ(tag, expectedTag);
48954923
}
48964924

@@ -4916,20 +4944,27 @@ namespace {
49164944
if (!defaultDest)
49174945
defaultDest = unreachableBB;
49184946

4919-
auto tagSwitch = SwitchBuilder::create(IGF, tag,
4920-
SwitchDefaultDest(defaultDest,
4921-
defaultDest == unreachableBB
4922-
? IsUnreachable
4923-
: IsNotUnreachable),
4924-
dests.size());
4947+
llvm::BasicBlock *continuationBB = nullptr;
4948+
4949+
unsigned numCasesEmitted = 0;
49254950

49264951
auto emitCase = [&](Element elt) {
4927-
auto tagVal =
4928-
llvm::ConstantInt::get(IGF.IGM.Int32Ty,
4929-
getResilientTagIndex(elt.decl));
49304952
auto found = destMap.find(elt.decl);
4931-
if (found != destMap.end())
4932-
tagSwitch->addCase(tagVal, found->second);
4953+
if (found != destMap.end()) {
4954+
if (continuationBB)
4955+
IGF.Builder.emitBlock(continuationBB);
4956+
4957+
auto tagVal = loadResilientTagIndex(IGF, elt.decl);
4958+
auto matchesTag = IGF.Builder.CreateICmpEQ(tag, tagVal);
4959+
4960+
// If we are not the last block create a continuation block.
4961+
if (++numCasesEmitted < dests.size())
4962+
continuationBB = llvm::BasicBlock::Create(C);
4963+
// Otherwise, our continuation is the default destination.
4964+
else
4965+
continuationBB = defaultDest;
4966+
IGF.Builder.CreateCondBr(matchesTag, found->second, continuationBB);
4967+
}
49334968
};
49344969

49354970
for (auto &elt : ElementsWithPayload)
@@ -4938,6 +4973,11 @@ namespace {
49384973
for (auto &elt : ElementsWithNoPayload)
49394974
emitCase(elt);
49404975

4976+
// If we have not emitted any cases jump to the default destination.
4977+
if (numCasesEmitted == 0) {
4978+
IGF.Builder.CreateBr(defaultDest);
4979+
}
4980+
49414981
// Delete the unreachable default block if we didn't use it, or emit it
49424982
// if we did.
49434983
if (unreachableBB->use_empty()) {
@@ -6107,6 +6147,15 @@ void IRGenModule::emitEnumDecl(EnumDecl *theEnum) {
61076147
}
61086148

61096149
emitFieldMetadataRecord(theEnum);
6150+
6151+
if (isResilient(theEnum, ResilienceExpansion::Maximal))
6152+
return;
6153+
6154+
// Emit resilient tag indices.
6155+
auto &strategy = getEnumImplStrategy(
6156+
*this,
6157+
theEnum->DeclContext::getDeclaredTypeInContext()->getCanonicalType());
6158+
strategy.emitResilientTagIndices(*this);
61106159
}
61116160

61126161
void irgen::emitSwitchAddressOnlyEnumDispatch(IRGenFunction &IGF,

lib/IRGen/GenEnum.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ class EnumImplStrategy {
214214

215215
/// Return a tag index in the range
216216
/// [-ElementsWithPayload..ElementsWithNoPayload-1].
217-
int getResilientTagIndex(EnumElementDecl *Case) const;
217+
virtual int getResilientTagIndex(EnumElementDecl *Case) const;
218218

219219
/// Map the given element to the appropriate index in the
220220
/// discriminator type.
@@ -440,7 +440,9 @@ class EnumImplStrategy {
440440
ReferenceCounting *rc) const {
441441
return false;
442442
}
443-
443+
444+
void emitResilientTagIndices(IRGenModule &IGM) const;
445+
444446
private:
445447
EnumImplStrategy(const EnumImplStrategy &) = delete;
446448
EnumImplStrategy &operator=(const EnumImplStrategy &) = delete;

lib/IRGen/GenOpaque.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -849,13 +849,11 @@ void irgen::emitDestructiveProjectEnumDataCall(IRGenFunction &IGF,
849849
/// The type must be dynamically known to have enum witnesses.
850850
void irgen::emitDestructiveInjectEnumTagCall(IRGenFunction &IGF,
851851
SILType T,
852-
unsigned tag,
852+
llvm::Value *tagValue,
853853
Address srcObject) {
854854
llvm::Value *metadata;
855855
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
856856
ValueWitness::DestructiveInjectEnumTag);
857-
llvm::Value *tagValue =
858-
llvm::ConstantInt::get(IGF.IGM.Int32Ty, tag);
859857
IGF.Builder.CreateCall(fn, {srcObject.getAddress(), tagValue, metadata});
860858
}
861859

lib/IRGen/GenOpaque.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ namespace irgen {
206206
/// The type must be dynamically known to have enum witnesses.
207207
void emitDestructiveInjectEnumTagCall(IRGenFunction &IGF,
208208
SILType T,
209-
unsigned tag,
209+
llvm::Value *tag,
210210
Address srcObject);
211211

212212
/// Emit a load of the 'size' value witness.

lib/IRGen/IRGenMangler.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,13 @@ class IRGenMangler : public Mangle::ASTMangler {
143143
return finalize();
144144
}
145145

146+
std::string mangleEnumCase(const ValueDecl *Decl) {
147+
beginMangling();
148+
appendEntity(Decl);
149+
appendOperator("WC");
150+
return finalize();
151+
}
152+
146153
std::string mangleDirectProtocolWitnessTable(const ProtocolConformance *C) {
147154
return mangleConformanceSymbol(Type(), C, "WP");
148155
}

lib/IRGen/IRGenModule.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1120,7 +1120,8 @@ private: \
11201120
ForDefinition_t forDefinition);
11211121

11221122
llvm::Function *emitDispatchThunk(SILDeclRef declRef);
1123-
1123+
Address getAddrOfEnumCase(EnumElementDecl *Case,
1124+
ForDefinition_t forDefinition);
11241125
Address getAddrOfFieldOffset(VarDecl *D, ForDefinition_t forDefinition);
11251126
llvm::Function *getAddrOfValueWitness(CanType concreteType,
11261127
ValueWitness index,

lib/IRGen/Linking.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ std::string LinkEntity::mangleAsString() const {
146146
return mangler.mangleProtocolConformanceDescriptor(
147147
cast<NormalProtocolConformance>(getProtocolConformance()));
148148

149+
case Kind::EnumCase:
150+
return mangler.mangleEnumCase(getDecl());
151+
149152
case Kind::FieldOffset:
150153
return mangler.mangleFieldOffset(getDecl());
151154

0 commit comments

Comments
 (0)