Files
swift-mirror/lib/SILGen/RValue.cpp
John McCall 20e58dcf93 Change the type of function values in SIL to SILFunctionType.
Perform major abstraction remappings in SILGen.  Introduce
thunking functions as necessary to map between abstraction
patterns.

Swift SVN r10562
2013-11-19 22:55:09 +00:00

573 lines
18 KiB
C++

//===--- RValue.cpp - Exploded RValue Representation ------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// A storage structure for holding a destructured rvalue with an optional
// cleanup(s).
// Ownership of the rvalue can be "forwarded" to disable the associated
// cleanup(s).
//
//===----------------------------------------------------------------------===//
#include "Initialization.h"
#include "SILGen.h"
#include "RValue.h"
#include "swift/SIL/SILArgument.h"
#include "swift/AST/CanTypeVisitor.h"
#include <deque>
using namespace swift;
using namespace Lowering;
namespace {
static unsigned getTupleSize(CanType t) {
if (TupleType *tt = dyn_cast<TupleType>(t))
return tt->getNumElements();
return 1;
}
class ExplodeTupleValue
: public CanTypeVisitor<ExplodeTupleValue,
/*RetTy=*/ void,
/*Args...=*/ ManagedValue, SILLocation>
{
public:
std::vector<ManagedValue> &values;
SILGenFunction &gen;
ExplodeTupleValue(std::vector<ManagedValue> &values,
SILGenFunction &gen)
: values(values), gen(gen)
{
}
void visitType(CanType t, ManagedValue v, SILLocation l) {
values.push_back(v);
}
void visitTupleType(CanTupleType t, ManagedValue mv, SILLocation l) {
SILValue v = mv.forward(gen);
if (v.getType().isAddressOnly(gen.F.getModule())) {
// Destructure address-only types by addressing the individual members.
for (unsigned i = 0, size = t->getNumElements(); i < size; ++i) {
CanType fieldCanTy = t.getElementType(i);
auto &fieldTI = gen.getTypeLowering(fieldCanTy);
SILType fieldTy = fieldTI.getLoweredType();
SILValue member = gen.B.createTupleElementAddr(l, v, i,
fieldTy.getAddressType());
assert(fieldTI.getSemanticType() == fieldTy);
if (fieldTI.isLoadable() && !isa<LValueType>(fieldCanTy))
member = gen.B.createLoad(l, member);
visit(fieldCanTy, gen.emitManagedRValueWithCleanup(member, fieldTI), l);
}
} else {
// Extract the elements from loadable tuples.
for (unsigned i = 0, size = t->getNumElements(); i < size; ++i) {
CanType fieldCanTy = t.getElementType(i);
auto &fieldTI = gen.getTypeLowering(fieldCanTy);
assert(fieldTI.isLoadable());
SILValue member = gen.B.createTupleExtract(l, v, i,
fieldTI.getLoweredType());
visit(fieldCanTy, gen.emitManagedRValueWithCleanup(member, fieldTI), l);
}
}
}
};
enum class ImplodeKind { Unmanaged, Forward };
template<ImplodeKind KIND>
class ImplodeLoadableTupleValue
: public CanTypeVisitor<ImplodeLoadableTupleValue<KIND>,
/*RetTy=*/ SILValue,
/*Args...=*/ SILLocation>
{
public:
ArrayRef<ManagedValue> values;
SILGenFunction &gen;
static SILValue getValue(SILGenFunction &gen, ManagedValue v) {
switch (KIND) {
case ImplodeKind::Unmanaged:
return v.getUnmanagedValue();
case ImplodeKind::Forward:
return v.forward(gen);
}
}
ImplodeLoadableTupleValue(ArrayRef<ManagedValue> values,
SILGenFunction &gen)
: values(values), gen(gen)
{}
SILValue visitType(CanType t, SILLocation l) {
SILValue result = getValue(gen, values[0]);
values = values.slice(1);
return result;
}
SILValue visitTupleType(CanTupleType t, SILLocation l) {
SmallVector<SILValue, 4> elts;
for (auto fieldTy : t.getElementTypes())
elts.push_back(this->visit(fieldTy, l));
SILType ty = gen.getLoweredLoadableType(t);
return gen.B.createTuple(l, ty, elts);
}
~ImplodeLoadableTupleValue() {
assert(values.empty() && "values not exhausted imploding tuple?!");
}
};
class ImplodeAddressOnlyTuple
: public CanTypeVisitor<ImplodeAddressOnlyTuple,
/*RetTy=*/ void,
/*Args...=*/ SILValue, SILLocation>
{
public:
ArrayRef<ManagedValue> values;
SILGenFunction &gen;
ImplodeAddressOnlyTuple(ArrayRef<ManagedValue> values,
SILGenFunction &gen)
: values(values), gen(gen)
{}
void visitType(CanType t, SILValue address, SILLocation l) {
ManagedValue v = values[0];
v.forwardInto(gen, l, address);
values = values.slice(1);
}
void visitTupleType(CanTupleType t, SILValue address, SILLocation l) {
for (unsigned n = 0, size = t->getNumElements(); n < size; ++n) {
CanType fieldCanTy = t.getElementType(n);
SILType fieldTy = gen.getLoweredType(fieldCanTy);
SILValue fieldAddr = gen.B.createTupleElementAddr(l,
address, n,
fieldTy.getAddressType());
this->visit(fieldCanTy, fieldAddr, l);
}
}
~ImplodeAddressOnlyTuple() {
assert(values.empty() && "values not exhausted imploding tuple?!");
}
};
template<ImplodeKind KIND>
static SILValue implodeTupleValues(ArrayRef<ManagedValue> values,
SILGenFunction &gen,
CanType tupleType, SILLocation l) {
// Non-tuples don't need to be imploded.
if (!isa<TupleType>(tupleType)) {
assert(values.size() == 1 && "exploded non-tuple value?!");
return ImplodeLoadableTupleValue<KIND>::getValue(gen, values[0]);
}
SILType loweredType = gen.getLoweredType(tupleType);
// To implode an address-only tuple, we need to create a buffer to hold the
// result tuple.
if (loweredType.isAddressOnly(gen.F.getModule())) {
assert(KIND != ImplodeKind::Unmanaged &&
"address-only values are always managed!");
SILValue buffer = gen.emitTemporaryAllocation(l, loweredType);
ImplodeAddressOnlyTuple(values, gen).visit(tupleType, buffer, l);
return buffer;
}
// To implode loadable tuples, we just need to combine the elements with
// TupleInsts.
return ImplodeLoadableTupleValue<KIND>(values, gen).visit(tupleType, l);
}
class InitializeTupleValues
: public CanTypeVisitor<InitializeTupleValues,
/*RetTy=*/ void,
/*Args...=*/ Initialization*>
{
public:
ArrayRef<ManagedValue> values;
SILGenFunction &gen;
SILLocation loc;
InitializeTupleValues(ArrayRef<ManagedValue> values, SILGenFunction &gen,
SILLocation l)
: values(values), gen(gen), loc(l)
{}
void visitType(CanType t, Initialization *I) {
// Pop a result off.
ManagedValue result = values[0];
values = values.slice(1);
switch (I->kind) {
case Initialization::Kind::AddressBinding:
llvm_unreachable("cannot emit into a inout binding");
case Initialization::Kind::Tuple:
llvm_unreachable("tuple initialization not destructured?!");
case Initialization::Kind::Ignored:
// Throw out the value without storing it.
return;
case Initialization::Kind::Translating:
I->translateValue(gen, loc, result);
I->finishInitialization(gen);
return;
case Initialization::Kind::SingleBuffer: {
// If we didn't evaluate into the initialization buffer, do so now.
if (result.getValue() != I->getAddress()) {
result.forwardInto(gen, loc, I->getAddress());
} else {
// If we did evaluate into the initialization buffer, disable the
// cleanup.
result.forwardCleanup(gen);
}
I->finishInitialization(gen);
return;
}
}
}
void visitTupleType(CanTupleType t, Initialization *I) {
// Break up the aggregate initialization.
SmallVector<InitializationPtr, 4> subInitBuf;
auto subInits = I->getSubInitializationsForTuple(gen, t, subInitBuf, loc);
assert(subInits.size() == t->getNumElements() &&
"initialization does not match tuple?!");
for (unsigned i = 0, e = subInits.size(); i < e; ++i)
visit(t.getElementType(i), subInits[i].get());
}
};
class EmitBBArguments : public CanTypeVisitor<EmitBBArguments,
/*RetTy*/ RValue>
{
public:
SILGenFunction &gen;
SILBasicBlock *parent;
SILLocation loc;
EmitBBArguments(SILGenFunction &gen, SILBasicBlock *parent,
SILLocation l)
: gen(gen), parent(parent), loc(l) {}
RValue visitType(CanType t) {
SILValue arg = new (gen.SGM.M)
SILArgument(gen.getLoweredType(t), parent, loc.getAsASTNode<VarDecl>());
ManagedValue mv = isa<LValueType>(t)
? ManagedValue(arg, ManagedValue::LValue)
: gen.emitManagedRValueWithCleanup(arg);
return RValue(gen, loc, t, mv);
}
RValue visitTupleType(CanTupleType t) {
RValue rv{t};
for (auto fieldType : t.getElementTypes())
rv.addElement(visit(fieldType));
return rv;
}
};
} // end anonymous namespace
/// Return the number of rvalue elements in the given canonical type.
static unsigned getRValueSize(CanType type) {
if (auto tupleType = dyn_cast<TupleType>(type)) {
unsigned count = 0;
for (auto eltType : tupleType.getElementTypes())
count += getRValueSize(eltType);
return count;
}
return 1;
}
RValue::RValue(ArrayRef<ManagedValue> values, CanType type)
: values(values.begin(), values.end()), type(type), elementsToBeAdded(0)
{
}
RValue::RValue(SILGenFunction &gen, SILLocation l, CanType formalType,
ManagedValue v)
: type(formalType), elementsToBeAdded(0)
{
ExplodeTupleValue(values, gen).visit(type, v, l);
assert(values.size() == getRValueSize(type));
}
RValue::RValue(SILGenFunction &gen, Expr *expr, ManagedValue v)
: type(expr->getType()->getCanonicalType()), elementsToBeAdded(0)
{
ExplodeTupleValue(values, gen).visit(type, v, expr);
assert(values.size() == getRValueSize(type));
}
RValue::RValue(CanType type)
: type(type), elementsToBeAdded(getTupleSize(type)) {
}
RValue RValue::emitBBArguments(CanType type,
SILGenFunction &gen,
SILBasicBlock *parent,
SILLocation l) {
return EmitBBArguments(gen, parent, l).visit(type);
}
void RValue::addElement(RValue &&element) & {
assert(!isComplete() && "rvalue already complete");
assert(!isUsed() && "rvalue already used");
--elementsToBeAdded;
values.insert(values.end(),
element.values.begin(), element.values.end());
element.makeUsed();
assert(!isComplete() || values.size() == getRValueSize(type));
}
void RValue::addElement(SILGenFunction &gen, ManagedValue element,
CanType formalType, SILLocation l) & {
assert(!isComplete() && "rvalue already complete");
assert(!isUsed() && "rvalue already used");
--elementsToBeAdded;
ExplodeTupleValue(values, gen).visit(formalType, element, l);
assert(!isComplete() || values.size() == getRValueSize(type));
}
SILValue RValue::forwardAsSingleValue(SILGenFunction &gen, SILLocation l) && {
assert(isComplete() && "rvalue is not complete");
SILValue result
= implodeTupleValues<ImplodeKind::Forward>(values, gen, type, l);
makeUsed();
return result;
}
SILValue RValue::forwardAsSingleStorageValue(SILGenFunction &gen,
SILType storageType,
SILLocation l) && {
assert(isComplete() && "rvalue is not complete");
SILValue result = std::move(*this).forwardAsSingleValue(gen, l);
return gen.emitConversionFromSemanticValue(l, result, storageType);
}
void RValue::forwardInto(SILGenFunction &gen, Initialization *I,
SILLocation loc) && {
assert(isComplete() && "rvalue is not complete");
InitializeTupleValues(values, gen, loc).visit(type, I);
}
ManagedValue RValue::getAsSingleValue(SILGenFunction &gen, SILLocation l) && {
// Avoid killing and re-emitting the cleanup if the enclosed value isn't a
// tuple.
if (!isa<TupleType>(type)) {
assert(values.size() == 1 && "exploded non-tuple?!");
ManagedValue result = values[0];
makeUsed();
return result;
}
// Forward into a single value, then install a cleanup on the resulting
// imploded value.
return gen.emitManagedRValueWithCleanup(
std::move(*this).forwardAsSingleValue(gen, l));
}
SILValue RValue::getUnmanagedSingleValue(SILGenFunction &gen,
SILLocation l) const & {
assert(isComplete() && "rvalue is not complete");
return implodeTupleValues<ImplodeKind::Unmanaged>(values, gen, type, l);
}
void RValue::forwardAll(SILGenFunction &gen,
SmallVectorImpl<SILValue> &dest) && {
assert(isComplete() && "rvalue is not complete");
for (auto value : values)
dest.push_back(value.forward(gen));
makeUsed();
}
void RValue::getAll(SmallVectorImpl<ManagedValue> &dest) && {
assert(isComplete() && "rvalue is not complete");
dest.append(values.begin(), values.end());
makeUsed();
}
void RValue::getAllUnmanaged(SmallVectorImpl<SILValue> &dest) const & {
assert(isComplete() && "rvalue is not complete");
for (auto value : values)
dest.push_back(value.getUnmanagedValue());
}
/// Return the range of indexes for the given tuple type element.
static std::pair<unsigned,unsigned>
getElementRange(CanTupleType tupleType, unsigned eltIndex) {
assert(eltIndex < tupleType->getNumElements());
unsigned begin = 0;
for (unsigned i = 0; i < eltIndex; ++i) {
begin += getRValueSize(tupleType.getElementType(i));
}
unsigned end = begin + getRValueSize(tupleType.getElementType(eltIndex));
return { begin, end };
}
RValue RValue::extractElement(unsigned n) && {
assert(isComplete() && "rvalue is not complete");
auto tupleTy = cast<TupleType>(type);
auto range = getElementRange(tupleTy, n);
unsigned from = range.first, to = range.second;
CanType eltType = cast<TupleType>(type).getElementType(n);
RValue element(llvm::makeArrayRef(values).slice(from, to - from), eltType);
makeUsed();
return element;
}
void RValue::extractElements(SmallVectorImpl<RValue> &elements) && {
assert(isComplete() && "rvalue is not complete");
unsigned from = 0;
for (auto eltType : cast<TupleType>(type).getElementTypes()) {
unsigned to = from + getRValueSize(eltType);
elements.push_back({llvm::makeArrayRef(values).slice(from, to - from),
eltType});
from = to;
}
assert(from == values.size());
makeUsed();
}
RValue::RValue(const RValue &copied, SILGenFunction &gen, SILLocation l)
: type(copied.type),
elementsToBeAdded(copied.elementsToBeAdded)
{
assert((copied.isComplete() || copied.isUsed())
&& "can't copy incomplete rvalue");
values.reserve(copied.values.size());
for (ManagedValue value : copied.values) {
values.push_back(value.copy(gen, l));
}
}
void ManagedValue::forwardInto(SILGenFunction &gen, SILLocation loc,
SILValue address) {
if (hasCleanup())
forwardCleanup(gen);
auto &addrTL = gen.getTypeLowering(address.getType());
gen.emitSemanticStore(loc, getValue(), address, addrTL, IsInitialization);
}
void ManagedValue::assignInto(SILGenFunction &gen, SILLocation loc,
SILValue address) {
if (hasCleanup())
forwardCleanup(gen);
auto &addrTL = gen.getTypeLowering(address.getType());
gen.emitSemanticStore(loc, getValue(), address, addrTL,
IsNotInitialization);
}
ManagedValue RValue::materialize(SILGenFunction &gen, SILLocation loc) && {
auto &paramTL = gen.getTypeLowering(getType());
// If we're already materialized, we're done.
if (values.size() == 1 &&
values[0].getType() == paramTL.getLoweredType().getAddressType()) {
auto value = values[0];
makeUsed();
return value;
}
// Otherwise, emit to a temporary.
auto temp = gen.emitTemporary(loc, paramTL);
std::move(*this).forwardInto(gen, temp.get(), loc);
return temp->getManagedAddress();
}
RValue &RValueSource::forceAndPeekRValue(SILGenFunction &gen) & {
if (isRValue()) {
return Storage.TheRV.Value;
}
auto expr = asKnownExpr();
IsRValue = true;
new (&Storage.TheRV.Value) RValue(gen.emitRValue(expr));
Storage.TheRV.Loc = expr;
return Storage.TheRV.Value;
}
void RValueSource::rewriteType(CanType newType) & {
if (isRValue()) {
Storage.TheRV.Value.rewriteType(newType);
} else {
Expr *expr = Storage.TheExpr;
if (expr->getType()->isEqual(newType)) return;
assert(0 && "unimplemented! hope it doesn't happen");
}
}
RValue RValueSource::getAsRValue(SILGenFunction &gen) && {
if (isRValue()) {
return std::move(*this).asKnownRValue();
} else {
return gen.emitRValue(std::move(*this).asKnownExpr());
}
}
ManagedValue RValueSource::getAsSingleValue(SILGenFunction &gen) && {
if (isRValue()) {
auto loc = getKnownRValueLocation();
return std::move(*this).asKnownRValue().getAsSingleValue(gen, loc);
}
auto e = std::move(*this).asKnownExpr();
return gen.emitRValue(e).getAsSingleValue(gen, e);
}
void RValueSource::forwardInto(SILGenFunction &gen, Initialization *dest) && {
if (isRValue()) {
auto loc = getKnownRValueLocation();
return std::move(*this).asKnownRValue().forwardInto(gen, dest, loc);
}
auto e = std::move(*this).asKnownExpr();
return gen.emitExprInto(e, dest);
}
ManagedValue RValueSource::materialize(SILGenFunction &gen) && {
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();
}