mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[silgen] Add a new API for building switches: SwitchEnumBuilder.
This is a closure based API for creating switches that obey ownership
convensions. The way you use it with objects is as follows:
SwitchEnumBuilder S(...);
S.addCase(Decl, Block, [](ManagedValue Arg) -> void {
...
});
S.addCase(Decl, Block, [](ManagedValue Arg) -> void {
...
});
S.addDefaultCase(Block, [](ManagedValue Arg) -> void {
...
});
std::move(S).emit();
What is important is that it sets up the switch_enum destination blocks with the
proper cleanups for code emitted into the destination block and also provides
the default error with the passed in value with the appropriate cleanups.
It does not handle exits from the switch_enum on purpose since diamond
switch_enum APIs form a subset of APIs. It also expects the closure to create
terminators if appropriate.
In the switch_enum_addr case you have to do a bit more work, but it is still a
nicer API than doing it by hand as we do today.
rdar://29791263
This commit is contained in:
@@ -11,7 +11,11 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "SILGenBuilder.h"
|
||||
#include "ArgumentSource.h"
|
||||
#include "RValue.h"
|
||||
#include "SILGenFunction.h"
|
||||
#include "Scope.h"
|
||||
#include "SwitchCaseFullExpr.h"
|
||||
|
||||
using namespace swift;
|
||||
using namespace Lowering;
|
||||
@@ -546,12 +550,45 @@ void SILGenBuilder::createCheckedCastBranch(SILLocation loc, bool isExact,
|
||||
trueBlock, falseBlock);
|
||||
}
|
||||
|
||||
ManagedValue SILGenBuilder::createUpcast(SILLocation Loc, ManagedValue Original,
|
||||
SILType Type) {
|
||||
CleanupCloner Cloner(*this, Original);
|
||||
ManagedValue SILGenBuilder::createUpcast(SILLocation loc, ManagedValue original,
|
||||
SILType type) {
|
||||
CleanupCloner cloner(*this, original);
|
||||
SILValue convertedValue =
|
||||
SILBuilder::createUpcast(Loc, Original.forward(gen), Type);
|
||||
return Cloner.clone(convertedValue);
|
||||
SILBuilder::createUpcast(loc, original.forward(gen), type);
|
||||
return cloner.clone(convertedValue);
|
||||
}
|
||||
|
||||
ManagedValue SILGenBuilder::createOptionalSome(SILLocation loc,
|
||||
ManagedValue arg) {
|
||||
CleanupCloner cloner(*this, arg);
|
||||
auto &argTL = getFunction().getTypeLowering(arg.getType());
|
||||
SILType optionalType = arg.getType().wrapAnyOptionalType(getFunction());
|
||||
if (argTL.isLoadable()) {
|
||||
SILValue someValue =
|
||||
SILBuilder::createOptionalSome(loc, arg.forward(gen), optionalType);
|
||||
return cloner.clone(someValue);
|
||||
}
|
||||
|
||||
SILValue tempResult = gen.emitTemporaryAllocation(loc, optionalType);
|
||||
RValue rvalue(gen, loc, arg.getType().getSwiftRValueType(), arg);
|
||||
ArgumentSource argValue(loc, std::move(rvalue));
|
||||
gen.emitInjectOptionalValueInto(
|
||||
loc, std::move(argValue), tempResult,
|
||||
getFunction().getTypeLowering(tempResult->getType()));
|
||||
return ManagedValue::forUnmanaged(tempResult);
|
||||
}
|
||||
|
||||
ManagedValue SILGenBuilder::createManagedOptionalNone(SILLocation loc,
|
||||
SILType type) {
|
||||
if (!type.isAddressOnly(getModule())) {
|
||||
SILValue noneValue = SILBuilder::createOptionalNone(loc, type);
|
||||
return ManagedValue::forUnmanaged(noneValue);
|
||||
}
|
||||
|
||||
SILValue tempResult = gen.emitTemporaryAllocation(loc, type);
|
||||
gen.emitInjectOptionalNothingInto(loc, tempResult,
|
||||
gen.F.getTypeLowering(type));
|
||||
return ManagedValue::forUnmanaged(tempResult);
|
||||
}
|
||||
|
||||
ManagedValue SILGenBuilder::createTupleElementAddr(SILLocation Loc,
|
||||
@@ -569,3 +606,84 @@ ManagedValue SILGenBuilder::createTupleElementAddr(SILLocation Loc,
|
||||
SILType Type = Value.getType().getTupleElementType(Index);
|
||||
return createTupleElementAddr(Loc, Value, Index, Type);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Switch Enum Builder
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void SwitchEnumBuilder::emit() && {
|
||||
bool isAddressOnly = optional.getType().isAddressOnly(builder.getModule());
|
||||
using DeclBlockPair = std::pair<EnumElementDecl *, SILBasicBlock *>;
|
||||
{
|
||||
// TODO: We could store the data in CaseBB form and not have to do this.
|
||||
llvm::SmallVector<DeclBlockPair, 8> caseBlocks;
|
||||
std::transform(caseDataArray.begin(), caseDataArray.end(),
|
||||
std::back_inserter(caseBlocks),
|
||||
[](NormalCaseData &caseData) -> DeclBlockPair {
|
||||
return {caseData.decl, caseData.block};
|
||||
});
|
||||
SILBasicBlock *defaultBlock =
|
||||
defaultBlockData ? defaultBlockData->block : nullptr;
|
||||
if (isAddressOnly) {
|
||||
builder.createSwitchEnumAddr(loc, optional.getValue(), defaultBlock,
|
||||
caseBlocks);
|
||||
} else {
|
||||
if (optional.getType().isAddress()) {
|
||||
// TODO: Refactor this into a maybe load.
|
||||
if (optional.hasCleanup()) {
|
||||
optional = builder.createLoadTake(loc, optional);
|
||||
} else {
|
||||
optional = builder.createLoadCopy(loc, optional);
|
||||
}
|
||||
}
|
||||
builder.createSwitchEnum(loc, optional.forward(getSGF()), defaultBlock,
|
||||
caseBlocks);
|
||||
}
|
||||
}
|
||||
|
||||
for (NormalCaseData &caseData : caseDataArray) {
|
||||
EnumElementDecl *decl = caseData.decl;
|
||||
SILBasicBlock *caseBlock = caseData.block;
|
||||
NullablePtr<SILBasicBlock> contBlock = caseData.contBlock;
|
||||
NormalCaseHandler handler = caseData.handler;
|
||||
|
||||
// Don't allow cleanups to escape the conditional block.
|
||||
SwitchCaseFullExpr presentScope(builder.getSILGenFunction(),
|
||||
CleanupLocation::get(loc),
|
||||
contBlock.getPtrOrNull());
|
||||
builder.emitBlock(caseBlock);
|
||||
|
||||
ManagedValue input;
|
||||
if (decl->getArgumentInterfaceType()) {
|
||||
// Pull the payload out if we have one.
|
||||
SILType inputType =
|
||||
optional.getType().getEnumElementType(decl, builder.getModule());
|
||||
input = optional;
|
||||
if (!isAddressOnly) {
|
||||
input = builder.createOwnedPHIArgument(inputType);
|
||||
}
|
||||
}
|
||||
handler(input, presentScope);
|
||||
assert(!builder.hasValidInsertionPoint());
|
||||
}
|
||||
|
||||
// If we have a default BB, create an argument for the original loaded value
|
||||
// and destroy it there.
|
||||
if (defaultBlockData) {
|
||||
SILBasicBlock *defaultBlock = defaultBlockData->block;
|
||||
NullablePtr<SILBasicBlock> contBB = defaultBlockData->contBlock;
|
||||
DefaultCaseHandler handler = defaultBlockData->handler;
|
||||
|
||||
// Don't allow cleanups to escape the conditional block.
|
||||
SwitchCaseFullExpr presentScope(builder.getSILGenFunction(),
|
||||
CleanupLocation::get(loc),
|
||||
contBB.getPtrOrNull());
|
||||
builder.emitBlock(defaultBlock);
|
||||
ManagedValue input = optional;
|
||||
if (!isAddressOnly) {
|
||||
input = builder.createOwnedPHIArgument(optional.getType());
|
||||
}
|
||||
handler(input, presentScope);
|
||||
assert(!builder.hasValidInsertionPoint());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user