Skip to content

Make the general path of emitRValueForStorageLoad use LValues #20352

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
246 changes: 0 additions & 246 deletions lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -903,252 +903,6 @@ emitRValueForDecl(SILLocation loc, ConcreteDeclRef declRef, Type ncRefType,
return RValue(*this, loc, refType, result);
}

static AbstractionPattern
getFormalStorageAbstractionPattern(SILGenFunction &SGF, AbstractStorageDecl *field) {
if (auto var = dyn_cast<VarDecl>(field)) {
auto origType = SGF.SGM.Types.getAbstractionPattern(var);
return origType.getReferenceStorageReferentType();
}
auto sub = cast<SubscriptDecl>(field);
return SGF.SGM.Types.getAbstractionPattern(sub);
}

static SILDeclRef getRValueAccessorDeclRef(SILGenFunction &SGF,
AbstractStorageDecl *storage,
AccessStrategy strategy) {
switch (strategy.getKind()) {
case AccessStrategy::BehaviorStorage:
llvm_unreachable("shouldn't load an rvalue via behavior storage!");

case AccessStrategy::Storage:
llvm_unreachable("should already have been filtered out!");

case AccessStrategy::MaterializeToTemporary:
llvm_unreachable("never used for read accesses");

case AccessStrategy::DirectToAccessor:
case AccessStrategy::DispatchToAccessor: {
auto accessor = strategy.getAccessor();
return SGF.SGM.getAccessorDeclRef(storage->getAccessor(accessor));
}
}
llvm_unreachable("should already have been filtered out!");
}

static RValue getTargetRValue(SILGenFunction &SGF, SILLocation loc,
ManagedValue value,
AbstractionPattern origFormalType,
CanType substFormalType,
SGFContext C) {
SILType loweredSubstType = SGF.getLoweredType(substFormalType);

bool hasAbstraction =
(loweredSubstType.getObjectType() != value.getType().getObjectType());

if (value.isLValue() ||
(value.getType().isAddress() && !loweredSubstType.isAddress())) {
auto isTake =
IsTake_t(!value.isLValue() && !value.isPlusZeroRValueOrTrivial());
value = SGF.emitLoad(loc,
(isTake ? value.forward(SGF)
: value.getUnmanagedValue()),
SGF.getTypeLowering(value.getType()),
(hasAbstraction ? SGFContext() : C),
isTake);
}

RValue result(SGF, loc, substFormalType, value);
if (hasAbstraction) {
result = SGF.emitOrigToSubstValue(loc, std::move(result), origFormalType,
substFormalType, C);
}
return result;
}

static RValue
emitRValueWithAccessor(SILGenFunction &SGF, SILLocation loc,
AbstractStorageDecl *storage,
SubstitutionMap substitutions,
ArgumentSource &&baseRV,
PreparedArguments &&subscriptIndices,
bool isSuper, AccessStrategy strategy,
SILDeclRef accessor,
AbstractionPattern origFormalType,
CanType substFormalType,
SGFContext C) {
assert(strategy.getKind() == AccessStrategy::DirectToAccessor ||
strategy.getKind() == AccessStrategy::DispatchToAccessor);
bool isDirectUse = (strategy.getKind() == AccessStrategy::DirectToAccessor);

// The easy path here is if we don't need to use an addressor.
if (strategy.getAccessor() == AccessorKind::Get) {
return SGF.emitGetAccessor(loc, accessor, substitutions,
std::move(baseRV), isSuper, isDirectUse,
std::move(subscriptIndices), C);
}

assert(strategy.getAccessor() == AccessorKind::Address);

auto &storageTL = SGF.getTypeLowering(origFormalType, substFormalType);
SILType storageType = storageTL.getLoweredType().getAddressType();

auto addressorResult =
SGF.emitAddressorAccessor(loc, accessor, substitutions,
std::move(baseRV), isSuper, isDirectUse,
std::move(subscriptIndices), storageType);

RValue result = getTargetRValue(SGF, loc, addressorResult.first,
origFormalType, substFormalType, C);

switch (cast<AccessorDecl>(accessor.getDecl())->getAddressorKind()) {
case AddressorKind::NotAddressor: llvm_unreachable("inconsistent");
case AddressorKind::Unsafe:
// Nothing to do.
break;
case AddressorKind::Owning:
case AddressorKind::NativeOwning:
// Emit the release immediately.
SGF.B.emitDestroyValueOperation(loc, addressorResult.second.forward(SGF));
break;
}

return result;
}

