mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Correct format: ``` //===--- Name of file - Description ----------------------------*- Lang -*-===// ``` Notes: * Comment line should be exactly 80 chars. * Padding: Pad with dashes after "Description" to reach 80 chars. * "Name of file", "Description" and "Lang" are all optional. * In case of missing "Lang": drop the "-*-" markers. * In case of missing space: drop one, two or three dashes before "Name of file".
306 lines
9.1 KiB
C++
306 lines
9.1 KiB
C++
//===--- ArgumentSource.h - Abstracted source of an argument ----*- C++ -*-===//
|
|
//
|
|
// 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 http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// A structure for holding an abstracted source of a call argument.
|
|
// It's either:
|
|
//
|
|
// - an expression, yielding an l-value or r-value
|
|
// - an RValue
|
|
// - an LValue
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_LOWERING_ARGUMENTSOURCE_H
|
|
#define SWIFT_LOWERING_ARGUMENTSOURCE_H
|
|
|
|
#include "RValue.h"
|
|
#include "LValue.h"
|
|
|
|
namespace swift {
|
|
namespace Lowering {
|
|
|
|
/// A means of generating an argument.
|
|
///
|
|
/// This is useful as a way to pass values around without either:
|
|
/// - requiring them to have already been evaluated or
|
|
/// - requiring them to come from an identifiable expression.
|
|
///
|
|
/// Being able to propagate values is important because there are a
|
|
/// number of cases (involving, say, property accessors) where values
|
|
/// are implicitly or previously generated. However, being able to
|
|
/// propagate Expr*s is also important because there are several kinds
|
|
/// of expressions (such as closures) which can be emitted more
|
|
/// efficiently with a known target abstraction level.
|
|
///
|
|
/// Because an ArgumentSource might contain an unevaluated expression,
|
|
/// care must be taken when dealing with multiple ArgumentSources to
|
|
/// preserve the original evaluation order of the program. APIs
|
|
/// working with multiple ArgumentSources should document the order in
|
|
/// which they plan to evaluate them.
|
|
class ArgumentSource {
|
|
union Storage {
|
|
struct {
|
|
RValue Value;
|
|
SILLocation Loc;
|
|
} TheRV;
|
|
struct {
|
|
LValue Value;
|
|
SILLocation Loc;
|
|
} TheLV;
|
|
Expr *TheExpr;
|
|
|
|
Storage() {}
|
|
~Storage() {}
|
|
} Storage;
|
|
|
|
enum class Kind : unsigned char {
|
|
RValue,
|
|
LValue,
|
|
Expr,
|
|
} StoredKind;
|
|
|
|
void initRV(SILLocation loc, RValue &&value) {
|
|
assert(StoredKind == Kind::RValue);
|
|
Storage.TheRV.Loc = loc;
|
|
new (&Storage.TheRV.Value) RValue(std::move(value));
|
|
}
|
|
|
|
void initLV(SILLocation loc, LValue &&value) {
|
|
assert(StoredKind == Kind::LValue);
|
|
Storage.TheLV.Loc = loc;
|
|
new (&Storage.TheLV.Value) LValue(std::move(value));
|
|
}
|
|
|
|
public:
|
|
ArgumentSource() : StoredKind(Kind::Expr) {
|
|
Storage.TheExpr = nullptr;
|
|
}
|
|
ArgumentSource(SILLocation loc, RValue &&value) : StoredKind(Kind::RValue) {
|
|
initRV(loc, std::move(value));
|
|
}
|
|
ArgumentSource(SILLocation loc, LValue &&value) : StoredKind(Kind::LValue) {
|
|
initLV(loc, std::move(value));
|
|
}
|
|
ArgumentSource(Expr *e) : StoredKind(Kind::Expr) {
|
|
assert(e && "initializing ArgumentSource with null expression");
|
|
Storage.TheExpr = e;
|
|
}
|
|
|
|
// Cannot be copied.
|
|
ArgumentSource(const ArgumentSource &other) = delete;
|
|
ArgumentSource &operator=(const ArgumentSource &other) = delete;
|
|
|
|
// Can be moved.
|
|
ArgumentSource(ArgumentSource &&other) : StoredKind(other.StoredKind) {
|
|
switch (StoredKind) {
|
|
case Kind::RValue:
|
|
initRV(other.getKnownRValueLocation(), std::move(other).asKnownRValue());
|
|
return;
|
|
case Kind::LValue:
|
|
initLV(other.getKnownLValueLocation(), std::move(other).asKnownLValue());
|
|
return;
|
|
case Kind::Expr:
|
|
Storage.TheExpr = std::move(other).asKnownExpr();
|
|
return;
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
ArgumentSource &operator=(ArgumentSource &&other) {
|
|
// If the kinds don't align, just move the other object over this.
|
|
if (StoredKind != other.StoredKind) {
|
|
this->~ArgumentSource();
|
|
new (this) ArgumentSource(std::move(other));
|
|
return *this;
|
|
}
|
|
|
|
// Otherwise, move RValue and LValue objects in-place.
|
|
switch (StoredKind) {
|
|
case Kind::RValue:
|
|
Storage.TheRV.Value = std::move(other).asKnownRValue();
|
|
Storage.TheRV.Loc = other.getKnownRValueLocation();
|
|
return *this;
|
|
case Kind::LValue:
|
|
Storage.TheLV.Value = std::move(other).asKnownLValue();
|
|
Storage.TheLV.Loc = other.getKnownLValueLocation();
|
|
return *this;
|
|
case Kind::Expr:
|
|
Storage.TheExpr = std::move(other).asKnownExpr();
|
|
return *this;
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
~ArgumentSource() {
|
|
switch (StoredKind) {
|
|
case Kind::RValue:
|
|
asKnownRValue().~RValue();
|
|
return;
|
|
case Kind::LValue:
|
|
asKnownLValue().~LValue();
|
|
return;
|
|
case Kind::Expr:
|
|
return;
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
explicit operator bool() const & {
|
|
switch (StoredKind) {
|
|
case Kind::RValue:
|
|
return bool(asKnownRValue());
|
|
case Kind::LValue:
|
|
return asKnownLValue().isValid();
|
|
case Kind::Expr:
|
|
return asKnownExpr() != nullptr;
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
CanType getSubstType() const & {
|
|
switch (StoredKind) {
|
|
case Kind::RValue:
|
|
return asKnownRValue().getType();
|
|
case Kind::LValue:
|
|
return CanInOutType::get(asKnownLValue().getSubstFormalType());
|
|
case Kind::Expr:
|
|
return asKnownExpr()->getType()->getCanonicalType();
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
CanType getSubstRValueType() const & {
|
|
switch (StoredKind) {
|
|
case Kind::RValue:
|
|
return asKnownRValue().getType();
|
|
case Kind::LValue:
|
|
return asKnownLValue().getSubstFormalType();
|
|
case Kind::Expr:
|
|
return asKnownExpr()->getType()->getInOutObjectType()->getCanonicalType();
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
bool hasLValueType() const & {
|
|
switch (StoredKind) {
|
|
case Kind::RValue: return false;
|
|
case Kind::LValue: return true;
|
|
case Kind::Expr: return asKnownExpr()->getType()->is<InOutType>();
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
SILLocation getLocation() const & {
|
|
switch (StoredKind) {
|
|
case Kind::RValue:
|
|
return getKnownRValueLocation();
|
|
case Kind::LValue:
|
|
return getKnownLValueLocation();
|
|
case Kind::Expr:
|
|
return asKnownExpr();
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
bool isRValue() const & { return StoredKind == Kind::RValue; }
|
|
bool isLValue() const & { return StoredKind == Kind::LValue; }
|
|
|
|
/// Given that this source is storing an RValue, extract and clear
|
|
/// that value.
|
|
RValue &&asKnownRValue() && {
|
|
assert(isRValue());
|
|
return std::move(Storage.TheRV.Value);
|
|
}
|
|
SILLocation getKnownRValueLocation() const & {
|
|
assert(isRValue());
|
|
return Storage.TheRV.Loc;
|
|
}
|
|
|
|
/// Given that this source is storing an LValue, extract and clear
|
|
/// that value.
|
|
LValue &&asKnownLValue() && {
|
|
assert(isLValue());
|
|
return std::move(Storage.TheLV.Value);
|
|
}
|
|
SILLocation getKnownLValueLocation() const & {
|
|
assert(isLValue());
|
|
return Storage.TheLV.Loc;
|
|
}
|
|
|
|
/// Given that this source is an expression, extract and clear
|
|
/// that expression.
|
|
Expr *asKnownExpr() && {
|
|
assert(StoredKind == Kind::Expr);
|
|
Expr *result = Storage.TheExpr;
|
|
Storage.TheExpr = nullptr;
|
|
return result;
|
|
}
|
|
|
|
/// Force this source to become an r-value, then return an unmoved
|
|
/// handle to that r-value.
|
|
RValue &forceAndPeekRValue(SILGenFunction &gen) &;
|
|
|
|
/// Return an unowned handle to the r-value stored in this source. Undefined
|
|
/// if this ArgumentSource is not an rvalue.
|
|
RValue &peekRValue() &;
|
|
|
|
RValue getAsRValue(SILGenFunction &gen, SGFContext C = SGFContext()) &&;
|
|
ManagedValue getAsSingleValue(SILGenFunction &gen,
|
|
SGFContext C = SGFContext()) &&;
|
|
ManagedValue getAsSingleValue(SILGenFunction &gen,
|
|
AbstractionPattern origFormalType,
|
|
SGFContext C = SGFContext()) &&;
|
|
|
|
void forwardInto(SILGenFunction &gen, Initialization *dest) &&;
|
|
void forwardInto(SILGenFunction &gen, AbstractionPattern origFormalType,
|
|
Initialization *dest, const TypeLowering &destTL) &&;
|
|
|
|
ManagedValue materialize(SILGenFunction &gen) &&;
|
|
|
|
/// Emit this value to memory so that it follows the abstraction
|
|
/// patterns of the original formal type.
|
|
///
|
|
/// \param expectedType - the lowering of getSubstType() under the
|
|
/// abstractions of origFormalType
|
|
ManagedValue materialize(SILGenFunction &gen,
|
|
AbstractionPattern origFormalType,
|
|
SILType expectedType = SILType()) &&;
|
|
|
|
// This is a hack and should be avoided.
|
|
void rewriteType(CanType newType) &;
|
|
|
|
private:
|
|
// Make the non-move accessors private to make it more difficult
|
|
// to accidentally re-emit values.
|
|
const RValue &asKnownRValue() const & {
|
|
assert(isRValue());
|
|
return Storage.TheRV.Value;
|
|
}
|
|
|
|
// Make the non-move accessors private to make it more difficult
|
|
// to accidentally re-emit values.
|
|
const LValue &asKnownLValue() const & {
|
|
assert(isLValue());
|
|
return Storage.TheLV.Value;
|
|
}
|
|
|
|
Expr *asKnownExpr() const & {
|
|
assert(StoredKind == Kind::Expr);
|
|
return Storage.TheExpr;
|
|
}
|
|
};
|
|
|
|
} // end namespace Lowering
|
|
} // end namespace swift
|
|
|
|
#endif
|