Skip to content

Commit 72bc61c

Browse files
authored
Merge pull request #8414 from gottesmm/fixup_enum_initializers
[silgen] Fix up EnumElementPatternInitialization::emitEnumMatch to use ownership.
2 parents d2efb5e + 79b225f commit 72bc61c

20 files changed

+515
-273
lines changed

include/swift/AST/Decl.h

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2971,7 +2971,51 @@ class EnumDecl : public NominalTypeDecl {
29712971
ElementRange getAllElements() const {
29722972
return ElementRange(getMembers());
29732973
}
2974-
2974+
2975+
unsigned getNumElements() const {
2976+
auto eltRange = getAllElements();
2977+
return std::distance(eltRange.begin(), eltRange.end());
2978+
}
2979+
2980+
/// If this is an enum with two cases, return the other case. Otherwise,
2981+
/// return nullptr.
2982+
EnumElementDecl *getOppositeBinaryDecl(EnumElementDecl *decl) const {
2983+
ElementRange range = getAllElements();
2984+
auto iter = range.begin();
2985+
if (iter == range.end())
2986+
return nullptr;
2987+
bool seenDecl = false;
2988+
EnumElementDecl *result = nullptr;
2989+
if (*iter == decl) {
2990+
seenDecl = true;
2991+
} else {
2992+
result = *iter;
2993+
}
2994+
2995+
++iter;
2996+
if (iter == range.end())
2997+
return nullptr;
2998+
if (seenDecl) {
2999+
assert(!result);
3000+
result = *iter;
3001+
} else {
3002+
if (decl != *iter)
3003+
return nullptr;
3004+
seenDecl = true;
3005+
}
3006+
++iter;
3007+
3008+
// If we reach this point, we saw the decl we were looking for and one other
3009+
// case. If we have any additional cases, then we do not have a binary enum.
3010+
if (iter != range.end())
3011+
return nullptr;
3012+
3013+
// This is always true since we have already returned earlier nullptr if we
3014+
// did not see the decl at all.
3015+
assert(seenDecl);
3016+
return result;
3017+
}
3018+
29753019
/// Return a range that iterates over all the cases of an enum.
29763020
CaseRange getAllCases() const {
29773021
return CaseRange(getMembers());

include/swift/SIL/SILBasicBlock.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,9 @@ public llvm::ilist_node<SILBasicBlock>, public SILAllocated<SILBasicBlock> {
322322
/// no-return apply or builtin.
323323
bool isNoReturn() const;
324324

325+
/// Returns true if this instruction only contains a branch instruction.
326+
bool isTrampoline() const;
327+
325328
//===--------------------------------------------------------------------===//
326329
// Debugging
327330
//===--------------------------------------------------------------------===//

include/swift/SIL/SILInstruction.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5323,6 +5323,9 @@ class SwitchEnumInstBase : public TermInst {
53235323
return {getCaseBuf()[i], getSuccessorBuf()[i].getBB()};
53245324
}
53255325

5326+
// Swap the cases at indices \p i and \p j.
5327+
void swapCase(unsigned i, unsigned j);
5328+
53265329
/// \brief Return the block that will be branched to on the specified enum
53275330
/// case.
53285331
SILBasicBlock *getCaseDestination(EnumElementDecl *D) {

lib/SIL/SILBasicBlock.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,3 +346,10 @@ bool SILBasicBlock::isNoReturn() const {
346346

347347
return false;
348348
}
349+
350+
bool SILBasicBlock::isTrampoline() const {
351+
auto *Branch = dyn_cast<BranchInst>(getTerminator());
352+
if (!Branch)
353+
return false;
354+
return begin() == Branch->getIterator();
355+
}

lib/SIL/SILInstructions.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,28 @@ SwitchEnumInstBase::SwitchEnumInstBase(
13371337
::new (succs + NumCases) SILSuccessor(this, DefaultBB);
13381338
}
13391339

1340+
void SwitchEnumInstBase::swapCase(unsigned i, unsigned j) {
1341+
assert(i < getNumCases() && "First index is out of bounds?!");
1342+
assert(j < getNumCases() && "Second index is out of bounds?!");
1343+
1344+
auto *succs = getSuccessorBuf();
1345+
1346+
// First grab our destination blocks.
1347+
SILBasicBlock *iBlock = succs[i].getBB();
1348+
SILBasicBlock *jBlock = succs[j].getBB();
1349+
1350+
// Then destroy the sil successors and reinitialize them with the new things
1351+
// that they are pointing at.
1352+
succs[i].~SILSuccessor();
1353+
::new (succs + i) SILSuccessor(this, jBlock);
1354+
succs[j].~SILSuccessor();
1355+
::new (succs + j) SILSuccessor(this, iBlock);
1356+
1357+
// Now swap our cases.
1358+
auto *cases = getCaseBuf();
1359+
std::swap(cases[i], cases[j]);
1360+
}
1361+
13401362
namespace {
13411363
template <class Inst> EnumElementDecl *
13421364
getUniqueCaseForDefaultValue(Inst *inst, SILValue enumValue) {

lib/SIL/SILVerifier.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3330,7 +3330,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
33303330
SOI->getOperand()->getType(),
33313331
"Switch enum default block should have one argument that is "
33323332
"the same as the input type");
3333-
} else {
3333+
} else if (F.hasUnqualifiedOwnership()) {
33343334
require(SOI->getDefaultBB()->args_empty(),
33353335
"switch_enum default destination must take no arguments");
33363336
}

lib/SILGen/ManagedValue.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,15 @@ ManagedValue ManagedValue::formalAccessBorrow(SILGenFunction &SGF,
144144
return ManagedValue::forUnmanaged(getValue());
145145
return SGF.emitFormalEvaluationManagedBeginBorrow(loc, getValue());
146146
}
147+
148+
void ManagedValue::print(raw_ostream &os) const {
149+
if (SILValue v = getValue()) {
150+
v->print(os);
151+
}
152+
}
153+
154+
void ManagedValue::dump() const {
155+
#ifndef NDEBUG
156+
print(llvm::dbgs());
157+
#endif
158+
}

lib/SILGen/ManagedValue.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,9 @@ class ManagedValue {
296296
// "InContext" is not considered false.
297297
return bool(getValue()) || valueAndFlag.getInt();
298298
}
299+
300+
void dump() const;
301+
void print(raw_ostream &os) const;
299302
};
300303

301304
/// A ManagedValue which may not be intended to be consumed.

lib/SILGen/SILGenBuilder.cpp

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,28 @@ void SwitchEnumBuilder::emit() && {
674674
}
675675
}
676676

677+
// If we are asked to create a default block and it is specified that the
678+
// default block should be emitted before normal cases, emit it now.
679+
if (defaultBlockData &&
680+
defaultBlockData->dispatchTime ==
681+
DefaultDispatchTime::BeforeNormalCases) {
682+
SILBasicBlock *defaultBlock = defaultBlockData->block;
683+
NullablePtr<SILBasicBlock> contBB = defaultBlockData->contBlock;
684+
DefaultCaseHandler handler = defaultBlockData->handler;
685+
686+
// Don't allow cleanups to escape the conditional block.
687+
SwitchCaseFullExpr presentScope(builder.getSILGenFunction(),
688+
CleanupLocation::get(loc),
689+
contBB.getPtrOrNull());
690+
builder.emitBlock(defaultBlock);
691+
ManagedValue input = optional;
692+
if (!isAddressOnly) {
693+
input = builder.createOwnedPHIArgument(optional.getType());
694+
}
695+
handler(input, presentScope);
696+
assert(!builder.hasValidInsertionPoint());
697+
}
698+
677699
for (NormalCaseData &caseData : caseDataArray) {
678700
EnumElementDecl *decl = caseData.decl;
679701
SILBasicBlock *caseBlock = caseData.block;
@@ -684,6 +706,7 @@ void SwitchEnumBuilder::emit() && {
684706
SwitchCaseFullExpr presentScope(builder.getSILGenFunction(),
685707
CleanupLocation::get(loc),
686708
contBlock.getPtrOrNull());
709+
687710
builder.emitBlock(caseBlock);
688711

689712
ManagedValue input;
@@ -700,9 +723,10 @@ void SwitchEnumBuilder::emit() && {
700723
assert(!builder.hasValidInsertionPoint());
701724
}
702725

703-
// If we have a default BB, create an argument for the original loaded value
704-
// and destroy it there.
705-
if (defaultBlockData) {
726+
// If we are asked to create a default block and it is specified that the
727+
// default block should be emitted after normal cases, emit it now.
728+
if (defaultBlockData &&
729+
defaultBlockData->dispatchTime == DefaultDispatchTime::AfterNormalCases) {
706730
SILBasicBlock *defaultBlock = defaultBlockData->block;
707731
NullablePtr<SILBasicBlock> contBB = defaultBlockData->contBlock;
708732
DefaultCaseHandler handler = defaultBlockData->handler;

lib/SILGen/SILGenBuilder.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,8 @@ class SwitchEnumBuilder {
276276
using DefaultCaseHandler =
277277
std::function<void(ManagedValue, SwitchCaseFullExpr &)>;
278278

279+
enum class DefaultDispatchTime { BeforeNormalCases, AfterNormalCases };
280+
279281
private:
280282
struct NormalCaseData {
281283
EnumElementDecl *decl;
@@ -294,10 +296,13 @@ class SwitchEnumBuilder {
294296
SILBasicBlock *block;
295297
NullablePtr<SILBasicBlock> contBlock;
296298
DefaultCaseHandler handler;
299+
DefaultDispatchTime dispatchTime;
297300

298301
DefaultCaseData(SILBasicBlock *block, NullablePtr<SILBasicBlock> contBlock,
299-
DefaultCaseHandler handler)
300-
: block(block), contBlock(contBlock), handler(handler) {}
302+
DefaultCaseHandler handler,
303+
DefaultDispatchTime dispatchTime)
304+
: block(block), contBlock(contBlock), handler(handler),
305+
dispatchTime(dispatchTime) {}
301306
~DefaultCaseData() = default;
302307
};
303308

@@ -314,8 +319,10 @@ class SwitchEnumBuilder {
314319

315320
void addDefaultCase(SILBasicBlock *defaultBlock,
316321
NullablePtr<SILBasicBlock> contBlock,
317-
DefaultCaseHandler handle) {
318-
defaultBlockData.emplace(defaultBlock, contBlock, handle);
322+
DefaultCaseHandler handle,
323+
DefaultDispatchTime dispatchTime =
324+
DefaultDispatchTime::AfterNormalCases) {
325+
defaultBlockData.emplace(defaultBlock, contBlock, handle, dispatchTime);
319326
}
320327

321328
void addCase(EnumElementDecl *decl, SILBasicBlock *caseBlock,

lib/SILGen/SILGenConvert.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -340,14 +340,14 @@ SILGenFunction::emitOptionalToOptional(SILLocation loc,
340340

341341
if (!(resultTL.isAddressOnly() && silConv.useLoweredAddresses())) {
342342
SILValue some = B.createOptionalSome(loc, result).forward(*this);
343-
return scope.exit(loc, some);
343+
return scope.exitAndBranch(loc, some);
344344
}
345345

346346
RValue R(*this, loc, noOptResultTy.getSwiftRValueType(), result);
347347
ArgumentSource resultValueRV(loc, std::move(R));
348348
emitInjectOptionalValueInto(loc, std::move(resultValueRV),
349349
finalResult.getValue(), resultTL);
350-
return scope.exit(loc);
350+
return scope.exitAndBranch(loc);
351351
});
352352

353353
SEBuilder.addCase(
@@ -356,11 +356,11 @@ SILGenFunction::emitOptionalToOptional(SILLocation loc,
356356
if (!(resultTL.isAddressOnly() && silConv.useLoweredAddresses())) {
357357
SILValue none =
358358
B.createManagedOptionalNone(loc, resultTy).forward(*this);
359-
return scope.exit(loc, none);
359+
return scope.exitAndBranch(loc, none);
360360
}
361361

362362
emitInjectOptionalNothingInto(loc, finalResult.getValue(), resultTL);
363-
return scope.exit(loc);
363+
return scope.exitAndBranch(loc);
364364
});
365365

366366
std::move(SEBuilder).emit();

0 commit comments

Comments
 (0)