//===--- Callee.h - Information about a physical callee ---------*- 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 // //===----------------------------------------------------------------------===// // // This file defines the Callee type, which stores all necessary // information about a physical callee. // //===----------------------------------------------------------------------===// #ifndef SWIFT_IRGEN_CALLEE_H #define SWIFT_IRGEN_CALLEE_H #include #include "llvm/IR/DerivedTypes.h" #include "swift/SIL/SILType.h" #include "CallingConvention.h" #include "Explosion.h" #include "IRGen.h" namespace llvm { class PointerType; } namespace swift { class Substitution; namespace irgen { class Callee; class IRGenFunction; /// Abstract information about how we can emit a call. class AbstractCallee { /// The best explosion level available for the call. unsigned ExplosionLevel : 1; /// The kind of extra data this call receives. unsigned Data : 2; /// The abstract calling convention. unsigned Convention : 4; /// The min uncurrying level available for the function. unsigned MinUncurryLevel : 2; /// The max uncurrying level available for the function. unsigned MaxUncurryLevel : 9; public: AbstractCallee(SILFunctionTypeRepresentation convention, ResilienceExpansion level, unsigned minUncurry, unsigned maxUncurry, ExtraData data) : ExplosionLevel(unsigned(level)), Data(unsigned(data)), Convention(unsigned(convention)), MinUncurryLevel(minUncurry), MaxUncurryLevel(maxUncurry) {} static AbstractCallee forIndirect() { return AbstractCallee(SILFunctionTypeRepresentation::Thin, ResilienceExpansion::Minimal, /*min uncurry*/ 0, /*max uncurry*/ 0, ExtraData::Retainable); } SILFunctionTypeRepresentation getRepresentation() const { return SILFunctionTypeRepresentation(Convention); } /// Returns the best explosion level at which we can emit this /// call. We assume that we can call it at lower levels. ResilienceExpansion getBestExplosionLevel() const { return ResilienceExpansion(ExplosionLevel); } /// Whether the function requires a data pointer. bool needsDataPointer() const { return getExtraData() != ExtraData::None; } /// Whether the function requires a data pointer. ExtraData getExtraData() const { return ExtraData(Data); } /// The maximum uncurrying level at which the function can be called. unsigned getMaxUncurryLevel() const { return MaxUncurryLevel; } /// The minimum uncurrying level at which the function can be called. unsigned getMinUncurryLevel() const { return MinUncurryLevel; } }; class Callee { /// The unsubstituted function type being called. CanSILFunctionType OrigFnType; /// The substituted result type of the function being called. CanSILFunctionType SubstFnType; /// The pointer to the actual function. llvm::Value *FnPtr; /// The data pointer required by the function. There's an /// invariant that this never stores an llvm::ConstantPointerNull. llvm::Value *DataPtr; /// The archetype substitutions under which the function is being /// called. std::vector Substitutions; public: Callee() = default; /// Prepare a callee for a known freestanding function that /// requires no data pointer. static Callee forFreestandingFunction(CanSILFunctionType origFnType, CanSILFunctionType substFnType, ArrayRef subs, llvm::Constant *fn) { return forKnownFunction(origFnType, substFnType, subs, fn, nullptr); } /// Prepare a callee for a known instance method. Methods never /// require a data pointer. The formal type here should /// include the 'self' clause. static Callee forMethod(CanSILFunctionType origFnType, CanSILFunctionType substFnType, ArrayRef subs, llvm::Constant *fn) { return forKnownFunction(origFnType, substFnType, subs, fn, nullptr); } /// Prepare a callee for a known function with a known data pointer. static Callee forKnownFunction(CanSILFunctionType origFnType, CanSILFunctionType substFnType, ArrayRef subs, llvm::Value *fn, llvm::Value *data) { // Invariant on the function pointer. assert(cast(fn->getType()) ->getElementType()->isFunctionTy()); Callee result; result.OrigFnType = origFnType; result.SubstFnType = substFnType; result.FnPtr = fn; result.DataPtr = data; result.Substitutions = subs; return result; } SILFunctionTypeRepresentation getRepresentation() const { return OrigFnType->getRepresentation(); } CanSILFunctionType getOrigFunctionType() const { return OrigFnType; } CanSILFunctionType getSubstFunctionType() const { return SubstFnType; } bool hasSubstitutions() const { return !Substitutions.empty(); } ArrayRef getSubstitutions() const { return Substitutions; } llvm::Value *getFunction() const { return FnPtr; } llvm::FunctionType *getLLVMFunctionType() { return cast(FnPtr->getType()->getPointerElementType()); } /// Return the function pointer as an i8*. llvm::Value *getOpaqueFunctionPointer(IRGenFunction &IGF) const; /// Return the function pointer as an appropriate pointer-to-function. llvm::Value *getFunctionPointer() const { return FnPtr; } /// Is it possible that this function requires a non-null data pointer? bool hasDataPointer() const { return DataPtr != nullptr; } /// Return the data pointer as a %swift.refcounted*. llvm::Value *getDataPointer(IRGenFunction &IGF) const; }; } // end namespace irgen } // end namespace swift #endif