Skip to content

Implement a syntactic peephole for reversing implicit bridging conversions #10987

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 5 commits into from
Jul 15, 2017
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
36 changes: 34 additions & 2 deletions include/swift/Basic/ExternalUnion.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#ifndef SWIFT_BASIC_EXTERNALUNION_H
#define SWIFT_BASIC_EXTERNALUNION_H

#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "swift/Basic/type_traits.h"
#include <utility>
#include <assert.h>
Expand Down Expand Up @@ -160,6 +160,26 @@ class BasicExternalUnion {
return reinterpret_cast<const T &>(Storage);
}

/// Destruct the current union member.
template <class T>
void resetToEmptyWithoutIndex() {
constexpr int typeIndex = indexOf<T, Members...>::value;
static_assert(typeIndex != -1, "type not in union");

reinterpret_cast<T&>(Storage).T::~T();
}

/// Destroy the current union member.
template <class T>
void resetToEmpty(int oldIndex, int newIndex) {
constexpr int typeIndex = indexOf<T, Members...>::value;
static_assert(typeIndex != -1, "type not in union");
assert(oldIndex == typeIndex && "current kind is wrong for value");
assert(newIndex == -1 && "new kind is not in union");

reinterpret_cast<T&>(Storage).T::~T();
}

/// Copy-construct the union from another union.
void copyConstruct(int index, const BasicExternalUnion &other) {
if (index != -1) {
Expand Down Expand Up @@ -252,6 +272,18 @@ class ExternalUnion {
#endif
}

/// Destroy the current member of the union and switch to a member
/// that has no storage.
template <class T>
void resetToEmpty(Kind curKind, Kind newKind) {
#ifndef NDEBUG
return Union.template resetToEmpty<T>(GetIndexForKind(curKind),
GetIndexForKind(newKind));
#else
return Union.template resetToEmptyWithoutIndex<T>();
#endif
}

/// Return a reference to a union member, asserting that the current
/// kind is right.
template <class T>
Expand Down Expand Up @@ -299,7 +331,7 @@ class ExternalUnion {
/// Destroy the union from another union.
void destruct(Kind kind) {
Union.destruct(GetIndexForKind(kind));
}
}
};

/// A helper class for defining special members.
Expand Down
231 changes: 183 additions & 48 deletions lib/SILGen/ArgumentSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,32 +26,49 @@ RValue &ArgumentSource::forceAndPeekRValue(SILGenFunction &SGF) & {
return peekRValue();
}

auto expr = asKnownExpr();
// Extract an r-value.
SILLocation loc = getLocation();
RValue value = std::move(*this).getAsRValue(SGF);

// Destroy the current state.
Storage.destruct(StoredKind);

// Emplace the r-value back into the source.
StoredKind = Kind::RValue;
new (&Storage.TheRV.Value) RValue(SGF.emitRValue(expr));
Storage.TheRV.Loc = expr;
return Storage.TheRV.Value;
Storage.emplaceAggregate<RValueStorage>(StoredKind, std::move(value), loc);

return peekRValue();
}

RValue &ArgumentSource::peekRValue() & {
assert(isRValue() && "Undefined behavior to call this method without the "
"ArgumentSource actually being an RValue");
return Storage.TheRV.Value;
return Storage.get<RValueStorage>(StoredKind).Value;
}