/// Produce a singular RValue for a load from the specified property. This is
/// designed to work with RValue ManagedValue bases that are either +0 or +1.
RValue SILGenFunction::emitRValueForStorageLoad(
SILLocation loc, ManagedValue base, CanType baseFormalType,
bool isSuper, AbstractStorageDecl *storage,
PreparedArguments &&subscriptIndices,
SubstitutionMap substitutions,
AccessSemantics semantics, Type propTy, SGFContext C,
bool isBaseGuaranteed) {
AccessStrategy strategy =
storage->getAccessStrategy(semantics, AccessKind::Read, FunctionDC);

// If we should call an accessor of some kind, do so.
if (strategy.getKind() != AccessStrategy::Storage) {
auto accessor = getRValueAccessorDeclRef(*this, storage, strategy);
ArgumentSource baseRV = prepareAccessorBaseArg(loc, base,
baseFormalType,
accessor);

AbstractionPattern origFormalType =
getFormalStorageAbstractionPattern(*this, storage);
auto substFormalType = propTy->getCanonicalType();

return emitRValueWithAccessor(*this, loc, storage, substitutions,
std::move(baseRV),
std::move(subscriptIndices),
isSuper, strategy, accessor,
origFormalType, substFormalType, C);
}
assert(isa<VarDecl>(storage) && "only properties should have storage");
auto field = cast<VarDecl>(storage);
assert(field->hasStorage() &&
"Cannot directly access value without storage");

// For static variables, emit a reference to the global variable backing
// them.
// FIXME: This has to be dynamically looked up for classes, and
// dynamically instantiated for generics.
if (field->isStatic()) {
auto baseMeta = base.getType().castTo<MetatypeType>().getInstanceType();
(void)baseMeta;
assert(!baseMeta->is<BoundGenericType>() &&
"generic static stored properties not implemented");
if (field->getDeclContext()->getSelfClassDecl() &&
field->hasStorage())
// FIXME: don't need to check hasStorage, already done above
assert(field->isFinal() && "non-final class stored properties not implemented");

return emitRValueForDecl(loc, field, propTy, semantics, C);
}


// rvalue MemberRefExprs are produced in two cases: when accessing a 'let'
// decl member, and when the base is a (non-lvalue) struct.
assert(baseFormalType->getAnyNominal() &&
base.getType().getASTType()->getAnyNominal() &&
"The base of an rvalue MemberRefExpr should be an rvalue value");

// If the accessed field is stored, emit a StructExtract on the base.

auto substFormalType = propTy->getCanonicalType();
auto &lowering = getTypeLowering(substFormalType);

// Check for an abstraction difference.
AbstractionPattern origFormalType = getFormalStorageAbstractionPattern(*this, field);
bool hasAbstractionChange = false;
auto &abstractedTL = getTypeLowering(origFormalType, substFormalType);
if (!origFormalType.isExactType(substFormalType)) {
hasAbstractionChange =
(abstractedTL.getLoweredType() != lowering.getLoweredType());
}

// If the base is a reference type, just handle this as loading the lvalue.
ManagedValue result;
if (baseFormalType->hasReferenceSemantics()) {
LValue LV = emitPropertyLValue(loc, base, baseFormalType, field,
LValueOptions(),
SGFAccessKind::OwnedObjectRead,
AccessSemantics::DirectToStorage);
auto loaded = emitLoadOfLValue(loc, std::move(LV), C, isBaseGuaranteed);
// If we don't have to reabstract, the load is sufficient.
if (!hasAbstractionChange)
return loaded;

// Otherwise, bring the component up to +1 so we can reabstract it.
result = std::move(loaded).getAsSingleValue(*this, loc)
.copyUnmanaged(*this, loc);
} else if (!base.getType().isAddress()) {
// For non-address-only structs, we emit a struct_extract sequence.
result = B.createStructExtract(loc, base, field);

if (result.getType().is<ReferenceStorageType>()) {
// For weak and unowned types, convert the reference to the right
// pointer, producing a +1.
result = emitConversionToSemanticRValue(loc, result, lowering);

} else if (hasAbstractionChange ||
(!C.isImmediatePlusZeroOk() &&
!(C.isGuaranteedPlusZeroOk() && isBaseGuaranteed))) {
// If we have an abstraction change or if we have to produce a result at
// +1, then copy the value. If we know that our base will stay alive for
// the entire usage of this value, we can borrow the value at +0 for a
// guaranteed consumer. Otherwise, since we do not have enough information
// to know if the base's lifetime last's as long as our use of the access,
// we can only emit at +0 for immediate clients.
result = result.copyUnmanaged(*this, loc);
}
} else {
// Create a tiny unenforced access scope around a load from local memory. No
// cleanup is necessary since we directly emit the load here. This will
// probably go away with opaque values.
UnenforcedAccess access;
SILValue accessAddress =
access.beginAccess(*this, loc, base.getValue(), SILAccessKind::Read);

// For address-only sequences, the base is in memory. Emit a
// struct_element_addr to get to the field, and then load the element as an
// rvalue.
SILValue ElementPtr = B.createStructElementAddr(loc, accessAddress, field);

result = emitLoad(loc, ElementPtr, abstractedTL,
hasAbstractionChange ? SGFContext() : C, IsNotTake);
access.endAccess(*this);
}

// If we're accessing this member with an abstraction change, perform that
// now.
if (hasAbstractionChange)
result =
emitOrigToSubstValue(loc, result, origFormalType, substFormalType, C);
return RValue(*this, loc, substFormalType, result);
}


RValue RValueEmitter::visitDeclRefExpr(DeclRefExpr *E, SGFContext C) {
return SGF.emitRValueForDecl(E, E->getDeclRef(), E->getType(),
E->getAccessSemantics(), C);
Expand Down
Loading