Skip to content

Commit 7496730

Browse files
committed
SILGen: Add a new SILGenFunction::emitInjectEnum() function, NFC
This factors out code duplication between InjectIntoOptionalExpr and enum case constructors, and will eventually be used in other places too.
1 parent 2fa0bf8 commit 7496730

File tree

4 files changed

+211
-97
lines changed

4 files changed

+211
-97
lines changed

lib/SILGen/SILGenApply.cpp

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2974,6 +2974,159 @@ void ArgEmitter::emitShuffle(TupleShuffleExpr *E,
29742974
origParamType);
29752975
}
29762976

2977+
namespace {
2978+
/// Cleanup to destroy an uninitialized box.
2979+
class DeallocateUninitializedBox : public Cleanup {
2980+
SILValue box;
2981+
public:
2982+
DeallocateUninitializedBox(SILValue box) : box(box) {}
2983+
2984+
void emit(SILGenFunction &gen, CleanupLocation l) override {
2985+
gen.B.createDeallocBox(l, box);
2986+
}
2987+
};
2988+
} // end anonymous namespace
2989+
2990+
static CleanupHandle enterDeallocBoxCleanup(SILGenFunction &gen, SILValue box) {
2991+
gen.Cleanups.pushCleanup<DeallocateUninitializedBox>(box);
2992+
return gen.Cleanups.getTopCleanup();
2993+
}
2994+
2995+
/// This is an initialization for a box.
2996+
class BoxInitialization : public SingleBufferInitialization {
2997+
SILValue box;
2998+
SILValue addr;
2999+
CleanupHandle uninitCleanup;
3000+
CleanupHandle initCleanup;
3001+
3002+
public:
3003+
BoxInitialization(SILValue box, SILValue addr,
3004+
CleanupHandle uninitCleanup,
3005+
CleanupHandle initCleanup)
3006+
: box(box), addr(addr),
3007+
uninitCleanup(uninitCleanup),
3008+
initCleanup(initCleanup) {}
3009+
3010+
void finishInitialization(SILGenFunction &gen) override {
3011+
gen.Cleanups.setCleanupState(uninitCleanup, CleanupState::Dead);
3012+
if (initCleanup.isValid())
3013+
gen.Cleanups.setCleanupState(initCleanup, CleanupState::Active);
3014+
}
3015+
3016+
SILValue getAddressOrNull() const override {
3017+
return addr;
3018+
}
3019+
3020+
ManagedValue getManagedBox() const {
3021+
return ManagedValue(box, initCleanup);
3022+
}
3023+
};
3024+
3025+
/// Emits SIL instructions to create an enum value. Attempts to avoid
3026+
/// unnecessary copies by emitting the payload directly into the enum
3027+
/// payload, or into the box in the case of an indirect payload.
3028+
ManagedValue SILGenFunction::emitInjectEnum(SILLocation loc,
3029+
ArgumentSource payload,
3030+
SILType enumTy,
3031+
EnumElementDecl *element,
3032+
SGFContext C) {
3033+
// Easy case -- no payload
3034+
if (!payload) {
3035+
if (enumTy.isLoadable(SGM.M)) {
3036+
return emitManagedRValueWithCleanup(
3037+
B.createEnum(loc, SILValue(), element,
3038+
enumTy.getObjectType()));
3039+
}
3040+
3041+
// Emit the enum directly into the context if possible
3042+
SILValue resultSlot = getBufferForExprResult(loc, enumTy, C);
3043+
B.createInjectEnumAddr(loc, resultSlot, element);
3044+
return manageBufferForExprResult(resultSlot,
3045+
getTypeLowering(enumTy), C);
3046+
}
3047+
3048+
ManagedValue payloadMV;
3049+
AbstractionPattern origFormalType(element->getArgumentType());
3050+
auto &payloadTL = getTypeLowering(origFormalType,
3051+
payload.getSubstType());
3052+
3053+
SILType loweredPayloadType = payloadTL.getLoweredType();
3054+
3055+
// If the payload is indirect, emit it into a heap allocated box.
3056+
//
3057+
// To avoid copies, evaluate it directly into the box, being
3058+
// careful to stage the cleanups so that if the expression
3059+
// throws, we know to deallocate the uninitialized box.
3060+
if (element->isIndirect() ||
3061+
element->getParentEnum()->isIndirect()) {
3062+
auto box = B.createAllocBox(loc, payloadTL.getLoweredType());
3063+
3064+
CleanupHandle initCleanup = enterDestroyCleanup(box);
3065+
Cleanups.setCleanupState(initCleanup, CleanupState::Dormant);
3066+
CleanupHandle uninitCleanup = enterDeallocBoxCleanup(*this, box);
3067+
3068+
BoxInitialization dest(box, box->getAddressResult(),
3069+
uninitCleanup, initCleanup);
3070+
3071+
std::move(payload).forwardInto(*this, origFormalType,
3072+
&dest, payloadTL);
3073+
3074+
payloadMV = dest.getManagedBox();
3075+
loweredPayloadType = payloadMV.getType();
3076+
}
3077+
3078+
// Loadable with payload
3079+
if (enumTy.isLoadable(SGM.M)) {
3080+
if (!payloadMV) {
3081+
// If the payload was indirect, we already evaluated it and
3082+
// have a single value. Otherwise, evaluate the payload.
3083+
payloadMV = std::move(payload).getAsSingleValue(*this, origFormalType);
3084+
}
3085+
3086+
SILValue argValue = payloadMV.forward(*this);
3087+
3088+
return emitManagedRValueWithCleanup(
3089+
B.createEnum(loc, argValue, element,
3090+
enumTy.getObjectType()));
3091+
}
3092+
3093+
// Address-only with payload
3094+
SILValue resultSlot = getBufferForExprResult(loc, enumTy, C);
3095+
3096+
SILValue resultData =
3097+
B.createInitEnumDataAddr(loc, resultSlot, element,
3098+
loweredPayloadType.getAddressType());
3099+
3100+
if (payloadMV) {
3101+
// If the payload was indirect, we already evaluated it and
3102+
// have a single value. Store it into the result.
3103+
B.createStore(loc, payloadMV.forward(*this), resultData);
3104+
} else if (payloadTL.isLoadable()) {
3105+
// The payload of this specific enum case might be loadable
3106+
// even if the overall enum is address-only.
3107+
payloadMV = std::move(payload).getAsSingleValue(*this, origFormalType);
3108+
B.createStore(loc, payloadMV.forward(*this), resultData);
3109+
} else {
3110+
// The payload is address-only. Evaluate it directly into
3111+
// the enum.
3112+
CleanupHandle cleanup = enterDestroyCleanup(resultSlot);
3113+
Cleanups.setCleanupState(cleanup, CleanupState::Dormant);
3114+
3115+
TemporaryInitialization dest(resultData, cleanup);
3116+
std::move(payload).forwardInto(*this, origFormalType,
3117+
&dest, payloadTL);
3118+
3119+
// Kill the old cleanup -- we're going to enter a new one.
3120+
Cleanups.setCleanupState(cleanup, CleanupState::Dead);
3121+
}
3122+
3123+
// The payload is initialized, now apply the tag.
3124+
B.createInjectEnumAddr(loc, resultSlot, element);
3125+
3126+
return manageBufferForExprResult(resultSlot,
3127+
getTypeLowering(enumTy), C);
3128+
}
3129+
29773130
namespace {
29783131
/// A structure for conveniently claiming sets of uncurried parameters.
29793132
struct ParamLowering {

lib/SILGen/SILGenConstructor.cpp

Lines changed: 42 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "SILGenFunction.h"
14+
#include "ArgumentSource.h"
1415
#include "Initialization.h"
1516
#include "LValue.h"
1617
#include "RValue.h"
@@ -344,108 +345,66 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) {
344345
}
345346
}
346347