void ArgumentSource::rewriteType(CanType newType) & {
assert(!isLValue());
if (isRValue()) {
Storage.TheRV.Value.rewriteType(newType);
} else {
Expr *expr = Storage.TheExpr;
switch (StoredKind) {
case Kind::Invalid:
llvm_unreachable("argument source is invalid");
case Kind::LValue:
llvm_unreachable("cannot rewrite type of l-value");
case Kind::Tuple:
llvm_unreachable("cannot rewrite type of tuple");
case Kind::RValue:
Storage.get<RValueStorage>(StoredKind).Value.rewriteType(newType);
return;
case Kind::Expr:
Expr *expr = Storage.get<Expr*>(StoredKind);
if (expr->getType()->isEqual(newType)) return;
llvm_unreachable("unimplemented! hope it doesn't happen");
}
llvm_unreachable("bad kind");
}

bool ArgumentSource::requiresCalleeToEvaluate() {
bool ArgumentSource::requiresCalleeToEvaluate() const {
switch (StoredKind) {
case Kind::Invalid:
llvm_unreachable("argument source is invalid");
case Kind::RValue:
case Kind::LValue:
return false;
Expand Down Expand Up @@ -85,38 +102,103 @@ bool ArgumentSource::requiresCalleeToEvaluate() {
}
}
return false;
case Kind::Tuple:
for (auto &source : Storage.get<TupleStorage>(StoredKind).Elements) {
if (source.requiresCalleeToEvaluate())
return true;
}
return false;
}

llvm_unreachable("Unhandled Kind in switch.");
llvm_unreachable("bad kind");
}

RValue ArgumentSource::getAsRValue(SILGenFunction &SGF, SGFContext C) && {
assert(!isLValue());
if (isRValue())
switch (StoredKind) {
case Kind::Invalid:
llvm_unreachable("argument source is invalid");
case Kind::LValue:
llvm_unreachable("cannot get l-value as r-value");
case Kind::RValue:
return std::move(*this).asKnownRValue();
case Kind::Expr:
return SGF.emitRValue(std::move(*this).asKnownExpr(), C);
case Kind::Tuple:
return std::move(*this).getKnownTupleAsRValue(SGF, C);
}
llvm_unreachable("bad kind");
}

RValue
ArgumentSource::getKnownTupleAsRValue(SILGenFunction &SGF, SGFContext C) && {

return std::move(*this).withKnownTupleElementSources<RValue>(
[&](SILLocation loc, CanTupleType type,
MutableArrayRef<ArgumentSource> elements) {
// If there's a target initialization, and we can split it, do so.
if (auto init = C.getEmitInto()) {
if (init->canSplitIntoTupleElements()) {
// Split the tuple.
SmallVector<InitializationPtr, 4> scratch;
auto eltInits = init->splitIntoTupleElements(SGF, loc, type, scratch);

// Emit each element into the corresponding element initialization.
for (auto i : indices(eltInits)) {
std::move(elements[i]).forwardInto(SGF, eltInits[i].get());
}

// Finish initialization.
init->finishInitialization(SGF);

return SGF.emitRValue(std::move(*this).asKnownExpr(), C);
return RValue::forInContext();
}
}

// Otherwise, emit all of the elements into a single big r-value.
RValue result(type);
for (auto &element : elements) {
result.addElement(std::move(element).getAsRValue(SGF));
}
return result;
});
}

ManagedValue ArgumentSource::getAsSingleValue(SILGenFunction &SGF,
SGFContext C) && {
if (isRValue()) {
auto loc = getKnownRValueLocation();
return std::move(*this).asKnownRValue().getAsSingleValue(SGF, loc);
}
if (isLValue()) {
switch (StoredKind) {
case Kind::Invalid:
llvm_unreachable("argument source is invalid");
case Kind::LValue: {
auto loc = getKnownLValueLocation();
return SGF.emitAddressOfLValue(loc, std::move(*this).asKnownLValue(),
AccessKind::ReadWrite);
}

auto e = std::move(*this).asKnownExpr();
if (e->getType()->is<InOutType>()) {
return SGF.emitAddressOfLValue(e, SGF.emitLValue(e, AccessKind::ReadWrite),
AccessKind::ReadWrite);
} else {
return SGF.emitRValueAsSingleValue(e, C);
case Kind::RValue: {
auto loc = getKnownRValueLocation();
if (auto init = C.getEmitInto()) {
std::move(*this).asKnownRValue().forwardInto(SGF, loc, init);
return ManagedValue::forInContext();
} else {
return std::move(*this).asKnownRValue().getAsSingleValue(SGF, loc);
}
}
case Kind::Expr: {
auto e = std::move(*this).asKnownExpr();
if (e->getType()->is<InOutType>()) {
return SGF.emitAddressOfLValue(e, SGF.emitLValue(e, AccessKind::ReadWrite),
AccessKind::ReadWrite);
} else {
return SGF.emitRValueAsSingleValue(e, C);
}
}
case Kind::Tuple: {
auto loc = getKnownTupleLocation();
auto rvalue = std::move(*this).getKnownTupleAsRValue(SGF, C);
if (rvalue.isInContext())
return ManagedValue::forInContext();
return std::move(rvalue).getAsSingleValue(SGF, loc);
}
}
llvm_unreachable("bad kind");
}


Expand All @@ -131,40 +213,58 @@ ManagedValue ArgumentSource::getAsSingleValue(SILGenFunction &SGF,
ManagedValue ArgumentSource::getConverted(SILGenFunction &SGF,
const Conversion &conversion,
SGFContext C) && {
assert(!isLValue());

if (isRValue()) {
auto loc = getKnownRValueLocation();
auto result = std::move(*this).asKnownRValue().getAsSingleValue(SGF, loc);
return conversion.emit(SGF, loc, result, C);
switch (StoredKind) {
case Kind::Invalid:
llvm_unreachable("argument source is invalid");
case Kind::LValue:
llvm_unreachable("cannot get converted l-value");
case Kind::RValue:
case Kind::Expr:
case Kind::Tuple:
return SGF.emitConvertedRValue(getLocation(), conversion, C,
[&](SILGenFunction &SGF, SILLocation loc, SGFContext C) {
return std::move(*this).getAsSingleValue(SGF, C);
});
}

auto e = std::move(*this).asKnownExpr();
assert(!e->getType()->is<InOutType>());
return SGF.emitConvertedRValue(e, conversion, C);
llvm_unreachable("bad kind");
}

void ArgumentSource::forwardInto(SILGenFunction &SGF, Initialization *dest) && {
assert(!isLValue());
if (isRValue()) {
switch (StoredKind) {
case Kind::Invalid:
llvm_unreachable("argument source is invalid");
case Kind::LValue:
llvm_unreachable("cannot forward an l-value");
case Kind::RValue: {
auto loc = getKnownRValueLocation();
return std::move(*this).asKnownRValue().forwardInto(SGF, loc, dest);
std::move(*this).asKnownRValue().forwardInto(SGF, loc, dest);
return;
}

auto e = std::move(*this).asKnownExpr();
return SGF.emitExprInto(e, dest);
case Kind::Expr: {
auto e = std::move(*this).asKnownExpr();
SGF.emitExprInto(e, dest);
return;
}
case Kind::Tuple: {
auto loc = getKnownTupleLocation();
auto rvalue = std::move(*this).getKnownTupleAsRValue(SGF, SGFContext(dest));
if (!rvalue.isInContext())
std::move(rvalue).forwardInto(SGF, loc, dest);
return;
}
}
llvm_unreachable("bad kind");
}

ManagedValue ArgumentSource::materialize(SILGenFunction &SGF) && {
assert(!isLValue());
if (isRValue()) {
auto loc = getKnownRValueLocation();
return std::move(*this).asKnownRValue().materialize(SGF, loc);
}

auto expr = std::move(*this).asKnownExpr();
auto temp = SGF.emitTemporary(expr, SGF.getTypeLowering(expr->getType()));
SGF.emitExprInto(expr, temp.get());
auto loc = getLocation();
auto temp = SGF.emitTemporary(loc, SGF.getTypeLowering(getSubstType()));
std::move(*this).forwardInto(SGF, temp.get());
return temp->getManagedAddress();
}

Expand Down Expand Up @@ -245,3 +345,38 @@ SILType ArgumentSource::getSILSubstType(SILGenFunction &SGF) const & {
AbstractionPattern origType(funcType->getGenericSignature(), substType);
return SGF.getLoweredType(origType, substType);
}

void ArgumentSource::dump() const {
dump(llvm::errs());
}
void ArgumentSource::dump(raw_ostream &out, unsigned indent) const {
out.indent(indent) << "ArgumentSource::";
switch (StoredKind) {
case Kind::Invalid:
out << "Invalid\n";
return;
case Kind::LValue:
out << "LValue\n";
Storage.get<LValueStorage>(StoredKind).Value.dump(out, indent + 2);
return;
case Kind::Tuple: {
out << "Tuple\n";
auto &storage = Storage.get<TupleStorage>(StoredKind);
storage.SubstType.dump(out, indent + 2);
for (auto &elt : storage.Elements) {
elt.dump(out, indent + 2);
out << '\n';
}
return;
}
case Kind::RValue:
out << "RValue\n";
Storage.get<RValueStorage>(StoredKind).Value.dump(out, indent + 2);
return;
case Kind::Expr:
out << "Expr\n";
Storage.get<Expr*>(StoredKind)->dump(out); // FIXME: indent
return;
}
llvm_unreachable("bad kind");
}
Loading