mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
192 lines
6.5 KiB
C++
192 lines
6.5 KiB
C++
//===--- ArgumentSource.cpp - Latent value representation -----------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// A structure for holding a r-value or l-value
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "ArgumentSource.h"
|
|
#include "Initialization.h"
|
|
|
|
using namespace swift;
|
|
using namespace Lowering;
|
|
|
|
RValue &ArgumentSource::forceAndPeekRValue(SILGenFunction &gen) & {
|
|
if (isRValue()) {
|
|
return peekRValue();
|
|
}
|
|
|
|
auto expr = asKnownExpr();
|
|
StoredKind = Kind::RValue;
|
|
new (&Storage.TheRV.Value) RValue(gen.emitRValue(expr));
|
|
Storage.TheRV.Loc = expr;
|
|
return Storage.TheRV.Value;
|
|
}
|
|
|
|
RValue &ArgumentSource::peekRValue() & {
|
|
assert(isRValue() && "Undefined behavior to call this method without the "
|
|
"ArgumentSource actually being an RValue");
|
|
return Storage.TheRV.Value;
|
|
}
|
|
|
|
void ArgumentSource::rewriteType(CanType newType) & {
|
|
assert(!isLValue());
|
|
if (isRValue()) {
|
|
Storage.TheRV.Value.rewriteType(newType);
|
|
} else {
|
|
Expr *expr = Storage.TheExpr;
|
|
if (expr->getType()->isEqual(newType)) return;
|
|
llvm_unreachable("unimplemented! hope it doesn't happen");
|
|
}
|
|
}
|
|
|
|
bool ArgumentSource::requiresCalleeToEvaluate() {
|
|
switch (StoredKind) {
|
|
case Kind::RValue:
|
|
case Kind::LValue:
|
|
return false;
|
|
case Kind::Expr:
|
|
return isa<TupleShuffleExpr>(asKnownExpr());
|
|
}
|
|
|
|
llvm_unreachable("Unhandled Kind in switch.");
|
|
}
|
|
|
|
RValue ArgumentSource::getAsRValue(SILGenFunction &gen, SGFContext C) && {
|
|
assert(!isLValue());
|
|
if (isRValue())
|
|
return std::move(*this).asKnownRValue();
|
|
|
|
return gen.emitRValue(std::move(*this).asKnownExpr(), C);
|
|
}
|
|
|
|
ManagedValue ArgumentSource::getAsSingleValue(SILGenFunction &gen,
|
|
SGFContext C) && {
|
|
if (isRValue()) {
|
|
auto loc = getKnownRValueLocation();
|
|
return std::move(*this).asKnownRValue().getAsSingleValue(gen, loc);
|
|
}
|
|
if (isLValue()) {
|
|
auto loc = getKnownLValueLocation();
|
|
return gen.emitAddressOfLValue(loc, std::move(*this).asKnownLValue(),
|
|
AccessKind::ReadWrite);
|
|
}
|
|
|
|
auto e = std::move(*this).asKnownExpr();
|
|
if (e->getType()->is<InOutType>()) {
|
|
return gen.emitAddressOfLValue(e, gen.emitLValue(e, AccessKind::ReadWrite),
|
|
AccessKind::ReadWrite);
|
|
} else {
|
|
return gen.emitRValueAsSingleValue(e, C);
|
|
}
|
|
}
|
|
|
|
|
|
ManagedValue ArgumentSource::getAsSingleValue(SILGenFunction &gen,
|
|
AbstractionPattern origFormalType,
|
|
SGFContext C) && {
|
|
auto loc = getLocation();
|
|
auto substFormalType = getSubstType();
|
|
ManagedValue outputValue = std::move(*this).getAsSingleValue(gen);
|
|
return gen.emitSubstToOrigValue(loc,
|
|
outputValue, origFormalType,
|
|
substFormalType, C);
|
|
}
|
|
|
|
void ArgumentSource::forwardInto(SILGenFunction &gen, Initialization *dest) && {
|
|
assert(!isLValue());
|
|
if (isRValue()) {
|
|
auto loc = getKnownRValueLocation();
|
|
return std::move(*this).asKnownRValue().forwardInto(gen, loc, dest);
|
|
}
|
|
|
|
auto e = std::move(*this).asKnownExpr();
|
|
return gen.emitExprInto(e, dest);
|
|
}
|
|
|
|
ManagedValue ArgumentSource::materialize(SILGenFunction &gen) && {
|
|
assert(!isLValue());
|
|
if (isRValue()) {
|
|
auto loc = getKnownRValueLocation();
|
|
return std::move(*this).asKnownRValue().materialize(gen, loc);
|
|
}
|
|
|
|
auto expr = std::move(*this).asKnownExpr();
|
|
auto temp = gen.emitTemporary(expr, gen.getTypeLowering(expr->getType()));
|
|
gen.emitExprInto(expr, temp.get());
|
|
return temp->getManagedAddress();
|
|
}
|
|
|
|
ManagedValue ArgumentSource::materialize(SILGenFunction &SGF,
|
|
AbstractionPattern origFormalType,
|
|
SILType destType) && {
|
|
auto substFormalType = CanType(getSubstType()->getInOutObjectType());
|
|
assert(!destType || destType.getObjectType() ==
|
|
SGF.SGM.Types.getLoweredType(origFormalType,
|
|
substFormalType).getObjectType());
|
|
|
|
// Fast path: if the types match exactly, no abstraction difference
|
|
// is possible and we can just materialize as normal.
|
|
if (origFormalType.isExactType(substFormalType))
|
|
return std::move(*this).materialize(SGF);
|
|
|
|
auto &destTL =
|
|
(destType ? SGF.getTypeLowering(destType)
|
|
: SGF.getTypeLowering(origFormalType, substFormalType));
|
|
if (!destType) destType = destTL.getLoweredType();
|
|
|
|
// If there's no abstraction difference, we can just materialize as normal.
|
|
if (destTL.getLoweredType() == SGF.getLoweredType(substFormalType)) {
|
|
return std::move(*this).materialize(SGF);
|
|
}
|
|
|
|
// Emit a temporary at the given address.
|
|
auto temp = SGF.emitTemporary(getLocation(), destTL);
|
|
|
|
// Forward into it.
|
|
std::move(*this).forwardInto(SGF, origFormalType, temp.get(), destTL);
|
|
|
|
return temp->getManagedAddress();
|
|
}
|
|
|
|
void ArgumentSource::forwardInto(SILGenFunction &SGF,
|
|
AbstractionPattern origFormalType,
|
|
Initialization *dest,
|
|
const TypeLowering &destTL) && {
|
|
auto substFormalType = getSubstType();
|
|
assert(destTL.getLoweredType() ==
|
|
SGF.getLoweredType(origFormalType, substFormalType));
|
|
|
|
// If there are no abstraction changes, we can just forward
|
|
// normally.
|
|
if (origFormalType.isExactType(substFormalType) ||
|
|
destTL.getLoweredType() == SGF.getLoweredType(substFormalType)) {
|
|
std::move(*this).forwardInto(SGF, dest);
|
|
return;
|
|
}
|
|
|
|
// Otherwise, emit as a single independent value.
|
|
SILLocation loc = getLocation();
|
|
ManagedValue outputValue =
|
|
std::move(*this).getAsSingleValue(SGF, origFormalType,
|
|
SGFContext(dest));
|
|
|
|
if (outputValue.isInContext()) return;
|
|
|
|
// Use RValue's forward-into-initialization code. We have to lie to
|
|
// RValue about the formal type (by using the lowered type) because
|
|
// we're emitting into an abstracted value, which RValue doesn't
|
|
// really handle.
|
|
auto substLoweredType = destTL.getLoweredType().getSwiftRValueType();
|
|
RValue(SGF, loc, substLoweredType, outputValue).forwardInto(SGF, loc, dest);
|
|
}
|