347-
static void boxIndirectEnumPayload(SILGenFunction &gen,
348-
ManagedValue &payload,
349-
SILLocation loc,
350-
EnumElementDecl *element) {
351-
// If the payload is indirect, we'll need to box it.
352-
if (payload && (element->isIndirect() ||
353-
element->getParentEnum()->isIndirect())) {
354-
auto box = gen.B.createAllocBox(loc, payload.getType());
355-
payload.forwardInto(gen, loc, box->getAddressResult());
356-
payload = gen.emitManagedRValueWithCleanup(box);
357-
}
358-
}
348+
void SILGenFunction::emitEnumConstructor(EnumElementDecl *element) {
349+
CanType enumTy = element->getParentEnum()
350+
->getDeclaredTypeInContext()
351+
->getCanonicalType();
352+
auto &enumTI = getTypeLowering(enumTy);
359353

360-
static void emitAddressOnlyEnumConstructor(SILGenFunction &gen,
361-
SILType enumTy,
362-
EnumElementDecl *element) {
363354
RegularLocation Loc(element);
364355
CleanupLocation CleanupLoc(element);
365356
Loc.markAutoGenerated();
366357

367358
// Emit the indirect return slot.
368-
auto &AC = gen.getASTContext();
369-
auto VD = new (AC) ParamDecl(/*IsLet*/ false, SourceLoc(),
370-
AC.getIdentifier("$return_value"),
371-
SourceLoc(),
372-
AC.getIdentifier("$return_value"),
373-
enumTy.getSwiftType(),
374-
element->getDeclContext());
375-
SILValue resultSlot
376-
= new (gen.F.getModule()) SILArgument(gen.F.begin(), enumTy, VD);
377-
378-
Scope scope(gen.Cleanups, CleanupLoc);
379-
380-
// Emit the exploded constructor argument.
381-
ManagedValue argValue;
382-
if (element->hasArgumentType()) {
383-
RValue arg = emitImplicitValueConstructorArg
384-
(gen, Loc, element->getArgumentType()->getCanonicalType(),
385-
element->getDeclContext());
386-
argValue = std::move(arg).getAsSingleValue(gen, Loc);
387-
}
388-
emitConstructorMetatypeArg(gen, element);
389-
390-
boxIndirectEnumPayload(gen, argValue, Loc, element);
391-
392-
// Store the data, if any.
393-
if (argValue) {
394-
SILValue resultData = gen.B.createInitEnumDataAddr(element, resultSlot,
395-
element, argValue.getType().getAddressType());
396-
argValue.forwardInto(gen, element, resultData);
359+
std::unique_ptr<Initialization> dest;
360+
if (enumTI.isAddressOnly()) {
361+
auto &AC = getASTContext();
362+
auto VD = new (AC) ParamDecl(/*IsLet*/ false, SourceLoc(),
363+
AC.getIdentifier("$return_value"),
364+
SourceLoc(),
365+
AC.getIdentifier("$return_value"),
366+
CanInOutType::get(enumTy),
367+
element->getDeclContext());
368+
auto resultSlot = new (SGM.M) SILArgument(F.begin(),
369+
enumTI.getLoweredType(),
370+
VD);
371+
dest = std::unique_ptr<Initialization>(
372+
new KnownAddressInitialization(resultSlot));
397373
}
398374

399-
// Apply the tag.
400-
gen.B.createInjectEnumAddr(Loc, resultSlot, element);
401-
scope.pop();
402-
gen.B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(Loc),
403-
gen.emitEmptyTuple(element));
404-
}
405-
406-
static void emitLoadableEnumConstructor(SILGenFunction &gen, SILType enumTy,
407-
EnumElementDecl *element) {
408-
RegularLocation Loc(element);
409-
CleanupLocation CleanupLoc(element);
410-
Loc.markAutoGenerated();
411-
412-
Scope scope(gen.Cleanups, CleanupLoc);
375+
Scope scope(Cleanups, CleanupLoc);
413376

414377
// Emit the exploded constructor argument.
415-
ManagedValue payload;
378+
ArgumentSource payload;
416379
if (element->hasArgumentType()) {
417380
RValue arg = emitImplicitValueConstructorArg
418-
(gen, Loc,
419-
element->getArgumentType()->getCanonicalType(),
381+
(*this, Loc, element->getArgumentType()->getCanonicalType(),
420382
element->getDeclContext());
421-
payload = std::move(arg).getAsSingleValue(gen, Loc);
383+
payload = ArgumentSource(Loc, std::move(arg));
422384
}
423385

424-
emitConstructorMetatypeArg(gen, element);
386+
// Emit the metatype argument.
387+
emitConstructorMetatypeArg(*this, element);
425388

426-
boxIndirectEnumPayload(gen, payload, Loc, element);
427-
428-
// Create and return the enum value.
429-
SILValue argValue;
430-
if (payload)
431-
argValue = payload.forward(gen);
432-
SILValue result = gen.B.createEnum(Loc, argValue, element, enumTy);
433-
scope.pop();
434-
gen.B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(Loc), result);
435-
}
389+
// If possible, emit the enum directly into the indirect return.
390+
SGFContext C = (dest ? SGFContext(dest.get()) : SGFContext());
391+
ManagedValue mv = emitInjectEnum(Loc, std::move(payload),
392+
enumTI.getLoweredType(),
393+
element, C);
436394

437-
void SILGenFunction::emitEnumConstructor(EnumElementDecl *element) {
438-
Type enumTy = element->getType()->getAs<AnyFunctionType>()->getResult();
439-
if (element->hasArgumentType())
440-
enumTy = enumTy->getAs<AnyFunctionType>()->getResult();
441-
auto &enumTI = getTypeLowering(enumTy);
395+
// Return the enum.
396+
auto ReturnLoc = ImplicitReturnLocation::getImplicitReturnLoc(Loc);
442397

443-
if (enumTI.isAddressOnly()) {
444-
return emitAddressOnlyEnumConstructor(*this, enumTI.getLoweredType(),
445-
element);
398+
if (mv.isInContext()) {
399+
assert(enumTI.isAddressOnly());
400+
scope.pop();
401+
B.createReturn(ReturnLoc, emitEmptyTuple(Loc));
402+
} else {
403+
assert(enumTI.isLoadable());
404+
SILValue result = mv.forward(*this);
405+
scope.pop();
406+
B.createReturn(ReturnLoc, result);
446407
}
447-
return emitLoadableEnumConstructor(*this, enumTI.getLoweredType(),
448-
element);
449408
}
450409

451410
bool Lowering::usesObjCAllocator(ClassDecl *theClass) {

lib/SILGen/SILGenExpr.cpp

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2337,20 +2337,16 @@ RValue RValueEmitter::visitInjectIntoOptionalExpr(InjectIntoOptionalExpr *E,
23372337
ManagedValue bitcastMV = ManagedValue(bitcast, result.getCleanup());
23382338
return RValue(SGF, E, bitcastMV);
23392339
}
2340-
2341-
// Create a buffer for the result if this is an address-only optional.
2342-
auto &optTL = SGF.getTypeLowering(E->getType());
2343-
if (!optTL.isAddressOnly()) {
2344-
auto result = SGF.emitRValueAsSingleValue(E->getSubExpr());
2345-
result = SGF.getOptionalSomeValue(E, result, optTL);
2346-
return RValue(SGF, E, result);
2347-
}
2348-
2349-
SILValue optAddr = SGF.getBufferForExprResult(E, optTL.getLoweredType(), C);
2350-
2351-
SGF.emitInjectOptionalValueInto(E, E->getSubExpr(), optAddr, optTL);
2352-
2353-
ManagedValue result = SGF.manageBufferForExprResult(optAddr, optTL, C);
2340+
2341+
OptionalTypeKind OTK;
2342+
E->getType()->getAnyOptionalObjectType(OTK);
2343+
assert(OTK != OTK_None);
2344+
2345+
auto someDecl = SGF.getASTContext().getOptionalSomeDecl(OTK);
2346+
2347+
ManagedValue result = SGF.emitInjectEnum(E, ArgumentSource(E->getSubExpr()),
2348+
SGF.getLoweredType(E->getType()),
2349+
someDecl, C);
23542350
if (result.isInContext())
23552351
return RValue();
23562352
return RValue(SGF, E, result);

lib/SILGen/SILGenFunction.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,12 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
762762
// Type conversions for expr emission and thunks
763763
//===--------------------------------------------------------------------===//
764764

765+
ManagedValue emitInjectEnum(SILLocation loc,
766+
ArgumentSource payload,
767+
SILType enumTy,
768+
EnumElementDecl *element,
769+
SGFContext C);
770+
765771
ManagedValue emitInjectOptional(SILLocation loc,
766772
ManagedValue v,
767773
CanType inputFormalType,

0 commit comments

Comments
 (0)