Files
swift-mirror/lib/SILGen/SILGenFunction.h
Joe Groff a3a54545e5 SIL: Fix up ownership and bridging when emitting dynamic method calls.
There were a bunch of things broken here--it's amazing this ever appeared to work.

- Retain 'self' before partial_applying it to the method, so we don't overrelease it.
- Correctly lower the ownership conventions of the dynamic method against the SILDeclRef, so we don't overrelease arguments or over-over-release self, and we handle ObjC methods with weird conventions correctly.
- Thunk when there are bridging type differences between the partially-applied ObjC method and a Swift method, so we don't crash if the method takes NSStrings or other bridged types.

Add verifier checks that the result of 'dynamic_method' and BB arg of 'dynamic_method_br' actually match the method they're dispatching.

Swift SVN r17198
2014-05-01 22:46:11 +00:00

962 lines
40 KiB
C++

//===--- SILGenFunction.h - Function Specific AST lower context -*- 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
//
//===----------------------------------------------------------------------===//
#ifndef SILGENFUNCTION_H
#define SILGENFUNCTION_H
#include "SILGen.h"
#include "Condition.h"
#include "JumpDest.h"
#include "swift/AST/AnyFunctionRef.h"
#include "llvm/ADT/PointerIntPair.h"
#include "swift/SIL/SILBuilder.h"
namespace swift {
namespace Lowering {
struct Materialize;
/// SGFContext - Internal context information for the SILGenFunction visitor.
///
/// In general, emission methods which take an SGFContext indicate
/// that they've initialized the emit-into buffer (if they have) by
/// returning a "isInContext()" ManagedValue of whatever type. Callers who
/// propagate down an SGFContext that might have a emit-into buffer must be
/// aware of this.
///
/// Clients of emission routines that take an SGFContext can also specify that
/// they are ok getting back an RValue at +0 instead of requiring it to be at
/// +1. The client is then responsible for checking the ManagedValue to see if
/// it got back a ManagedValue at +0 or +1.
class SGFContext {
llvm::PointerIntPair<Initialization *, 1, bool> state;
public:
SGFContext() = default;
enum AllowPlusZero_t {
AllowPlusZero
};
/// Creates an emitInto context that will store the result of the visited expr
/// into the given Initialization.
explicit SGFContext(Initialization *emitInto) : state(emitInto, false) {
}
/*implicit*/
SGFContext(AllowPlusZero_t) : state(nullptr, true) {
}
/// Returns a pointer to the Initialization that the current expression should
/// store its result to, or null if the expression should allocate temporary
/// storage for its result.
Initialization *getEmitInto() const {
return state.getPointer();
}
/// Return true if a ManagedValue producer is encouraged to return its value
/// at +0 instead of +1.
bool isPlusZeroOk() const {
return state.getInt();
}
};
class SwitchContext;
struct LValueWriteback;
/// SILGenFunction - an ASTVisitor for producing SIL from function bodies.
class LLVM_LIBRARY_VISIBILITY SILGenFunction
: public ASTVisitor<SILGenFunction>
{ // style violation because Xcode <rdar://problem/13065676>
public:
/// The SILGenModule this function belongs to.
SILGenModule &SGM;
/// The SILFunction being constructed.
SILFunction &F;
/// The name of the function currently being emitted, as presented to user
/// code by __FUNCTION__.
DeclName MagicFunctionName;
std::string MagicFunctionString;
ASTContext &getASTContext() const { return SGM.M.getASTContext(); }
/// This is used to keep track of all SILInstructions inserted by \c B.
SmallVector<SILInstruction*, 32> InsertedInstrs;
size_t LastInsnWithoutScope;
/// B - The SILBuilder used to construct the SILFunction. It is what maintains
/// the notion of the current block being emitted into.
SILBuilder B;
/// IndirectReturnAddress - For a function with an indirect return, holds a
/// value representing the address to initialize with the return value. Null
/// for a function that returns by value.
SILValue IndirectReturnAddress;
std::vector<std::tuple<LabeledStmt*, JumpDest, JumpDest>>
BreakContinueDestStack;
std::vector<SwitchContext*> SwitchStack;
/// Keep track of our current nested scope.
std::vector<SILDebugScope*> DebugScopeStack;
/// The cleanup depth and BB for when the operand of a
/// BindOptionalExpr is a missing value.
SmallVector<JumpDest, 2> BindOptionalFailureDests;
/// The cleanup depth and epilog BB for "return" instructions.
JumpDest ReturnDest;
/// \brief True if a non-void return is required in this function.
bool NeedsReturn : 1;
/// FIXME: Hack to temporarily use dispatched delegation only for
/// convenience initializers.
bool isConvenienceInit = false;
/// \brief The SIL location corresponding to the AST node being processed.
SILLocation CurrentSILLoc;
/// Cleanups - This records information about the currently active cleanups.
CleanupManager Cleanups;
/// The stack of pending writebacks.
std::vector<LValueWriteback> *WritebackStack = 0;
std::vector<LValueWriteback> &getWritebackStack();
bool InWritebackScope = false;
bool InInOutConversionScope = false;
/// freeWritebackStack - Just deletes WritebackStack. Out of line to avoid
/// having to put the definition of LValueWriteback in this header.
void freeWritebackStack();
/// VarLoc - representation of an emitted local variable. Local variables can
/// either have a singular constant value that is always returned (in which
/// case VarLoc holds that value), or may be emitted into a box. If they are
/// emitted into a box, the retainable pointer is also stored.
struct VarLoc {
/// addressOrValue - the address at which the variable is stored, or the
/// value of the decl if it is a constant.
llvm::PointerIntPair<SILValue, 1, bool> addressOrValue;
public:
/// box - For a non-constant value, this is the retainable box for the
/// variable. It may be invalid if no box was made for the value (e.g.,
/// because it was an inout value, or constant).
SILValue box;
bool isConstant() const { return addressOrValue.getInt(); }
bool isAddress() const { return !isConstant(); }
SILValue getAddress() const {
assert(isAddress() && "Can't get the address of a constant");
return addressOrValue.getPointer();
}
SILValue getConstant() const {
assert(isConstant() && "Emit a load to get the value of an address");
return addressOrValue.getPointer();
}
static VarLoc getConstant(SILValue Val) {
VarLoc Result;
Result.addressOrValue.setPointerAndInt(Val, true);
return Result;
}
static VarLoc getAddress(SILValue Addr, SILValue Box = SILValue()) {
VarLoc Result;
Result.addressOrValue.setPointerAndInt(Addr, false);
Result.box = Box;
return Result;
}
};
/// VarLocs - Entries in this map are generated when a PatternBindingDecl is
/// emitted. The map is queried to produce the lvalue for a DeclRefExpr to
/// a local variable.
llvm::DenseMap<ValueDecl*, VarLoc> VarLocs;
/// LocalFunctions - Entries in this map are generated when a local function
/// declaration that requires local context, such as a func closure, is
/// emitted. This map is then queried to produce the value for a DeclRefExpr
/// to a local constant.
llvm::DenseMap<SILDeclRef, SILValue> LocalFunctions;
/// Mapping from active opaque value expressions to their values,
/// along with a bit for each indicating whether it has been consumed yet.
llvm::DenseMap<OpaqueValueExpr *, std::pair<SILValue, bool>> OpaqueValues;
/// RAII object that introduces a temporary binding for an opaque value.
///
/// Each time the opaque value expression is referenced, it will be
/// retained/released separately. When this RAII object goes out of
/// scope, the value will be destroyed if requested.
class OpaqueValueRAII {
SILGenFunction &Self;
OpaqueValueExpr *OpaqueValue;
bool Destroy;
OpaqueValueRAII(const OpaqueValueRAII &) = delete;
OpaqueValueRAII &operator=(const OpaqueValueRAII &) = delete;
public:
OpaqueValueRAII(SILGenFunction &self, OpaqueValueExpr *opaqueValue,
SILValue value, bool destroy)
: Self(self), OpaqueValue(opaqueValue), Destroy(destroy)
{
assert(Self.OpaqueValues.count(OpaqueValue) == 0 &&
"Opaque value already has a binding");
Self.OpaqueValues[OpaqueValue] = std::make_pair(value, false);
}
~OpaqueValueRAII();
};
/// True if 'return' without an operand or falling off the end of the current
/// function is valid.
bool allowsVoidReturn() const {
return ReturnDest.getBlock()->bbarg_empty();
}
/// This location, when set, is used as an override location for magic
/// identifier expansion (e.g. __FILE__). This allows default argument
/// expansion to report the location of the call, instead of the location
/// of the original expr.
SourceLoc overrideLocationForMagicIdentifiers;
SILGenFunction(SILGenModule &SGM, SILFunction &F);
~SILGenFunction();
/// Return a stable reference to the current cleanup.
CleanupsDepth getCleanupsDepth() const {
return Cleanups.getCleanupsDepth();
}
CleanupHandle getTopCleanup() const {
return Cleanups.getTopCleanup();
}
SILFunction &getFunction() { return F; }
SILBuilder &getBuilder() { return B; }
const TypeLowering &getTypeLowering(AbstractionPattern orig, Type subst,
unsigned uncurryLevel = 0) {
return SGM.Types.getTypeLowering(orig, subst, uncurryLevel);
}
const TypeLowering &getTypeLowering(Type t, unsigned uncurryLevel = 0) {
return SGM.Types.getTypeLowering(t, uncurryLevel);
}
SILType getLoweredType(AbstractionPattern orig, Type subst,
unsigned uncurryLevel = 0) {
return SGM.Types.getLoweredType(orig, subst, uncurryLevel);
}
SILType getLoweredType(Type t, unsigned uncurryLevel = 0) {
return SGM.Types.getLoweredType(t, uncurryLevel);
}
SILType getLoweredLoadableType(Type t, unsigned uncurryLevel = 0) {
return SGM.Types.getLoweredLoadableType(t, uncurryLevel);
}
const TypeLowering &getTypeLowering(SILType type) {
return SGM.Types.getTypeLowering(type);
}
SILConstantInfo getConstantInfo(SILDeclRef constant) {
return SGM.Types.getConstantInfo(constant);
}
SourceManager &getSourceManager() { return SGM.M.getASTContext().SourceMgr; }
/// enterDebugScope - Push a new debug scope and set its parent pointer.
void enterDebugScope(SILDebugScope *DS) {
if (DebugScopeStack.size())
DS->setParent(DebugScopeStack.back());
else
DS->setParent(F.getDebugScope());
DebugScopeStack.push_back(DS);
setDebugScopeForInsertedInstrs(DS->Parent);
}
/// enterDebugScope - return to the previous debug scope.
void leaveDebugScope() {
assert(DebugScopeStack.size());
setDebugScopeForInsertedInstrs(DebugScopeStack.back());
DebugScopeStack.pop_back();
}
/// Set the debug scope for all SILInstructions that where emitted
/// from when we entered the last scope up to the current one.
void setDebugScopeForInsertedInstrs(SILDebugScope *DS) {
while (LastInsnWithoutScope < InsertedInstrs.size()) {
InsertedInstrs[LastInsnWithoutScope++]->setDebugScope(DS);
}
}
//===--------------------------------------------------------------------===//
// Entry points for codegen
//===--------------------------------------------------------------------===//
/// \brief Generates code for a FuncDecl.
void emitFunction(FuncDecl *fd);
/// \brief Emits code for a ClosureExpr.
void emitClosure(AbstractClosureExpr *ce);
/// Generates code for a class destroying destructor. This
/// emits the body code from the DestructorDecl, calls the base class
/// destructor, then implicitly releases the elements of the class.
void emitDestroyingDestructor(DestructorDecl *dd);
/// Generates code for a class deallocating destructor. This
/// calls the destroying destructor and then deallocates 'self'.
void emitDeallocatingDestructor(DestructorDecl *dd);
/// Generates code for a struct constructor.
/// This allocates the new 'self' value, emits the
/// body code, then returns the final initialized 'self'.
void emitValueConstructor(ConstructorDecl *ctor);
/// Generates code for an enum case constructor.
/// This allocates the new 'self' value, injects the enum case,
/// then returns the final initialized 'self'.
void emitEnumConstructor(EnumElementDecl *element);
/// Generates code for a class constructor's
/// allocating entry point. This allocates the new 'self' value, passes it to
/// the initializer entry point, then returns the initialized 'self'.
void emitClassConstructorAllocator(ConstructorDecl *ctor);
/// Generates code for a class constructor's
/// initializing entry point. This takes 'self' and the constructor arguments
/// as parameters and executes the constructor body to initialize 'self'.
void emitClassConstructorInitializer(ConstructorDecl *ctor);
/// Generates code to initialize instance variables from their
/// initializers.
///
/// \param selfDecl The 'self' declaration within the current function.
/// \param nominal The type whose members are being initialized.
void emitMemberInitializers(VarDecl *selfDecl, NominalTypeDecl *nominal);
/// Emit a method that initializes the ivars of a class.
void emitIVarInitializer(SILDeclRef ivarInitializer);
/// Emit a method that destroys the ivars of a class.
void emitIVarDestroyer(SILDeclRef ivarDestroyer);
/// Generates code to destroy the instance variables of a class.
///
/// \param selfValue The 'self' value.
/// \param cd The class declaration whose members are being destroyed.
void emitClassMemberDestruction(SILValue selfValue, ClassDecl *cd,
RegularLocation loc,
CleanupLocation cleanupLoc);
/// Generates code for a curry thunk from one uncurry level
/// of a function to another.
void emitCurryThunk(FuncDecl *fd, SILDeclRef fromLevel, SILDeclRef toLevel);
/// Generates a thunk from a foreign function to the native Swift conventions.
void emitForeignThunk(SILDeclRef thunk);
// Generate a nullary function that returns the given value.
void emitGeneratorFunction(SILDeclRef function, Expr *value);
/// Generate an ObjC-compatible thunk for a method.
void emitObjCMethodThunk(SILDeclRef thunk);
/// Generate an ObjC-compatible getter for a property or subscript.
void emitObjCGetter(SILDeclRef getter);
/// Generate an ObjC-compatible setter for a property or subscript.
void emitObjCSetter(SILDeclRef setter);
/// Generate an ObjC-compatible destructor (-dealloc).
void emitObjCDestructor(SILDeclRef dtor);
/// Generate a lazy global initializer.
void emitLazyGlobalInitializer(PatternBindingDecl *binding);
/// Generate a global accessor, using the given initializer token and
/// function
void emitGlobalAccessor(VarDecl *global,
FuncDecl *builtinOnceDecl,
SILGlobalVariable *onceToken,
SILFunction *onceFunc);
/// Generate a protocol witness entry point, invoking 'witness' at the
/// abstraction level of 'requirement'.
void emitProtocolWitness(ProtocolConformance *conformance,
SILDeclRef requirement,
SILDeclRef witness,
ArrayRef<Substitution> witnessSubs,
IsFreeFunctionWitness_t isFree,
HasInOutSelfAbstractionDifference_t inOutSelf);
/// Convert a block to a native function with a thunk.
ManagedValue emitBlockToFunc(SILLocation loc,
ManagedValue block,
CanSILFunctionType funcTy);
//===--------------------------------------------------------------------===//
// Control flow
//===--------------------------------------------------------------------===//
/// emitCondition - Emit a boolean expression as a control-flow condition.
///
/// \param E - The expression to be evaluated as a condition.
/// \param hasFalseCode - true if the false branch doesn't just lead
/// to the fallthrough.
/// \param invertValue - true if this routine should invert the value before
/// testing true/false.
/// \param contArgs - the types of the arguments to the continuation BB.
/// Matching argument values must be passed to exitTrue and exitFalse
/// of the resulting Condition object.
Condition emitCondition(Expr *E,
bool hasFalseCode = true, bool invertValue = false,
ArrayRef<SILType> contArgs = {});
Condition emitCondition(SILValue V, SILLocation Loc,
bool hasFalseCode = true, bool invertValue = false,
ArrayRef<SILType> contArgs = {});
SILBasicBlock *createBasicBlock() {
return new (F.getModule()) SILBasicBlock(&F);
}
//===--------------------------------------------------------------------===//
// Memory management
//===--------------------------------------------------------------------===//
/// emitProlog - Generates prolog code to allocate and clean up mutable
/// storage for closure captures and local arguments.
void emitProlog(AnyFunctionRef TheClosure, ArrayRef<Pattern*> paramPatterns,
Type resultType);
void emitProlog(ArrayRef<Pattern*> paramPatterns,
Type resultType, DeclContext *DeclCtx);
/// \brief Create (but do not emit) the epilog branch, and save the
/// current cleanups depth as the destination for return statement branches.
///
/// \param returnType If non-null, the epilog block will be created with an
/// argument of this type to receive the return value for
/// the function.
/// \param L The SILLocation which should be accosocated with
/// cleanup instructions.
void prepareEpilog(Type returnType, CleanupLocation L);
/// \brief Branch to and emit the epilog basic block. This will fuse
/// the epilog to the current basic block if the epilog bb has no predecessor.
/// The insertion point will be moved into the epilog block if it is
/// reachable.
///
/// \param TopLevelLoc The location of the top level AST node for which we are
/// constructing the epilog, such as a AbstractClosureExpr.
/// \returns Nothing if the epilog block is unreachable. Otherwise, returns
/// the epilog block's return value argument, or a null SILValue if
/// the epilog doesn't take a return value. Also returns the location
/// of the return instrcution if the epilog block is supposed to host
/// the ReturnLocation (This happens in case the predecessor block is
/// merged with the epilog block.)
std::pair<Optional<SILValue>, SILLocation>
emitEpilogBB(SILLocation TopLevelLoc);
/// \brief Emits a standard epilog which runs top-level cleanups then returns
/// the function return value, if any.
///
/// \param TopLevelLoc The location of the top-level expression during whose
/// evaluation the epilog is being produced, for example, the
/// AbstractClosureExpr.
/// \param IsAutoGen Flags if the prolog is auto-generated.
void emitEpilog(SILLocation TopLevelLoc, bool IsAutoGen = false);
/// emitSelfDecl - Emit a SILArgument for 'self', register it in varlocs, set
/// up debug info, etc. This returns the 'self' value.
SILValue emitSelfDecl(VarDecl *selfDecl);
/// Emits a temporary allocation that will be deallocated automatically at the
/// end of the current scope. Returns the address of the allocation.
SILValue emitTemporaryAllocation(SILLocation loc, SILType ty);
/// Prepares a buffer to receive the result of an expression, either using the
/// 'emit into' initialization buffer if available, or allocating a temporary
/// allocation if not.
///
/// The caller should call manageBufferForExprResult at the instant
/// that the buffer has been initialized.
SILValue getBufferForExprResult(SILLocation loc, SILType ty, SGFContext C);
/// Flag that the buffer for an expression result has been properly
/// initialized.
///
/// Returns an empty value if the buffer was taken from the context.
ManagedValue manageBufferForExprResult(SILValue buffer,
const TypeLowering &bufferTL,
SGFContext C);
//===--------------------------------------------------------------------===//
// Recursive entry points
//===--------------------------------------------------------------------===//
using ASTVisitorType::visit;
//===--------------------------------------------------------------------===//
// Statements
//===--------------------------------------------------------------------===//
void visitBraceStmt(BraceStmt *S);
void visitReturnStmt(ReturnStmt *S);
void visitIfStmt(IfStmt *S);
void visitIfConfigStmt(IfConfigStmt *S);
void visitWhileStmt(WhileStmt *S);
void visitDoWhileStmt(DoWhileStmt *S);
void visitForStmt(ForStmt *S);
void visitForEachStmt(ForEachStmt *S);
void visitBreakStmt(BreakStmt *S);
void visitContinueStmt(ContinueStmt *S);
void visitFallthroughStmt(FallthroughStmt *S);
void visitSwitchStmt(SwitchStmt *S);
void visitCaseStmt(CaseStmt *S);
//===--------------------------------------------------------------------===//
// Patterns
//===--------------------------------------------------------------------===//
void emitSwitchStmt(SwitchStmt *S);
void emitSwitchFallthrough(FallthroughStmt *S);
//===--------------------------------------------------------------------===//
// Expressions
//===--------------------------------------------------------------------===//
RValue visit(Expr *E) = delete;
/// Generate SIL for the given expression, storing the final result into the
/// specified Initialization buffer(s). This avoids an allocation and copy if
/// the result would be allocated into temporary memory normally.
void emitExprInto(Expr *E, Initialization *I);
/// Emit the given expression as an r-value.
RValue emitRValue(Expr *E, SGFContext C = SGFContext());
/// Emit the given expression, ignoring its result.
void emitIgnoredExpr(Expr *E);
/// Emit the given expression as an r-value, then (if it is a tuple), combine
/// it together into a single ManagedValue.
ManagedValue emitRValueAsSingleValue(Expr *E, SGFContext C = SGFContext());
ManagedValue emitArrayInjectionCall(ManagedValue ObjectPtr,
SILValue BasePtr,
SILValue Length,
Expr *ArrayInjectionFunction,
SILLocation Loc);
SILValue emitConversionToSemanticRValue(SILLocation loc, SILValue value,
const TypeLowering &valueTL);
/// Emit the empty tuple value by emitting
SILValue emitEmptyTuple(SILLocation loc);
/// "Emit" an RValue representing an empty tuple.
RValue emitEmptyTupleRValue(SILLocation loc);
/// Returns a reference to a constant in global context. For local func decls
/// this returns the function constant with unapplied closure context.
SILValue emitGlobalFunctionRef(SILLocation loc, SILDeclRef constant) {
return emitGlobalFunctionRef(loc, constant, getConstantInfo(constant));
}
SILValue emitGlobalFunctionRef(SILLocation loc, SILDeclRef constant,
SILConstantInfo constantInfo);
/// Returns a reference to a constant in local context. This will return a
/// closure object reference if the constant refers to a local func decl.
/// In rvalue contexts, emitFunctionRef should be used instead, which retains
/// a local constant and returns a ManagedValue with a cleanup.
SILValue emitUnmanagedFunctionRef(SILLocation loc, SILDeclRef constant);
/// Returns a reference to a constant in local context. This will return a
/// retained closure object reference if the constant refers to a local func
/// decl.
ManagedValue emitFunctionRef(SILLocation loc, SILDeclRef constant);
ManagedValue emitFunctionRef(SILLocation loc, SILDeclRef constant,
SILConstantInfo constantInfo);
/// Emit the specified VarDecl as an LValue if possible, otherwise return
/// null.
ManagedValue emitLValueForDecl(SILLocation loc, VarDecl *var,
bool isDirectPropertyAccess = false);
/// Produce a singular RValue for a reference to the specified declaration,
/// with the given type and in response to the specified epxression. Try to
/// emit into the specified SGFContext to avoid copies (when provided).
ManagedValue emitRValueForDecl(SILLocation loc, ConcreteDeclRef decl, Type ty,
SGFContext C = SGFContext());
/// Produce a singular RValue for a load from the specified property.
ManagedValue emitRValueForPropertyLoad(SILLocation loc, ManagedValue base,
bool isSuper, VarDecl *property,
ArrayRef<Substitution> substitutions,
bool isDirectPropertyAccess,
Type propTy, SGFContext C);
ManagedValue emitClosureValue(SILLocation loc,
SILDeclRef function,
ArrayRef<Substitution> forwardSubs,
AnyFunctionRef TheClosure);
Materialize emitMaterialize(SILLocation loc, ManagedValue v);
RValueSource prepareAccessorBaseArg(SILLocation loc, ManagedValue base,
AbstractFunctionDecl *decl);
ManagedValue emitGetAccessor(SILLocation loc, AbstractStorageDecl *decl,
ArrayRef<Substitution> substitutions,
RValueSource &&optionalSelfValue,
bool isSuper,
RValue &&optionalSubscripts, SGFContext C);
void emitSetAccessor(SILLocation loc, AbstractStorageDecl *decl,
ArrayRef<Substitution> substitutions,
RValueSource &&optionalSelfValue,
bool isSuper,
RValue &&optionalSubscripts, RValue &&value);
ManagedValue emitApplyConversionFunction(SILLocation loc,
Expr *funcExpr,
Type resultType,
RValue &&operand);
ManagedValue emitManagedRetain(SILLocation loc, SILValue v);
ManagedValue emitManagedRetain(SILLocation loc, SILValue v,
const TypeLowering &lowering);
ManagedValue emitManagedRValueWithCleanup(SILValue v);
ManagedValue emitManagedRValueWithCleanup(SILValue v,
const TypeLowering &lowering);
ManagedValue emitManagedBufferWithCleanup(SILValue addr);
ManagedValue emitManagedBufferWithCleanup(SILValue addr,
const TypeLowering &lowering);
void emitSemanticLoadInto(SILLocation loc, SILValue src,
const TypeLowering &srcLowering,
SILValue dest,
const TypeLowering &destLowering,
IsTake_t isTake, IsInitialization_t isInit);
SILValue emitSemanticLoad(SILLocation loc, SILValue src,
const TypeLowering &srcLowering,
const TypeLowering &rvalueLowering,
IsTake_t isTake);
void emitSemanticStore(SILLocation loc, SILValue value,
SILValue dest, const TypeLowering &destTL,
IsInitialization_t isInit);
SILValue emitConversionFromSemanticValue(SILLocation loc,
SILValue semanticValue,
SILType storageType);
ManagedValue emitLoad(SILLocation loc, SILValue addr,
const TypeLowering &rvalueTL,
SGFContext C, IsTake_t isTake);
void emitAssignToLValue(SILLocation loc, RValue &&src,
const LValue &dest);
void emitAssignLValueToLValue(SILLocation loc,
const LValue &src, const LValue &dest);
void emitCopyLValueInto(SILLocation loc, const LValue &src,
Initialization *dest);
ManagedValue emitAddressOfLValue(SILLocation loc, const LValue &src);
ManagedValue emitLoadOfLValue(SILLocation loc, const LValue &src,
SGFContext C);
/// Emit a reference to a method from within another method of the type, and
/// gather all the substitutions necessary to invoke it, without
/// dynamic dispatch.
std::tuple<ManagedValue, SILType, ArrayRef<Substitution>>
emitSiblingMethodRef(SILLocation loc,
SILValue selfValue,
SILDeclRef methodConstant,
ArrayRef<Substitution> innerSubstitutions);
SILValue emitMetatypeOfValue(SILLocation loc, SILValue base);
void emitReturnExpr(SILLocation loc, Expr *ret);
/// Convert a value with the abstraction patterns of the original type
/// to a value with the abstraction patterns of the substituted type.
ManagedValue emitOrigToSubstValue(SILLocation loc, ManagedValue input,
AbstractionPattern origType,
CanType substType,
SGFContext ctx = SGFContext());
/// Convert a value with the abstraction patterns of the substituted
/// type to a value with the abstraction patterns of the original type.
ManagedValue emitSubstToOrigValue(SILLocation loc, ManagedValue input,
AbstractionPattern origType,
CanType substType,
SGFContext ctx = SGFContext());
/// Convert a value with a specialized representation (such as a thin function
/// reference, or a function reference with a foreign calling convention) to
/// the generalized representation of its Swift type, which can then be stored
/// to a variable or passed as an argument or return value.
ManagedValue emitGeneralizedValue(SILLocation loc, ManagedValue input,
AbstractionPattern origType,
CanType substType,
SGFContext ctxt = SGFContext());
ManagedValue emitGeneralizedFunctionValue(SILLocation loc,
ManagedValue input,
AbstractionPattern origType,
CanAnyFunctionType resultType);
/// Convert a native Swift value to a value that can be passed as an argument
/// to or returned as the result of a function with the given calling
/// convention.
ManagedValue emitNativeToBridgedValue(SILLocation loc, ManagedValue v,
AbstractCC destCC,
CanType origNativeTy,
CanType substNativeTy,
CanType bridgedTy);
/// Convert a value received as the result or argument of a function with
/// the given calling convention to a native Swift value of the given type.
ManagedValue emitBridgedToNativeValue(SILLocation loc, ManagedValue v,
AbstractCC srcCC,
CanType nativeTy);
//
// Helpers for emitting ApplyExpr chains.
//
RValue emitApplyExpr(ApplyExpr *e, SGFContext c);
/// A convenience method for emitApply that just handles monomorphic
/// applications.
ManagedValue emitMonomorphicApply(SILLocation loc,
ManagedValue fn,
ArrayRef<ManagedValue> args,
CanType resultType,
bool transparent = false,
Optional<AbstractCC> overrideCC = Nothing);
ManagedValue emitApplyOfLibraryIntrinsic(SILLocation loc,
FuncDecl *fn,
ArrayRef<Substitution> subs,
ArrayRef<ManagedValue> args,
SGFContext ctx);
/// Emit a dynamic member reference.
RValue emitDynamicMemberRefExpr(DynamicMemberRefExpr *e, SGFContext c);
/// Emit a dynamic subscript.
RValue emitDynamicSubscriptExpr(DynamicSubscriptExpr *e, SGFContext c);
/// \brief Emit an unconditional checked cast, including any necessary
/// abstraction difference between the original and destination types.
///
/// \param loc The AST location associated with the operation.
/// \param original The value to cast.
/// \param origTy The original AST-level type.
/// \param castTy The destination type.
/// \param kind The semantics of the cast.
///
/// \returns the cast value, at its natural abstraction level.
SILValue emitUnconditionalCheckedCast(SILLocation loc,
SILValue original,
Type origTy,
Type castTy,
CheckedCastKind kind);
/// \brief Emits the abstraction change needed, if any, to perform casts from
/// the type represented by \c origTL to each of the types represented by
/// \c castTLs.
///
/// \param loc The AST location associated with the operation.
/// \param original The value to cast.
/// \param origTL The original type.
/// \param castTLs The types to which to cast.
///
/// \returns The value shifted to the highest abstraction level necessary
/// for the casts, or a null SILValue if no abstraction changes are needed.
SILValue emitCheckedCastAbstractionChange(SILLocation loc,
SILValue original,
const TypeLowering &origTL,
ArrayRef<const TypeLowering *> castTLs);
/// \brief Emit a conditional checked cast branch. Does not re-abstract the
/// argument to the success branch. Terminates the current BB.
///
/// \param loc The AST location associated with the operation.
/// \param original The value to cast.
/// \param originalAbstracted
/// The result of \c emitCheckedCastAbstractionChange
/// applied to the original value.
/// \param origTL The original AST-level type.
/// \param castTL The destination type.
/// \param kind The semantics of the cast.
///
/// \returns a pair of SILBasicBlocks, representing the success and failure
/// branches of the cast. The argument to the success block is not adjusted
/// to its natural abstraction level.
std::pair<SILBasicBlock*, SILBasicBlock*>
emitCheckedCastBranch(SILLocation loc,
SILValue original,
SILValue originalAbstracted,
const TypeLowering &origTL,
const TypeLowering &castTL,
CheckedCastKind kind);
/// Initialize a memory location with an optional value.
///
/// \param loc The location to use for the resulting optional.
/// \param value The value to inject into an optional.
/// \param dest The uninitialized memory in which to store the result value.
/// \param optTL Type lowering information for the optional to create.
void emitInjectOptionalValueInto(SILLocation loc,
RValueSource &&value,
SILValue dest,
const TypeLowering &optTL);
/// Initialize a memory location with an optional "nothing"
/// value.
///
/// \param loc The location to use for the resulting optional.
/// \param dest The uninitialized memory in which to store the result value.
/// \param optTL Type lowering information for the optional to create.
void emitInjectOptionalNothingInto(SILLocation loc,
SILValue dest,
const TypeLowering &optTL);
/// \brief Emit a call to the library intrinsic _doesOptionalHaveValue.
///
/// The result is a Builtin.Int1.
SILValue emitDoesOptionalHaveValue(SILLocation loc, SILValue addr);
/// \brief Emit a call to the library intrinsic _getOptionalValue
/// given the address of the optional.
ManagedValue emitGetOptionalValueFrom(SILLocation loc, ManagedValue addr,
const TypeLowering &optTL,
SGFContext C);
typedef std::function<ManagedValue(SILGenFunction &gen,
SILLocation loc,
ManagedValue input,
SILType loweredResultTy)> ValueTransform;
/// Emit a transformation on the value of an optional type.
ManagedValue emitOptionalToOptional(SILLocation loc,
ManagedValue input,
SILType loweredResultTy,
const ValueTransform &transform);
/// Build the type of a function transformation thunk.
CanSILFunctionType buildThunkType(ManagedValue fn,
CanSILFunctionType expectedType,
CanSILFunctionType &substFnType,
SmallVectorImpl<Substitution> &subs);
//===--------------------------------------------------------------------===//
// Declarations
//===--------------------------------------------------------------------===//
void visitDecl(Decl *D) {
llvm_unreachable("Not yet implemented");
}
void visitNominalTypeDecl(NominalTypeDecl *D);
void visitFuncDecl(FuncDecl *D);
void visitPatternBindingDecl(PatternBindingDecl *D);
std::unique_ptr<Initialization> emitPatternBindingInitialization(Pattern *P);
void visitTypeAliasDecl(TypeAliasDecl *D) {
// No lowering support needed.
}
void visitGenericTypeParamDecl(GenericTypeParamDecl *D) {
// No lowering support needed.
}
void visitAssociatedTypeDecl(AssociatedTypeDecl *D) {
// No lowering support needed.
}
void visitVarDecl(VarDecl *D) {
// We handle these in pattern binding.
}
/// Emit an Initialization for a 'var' or 'let' decl in a pattern.
std::unique_ptr<Initialization> emitInitializationForVarDecl(VarDecl *vd,
bool isArgument,
Type patternType);
/// Emit the allocation for a local variable. Returns the address of the
/// value. Does not register a cleanup.
void emitLocalVariable(VarDecl *D);
/// Emit the allocation for a local variable, provides an Initialization
/// that can be used to initialize it, and registers cleanups in the active
/// scope.
std::unique_ptr<Initialization> emitLocalVariableWithCleanup(VarDecl *D);
/// Emit the allocation for a local temporary, provides an
/// Initialization that can be used to initialize it, and registers
/// cleanups in the active scope.
///
/// The initialization is guaranteed to be a single buffer.
std::unique_ptr<TemporaryInitialization>
emitTemporary(SILLocation loc, const TypeLowering &tempTL);
/// Enter a currently-dormant cleanup to destroy the value in the
/// given address.
CleanupHandle enterDormantTemporaryCleanup(SILValue temp,
const TypeLowering &tempTL);
/// Destroy and deallocate an initialized local variable.
void destroyLocalVariable(SILLocation L, VarDecl *D);
/// Deallocate an uninitialized local variable.
void deallocateUninitializedLocalVariable(SILLocation L, VarDecl *D);
/// Enter a cleanup to deallocate a stack variable.
CleanupHandle enterDeallocStackCleanup(SILValue address);
/// Enter a cleanup to emit a ReleaseValue/destroyAddr of the specified value.
CleanupHandle enterDestroyCleanup(SILValue valueOrAddr);
/// Evaluate an Expr as an lvalue.
LValue emitLValue(Expr *E);
/// Emit an lvalue that directly refers to the given instance
/// variable (without going through getters or setters).
LValue emitDirectIVarLValue(SILLocation loc, ManagedValue base, VarDecl *var);
/// Build an identity substitution map for the given generic parameter list.
ArrayRef<Substitution>
buildForwardingSubstitutions(GenericParamList *params);
/// Return forwarding substitutions for the archetypes in the current
/// function.
ArrayRef<Substitution> getForwardingSubstitutions();
};
} // end namespace Lowering
} // end namespace swift
#endif