[silgen] Copy the body of emitEnumElementDispatch to emitEnumElementDispatchWithOwnership.

The reason I am doing this is that I am going to in the next couple of commits
change enum element dispatch to with or without semantic SIL use proper
ownership.

In this commit, I just did the copy and eliminated any parts of the code that
were predicated on having an address.
This commit is contained in:
Michael Gottesman
2017-03-26 19:38:10 -07:00
parent 0e7316d3d0
commit ba1e9f76d8
2 changed files with 252 additions and 6 deletions

View File

@@ -446,6 +446,9 @@ private:
ConsumableManagedValue src,
const SpecializationHandler &handleSpec,
const FailureHandler &failure);
void emitEnumElementDispatchWithOwnership(
ArrayRef<RowToSpecialize> rows, ConsumableManagedValue src,
const SpecializationHandler &handleSpec, const FailureHandler &failure);
void emitEnumElementDispatch(ArrayRef<RowToSpecialize> rows,
ConsumableManagedValue src,
const SpecializationHandler &handleSpec,
@@ -1568,11 +1571,253 @@ void PatternMatchEmission::emitIsDispatch(ArrayRef<RowToSpecialize> rows,
/// Perform specialized dispatch for a sequence of EnumElementPattern or an
/// OptionalSomePattern.
void PatternMatchEmission::
emitEnumElementDispatch(ArrayRef<RowToSpecialize> rows,
ConsumableManagedValue src,
const SpecializationHandler &handleCase,
const FailureHandler &outerFailure) {
void PatternMatchEmission::emitEnumElementDispatchWithOwnership(
ArrayRef<RowToSpecialize> rows, ConsumableManagedValue src,
const SpecializationHandler &handleCase,
const FailureHandler &outerFailure) {
CanType sourceType = rows[0].Pattern->getType()->getCanonicalType();
struct CaseInfo {
EnumElementDecl *FormalElement;
Pattern *FirstMatcher;
bool Irrefutable = false;
SmallVector<SpecializedRow, 2> SpecializedRows;
};
SILBasicBlock *curBB = SGF.B.getInsertionBB();
// Collect the cases and specialized rows.
//
// These vectors are completely parallel, but the switch
// instructions want only the first information, so we split them up.
SmallVector<std::pair<EnumElementDecl *, SILBasicBlock *>, 4> caseBBs;
SmallVector<CaseInfo, 4> caseInfos;
SILBasicBlock *defaultBB = nullptr;
caseBBs.reserve(rows.size());
caseInfos.reserve(rows.size());
{
// Create destination blocks for all the cases.
llvm::DenseMap<EnumElementDecl *, unsigned> caseToIndex;
for (auto &row : rows) {
EnumElementDecl *formalElt;
Pattern *subPattern = nullptr;
if (auto eep = dyn_cast<EnumElementPattern>(row.Pattern)) {
formalElt = eep->getElementDecl();
subPattern = eep->getSubPattern();
} else {
auto *osp = cast<OptionalSomePattern>(row.Pattern);
formalElt = osp->getElementDecl();
subPattern = osp->getSubPattern();
}
auto elt = SGF.SGM.getLoweredEnumElementDecl(formalElt);
unsigned index = caseInfos.size();
auto insertionResult = caseToIndex.insert({elt, index});
if (!insertionResult.second) {
index = insertionResult.first->second;
} else {
curBB = SGF.createBasicBlock(curBB);
caseBBs.push_back({elt, curBB});
caseInfos.resize(caseInfos.size() + 1);
caseInfos.back().FormalElement = formalElt;
caseInfos.back().FirstMatcher = row.Pattern;
}
assert(caseToIndex[elt] == index);
assert(caseBBs[index].first == elt);
auto &info = caseInfos[index];
info.Irrefutable = (info.Irrefutable || row.Irrefutable);
info.SpecializedRows.resize(info.SpecializedRows.size() + 1);
auto &specRow = info.SpecializedRows.back();
specRow.RowIndex = row.RowIndex;
// Use the row pattern, if it has one.
if (subPattern) {
specRow.Patterns.push_back(subPattern);
// It's also legal to write:
// case .Some { ... }
// which is an implicit wildcard.
} else {
specRow.Patterns.push_back(nullptr);
}
}
// We always need a default block if the enum is resilient.
// If the enum is @_fixed_layout, we only need one if the
// switch is not exhaustive.
bool exhaustive = false;
auto enumDecl = sourceType.getEnumOrBoundGenericEnum();
// The SIL values will range over Optional, so count against
// Optional's cases.
if (enumDecl == SGF.getASTContext().getImplicitlyUnwrappedOptionalDecl()) {
enumDecl = SGF.getASTContext().getOptionalDecl();
}
// FIXME: Get expansion from SILFunction
if (enumDecl->hasFixedLayout(SGF.SGM.M.getSwiftModule(),
ResilienceExpansion::Maximal)) {
exhaustive = true;
for (auto elt : enumDecl->getAllElements()) {
if (!caseToIndex.count(elt)) {
exhaustive = false;
break;
}
}
}
if (!exhaustive)
defaultBB = SGF.createBasicBlock(curBB);
}
assert(caseBBs.size() == caseInfos.size());
SILValue srcValue = src.getFinalManagedValue().forward(SGF);
SILLocation loc = PatternMatchStmt;
loc.setDebugLoc(rows[0].Pattern);
SGF.B.createSwitchEnum(loc, srcValue, defaultBB, caseBBs);
// Okay, now emit all the cases.
for (unsigned i = 0, e = caseInfos.size(); i != e; ++i) {
auto &caseInfo = caseInfos[i];
SILLocation loc = caseInfo.FirstMatcher;
auto &specializedRows = caseInfo.SpecializedRows;
EnumElementDecl *elt = caseBBs[i].first;
EnumElementDecl *formalElt = caseInfos[i].FormalElement;
SILBasicBlock *caseBB = caseBBs[i].second;
SGF.B.setInsertionPoint(caseBB);
// We're in conditionally-executed code; enter a scope.
Scope scope(SGF.Cleanups, CleanupLocation::get(loc));
// Create a BB argument or 'unchecked_take_enum_data_addr'
// instruction to receive the enum case data if it has any.
SILType eltTy;
bool hasElt = false;
if (elt->getArgumentInterfaceType()) {
eltTy = src.getType().getEnumElementType(elt, SGF.SGM.M);
hasElt = !eltTy.getSwiftRValueType()->isVoid();
}
ConsumableManagedValue eltCMV, origCMV;
// Empty cases. Try to avoid making an empty tuple value if it's
// obviously going to be ignored. This assumes that we won't even
// try to touch the value in such cases, although we may touch the
// cleanup (enough to see that it's not present).
if (!hasElt) {
bool hasNonAny = false;
for (auto &specRow : specializedRows) {
auto pattern = specRow.Patterns[0];
if (pattern &&
!isa<AnyPattern>(pattern->getSemanticsProvidingPattern())) {
hasNonAny = true;
break;
}
}
SILValue result;
if (hasNonAny) {
result = SGF.emitEmptyTuple(loc);
} else {
result = SILUndef::get(SGF.SGM.Types.getEmptyTupleType(), SGF.SGM.M);
}
origCMV = ConsumableManagedValue::forUnmanaged(result);
eltCMV = origCMV;
// Okay, specialize on the argument.
} else {
auto *eltTL = &SGF.getTypeLowering(eltTy);
// Normally we'd just use the consumption of the source
// because the difference between TakeOnSuccess and TakeAlways
// doesn't matter for irrefutable rows. But if we need to
// re-abstract, we'll see a lot of benefit from figuring out
// that we can use TakeAlways here.
auto eltConsumption = src.getFinalConsumption();
if (caseInfo.Irrefutable &&
eltConsumption == CastConsumptionKind::TakeOnSuccess) {
assert(!SGF.F.getModule().getOptions().EnableSILOwnership &&
"TakeOnSuccess is not supported when compiling with ownership");
eltConsumption = CastConsumptionKind::TakeAlways;
}
SILValue eltValue =
caseBB->createPHIArgument(eltTy, ValueOwnershipKind::Owned);
origCMV = getManagedSubobject(SGF, eltValue, *eltTL, eltConsumption);
eltCMV = origCMV;
// If the payload is boxed, project it.
if (elt->isIndirect() || elt->getParentEnum()->isIndirect()) {
SILValue boxedValue =
SGF.B.createProjectBox(loc, origCMV.getValue(), 0);
eltTL = &SGF.getTypeLowering(boxedValue->getType());
if (eltTL->isLoadable()) {
ManagedValue newLoadedBoxValue = SGF.B.createLoadBorrow(
loc, ManagedValue::forUnmanaged(boxedValue));
boxedValue = newLoadedBoxValue.getUnmanagedValue();
}
// The boxed value may be shared, so we always have to copy it.
eltCMV = getManagedSubobject(SGF, boxedValue, *eltTL,
CastConsumptionKind::CopyOnSuccess);
}
// Reabstract to the substituted type, if needed.
CanType substEltTy =
sourceType
->getTypeOfMember(SGF.SGM.M.getSwiftModule(), formalElt,
formalElt->getArgumentInterfaceType())
->getCanonicalType();
AbstractionPattern origEltTy =
(elt->getParentEnum()->classifyAsOptionalType()
? AbstractionPattern(substEltTy)
: SGF.SGM.M.Types.getAbstractionPattern(elt));
eltCMV = emitReabstractedSubobject(SGF, loc, eltCMV, *eltTL, origEltTy,
substEltTy);
}
const FailureHandler *innerFailure = &outerFailure;
FailureHandler specializedFailure = [&](SILLocation loc) {
ArgUnforwarder unforwarder(SGF);
unforwarder.unforwardBorrowedValues(src, origCMV);
outerFailure(loc);
};
if (ArgUnforwarder::requiresUnforwarding(SGF, src))
innerFailure = &specializedFailure;
handleCase(eltCMV, specializedRows, *innerFailure);
assert(!SGF.B.hasValidInsertionPoint() && "did not end block");
}
// Emit the default block if we needed one.
if (defaultBB) {
SGF.B.setInsertionPoint(defaultBB);
outerFailure(rows.back().Pattern);
}
}
/// Perform specialized dispatch for a sequence of EnumElementPattern or an
/// OptionalSomePattern.
void PatternMatchEmission::emitEnumElementDispatch(
ArrayRef<RowToSpecialize> rows, ConsumableManagedValue src,
const SpecializationHandler &handleCase,
const FailureHandler &outerFailure) {
// If sil ownership is enabled and we have that our source type is an object,
// use the dispatch code path.
if (SGF.getOptions().EnableSILOwnership && src.getType().isObject()) {
return emitEnumElementDispatchWithOwnership(rows, src, handleCase,
outerFailure);
}
CanType sourceType = rows[0].Pattern->getType()->getCanonicalType();